From 7b676643bd371ba44f9a4464aed0acaa4309e4ac Mon Sep 17 00:00:00 2001 From: KtorZ Date: Wed, 15 Feb 2023 21:09:03 +0100 Subject: [PATCH] Lift 'error' up one level in the parser and remove its label. We now parse errors as a combination of a trace plus and error term. This is a baby step in order to simplify the code generation down the line and the internal representation of todo / errors. --- crates/aiken-lang/src/air.rs | 1 - crates/aiken-lang/src/builder.rs | 25 ++++-- crates/aiken-lang/src/expr.rs | 2 - crates/aiken-lang/src/format.rs | 4 +- crates/aiken-lang/src/parser.rs | 62 ++++++++------- crates/aiken-lang/src/tests/parser.rs | 108 ++++++++++++++++++++++++++ crates/aiken-lang/src/tipo/expr.rs | 12 +-- crates/aiken-lang/src/uplc.rs | 34 ++++---- 8 files changed, 176 insertions(+), 72 deletions(-) diff --git a/crates/aiken-lang/src/air.rs b/crates/aiken-lang/src/air.rs index ac43c86c..39909907 100644 --- a/crates/aiken-lang/src/air.rs +++ b/crates/aiken-lang/src/air.rs @@ -244,7 +244,6 @@ pub enum Air { ErrorTerm { scope: Vec, tipo: Arc, - label: Option, }, Trace { diff --git a/crates/aiken-lang/src/builder.rs b/crates/aiken-lang/src/builder.rs index 94205690..f204e91f 100644 --- a/crates/aiken-lang/src/builder.rs +++ b/crates/aiken-lang/src/builder.rs @@ -433,11 +433,22 @@ pub fn rearrange_clauses( sorted_clauses[sorted_clauses.len() - 1].clone().then } Pattern::Discard { .. } => sorted_clauses[sorted_clauses.len() - 1].clone().then, - _ => TypedExpr::ErrorTerm { - location: Span::empty(), - tipo: sorted_clauses[sorted_clauses.len() - 1].then.tipo(), - label: Some("Clause not filled".to_string()), - }, + _ => { + let tipo = sorted_clauses[sorted_clauses.len() - 1].then.tipo(); + TypedExpr::Trace { + location: Span::empty(), + tipo: tipo.clone(), + text: Box::new(TypedExpr::String { + location: Span::empty(), + tipo: crate::builtins::string(), + value: "Clause not filled".to_string(), + }), + then: Box::new(TypedExpr::ErrorTerm { + location: Span::empty(), + tipo, + }), + } + } }; for (index, clause) in sorted_clauses.iter().enumerate() { @@ -1676,12 +1687,12 @@ pub fn monomorphize( needs_variant = true; } } - Air::ErrorTerm { scope, label, tipo } => { + Air::ErrorTerm { scope, tipo } => { if tipo.is_generic() { let mut tipo = tipo.clone(); find_generics_to_replace(&mut tipo, &generic_types); - new_air[index] = Air::ErrorTerm { scope, tipo, label }; + new_air[index] = Air::ErrorTerm { scope, tipo }; needs_variant = true; } } diff --git a/crates/aiken-lang/src/expr.rs b/crates/aiken-lang/src/expr.rs index 29c17a58..9afb0803 100644 --- a/crates/aiken-lang/src/expr.rs +++ b/crates/aiken-lang/src/expr.rs @@ -152,7 +152,6 @@ pub enum TypedExpr { ErrorTerm { location: Span, tipo: Arc, - label: Option, }, RecordUpdate { @@ -429,7 +428,6 @@ pub enum UntypedExpr { ErrorTerm { location: Span, - label: Option, }, RecordUpdate { diff --git a/crates/aiken-lang/src/format.rs b/crates/aiken-lang/src/format.rs index cade25c2..12e42e40 100644 --- a/crates/aiken-lang/src/format.rs +++ b/crates/aiken-lang/src/format.rs @@ -743,9 +743,7 @@ impl<'comments> Formatter<'comments> { .append(suffix) } - UntypedExpr::ErrorTerm { label: None, .. } => "error".to_doc(), - - UntypedExpr::ErrorTerm { label: Some(l), .. } => docvec!["error(\"", l, "\")"], + UntypedExpr::ErrorTerm { .. } => "error".to_doc(), }; commented(document, comments) diff --git a/crates/aiken-lang/src/parser.rs b/crates/aiken-lang/src/parser.rs index 06bd9896..84816880 100644 --- a/crates/aiken-lang/src/parser.rs +++ b/crates/aiken-lang/src/parser.rs @@ -591,16 +591,14 @@ pub fn expr_seq_parser() -> impl Parser impl Parser( + r: Recursive<'a, Token, expr::UntypedExpr, ParseError>, + keyword: Token, + default_value: &'a str, +) -> impl Parser + 'a { + just(keyword) + .ignore_then(expr_parser(r.clone()).or_not()) + .then(r.clone().or_not()) + .map_with_span(|(text, then_), span| match then_ { + None => expr::UntypedExpr::Trace { + location: span, + then: Box::new(expr::UntypedExpr::ErrorTerm { location: span }), + text: Box::new(text.unwrap_or_else(|| expr::UntypedExpr::String { + location: span, + value: default_value.to_string(), + })), + }, + Some(e) => expr::UntypedExpr::Trace { + location: span, + then: Box::new( + expr::UntypedExpr::ErrorTerm { location: span }.append_in_sequence(e), + ), + text: Box::new(text.unwrap_or_else(|| expr::UntypedExpr::String { + location: span, + value: default_value.to_string(), + })), + }, + }) +} + pub fn expr_parser( seq_r: Recursive<'_, Token, expr::UntypedExpr, ParseError>, ) -> impl Parser + '_ { @@ -870,29 +898,6 @@ pub fn expr_parser( name, }); - let todo_parser = just(Token::Todo) - .ignore_then( - select! {Token::String {value} => value} - .delimited_by(just(Token::LeftParen), just(Token::RightParen)) - .or_not(), - ) - .map_with_span(|label, span| expr::UntypedExpr::Todo { - kind: TodoKind::Keyword, - location: span, - label, - }); - - let error_parser = just(Token::ErrorTerm) - .ignore_then( - select! {Token::String {value} => value} - .delimited_by(just(Token::LeftParen), just(Token::RightParen)) - .or_not(), - ) - .map_with_span(|label, span| expr::UntypedExpr::ErrorTerm { - location: span, - label, - }); - let tuple = r .clone() .separated_by(just(Token::Comma)) @@ -940,6 +945,7 @@ pub fn expr_parser( choice((just(Token::LeftParen), just(Token::NewLineLeftParen))), just(Token::RightParen), ), + just(Token::ErrorTerm).rewind().ignore_then(seq_r.clone()), )); let anon_fn_parser = just(Token::Fn) @@ -1083,8 +1089,6 @@ pub fn expr_parser( record_parser, field_access_constructor, var_parser, - todo_parser, - error_parser, tuple, bytearray, list_parser, diff --git a/crates/aiken-lang/src/tests/parser.rs b/crates/aiken-lang/src/tests/parser.rs index f5ddc28b..322ccb73 100644 --- a/crates/aiken-lang/src/tests/parser.rs +++ b/crates/aiken-lang/src/tests/parser.rs @@ -2704,3 +2704,111 @@ fn trace_expressions() { })], ) } + +#[test] +fn parse_keyword_error() { + let code = indoc! {r#" + fn foo() { + error "not implemented" + Void + } + + fn bar() { + when x is { + Something -> Void + _ -> error + } + } + "#}; + assert_definitions( + code, + vec![ + ast::Definition::Fn(Function { + arguments: vec![], + body: expr::UntypedExpr::Trace { + location: Span::new((), 13..43), + then: Box::new(expr::UntypedExpr::Sequence { + location: Span::new((), 13..43), + expressions: vec![ + expr::UntypedExpr::ErrorTerm { + location: Span::new((), 13..43), + }, + expr::UntypedExpr::Var { + location: Span::new((), 39..43), + name: "Void".to_string(), + }, + ], + }), + text: Box::new(expr::UntypedExpr::String { + location: Span::new((), 19..36), + value: "not implemented".to_string(), + }), + }, + doc: None, + location: Span::new((), 0..8), + name: "foo".to_string(), + public: false, + return_annotation: None, + return_type: (), + end_position: 44, + }), + ast::Definition::Fn(Function { + arguments: vec![], + body: expr::UntypedExpr::When { + location: Span::new((), 60..116), + subjects: vec![expr::UntypedExpr::Var { + location: Span::new((), 65..66), + name: "x".to_string(), + }], + clauses: vec![ + ast::Clause { + location: Span::new((), 78..95), + pattern: vec![ast::Pattern::Constructor { + is_record: false, + location: Span::new((), 78..87), + name: "Something".to_string(), + arguments: vec![], + module: None, + constructor: (), + with_spread: false, + tipo: (), + }], + alternative_patterns: vec![], + guard: None, + then: expr::UntypedExpr::Var { + location: Span::new((), 91..95), + name: "Void".to_string(), + }, + }, + ast::Clause { + location: Span::new((), 102..112), + pattern: vec![ast::Pattern::Discard { + name: "_".to_string(), + location: Span::new((), 102..103), + }], + alternative_patterns: vec![], + guard: None, + then: expr::UntypedExpr::Trace { + location: Span::new((), 107..112), + then: Box::new(expr::UntypedExpr::ErrorTerm { + location: Span::new((), 107..112), + }), + text: Box::new(expr::UntypedExpr::String { + location: Span::new((), 107..112), + value: "aiken::error".to_string(), + }), + }, + }, + ], + }, + doc: None, + location: Span::new((), 47..55), + name: "bar".to_string(), + public: false, + return_annotation: None, + return_type: (), + end_position: 117, + }), + ], + ) +} diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index 5b04947c..70b2e739 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -256,9 +256,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { .. } => Ok(self.infer_todo(location, kind, label)), - UntypedExpr::ErrorTerm { location, label } => { - Ok(self.infer_error_term(location, label)) - } + UntypedExpr::ErrorTerm { location } => Ok(self.infer_error_term(location)), UntypedExpr::Var { location, name, .. } => self.infer_var(name, location), @@ -1873,14 +1871,10 @@ impl<'a, 'b> ExprTyper<'a, 'b> { } } - fn infer_error_term(&mut self, location: Span, label: Option) -> TypedExpr { + fn infer_error_term(&mut self, location: Span) -> TypedExpr { let tipo = self.new_unbound_var(); - TypedExpr::ErrorTerm { - location, - tipo, - label, - } + TypedExpr::ErrorTerm { location, tipo } } fn infer_trace( diff --git a/crates/aiken-lang/src/uplc.rs b/crates/aiken-lang/src/uplc.rs index c3bbd0af..ab2dfc00 100644 --- a/crates/aiken-lang/src/uplc.rs +++ b/crates/aiken-lang/src/uplc.rs @@ -679,11 +679,10 @@ impl<'a> CodeGenerator<'a> { self.build_ir(tuple, ir_stack, scope); } - TypedExpr::ErrorTerm { tipo, label, .. } => { + TypedExpr::ErrorTerm { tipo, .. } => { ir_stack.push(Air::ErrorTerm { scope, tipo: tipo.clone(), - label: label.clone(), }); } } @@ -2568,10 +2567,19 @@ impl<'a> CodeGenerator<'a> { }); } + assert_vec.push(Air::Trace { + scope: scope.clone(), + tipo: tipo.clone(), + }); + + assert_vec.push(Air::String { + scope: scope.clone(), + value: "Constr index did not match any type variant".to_string(), + }); + assert_vec.push(Air::ErrorTerm { scope, tipo: tipo.clone(), - label: Some("Constr index did not match any type variant".to_string()), }); } } @@ -3496,14 +3504,13 @@ impl<'a> CodeGenerator<'a> { tipo: replaced_type, }; } - Air::ErrorTerm { tipo, scope, label } => { + Air::ErrorTerm { tipo, scope } => { let mut replaced_type = tipo.clone(); replace_opaque_type(&mut replaced_type, self.data_types.clone()); ir_stack[index] = Air::ErrorTerm { scope, tipo: replaced_type, - label, }; } Air::Trace { tipo, scope } => { @@ -5645,22 +5652,7 @@ impl<'a> CodeGenerator<'a> { arg_stack.push(term); } - Air::ErrorTerm { label, .. } => { - if let Some(label) = label { - let term = apply_wrap( - apply_wrap( - Term::Builtin(DefaultFunction::Trace).force_wrap(), - Term::Constant(UplcConstant::String(label).into()), - ), - Term::Delay(Term::Error.into()), - ) - .force_wrap(); - - arg_stack.push(term); - } else { - arg_stack.push(Term::Error) - } - } + Air::ErrorTerm { .. } => arg_stack.push(Term::Error), Air::TupleClause { tipo, indices,