Skip to content

Commit c3e5563

Browse files
committed
add error states for parsing tree and AST
This adds error states for `parse::Expression`, `ast::Expression` `ResolvedType` and `AliasedType`. Error recovery introduced by `chumsky` parser require some default states to recover to, which was represented before with dummy values, like unit type for expression or alias with `error` name. However, this kind of recovery is not desirable in case of further analyzing of parse tree, because it would lead to unrecognazible errors on analyzer.
1 parent 6bd62dc commit c3e5563

File tree

5 files changed

+63
-34
lines changed

5 files changed

+63
-34
lines changed

src/ast.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,13 @@ impl Expression {
160160
pub fn span(&self) -> &Span {
161161
&self.span
162162
}
163+
pub fn error(span: Span) -> Self {
164+
Self {
165+
inner: ExpressionInner::Error,
166+
ty: ResolvedType::error(),
167+
span,
168+
}
169+
}
163170
}
164171

165172
/// Variant of an expression.
@@ -171,6 +178,9 @@ pub enum ExpressionInner {
171178
/// Then, the block returns the value of its final expression.
172179
/// The block returns nothing (unit) if there is no final expression.
173180
Block(Arc<[Statement]>, Option<Arc<Expression>>),
181+
/// An error expression state, which indicates that parser didn't recognize this expression or
182+
/// analyzer failed to analyze this expression.
183+
Error,
174184
}
175185

176186
/// A single expression directly returns its value.
@@ -474,6 +484,7 @@ impl TreeLike for ExprTree<'_> {
474484
Tree::Unary(Self::Block(statements, maybe_expr))
475485
}
476486
ExpressionInner::Single(single) => Tree::Unary(Self::Single(single)),
487+
ExpressionInner::Error => Tree::Nullary,
477488
},
478489
Self::Block(statements, maybe_expr) => Tree::Nary(
479490
statements
@@ -913,6 +924,7 @@ impl AbstractSyntaxTree for Expression {
913924
span: *from.as_ref(),
914925
})
915926
}
927+
parse::ExpressionInner::Error => Ok(Self::error(*from.as_ref())),
916928
}
917929
}
918930
}

src/compile/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,10 @@ impl Expression {
294294
res
295295
}
296296
ExpressionInner::Single(e) => e.compile(scope),
297+
ExpressionInner::Error => Err(Error::CannotCompile(
298+
"Compiled from poisoned tree".to_string(),
299+
)
300+
.with_span(*self.as_ref())),
297301
}
298302
}
299303
}

src/parse.rs

Lines changed: 23 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,13 @@ impl Expression {
288288
span,
289289
}
290290
}
291+
292+
pub fn error(span: Span) -> Self {
293+
Self {
294+
inner: ExpressionInner::Error,
295+
span,
296+
}
297+
}
291298
}
292299

293300
impl_eq_hash!(Expression; inner);
@@ -301,6 +308,10 @@ pub enum ExpressionInner {
301308
/// Then, the block returns the value of its final expression.
302309
/// The block returns nothing (unit) if there is no final expression.
303310
Block(Arc<[Statement]>, Option<Arc<Expression>>),
311+
/// An error expression state, which indicates that parser cannot recognize this expression.
312+
/// Also tells an analyzer that we should skip analyzing this expression to not emmit more
313+
/// errors.
314+
Error,
304315
}
305316

306317
/// A single expression directly returns a value.
@@ -399,7 +410,7 @@ impl Match {
399410
}
400411
(MatchPattern::None, MatchPattern::Some(_, ty_r)) => AliasedType::option(ty_r.clone()),
401412
(MatchPattern::False, MatchPattern::True) => AliasedType::boolean(),
402-
_ => unreachable!("Match expressions have valid left and right arms"),
413+
_ => AliasedType::error(),
403414
}
404415
}
405416
}
@@ -614,6 +625,7 @@ impl TreeLike for ExprTree<'_> {
614625
Tree::Unary(Self::Block(statements, maybe_expr))
615626
}
616627
ExpressionInner::Single(single) => Tree::Unary(Self::Single(single)),
628+
ExpressionInner::Error => Tree::Nullary,
617629
},
618630
Self::Block(statements, maybe_expr) => Tree::Nary(
619631
statements
@@ -935,13 +947,7 @@ impl<A: ChumskyParse + std::fmt::Debug> ParseFromStrWithErrors for A {
935947

936948
handler.update(parse_errs);
937949

938-
// TODO: We should return parsed result if we found errors, but because analyzing in `ast` module
939-
// is not handling poisoned tree right now, we don't return parsed result
940-
if handler.get().is_empty() {
941-
ast
942-
} else {
943-
None
944-
}
950+
ast
945951
}
946952
}
947953

