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

View File

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

View File

@ -20,6 +20,7 @@ use crate::{
}, },
builtins::{bool, data, function, int, list, string, void}, builtins::{bool, data, function, int, list, string, void},
expr::TypedExpr, expr::TypedExpr,
line_numbers::{LineColumn, LineNumbers},
tipo::{PatternConstructor, TypeVar, ValueConstructor, ValueConstructorVariant}, 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( pub fn get_src_code_by_span(
module_name: &String, module_name: &String,
span: &Span, span: &Span,
module_src: &IndexMap<String, String>, module_src: &IndexMap<String, (String, LineNumbers)>,
) -> String { ) -> String {
let src = module_src let (src, _) = module_src
.get(module_name) .get(module_name)
.unwrap_or_else(|| panic!("Missing module {module_name}")); .unwrap_or_else(|| panic!("Missing module {module_name}"));
@ -1786,6 +1787,20 @@ pub fn get_src_code_by_span(
.to_string() .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 { pub fn air_holds_msg(air: &Air) -> bool {
match air { match air {
Air::AssertConstr { .. } | Air::AssertBool { .. } | Air::FieldsEmpty | Air::ListEmpty => { Air::AssertConstr { .. } | Air::AssertBool { .. } | Air::FieldsEmpty | Air::ListEmpty => {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,6 +8,7 @@ use aiken_lang::{
builder::{DataTypeKey, FunctionAccessKey}, builder::{DataTypeKey, FunctionAccessKey},
CodeGenerator, CodeGenerator,
}, },
line_numbers::LineNumbers,
parser::extra::{comments_before, Comment, ModuleExtra}, parser::extra::{comments_before, Comment, ModuleExtra},
tipo::TypeInfo, tipo::TypeInfo,
}; };
@ -401,7 +402,10 @@ impl CheckedModules {
| Definition::Use(_) => {} | 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(); let mut module_types_index = IndexMap::new();