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.
This commit is contained in:
KtorZ 2023-02-15 21:09:03 +01:00
parent 7abd76b6ad
commit 7b676643bd
No known key found for this signature in database
GPG Key ID: 33173CB6F77F4277
8 changed files with 176 additions and 72 deletions

View File

@ -244,7 +244,6 @@ pub enum Air {
ErrorTerm {
scope: Vec<u64>,
tipo: Arc<Type>,
label: Option<String>,
},
Trace {

View File

@ -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;
}
}

View File

@ -152,7 +152,6 @@ pub enum TypedExpr {
ErrorTerm {
location: Span,
tipo: Arc<Type>,
label: Option<String>,
},
RecordUpdate {
@ -429,7 +428,6 @@ pub enum UntypedExpr {
ErrorTerm {
location: Span,
label: Option<String>,
},
RecordUpdate {

View File

@ -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)

View File

@ -591,16 +591,14 @@ pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseE
recursive(|r| {
choice((
just(Token::Trace)
.ignore_then(
expr_parser(r.clone())
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
)
.ignore_then(expr_parser(r.clone()))
.then(r.clone())
.map_with_span(|(text, then_), span| expr::UntypedExpr::Trace {
location: span,
then: Box::new(then_),
text: Box::new(text),
}),
todo_parser(r.clone(), Token::ErrorTerm, "aiken::error"),
expr_parser(r.clone())
.then(r.repeated())
.foldl(|current, next| current.append_in_sequence(next)),
@ -608,6 +606,36 @@ pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseE
})
}
pub fn todo_parser<'a>(
r: Recursive<'a, Token, expr::UntypedExpr, ParseError>,
keyword: Token,
default_value: &'a str,
) -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> + '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<Token, expr::UntypedExpr, Error = ParseError> + '_ {
@ -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,

View File

@ -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,
}),
],
)
}

View File

@ -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<String>) -> 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(

View File

@ -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,