Fix missing locations from generated handler code.

This commit is contained in:
KtorZ 2024-09-03 20:06:29 +02:00 committed by Kasey
parent 2f33c4a8f4
commit 6a438bc8cd
3 changed files with 132 additions and 41 deletions

View File

@ -565,15 +565,15 @@ impl TypedValidator {
TypedExpr::sequence(&[ TypedExpr::sequence(&[
TypedExpr::let_( TypedExpr::let_(
TypedExpr::local_var(var_context, Type::script_context()), TypedExpr::local_var(var_context, Type::script_context(), self.location),
TypedPattern::Constructor { TypedPattern::Constructor {
is_record: false, is_record: false,
location: Span::empty(), location: Span::empty(),
name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(), name: well_known::SCRIPT_CONTEXT_CONSTRUCTORS[0].to_string(),
arguments: vec![ arguments: vec![
CallArg::var(var_transaction), CallArg::var(var_transaction, Span::empty()),
CallArg::var(var_redeemer), CallArg::var(var_redeemer, Span::empty()),
CallArg::var(var_purpose), CallArg::var(var_purpose, Span::empty()),
], ],
module: None, module: None,
constructor: PatternConstructor::Record { constructor: PatternConstructor::Record {
@ -587,11 +587,13 @@ impl TypedValidator {
), ),
}, },
Type::script_context(), Type::script_context(),
Span::empty(),
), ),
TypedExpr::When { TypedExpr::When {
location: Span::empty(), location: Span::empty(),
tipo: Type::bool(), tipo: Type::bool(),
subject: TypedExpr::local_var(var_purpose, Type::script_purpose()).into(), subject: TypedExpr::local_var(var_purpose, Type::script_purpose(), Span::empty())
.into(),
clauses: self clauses: self
.handlers .handlers
.iter() .iter()
@ -611,13 +613,37 @@ impl TypedValidator {
let transaction = handler.arguments.last().unwrap(); let transaction = handler.arguments.last().unwrap();
println!("REDEEMER SPAN: {:?}", redeemer.location);
let pattern = match handler.name.as_str() { let pattern = match handler.name.as_str() {
"spend" => TypedPattern::spend_purpose(var_purpose_arg, var_datum), "spend" => TypedPattern::spend_purpose(
"mint" => TypedPattern::mint_purpose(var_purpose_arg), (var_purpose_arg, purpose_arg.location),
"withdraw" => TypedPattern::withdraw_purpose(var_purpose_arg), (
"publish" => TypedPattern::publish_purpose(var_purpose_arg), var_datum,
"propose" => TypedPattern::propose_purpose(var_purpose_arg), datum.map(|x| x.location).unwrap_or(Span::empty()),
"vote" => TypedPattern::vote_purpose(var_purpose_arg), ),
redeemer.location,
),
"mint" => TypedPattern::mint_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"withdraw" => TypedPattern::withdraw_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"publish" => TypedPattern::publish_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"propose" => TypedPattern::propose_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
"vote" => TypedPattern::vote_purpose(
(var_purpose_arg, purpose_arg.location),
redeemer.location,
),
purpose => { purpose => {
unreachable!("unexpected/unknown purpose: {:?}", purpose) unreachable!("unexpected/unknown purpose: {:?}", purpose)
} }
@ -627,36 +653,52 @@ impl TypedValidator {
// expect redeemer: tipo = __redeemer__ // expect redeemer: tipo = __redeemer__
then.push(TypedExpr::flexible_expect( then.push(TypedExpr::flexible_expect(
TypedExpr::local_var(var_redeemer, Type::data()), TypedExpr::local_var(var_redeemer, Type::data(), redeemer.location),
TypedPattern::var(redeemer.get_variable_name().unwrap_or("_")), TypedPattern::var(redeemer.get_variable_name().unwrap_or("_")),
redeemer.tipo.clone(), redeemer.tipo.clone(),
redeemer.location,
)); ));
// Cast the datum, if any // Cast the datum, if any
if let Some(datum) = datum { if let Some(datum) = datum {
// expect datum: tipo = __datum__ // expect datum: tipo = __datum__
then.push(TypedExpr::flexible_expect( then.push(TypedExpr::flexible_expect(
TypedExpr::local_var(var_datum, Type::option(Type::data())), TypedExpr::local_var(
var_datum,
Type::option(Type::data()),
datum.location,
),
TypedPattern::var(datum.get_variable_name().unwrap_or("_")), TypedPattern::var(datum.get_variable_name().unwrap_or("_")),
datum.tipo.clone(), datum.tipo.clone(),
datum.location,
)) ))
} }
// let purpose_arg = __purpose_arg__ // let purpose_arg = __purpose_arg__
if let Some(arg_name) = purpose_arg.get_variable_name() { if let Some(arg_name) = purpose_arg.get_variable_name() {
then.push(TypedExpr::let_( then.push(TypedExpr::let_(
TypedExpr::local_var(var_purpose_arg, Type::data()), TypedExpr::local_var(
var_purpose_arg,
Type::data(),
purpose_arg.location,
),
TypedPattern::var(arg_name), TypedPattern::var(arg_name),
purpose_arg.tipo.clone(), purpose_arg.tipo.clone(),
purpose_arg.location,
)); ));
} }
// let last_arg_name = __transaction__ // let last_arg_name = __transaction__
if let Some(arg_name) = transaction.get_variable_name() { if let Some(arg_name) = transaction.get_variable_name() {
then.push(TypedExpr::let_( then.push(TypedExpr::let_(
TypedExpr::local_var(var_transaction, Type::data()), TypedExpr::local_var(
var_transaction,
Type::data(),
transaction.location,
),
TypedPattern::var(arg_name), TypedPattern::var(arg_name),
Type::data(), Type::data(),
transaction.location,
)); ));
} }
@ -676,14 +718,15 @@ impl TypedValidator {
let then = &[ let then = &[
TypedExpr::let_( TypedExpr::let_(
TypedExpr::local_var(var_context, arg.tipo.clone()), TypedExpr::local_var(var_context, arg.tipo.clone(), arg.location),
arg.get_variable_name().map(TypedPattern::var).unwrap_or( arg.get_variable_name().map(TypedPattern::var).unwrap_or(
TypedPattern::Discard { TypedPattern::Discard {
name: var_context.to_string(), name: var_context.to_string(),
location: Span::empty(), location: arg.location,
}, },
), ),
arg.tipo.clone(), arg.tipo.clone(),
arg.location,
), ),
fallback.body.clone(), fallback.body.clone(),
]; ];
@ -879,12 +922,12 @@ impl TypedCallArg {
} }
impl CallArg<TypedPattern> { impl CallArg<TypedPattern> {
pub fn var(name: &str) -> Self { pub fn var(name: &str, location: Span) -> Self {
CallArg { CallArg {
label: None, label: None,
location: Span::empty(), location: Span::empty(),
value: TypedPattern::Var { value: TypedPattern::Var {
location: Span::empty(), location,
name: name.to_string(), name: name.to_string(),
}, },
} }
@ -1456,10 +1499,15 @@ impl TypedPattern {
} }
} }
pub fn constructor(name: &str, arguments: &[CallArg<TypedPattern>], tipo: Rc<Type>) -> Self { pub fn constructor(
name: &str,
arguments: &[CallArg<TypedPattern>],
tipo: Rc<Type>,
location: Span,
) -> Self {
TypedPattern::Constructor { TypedPattern::Constructor {
is_record: false, is_record: false,
location: Span::empty(), location,
name: name.to_string(), name: name.to_string(),
arguments: arguments.to_vec(), arguments: arguments.to_vec(),
module: None, module: None,
@ -1472,60 +1520,88 @@ impl TypedPattern {
} }
} }
pub fn mint_purpose(var_purpose_arg: &str) -> Self { pub fn mint_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor( TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_MINT, well_known::SCRIPT_PURPOSE_MINT,
&[CallArg::var(var_purpose_arg)], &[CallArg::var(var_purpose_arg, purpose_span)],
Type::function(vec![Type::byte_array()], Type::script_purpose()), Type::function(vec![Type::byte_array()], Type::script_purpose()),
redeemer_span,
) )
} }
pub fn spend_purpose(var_purpose_arg: &str, var_datum: &str) -> Self { pub fn spend_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
(var_datum, datum_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor( TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_SPEND, well_known::SCRIPT_PURPOSE_SPEND,
&[CallArg::var(var_purpose_arg), CallArg::var(var_datum)], &[
CallArg::var(var_purpose_arg, purpose_span),
CallArg::var(var_datum, datum_span),
],
Type::function( Type::function(
vec![Type::data(), Type::option(Type::data())], vec![Type::data(), Type::option(Type::data())],
Type::script_purpose(), Type::script_purpose(),
), ),
redeemer_span,
) )
} }
pub fn withdraw_purpose(var_purpose_arg: &str) -> Self { pub fn withdraw_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor( TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_WITHDRAW, well_known::SCRIPT_PURPOSE_WITHDRAW,
&[CallArg::var(var_purpose_arg)], &[CallArg::var(var_purpose_arg, purpose_span)],
Type::function(vec![Type::data()], Type::script_purpose()), Type::function(vec![Type::data()], Type::script_purpose()),
redeemer_span,
) )
} }
pub fn publish_purpose(var_purpose_arg: &str) -> Self { pub fn publish_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor( TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_PUBLISH, well_known::SCRIPT_PURPOSE_PUBLISH,
&[ &[
CallArg::var("__discarded_purpose_ix__"), CallArg::var("__discarded_purpose_ix__", purpose_span),
CallArg::var(var_purpose_arg), CallArg::var(var_purpose_arg, purpose_span),
], ],
Type::function(vec![Type::int(), Type::data()], Type::script_purpose()), Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
redeemer_span,
) )
} }
pub fn vote_purpose(var_purpose_arg: &str) -> Self { pub fn vote_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor( TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_VOTE, well_known::SCRIPT_PURPOSE_VOTE,
&[CallArg::var(var_purpose_arg)], &[CallArg::var(var_purpose_arg, purpose_span)],
Type::function(vec![Type::data()], Type::script_purpose()), Type::function(vec![Type::data()], Type::script_purpose()),
redeemer_span,
) )
} }
pub fn propose_purpose(var_purpose_arg: &str) -> Self { pub fn propose_purpose(
(var_purpose_arg, purpose_span): (&str, Span),
redeemer_span: Span,
) -> Self {
TypedPattern::constructor( TypedPattern::constructor(
well_known::SCRIPT_PURPOSE_PROPOSE, well_known::SCRIPT_PURPOSE_PROPOSE,
&[ &[
CallArg::var("__discarded_purpose_ix__"), CallArg::var("__discarded_purpose_ix__", purpose_span),
CallArg::var(var_purpose_arg), CallArg::var(var_purpose_arg, purpose_span),
], ],
Type::function(vec![Type::int(), Type::data()], Type::script_purpose()), Type::function(vec![Type::int(), Type::data()], Type::script_purpose()),
redeemer_span,
) )
} }
} }

View File

@ -210,20 +210,24 @@ impl TypedExpr {
} }
} }
pub fn let_(value: Self, pattern: TypedPattern, tipo: Rc<Type>) -> Self { pub fn let_(value: Self, pattern: TypedPattern, tipo: Rc<Type>, location: Span) -> Self {
TypedExpr::Assignment { TypedExpr::Assignment {
location: Span::empty(),
tipo: tipo.clone(), tipo: tipo.clone(),
value: value.into(), value: value.into(),
pattern, pattern,
kind: AssignmentKind::let_(), kind: AssignmentKind::let_(),
location,
} }
} }
// Create an expect assignment, unless the target type is `Data`; then fallback to a let. // Create an expect assignment, unless the target type is `Data`; then fallback to a let.
pub fn flexible_expect(value: Self, pattern: TypedPattern, tipo: Rc<Type>) -> Self { pub fn flexible_expect(
value: Self,
pattern: TypedPattern,
tipo: Rc<Type>,
location: Span,
) -> Self {
TypedExpr::Assignment { TypedExpr::Assignment {
location: Span::empty(),
tipo: tipo.clone(), tipo: tipo.clone(),
value: value.into(), value: value.into(),
pattern, pattern,
@ -232,12 +236,12 @@ impl TypedExpr {
} else { } else {
AssignmentKind::expect() AssignmentKind::expect()
}, },
location,
} }
} }
pub fn local_var(name: &str, tipo: Rc<Type>) -> Self { pub fn local_var(name: &str, tipo: Rc<Type>, location: Span) -> Self {
TypedExpr::Var { TypedExpr::Var {
location: Span::empty(),
constructor: ValueConstructor { constructor: ValueConstructor {
public: true, public: true,
variant: ValueConstructorVariant::LocalVariable { variant: ValueConstructorVariant::LocalVariable {
@ -246,6 +250,7 @@ impl TypedExpr {
tipo: tipo.clone(), tipo: tipo.clone(),
}, },
name: name.to_string(), name: name.to_string(),
location,
} }
} }

View File

@ -1719,6 +1719,11 @@ pub fn get_src_code_by_span(
span: &Span, span: &Span,
module_src: &IndexMap<&str, &(String, LineNumbers)>, module_src: &IndexMap<&str, &(String, LineNumbers)>,
) -> String { ) -> String {
assert!(
*span != Span::empty(),
"tried to lookup source code from empty location"
);
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}"));
@ -1733,6 +1738,11 @@ pub fn get_line_columns_by_span(
span: &Span, span: &Span,
module_src: &IndexMap<&str, &(String, LineNumbers)>, module_src: &IndexMap<&str, &(String, LineNumbers)>,
) -> LineColumn { ) -> LineColumn {
assert!(
*span != Span::empty(),
"tried to lookup line & columns from empty location"
);
let (_, lines) = module_src let (_, lines) = module_src
.get(module_name) .get(module_name)
.unwrap_or_else(|| panic!("Missing module {module_name}")); .unwrap_or_else(|| panic!("Missing module {module_name}"));