@@ -1042,12 +1048,7 @@ impl ChumskyParse for AliasedType {
10421048
.then(ty.clone()),
10431049
Token::LAngle,
10441050
Token::RAngle,
1045-
|_| {
1046-
(
1047-
AliasedType::alias(AliasName::from_str_unchecked("error")),
1048-
AliasedType::alias(AliasName::from_str_unchecked("error")),
1049-
)
1050-
},
1051+
|_| (AliasedType::error(), AliasedType::error()),
10511052
);
10521053

10531054
let sum_type = just(Token::Ident("Either"))
@@ -1073,7 +1074,7 @@ impl ChumskyParse for AliasedType {
10731074
.map(|s: Vec<AliasedType>| AliasedType::tuple(s)),
10741075
Token::LParen,
10751076
Token::RParen,
1076-
|_| AliasedType::tuple(Vec::new()),
1077+
|_| AliasedType::error(),
10771078
)
10781079
.labelled("tuple");
10791080

@@ -1086,12 +1087,7 @@ impl ChumskyParse for AliasedType {
10861087
}),
10871088
Token::LBracket,
10881089
Token::RBracket,
1089-
|_| {
1090-
AliasedType::array(
1091-
AliasedType::alias(AliasName::from_str_unchecked("error")),
1092-
0,
1093-
)
1094-
},
1090+
|_| AliasedType::error(),
10951091
)
10961092
.labelled("array");
10971093

@@ -1113,19 +1109,12 @@ impl ChumskyParse for AliasedType {
11131109
})),
11141110
Token::LAngle,
11151111
Token::RAngle,
1116-
|_| {
1117-
(
1118-
AliasedType::alias(AliasName::from_str_unchecked("error")),
1119-
NonZeroPow2Usize::TWO,
1120-
)
1121-
},
1112+
|_| (AliasedType::error(), NonZeroPow2Usize::TWO),
11221113
))
11231114
.map(|(ty, size)| AliasedType::list(ty, size))
11241115
.labelled("List");
11251116

1126-
choice((sum_type, option_type, tuple, array, list, atom))
1127-
.map_with(|inner, _| inner)
1128-
.labelled("type")
1117+
choice((sum_type, option_type, tuple, array, list, atom)).labelled("type")
11291118
})
11301119
}
11311120
}
@@ -1164,7 +1153,7 @@ impl ChumskyParse for Item {
11641153
let type_parser = TypeAlias::parser().map(Item::TypeAlias);
11651154
let mod_parser = Module::parser().map(|_| Item::Module);
11661155

1167-
choice((func_parser, type_parser, mod_parser))
1156+
choice((func_parser, type_parser, mod_parser)).labelled("item")
11681157
}
11691158
}
11701159

@@ -1200,7 +1189,7 @@ impl ChumskyParse for Function {
12001189
(Token::LParen, Token::RParen),
12011190
(Token::LBracket, Token::RBracket),
12021191
],
1203-
Expression::empty,
1192+
Expression::error,
12041193
)))
12051194
.labelled("function body");
12061195

@@ -1493,7 +1482,7 @@ impl ChumskyParse for Expression {
14931482
(Token::RAngle, Token::RAngle),
14941483
(Token::LBracket, Token::RBracket),
14951484
],
1496-
|span| Expression::empty(span).inner().clone(),
1485+
|span| Expression::error(span).inner().clone(),
14971486
);
14981487

