[fine] Some resilience, a design improvement for iterator
This commit is contained in:
parent
15548afc38
commit
f2e82942df
4 changed files with 29 additions and 8 deletions
|
|
@ -318,6 +318,7 @@ struct CParser<'a> {
|
||||||
current: Token<'a>,
|
current: Token<'a>,
|
||||||
fuel: Cell<u32>,
|
fuel: Cell<u32>,
|
||||||
events: Vec<ParseEvent<'a>>,
|
events: Vec<ParseEvent<'a>>,
|
||||||
|
panic: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CParser<'a> {
|
impl<'a> CParser<'a> {
|
||||||
|
|
@ -327,6 +328,7 @@ impl<'a> CParser<'a> {
|
||||||
current: Token::new(TokenKind::EOF, 0, ""),
|
current: Token::new(TokenKind::EOF, 0, ""),
|
||||||
fuel: Cell::new(256),
|
fuel: Cell::new(256),
|
||||||
events: Vec::new(),
|
events: Vec::new(),
|
||||||
|
panic: false,
|
||||||
};
|
};
|
||||||
parser.current = parser.tokens.next();
|
parser.current = parser.tokens.next();
|
||||||
parser.skip_ephemera();
|
parser.skip_ephemera();
|
||||||
|
|
@ -412,6 +414,7 @@ impl<'a> CParser<'a> {
|
||||||
|
|
||||||
fn eat(&mut self, kind: TokenKind) -> bool {
|
fn eat(&mut self, kind: TokenKind) -> bool {
|
||||||
if self.at(kind) {
|
if self.at(kind) {
|
||||||
|
self.panic = false; // Check
|
||||||
self.advance();
|
self.advance();
|
||||||
true
|
true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -454,6 +457,11 @@ impl<'a> CParser<'a> {
|
||||||
where
|
where
|
||||||
T: Into<String>,
|
T: Into<String>,
|
||||||
{
|
{
|
||||||
|
if self.panic {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
self.panic = true;
|
||||||
|
|
||||||
let message: String = message.into();
|
let message: String = message.into();
|
||||||
let mut final_message = "Error ".to_string();
|
let mut final_message = "Error ".to_string();
|
||||||
|
|
||||||
|
|
@ -472,6 +480,10 @@ 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();
|
||||||
|
|
@ -599,21 +611,23 @@ fn field_decl(p: &mut CParser) {
|
||||||
p.end(m, TreeKind::FieldDecl);
|
p.end(m, TreeKind::FieldDecl);
|
||||||
}
|
}
|
||||||
|
|
||||||
const PARAM_LIST_RECOVERY: &[TokenKind] = &[TokenKind::Arrow, TokenKind::LeftBrace, TokenKind::Fun];
|
const PARAM_LIST_RECOVERY: &[TokenKind] = &[
|
||||||
|
TokenKind::Arrow,
|
||||||
|
TokenKind::LeftBrace,
|
||||||
|
TokenKind::Fun,
|
||||||
|
TokenKind::RightParen,
|
||||||
|
];
|
||||||
|
|
||||||
fn param_list(p: &mut CParser) {
|
fn param_list(p: &mut CParser) {
|
||||||
let m = p.start();
|
let m = p.start();
|
||||||
|
|
||||||
p.expect_start(TokenKind::LeftParen);
|
p.expect_start(TokenKind::LeftParen);
|
||||||
while !p.at(TokenKind::RightParen) && !p.eof() {
|
while !p.at_any(PARAM_LIST_RECOVERY) && !p.eof() {
|
||||||
if p.at(TokenKind::Identifier) {
|
if p.at(TokenKind::Identifier) {
|
||||||
parameter(p);
|
parameter(p);
|
||||||
} else if p.at(TokenKind::Selff) {
|
} else if p.at(TokenKind::Selff) {
|
||||||
self_parameter(p);
|
self_parameter(p);
|
||||||
} else {
|
} else {
|
||||||
if p.at_any(PARAM_LIST_RECOVERY) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
p.advance_with_error("expected parameter");
|
p.advance_with_error("expected parameter");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,16 +83,20 @@ fun more_examples(weapon: MeleeWeapon or RangedWeapon) -> f64 or () {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some fun with iterators
|
// Some fun with iterators
|
||||||
|
class Finished {}
|
||||||
|
let FINISHED = new Finished {}
|
||||||
|
|
||||||
class Iterator {
|
class Iterator {
|
||||||
current: f64;
|
current: f64;
|
||||||
|
|
||||||
fun next(self) -> f64 or () {
|
fun next(self) -> f64 or Finished {
|
||||||
if self.current < 10 {
|
if self.current < 10 {
|
||||||
let result = self.current;
|
let result = self.current;
|
||||||
self.current = self.current + 1;
|
self.current = self.current + 1;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
FINISHED
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,3 @@ fun test() {
|
||||||
// NOTE: These errors should be better
|
// NOTE: These errors should be better
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | 2:10: Error at 'true': expected a block after `if`
|
// | 2:10: Error at 'true': expected a block after `if`
|
||||||
// | 2:15: Error at '{': expect ';' to end an expression statement
|
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,12 @@ fun test() {
|
||||||
// We need to make sure things are parsed correctly.
|
// We need to make sure things are parsed correctly.
|
||||||
//
|
//
|
||||||
// TODO: Better parser recovery will improve the specifics of the errors.
|
// TODO: Better parser recovery will improve the specifics of the errors.
|
||||||
|
//
|
||||||
|
// TODO: This is parsed wrong; the `{` is consumed after the '.' and it
|
||||||
|
// should instead be ignored. This is the "greedy" expression parsing that
|
||||||
|
// matklad talks about in his resilient parser article.
|
||||||
|
//
|
||||||
// @expect-errors:
|
// @expect-errors:
|
||||||
// | 7:12: Error at '{': expected an expression
|
// | 7:12: Error at '{': expected an expression
|
||||||
// | 7:13: Error at 'let': 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 '}'
|
// | 8:0: Error at '}': unbalanced '}'
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue