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:
parent
7abd76b6ad
commit
7b676643bd
|
@ -244,7 +244,6 @@ pub enum Air {
|
||||||
ErrorTerm {
|
ErrorTerm {
|
||||||
scope: Vec<u64>,
|
scope: Vec<u64>,
|
||||||
tipo: Arc<Type>,
|
tipo: Arc<Type>,
|
||||||
label: Option<String>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
Trace {
|
Trace {
|
||||||
|
|
|
@ -433,11 +433,22 @@ pub fn rearrange_clauses(
|
||||||
sorted_clauses[sorted_clauses.len() - 1].clone().then
|
sorted_clauses[sorted_clauses.len() - 1].clone().then
|
||||||
}
|
}
|
||||||
Pattern::Discard { .. } => sorted_clauses[sorted_clauses.len() - 1].clone().then,
|
Pattern::Discard { .. } => sorted_clauses[sorted_clauses.len() - 1].clone().then,
|
||||||
_ => TypedExpr::ErrorTerm {
|
_ => {
|
||||||
|
let tipo = sorted_clauses[sorted_clauses.len() - 1].then.tipo();
|
||||||
|
TypedExpr::Trace {
|
||||||
location: Span::empty(),
|
location: Span::empty(),
|
||||||
tipo: sorted_clauses[sorted_clauses.len() - 1].then.tipo(),
|
tipo: tipo.clone(),
|
||||||
label: Some("Clause not filled".to_string()),
|
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() {
|
for (index, clause) in sorted_clauses.iter().enumerate() {
|
||||||
|
@ -1676,12 +1687,12 @@ pub fn monomorphize(
|
||||||
needs_variant = true;
|
needs_variant = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Air::ErrorTerm { scope, label, tipo } => {
|
Air::ErrorTerm { scope, tipo } => {
|
||||||
if tipo.is_generic() {
|
if tipo.is_generic() {
|
||||||
let mut tipo = tipo.clone();
|
let mut tipo = tipo.clone();
|
||||||
find_generics_to_replace(&mut tipo, &generic_types);
|
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;
|
needs_variant = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -152,7 +152,6 @@ pub enum TypedExpr {
|
||||||
ErrorTerm {
|
ErrorTerm {
|
||||||
location: Span,
|
location: Span,
|
||||||
tipo: Arc<Type>,
|
tipo: Arc<Type>,
|
||||||
label: Option<String>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
RecordUpdate {
|
RecordUpdate {
|
||||||
|
@ -429,7 +428,6 @@ pub enum UntypedExpr {
|
||||||
|
|
||||||
ErrorTerm {
|
ErrorTerm {
|
||||||
location: Span,
|
location: Span,
|
||||||
label: Option<String>,
|
|
||||||
},
|
},
|
||||||
|
|
||||||
RecordUpdate {
|
RecordUpdate {
|
||||||
|
|
|
@ -743,9 +743,7 @@ impl<'comments> Formatter<'comments> {
|
||||||
.append(suffix)
|
.append(suffix)
|
||||||
}
|
}
|
||||||
|
|
||||||
UntypedExpr::ErrorTerm { label: None, .. } => "error".to_doc(),
|
UntypedExpr::ErrorTerm { .. } => "error".to_doc(),
|
||||||
|
|
||||||
UntypedExpr::ErrorTerm { label: Some(l), .. } => docvec!["error(\"", l, "\")"],
|
|
||||||
};
|
};
|
||||||
|
|
||||||
commented(document, comments)
|
commented(document, comments)
|
||||||
|
|
|
@ -591,16 +591,14 @@ pub fn expr_seq_parser() -> impl Parser<Token, expr::UntypedExpr, Error = ParseE
|
||||||
recursive(|r| {
|
recursive(|r| {
|
||||||
choice((
|
choice((
|
||||||
just(Token::Trace)
|
just(Token::Trace)
|
||||||
.ignore_then(
|
.ignore_then(expr_parser(r.clone()))
|
||||||
expr_parser(r.clone())
|
|
||||||
.delimited_by(just(Token::LeftParen), just(Token::RightParen)),
|
|
||||||
)
|
|
||||||
.then(r.clone())
|
.then(r.clone())
|
||||||
.map_with_span(|(text, then_), span| expr::UntypedExpr::Trace {
|
.map_with_span(|(text, then_), span| expr::UntypedExpr::Trace {
|
||||||
location: span,
|
location: span,
|
||||||
then: Box::new(then_),
|
then: Box::new(then_),
|
||||||
text: Box::new(text),
|
text: Box::new(text),
|
||||||
}),
|
}),
|
||||||
|
todo_parser(r.clone(), Token::ErrorTerm, "aiken::error"),
|
||||||
expr_parser(r.clone())
|
expr_parser(r.clone())
|
||||||
.then(r.repeated())
|
.then(r.repeated())
|
||||||
.foldl(|current, next| current.append_in_sequence(next)),
|
.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(
|
pub fn expr_parser(
|
||||||
seq_r: Recursive<'_, Token, expr::UntypedExpr, ParseError>,
|
seq_r: Recursive<'_, Token, expr::UntypedExpr, ParseError>,
|
||||||
) -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> + '_ {
|
) -> impl Parser<Token, expr::UntypedExpr, Error = ParseError> + '_ {
|
||||||
|
@ -870,29 +898,6 @@ pub fn expr_parser(
|
||||||
name,
|
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
|
let tuple = r
|
||||||
.clone()
|
.clone()
|
||||||
.separated_by(just(Token::Comma))
|
.separated_by(just(Token::Comma))
|
||||||
|
@ -940,6 +945,7 @@ pub fn expr_parser(
|
||||||
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
choice((just(Token::LeftParen), just(Token::NewLineLeftParen))),
|
||||||
just(Token::RightParen),
|
just(Token::RightParen),
|
||||||
),
|
),
|
||||||
|
just(Token::ErrorTerm).rewind().ignore_then(seq_r.clone()),
|
||||||
));
|
));
|
||||||
|
|
||||||
let anon_fn_parser = just(Token::Fn)
|
let anon_fn_parser = just(Token::Fn)
|
||||||
|
@ -1083,8 +1089,6 @@ pub fn expr_parser(
|
||||||
record_parser,
|
record_parser,
|
||||||
field_access_constructor,
|
field_access_constructor,
|
||||||
var_parser,
|
var_parser,
|
||||||
todo_parser,
|
|
||||||
error_parser,
|
|
||||||
tuple,
|
tuple,
|
||||||
bytearray,
|
bytearray,
|
||||||
list_parser,
|
list_parser,
|
||||||
|
|
|
@ -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,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
|
@ -256,9 +256,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> {
|
||||||
..
|
..
|
||||||
} => Ok(self.infer_todo(location, kind, label)),
|
} => Ok(self.infer_todo(location, kind, label)),
|
||||||
|
|
||||||
UntypedExpr::ErrorTerm { location, label } => {
|
UntypedExpr::ErrorTerm { location } => Ok(self.infer_error_term(location)),
|
||||||
Ok(self.infer_error_term(location, label))
|
|
||||||
}
|
|
||||||
|
|
||||||
UntypedExpr::Var { location, name, .. } => self.infer_var(name, 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();
|
let tipo = self.new_unbound_var();
|
||||||
|
|
||||||
TypedExpr::ErrorTerm {
|
TypedExpr::ErrorTerm { location, tipo }
|
||||||
location,
|
|
||||||
tipo,
|
|
||||||
label,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn infer_trace(
|
fn infer_trace(
|
||||||
|
|
|
@ -679,11 +679,10 @@ impl<'a> CodeGenerator<'a> {
|
||||||
self.build_ir(tuple, ir_stack, scope);
|
self.build_ir(tuple, ir_stack, scope);
|
||||||
}
|
}
|
||||||
|
|
||||||
TypedExpr::ErrorTerm { tipo, label, .. } => {
|
TypedExpr::ErrorTerm { tipo, .. } => {
|
||||||
ir_stack.push(Air::ErrorTerm {
|
ir_stack.push(Air::ErrorTerm {
|
||||||
scope,
|
scope,
|
||||||
tipo: tipo.clone(),
|
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 {
|
assert_vec.push(Air::ErrorTerm {
|
||||||
scope,
|
scope,
|
||||||
tipo: tipo.clone(),
|
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,
|
tipo: replaced_type,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Air::ErrorTerm { tipo, scope, label } => {
|
Air::ErrorTerm { tipo, scope } => {
|
||||||
let mut replaced_type = tipo.clone();
|
let mut replaced_type = tipo.clone();
|
||||||
replace_opaque_type(&mut replaced_type, self.data_types.clone());
|
replace_opaque_type(&mut replaced_type, self.data_types.clone());
|
||||||
|
|
||||||
ir_stack[index] = Air::ErrorTerm {
|
ir_stack[index] = Air::ErrorTerm {
|
||||||
scope,
|
scope,
|
||||||
tipo: replaced_type,
|
tipo: replaced_type,
|
||||||
label,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
Air::Trace { tipo, scope } => {
|
Air::Trace { tipo, scope } => {
|
||||||
|
@ -5645,22 +5652,7 @@ impl<'a> CodeGenerator<'a> {
|
||||||
|
|
||||||
arg_stack.push(term);
|
arg_stack.push(term);
|
||||||
}
|
}
|
||||||
Air::ErrorTerm { label, .. } => {
|
Air::ErrorTerm { .. } => arg_stack.push(Term::Error),
|
||||||
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::TupleClause {
|
Air::TupleClause {
|
||||||
tipo,
|
tipo,
|
||||||
indices,
|
indices,
|
||||||
|
|
Loading…
Reference in New Issue