14991488
let statements = statement
@@ -1754,7 +1743,7 @@ impl Match {
17541743
}
17551744
_ => {
17561745
let match_arm_fallback = MatchArm {
1757-
expression: Arc::new(Expression::empty(Span::new(0, 0))),
1746+
expression: Arc::new(Expression::error(Span::new(0, 0))),
17581747
pattern: MatchPattern::False,
17591748
};
17601749

src/types.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ pub enum TypeInner<A> {
2727
Array(A, usize),
2828
/// List of the same type
2929
List(A, NonZeroPow2Usize),
30+
/// Error type
31+
Error,
3032
}
3133

3234
impl<A> TypeInner<A> {
@@ -85,6 +87,7 @@ impl<A> TypeInner<A> {
8587
write!(f, ", {bound}>")
8688
}
8789
},
90+
TypeInner::Error => write!(f, "ERROR"),
8891
}
8992
}
9093
}
@@ -324,6 +327,14 @@ impl ResolvedType {
324327
pub fn as_inner(&self) -> &TypeInner<Arc<Self>> {
325328
&self.0
326329
}
330+
331+
pub const fn error() -> Self {
332+
Self(TypeInner::Error)
333+
}
334+
335+
pub fn is_error(&self) -> bool {
336+
matches!(self.as_inner(), TypeInner::Error)
337+
}
327338
}
328339

329340
impl TypeConstructible for ResolvedType {
@@ -409,6 +420,7 @@ impl TreeLike for &ResolvedType {
409420
TypeInner::Option(l) | TypeInner::Array(l, _) | TypeInner::List(l, _) => Tree::Unary(l),
410421
TypeInner::Either(l, r) => Tree::Binary(l, r),
411422
TypeInner::Tuple(elements) => Tree::Nary(elements.iter().map(Arc::as_ref).collect()),
423+
TypeInner::Error => Tree::Nullary,
412424
}
413425
}
414426
}
@@ -548,6 +560,10 @@ impl AliasedType {
548560
}
549561
}
550562

563+
pub fn error() -> Self {
564+
Self(AliasedInner::Inner(TypeInner::Error))
565+
}
566+
551567
/// Create a type alias from the given `identifier`.
552568
pub const fn alias(name: AliasName) -> Self {
553569
Self(AliasedInner::Alias(name))
@@ -600,6 +616,7 @@ impl AliasedType {
600616
let element = output.pop().unwrap();
601617
output.push(ResolvedType::list(element, *bound));
602618
}
619+
TypeInner::Error => return Ok(ResolvedType::error()),
603620
},
604621
}
605622
}
@@ -711,6 +728,7 @@ impl TreeLike for &AliasedType {
711728
TypeInner::Tuple(elements) => {
712729
Tree::Nary(elements.iter().map(Arc::as_ref).collect())
713730
}
731+
TypeInner::Error => Tree::Nullary,
714732
},
715733
}
716734
}
@@ -1004,6 +1022,9 @@ impl From<&ResolvedType> for StructuralType {
10041022
let element = output.pop().unwrap();
10051023
output.push(StructuralType::list(element, *bound));
10061024
}
1025+
// Not sure what to put here, but it should not be unreachable in correctly builded
1026+
// AST.
1027+
TypeInner::Error => output.push(StructuralType::unit()),
10071028
}
10081029
}
10091030
debug_assert_eq!(output.len(), 1);

src/value.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ impl Value {
775775
}
776776
}
777777
}
778+
TypeInner::Error => return None,
778779
}
779780
}
780781
debug_assert_eq!(output.len(), 1);
@@ -836,6 +837,7 @@ impl crate::ArbitraryOfType for Value {
836837
.collect::<arbitrary::Result<Vec<Self>>>()?;
837838
Ok(Self::list(elements, ty.as_ref().clone(), *bound))
838839
}
840+
TypeInner::Error => Self::arbitrary_of_type(u, &ResolvedType::error()),
839841
}
840842
}
841843
}
@@ -1159,6 +1161,7 @@ impl TreeLike for Destructor<'_> {
11591161
),
11601162
None => Tree::Unary(Self::WrongType),
11611163
},
1164+
TypeInner::Error => Tree::Nullary,
11621165
}
11631166
}
11641167
}

0 commit comments

Comments
 (0)