[fine] More resilience
We don't lose function declarations and whatnot, although we get lost with broken return types.
This commit is contained in:
parent
93c9dcd13b
commit
7f30d0ccc3
3 changed files with 98 additions and 39 deletions
|
|
@ -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,
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 '}'
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue