Convert span's start to line number + col

This requires to make line numbers a first-class citizen in the module
  hierarchy but it is fortunately not _too involved_.
This commit is contained in:
KtorZ 2024-01-18 12:44:20 +01:00
parent e67d5863a1
commit 59c784778e
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
13 changed files with 165 additions and 26 deletions

View File

@ -1,6 +1,7 @@
use crate::{
builtins::{self, bool, g1_element, g2_element},
expr::{TypedExpr, UntypedExpr},
line_numbers::LineNumbers,
parser::token::{Base, Token},
tipo::{PatternConstructor, Type, TypeInfo},
};
@ -42,6 +43,7 @@ pub struct Module<Info, Definitions> {
pub docs: Vec<String>,
pub type_info: Info,
pub definitions: Vec<Definitions>,
pub lines: LineNumbers,
pub kind: ModuleKind,
}

View File

@ -27,10 +27,11 @@ use crate::{
gen_uplc::builder::{
check_replaceable_opaque_type, convert_opaque_type, erase_opaque_type_operations,
find_and_replace_generics, find_list_clause_or_default_first, get_arg_type_name,
get_generic_id_and_type, get_generic_variant_name, get_src_code_by_span, monomorphize,
pattern_has_conditions, wrap_as_multi_validator, wrap_validator_condition, CodeGenFunction,
SpecificClause,
get_generic_id_and_type, get_generic_variant_name, get_line_columns_by_span,
get_src_code_by_span, monomorphize, pattern_has_conditions, wrap_as_multi_validator,
wrap_validator_condition, CodeGenFunction, SpecificClause,
},
line_numbers::LineNumbers,
tipo::{
ModuleValueConstructor, PatternConstructor, Type, TypeInfo, ValueConstructor,
ValueConstructorVariant,
@ -55,7 +56,7 @@ pub struct CodeGenerator<'a> {
functions: IndexMap<FunctionAccessKey, &'a TypedFunction>,
data_types: IndexMap<DataTypeKey, &'a TypedDataType>,
module_types: IndexMap<&'a String, &'a TypeInfo>,
module_src: IndexMap<String, String>,
module_src: IndexMap<String, (String, LineNumbers)>,
/// immutable option
tracing: TraceLevel,
/// mutable index maps that are reset
@ -74,7 +75,7 @@ impl<'a> CodeGenerator<'a> {
functions: IndexMap<FunctionAccessKey, &'a TypedFunction>,
data_types: IndexMap<DataTypeKey, &'a TypedDataType>,
module_types: IndexMap<&'a String, &'a TypeInfo>,
module_src: IndexMap<String, String>,
module_src: IndexMap<String, (String, LineNumbers)>,
tracing: TraceLevel,
) -> Self {
CodeGenerator {
@ -132,10 +133,10 @@ impl<'a> CodeGenerator<'a> {
air_tree_fun = wrap_validator_condition(air_tree_fun, self.tracing);
let src_code = self.module_src.get(module_name).unwrap().clone();
let (src_code, lines) = self.module_src.get(module_name).unwrap().clone();
let mut validator_args_tree =
self.check_validator_args(&fun.arguments, true, air_tree_fun, &src_code);
self.check_validator_args(&fun.arguments, true, air_tree_fun, &src_code, &lines);
validator_args_tree = AirTree::no_op().hoist_over(validator_args_tree);
@ -154,8 +155,13 @@ impl<'a> CodeGenerator<'a> {
air_tree_fun_other = wrap_validator_condition(air_tree_fun_other, self.tracing);
let mut validator_args_tree_other =
self.check_validator_args(&other.arguments, true, air_tree_fun_other, &src_code);
let mut validator_args_tree_other = self.check_validator_args(
&other.arguments,
true,
air_tree_fun_other,
&src_code,
&lines,
);
validator_args_tree_other = AirTree::no_op().hoist_over(validator_args_tree_other);
@ -474,8 +480,12 @@ impl<'a> CodeGenerator<'a> {
if kind.is_expect() {
let msg = match self.tracing {
TraceLevel::Silent => unreachable!("excluded from pattern guards"),
// TODO: line number & col
TraceLevel::Compact => format!("{}", location.start),
TraceLevel::Compact => get_line_columns_by_span(
module_name,
location,
&self.module_src,
)
.to_string(),
TraceLevel::Verbose => {
get_src_code_by_span(module_name, location, &self.module_src)
}
@ -2746,6 +2756,7 @@ impl<'a> CodeGenerator<'a> {
has_context: bool,
body: AirTree,
src_code: &str,
lines: &LineNumbers,
) -> AirTree {
let checked_args = arguments
.iter()
@ -2764,8 +2775,10 @@ impl<'a> CodeGenerator<'a> {
TraceLevel::Compact | TraceLevel::Verbose => {
let msg = match self.tracing {
TraceLevel::Silent => unreachable!("excluded from pattern guards"),
// TODO: Show line number + column
TraceLevel::Compact => format!("{}", arg_span.start),
TraceLevel::Compact => lines
.line_and_column_number(arg_span.start)
.expect("Out of bounds span")
.to_string(),
TraceLevel::Verbose => src_code
.get(arg_span.start..arg_span.end)
.expect("Out of bounds span")

View File

@ -20,6 +20,7 @@ use crate::{
},
builtins::{bool, data, function, int, list, string, void},
expr::TypedExpr,
line_numbers::{LineColumn, LineNumbers},
tipo::{PatternConstructor, TypeVar, ValueConstructor, ValueConstructorVariant},
};
@ -1775,9 +1776,9 @@ pub fn extract_constant(term: &Term<Name>) -> Option<Rc<UplcConstant>> {
pub fn get_src_code_by_span(
module_name: &String,
span: &Span,
module_src: &IndexMap<String, String>,
module_src: &IndexMap<String, (String, LineNumbers)>,
) -> String {
let src = module_src
let (src, _) = module_src
.get(module_name)
.unwrap_or_else(|| panic!("Missing module {module_name}"));
@ -1786,6 +1787,20 @@ pub fn get_src_code_by_span(
.to_string()
}
pub fn get_line_columns_by_span(
module_name: &String,
span: &Span,
module_src: &IndexMap<String, (String, LineNumbers)>,
) -> LineColumn {
let (_, lines) = module_src
.get(module_name)
.unwrap_or_else(|| panic!("Missing module {module_name}"));
lines
.line_and_column_number(span.start)
.expect("Out of bounds span")
}
pub fn air_holds_msg(air: &Air) -> bool {
match air {
Air::AssertConstr { .. } | Air::AssertBool { .. } | Air::FieldsEmpty | Air::ListEmpty => {

View File

@ -1,6 +1,6 @@
use std::fmt::{self, Display};
#[derive(Debug)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct LineNumbers {
line_starts: Vec<usize>,
length: usize,

View File

@ -15,7 +15,7 @@ pub use definition::parser as definition;
pub use expr::parser as expression;
pub use pattern::parser as pattern;
use crate::ast;
use crate::{ast, line_numbers::LineNumbers};
use chumsky::prelude::*;
use error::ParseError;
use extra::ModuleExtra;
@ -30,8 +30,11 @@ pub fn module(
let definitions = definition().repeated().then_ignore(end()).parse(stream)?;
let lines = LineNumbers::new(src);
let module = ast::UntypedModule {
kind,
lines,
definitions,
docs: vec![],
name: "".to_string(),

View File

@ -19,5 +19,17 @@ Module {
},
),
],
lines: LineNumbers {
line_starts: [
0,
10,
11,
27,
],
length: 43,
last: Some(
27,
),
},
kind: Validator,
}

View File

@ -197,5 +197,32 @@ Module {
},
),
],
lines: LineNumbers {
line_starts: [
0,
13,
27,
34,
36,
37,
50,
64,
71,
73,
74,
87,
104,
106,
107,
120,
138,
154,
156,
],
length: 156,
last: Some(
156,
),
},
kind: Validator,
}

View File

@ -48,5 +48,18 @@ Module {
},
),
],
lines: LineNumbers {
line_starts: [
0,
11,
27,
31,
33,
],
length: 33,
last: Some(
33,
),
},
kind: Validator,
}

View File

@ -46,5 +46,18 @@ Module {
},
),
],
lines: LineNumbers {
line_starts: [
0,
11,
25,
29,
31,
],
length: 31,
last: Some(
31,
),
},
kind: Validator,
}

View File

@ -20,5 +20,15 @@ Module {
},
),
],
lines: LineNumbers {
line_starts: [
0,
16,
],
length: 16,
last: Some(
16,
),
},
kind: Validator,
}

View File

@ -1,3 +1,4 @@
use crate::line_numbers::LineNumbers;
use std::{cmp::Ordering, collections::HashMap, rc::Rc};
use vec1::Vec1;
@ -26,6 +27,8 @@ use super::{
#[derive(Debug)]
pub(crate) struct ExprTyper<'a, 'b> {
pub(crate) lines: &'a LineNumbers,
pub(crate) environment: &'a mut Environment<'b>,
// We tweak the tracing behavior during type-check. Traces are either kept or left out of the
@ -435,7 +438,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
TraceLevel::Compact => Some(TypedExpr::String {
location,
tipo: string(),
value: format!("{}", location.start),
value: self
.lines
.line_and_column_number(location.start)
.expect("Spans are within bounds.")
.to_string(),
}),
TraceLevel::Silent => None,
};
@ -1827,7 +1834,6 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
match self.tracing.trace_level(false) {
TraceLevel::Silent => Ok(then),
// TODO: use line numbers & cols
TraceLevel::Compact => Ok(TypedExpr::Trace {
location,
tipo,
@ -1835,7 +1841,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
text: Box::new(TypedExpr::String {
location,
tipo: string(),
value: format!("{}", location.start),
value: self
.lines
.line_and_column_number(location.start)
.expect("Spans are within bounds.")
.to_string(),
}),
}),
TraceLevel::Verbose => Ok(TypedExpr::Trace {
@ -1995,12 +2005,17 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
self.environment.instantiate(t, ids, &self.hydrator)
}
pub fn new(environment: &'a mut Environment<'b>, tracing: Tracing) -> Self {
pub fn new(
environment: &'a mut Environment<'b>,
lines: &'a LineNumbers,
tracing: Tracing,
) -> Self {
Self {
hydrator: Hydrator::new(),
environment,
tracing,
ungeneralised_function_used: false,
lines,
}
}

View File

@ -8,6 +8,7 @@ use crate::{
},
builtins,
builtins::function,
line_numbers::LineNumbers,
IdGenerator,
};
@ -79,8 +80,14 @@ impl UntypedModule {
}
for def in consts.into_iter().chain(not_consts) {
let definition =
infer_definition(def, &name, &mut hydrators, &mut environment, tracing)?;
let definition = infer_definition(
def,
&name,
&mut hydrators,
&mut environment,
&self.lines,
tracing,
)?;
definitions.push(definition);
}
@ -127,6 +134,7 @@ impl UntypedModule {
name: name.clone(),
definitions,
kind,
lines: self.lines,
type_info: TypeInfo {
name,
types,
@ -145,6 +153,7 @@ fn infer_definition(
module_name: &String,
hydrators: &mut HashMap<String, Hydrator>,
environment: &mut Environment<'_>,
lines: &LineNumbers,
tracing: Tracing,
) -> Result<TypedDefinition, Error> {
match def {
@ -181,7 +190,7 @@ fn infer_definition(
.map(|(arg_name, tipo)| arg_name.set_type(tipo.clone()))
.collect();
let mut expr_typer = ExprTyper::new(environment, tracing);
let mut expr_typer = ExprTyper::new(environment, lines, tracing);
expr_typer.hydrator = hydrators
.remove(&name)
@ -293,6 +302,7 @@ fn infer_definition(
module_name,
hydrators,
environment,
lines,
tracing,
)?
else {
@ -343,6 +353,7 @@ fn infer_definition(
module_name,
hydrators,
environment,
lines,
tracing,
)?
else {
@ -404,6 +415,7 @@ fn infer_definition(
module_name,
hydrators,
environment,
lines,
tracing,
)? {
environment.unify(f.return_type.clone(), builtins::bool(), f.location, false)?;
@ -585,7 +597,7 @@ fn infer_definition(
..
}) => {
let typed_expr =
ExprTyper::new(environment, tracing).infer_const(&annotation, *value)?;
ExprTyper::new(environment, lines, tracing).infer_const(&annotation, *value)?;
let tipo = typed_expr.tipo();

View File

@ -8,6 +8,7 @@ use aiken_lang::{
builder::{DataTypeKey, FunctionAccessKey},
CodeGenerator,
},
line_numbers::LineNumbers,
parser::extra::{comments_before, Comment, ModuleExtra},
tipo::TypeInfo,
};
@ -401,7 +402,10 @@ impl CheckedModules {
| Definition::Use(_) => {}
}
}
module_src.insert(module.name.clone(), module.code.clone());
module_src.insert(
module.name.clone(),
(module.code.clone(), LineNumbers::new(&module.code)),
);
}
let mut module_types_index = IndexMap::new();