[fine] More resilience

We don't lose function declarations and whatnot, although we get lost
with broken return types.
This commit is contained in:
John Doty 2024-01-31 07:46:20 -08:00
parent 93c9dcd13b
commit 7f30d0ccc3
3 changed files with 98 additions and 39 deletions

View file

@ -480,10 +480,6 @@ impl<'a> CParser<'a> {
}); });
} }
fn synchronize(&mut self) {
if self.panic {}
}
fn build_tree(self) -> (SyntaxTree<'a>, Lines) { fn build_tree(self) -> (SyntaxTree<'a>, Lines) {
let mut events = self.events; let mut events = self.events;
let mut stack = Vec::new(); let mut stack = Vec::new();
@ -551,7 +547,15 @@ fn file(p: &mut CParser) {
// the right-brace that a block would end with.) // the right-brace that a block would end with.)
p.advance_with_error("unbalanced '}'"); p.advance_with_error("unbalanced '}'");
} }
_ => statement(p), _ => {
if !statement(p) {
if p.at_any(STATEMENT_RECOVERY) {
break;
} else {
p.advance_with_error("expected statement");
}
}
}
} }
} }
p.end(m, TreeKind::File); p.end(m, TreeKind::File);
@ -715,19 +719,35 @@ fn type_parameter(p: &mut CParser) {
p.end(m, TreeKind::TypeParameter); p.end(m, TreeKind::TypeParameter);
} }
const STATEMENT_RECOVERY: &[TokenKind] = &[
TokenKind::RightBrace,
TokenKind::Fun,
TokenKind::LeftBrace,
TokenKind::Let,
TokenKind::Return,
TokenKind::For,
TokenKind::Class,
];
fn block(p: &mut CParser) { fn block(p: &mut CParser) {
let m = p.start(); let m = p.start();
p.expect_start(TokenKind::LeftBrace); p.expect_start(TokenKind::LeftBrace);
while !p.at(TokenKind::RightBrace) && !p.eof() { while !p.at(TokenKind::RightBrace) && !p.eof() {
statement(p); if !statement(p) {
if p.at_any(STATEMENT_RECOVERY) {
break;
} else {
p.advance_with_error("expected statement");
}
}
} }
p.expect(TokenKind::RightBrace, "expect '}' to end a block"); p.expect(TokenKind::RightBrace, "expect '}' to end a block");
p.end(m, TreeKind::Block); p.end(m, TreeKind::Block);
} }
fn statement(p: &mut CParser) { fn statement(p: &mut CParser) -> bool {
match p.peek() { match p.peek() {
TokenKind::Fun => function(p), TokenKind::Fun => function(p),
TokenKind::LeftBrace => block(p), TokenKind::LeftBrace => block(p),
@ -739,8 +759,16 @@ fn statement(p: &mut CParser) {
// require a semicolon at the end if it's all by itself. // require a semicolon at the end if it's all by itself.
TokenKind::If => statement_if(p), TokenKind::If => statement_if(p),
_ => statement_expression(p), _ => {
if p.at(TokenKind::Semicolon) || p.at_any(EXPRESSION_FIRST) {
statement_expression(p)
} else {
return false;
}
}
} }
true
} }
fn statement_if(p: &mut CParser) { fn statement_if(p: &mut CParser) {
@ -758,7 +786,9 @@ fn statement_let(p: &mut CParser) {
p.expect_start(TokenKind::Let); p.expect_start(TokenKind::Let);
p.expect(TokenKind::Identifier, "expected a name for the variable"); p.expect(TokenKind::Identifier, "expected a name for the variable");
p.expect(TokenKind::Equal, "expected a '=' after the variable name"); p.expect(TokenKind::Equal, "expected a '=' after the variable name");
expression(p); if p.at_any(EXPRESSION_FIRST) {
expression(p);
}
if !p.at(TokenKind::RightBrace) { if !p.at(TokenKind::RightBrace) {
p.expect(TokenKind::Semicolon, "expect ';' to end a let statement"); p.expect(TokenKind::Semicolon, "expect ';' to end a let statement");
} }
@ -770,8 +800,10 @@ fn statement_return(p: &mut CParser) {
let m = p.start(); let m = p.start();
p.expect_start(TokenKind::Return); p.expect_start(TokenKind::Return);
// TODO: Make expression optional if we're returning () if p.at_any(EXPRESSION_FIRST) {
expression(p); // TODO: Make expression optional if we're returning ()
expression(p);
}
if !p.at(TokenKind::RightBrace) { if !p.at(TokenKind::RightBrace) {
p.expect(TokenKind::Semicolon, "expect ';' to end a return statement"); p.expect(TokenKind::Semicolon, "expect ';' to end a return statement");
} }
@ -788,8 +820,12 @@ fn statement_for(p: &mut CParser) {
"expected an identifier for the loop variable", "expected an identifier for the loop variable",
); );
p.expect(TokenKind::In, "expect an 'in' after the loop variable"); p.expect(TokenKind::In, "expect an 'in' after the loop variable");
expression(p); if p.at_any(EXPRESSION_FIRST) {
block(p); expression(p);
}
if p.at(TokenKind::LeftBrace) {
block(p);
}
p.end(m, TreeKind::ForStatement); p.end(m, TreeKind::ForStatement);
} }
@ -797,7 +833,7 @@ fn statement_for(p: &mut CParser) {
fn statement_expression(p: &mut CParser) { fn statement_expression(p: &mut CParser) {
let m = p.start(); let m = p.start();
if !p.at(TokenKind::RightBrace) && !p.at(TokenKind::Semicolon) { if p.at_any(EXPRESSION_FIRST) {
expression(p); expression(p);
} }
if !p.at(TokenKind::RightBrace) { if !p.at(TokenKind::RightBrace) {
@ -810,6 +846,21 @@ fn statement_expression(p: &mut CParser) {
p.end(m, TreeKind::ExpressionStatement); p.end(m, TreeKind::ExpressionStatement);
} }
const EXPRESSION_FIRST: &[TokenKind] = &[
TokenKind::Number,
TokenKind::String,
TokenKind::True,
TokenKind::False,
TokenKind::LeftParen,
TokenKind::Bang,
TokenKind::Minus,
TokenKind::If,
TokenKind::Identifier,
TokenKind::Selff,
TokenKind::LeftBracket,
TokenKind::New,
];
fn expression(p: &mut CParser) { fn expression(p: &mut CParser) {
expression_with_power(p, 0) expression_with_power(p, 0)
} }
@ -840,7 +891,9 @@ fn infix_power(token: TokenKind) -> Option<(u8, u8)> {
} }
fn expression_with_power(p: &mut CParser, minimum_power: u8) { fn expression_with_power(p: &mut CParser, minimum_power: u8) {
let mut expr = prefix_expression(p); let Some(mut expr) = prefix_expression(p) else {
return;
};
while p.at(TokenKind::LeftParen) { while p.at(TokenKind::LeftParen) {
let m = p.start_before(expr); let m = p.start_before(expr);
argument_list(p); argument_list(p);
@ -877,7 +930,11 @@ fn argument_list(p: &mut CParser) {
p.expect_start(TokenKind::LeftParen); p.expect_start(TokenKind::LeftParen);
while !p.at(TokenKind::RightParen) && !p.eof() { while !p.at(TokenKind::RightParen) && !p.eof() {
argument(p); if p.at_any(EXPRESSION_FIRST) {
argument(p);
} else {
break;
}
} }
p.expect( p.expect(
TokenKind::RightParen, TokenKind::RightParen,
@ -898,8 +955,8 @@ fn argument(p: &mut CParser) {
p.end(m, TreeKind::Argument); p.end(m, TreeKind::Argument);
} }
fn prefix_expression(p: &mut CParser) -> MarkClosed { fn prefix_expression(p: &mut CParser) -> Option<MarkClosed> {
match p.peek() { let result = match p.peek() {
TokenKind::Number => literal(p), TokenKind::Number => literal(p),
TokenKind::String => literal(p), TokenKind::String => literal(p),
TokenKind::True => literal(p), TokenKind::True => literal(p),
@ -919,8 +976,12 @@ fn prefix_expression(p: &mut CParser) -> MarkClosed {
TokenKind::New => object_constructor(p), TokenKind::New => object_constructor(p),
_ => p.advance_with_error("expected an expression"), _ => {
} assert!(!p.at_any(EXPRESSION_FIRST));
return None;
}
};
Some(result)
} }
fn literal(p: &mut CParser) -> MarkClosed { fn literal(p: &mut CParser) -> MarkClosed {
@ -995,7 +1056,11 @@ fn list_constructor(p: &mut CParser) -> MarkClosed {
p.expect_start(TokenKind::LeftBracket); p.expect_start(TokenKind::LeftBracket);
while !p.at(TokenKind::RightBracket) && !p.eof() { while !p.at(TokenKind::RightBracket) && !p.eof() {
list_constructor_element(p); if p.at_any(EXPRESSION_FIRST) {
list_constructor_element(p);
} else {
break;
}
} }
p.expect( p.expect(
TokenKind::RightBracket, TokenKind::RightBracket,

View file

@ -8,10 +8,9 @@ class Bar {
} }
fun extract_value(v: Foo or Bar) -> f64 { fun extract_value(v: Foo or Bar) -> f64 {
if v is Foo { match v {
v.x // Magic type binding! v:Foo -> v.x,
} else if v is Bar { v:Bar -> v.y,
v.y // Same magic re-binding of the variable to the new type
} // No error; exhaustivity analysis should work. } // No error; exhaustivity analysis should work.
} }
@ -34,10 +33,9 @@ class Monster {
fun print(x:string) {} fun print(x:string) {}
fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) { fun in_range(weapon: MeleeWeapon or RangedWeapon, distance: f64) {
if weapon is w : RangedWeapon { weapon match {
distance >= w.minRange and distance <= w.maxRange w:RangedWeapon -> distance >= w.minRange and distance <= w.maxRange,
} else { _ -> distance == 1
distance == 1
} }
} }
@ -60,12 +58,9 @@ fun attack(weapon: MeleeWeapon or RangedWeapon, monster: Monster, distance: f64)
// local variables. The *almost* part is that the effective type of the // local variables. The *almost* part is that the effective type of the
// variable changes but not the binding. (Is this what we want?) // variable changes but not the binding. (Is this what we want?)
// //
// TODO: What do we do about captured variables? let damage = match weapon {
// w:MeleeWeapon -> roll_dice(w.damage),
let damage = if weapon is w: MeleeWeapon { w:RangedWeapon -> w.maxRange - w.minRange,
roll_dice(w.damage)
} else if weapon is w: RangedWeapon {
w.maxRange - w.minRange
}; };
if monster.health <= damage { if monster.health <= damage {
@ -87,7 +82,7 @@ fun more_examples(weapon: MeleeWeapon or RangedWeapon) -> f64 or () {
// Some fun with iterators // Some fun with iterators
class Finished {} class Finished {}
let FINISHED = new Finished {} let FINISHED = new Finished {};
class Iterator { class Iterator {
current: f64; current: f64;
@ -132,5 +127,5 @@ fun test() -> f64 {
// like the above. // like the above.
} }
// @ignore WIP /// @ignore WIP
// @no-errors // @no-errors

View file

@ -17,6 +17,5 @@ fun test() {
// matklad talks about in his resilient parser article. // matklad talks about in his resilient parser article.
// //
// @expect-errors: // @expect-errors:
// | 7:12: Error at '{': expected an expression // | 7:12: Error at '{': expect ';' to end a let statement
// | 7:26: cannot find value foo here // | 7:26: cannot find value foo here
// | 8:0: Error at '}': unbalanced '}'