Skip to content

Commit 4bdb877

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 c307dae commit 4bdb877

5 files changed

Lines changed: 63 additions & 32 deletions

File tree

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 & 32 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().with_span(*self.as_ref()),
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
@@ -936,13 +948,7 @@ impl<A: ChumskyParse + std::fmt::Debug> ParseFromStrWithErrors for A {
936948

937949
handler.update(parse_errs);
938950

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

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

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

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

@@ -1114,18 +1110,13 @@ impl ChumskyParse for AliasedType {
11141110
})),
11151111
Token::LAngle,
11161112
Token::RAngle,
1117-
|_| {
1118-
(
1119-
AliasedType::alias(AliasName::from_str_unchecked("error")),
1120-
NonZeroPow2Usize::TWO,
1121-
)
1122-
},
1113+
|_| (AliasedType::error(), NonZeroPow2Usize::TWO),
11231114
))
11241115
.map(|(ty, size)| AliasedType::list(ty, size))
11251116
.labelled("List");
11261117

11271118
choice((sum_type, option_type, tuple, array, list, atom))
1128-
.map_with(|inner, _| inner)
1119+
.map_with(|inner, e| inner.with_span(e.span()))
11291120
.labelled("type")
11301121
})
11311122
}
@@ -1165,7 +1156,7 @@ impl ChumskyParse for Item {
11651156
let type_parser = TypeAlias::parser().map(Item::TypeAlias);
11661157
let mod_parser = Module::parser().map(|_| Item::Module);
11671158

1168-
choice((func_parser, type_parser, mod_parser))
1159+
choice((func_parser, type_parser, mod_parser)).labelled("item")
11691160
}
11701161
}
11711162

@@ -1201,7 +1192,7 @@ impl ChumskyParse for Function {
12011192
(Token::LParen, Token::RParen),
12021193
(Token::LBracket, Token::RBracket),
12031194
],
1204-
Expression::empty,
1195+
Expression::error,
12051196
)))
12061197
.labelled("function body");
12071198

@@ -1495,7 +1486,7 @@ impl ChumskyParse for Expression {
14951486
(Token::RAngle, Token::RAngle),
14961487
(Token::LBracket, Token::RBracket),
14971488
],
1498-
|span| Expression::empty(span).inner().clone(),
1489+
|span| Expression::error(span).inner().clone(),
14991490
);
15001491

15011492
let statements = statement
@@ -1762,7 +1753,7 @@ impl Match {
17621753
}
17631754
_ => {
17641755
let match_arm_fallback = MatchArm {
1765-
expression: Arc::new(Expression::empty(Span::new(0, 0))),
1756+
expression: Arc::new(Expression::error(Span::new(0, 0))),
17661757
pattern: MatchPattern::False,
17671758
};
17681759

src/types.rs

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

3335
impl<A> TypeInner<A> {
@@ -86,6 +88,7 @@ impl<A> TypeInner<A> {
8688
write!(f, ", {bound}>")
8789
}
8890
},
91+
TypeInner::Error => write!(f, "ERROR"),
8992
}
9093
}
9194
}
@@ -325,6 +328,14 @@ impl ResolvedType {
325328
pub fn as_inner(&self) -> &TypeInner<Arc<Self>> {
326329
&self.0
327330
}
331+
332+
pub const fn error() -> Self {
333+
Self(TypeInner::Error)
334+
}
335+
336+
pub fn is_error(&self) -> bool {
337+
matches!(self.as_inner(), TypeInner::Error)
338+
}
328339
}
329340

330341
impl TypeConstructible for ResolvedType {
@@ -410,6 +421,7 @@ impl TreeLike for &ResolvedType {
410421
TypeInner::Option(l) | TypeInner::Array(l, _) | TypeInner::List(l, _) => Tree::Unary(l),
411422
TypeInner::Either(l, r) => Tree::Binary(l, r),
412423
TypeInner::Tuple(elements) => Tree::Nary(elements.iter().map(Arc::as_ref).collect()),
424+
TypeInner::Error => Tree::Nullary,
413425
}
414426
}
415427
}
@@ -561,6 +573,10 @@ impl AliasedType {
561573
Self(self.0, span)
562574
}
563575

576+
pub fn error() -> Self {
577+
Self::new(AliasedInner::Inner(TypeInner::Error))
578+
}
579+
564580
/// Create a type alias from the given `identifier`.
565581
pub const fn alias(name: AliasName) -> Self {
566582
Self::new(AliasedInner::Alias(name))
@@ -613,6 +629,7 @@ impl AliasedType {
613629
let element = output.pop().unwrap();
614630
output.push(ResolvedType::list(element, *bound));
615631
}
632+
TypeInner::Error => return Ok(ResolvedType::error()),
616633
},
617634
}
618635
}
@@ -724,6 +741,7 @@ impl TreeLike for &AliasedType {
724741
TypeInner::Tuple(elements) => {
725742
Tree::Nary(elements.iter().map(Arc::as_ref).collect())
726743
}
744+
TypeInner::Error => Tree::Nullary,
727745
},
728746
}
729747
}
@@ -1017,6 +1035,9 @@ impl From<&ResolvedType> for StructuralType {
10171035
let element = output.pop().unwrap();
10181036
output.push(StructuralType::list(element, *bound));
10191037
}
1038+
// Not sure what to put here, but it should not be unreachable in correctly builded
1039+
// AST.
1040+
TypeInner::Error => output.push(StructuralType::unit()),
10201041
}
10211042
}
10221043
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)