diff --git a/grammar.ron b/grammar.ron index c4f6283e61..18af8d1238 100644 --- a/grammar.ron +++ b/grammar.ron @@ -62,6 +62,7 @@ Grammar( ], nodes: [ "FILE", - "STRUCT_ITEM" + "STRUCT_ITEM", + "STRUCT_FIELD", ] ) \ No newline at end of file diff --git a/src/bin/gen.rs b/src/bin/gen.rs index 9d7f7e3893..5ebf3e2e88 100644 --- a/src/bin/gen.rs +++ b/src/bin/gen.rs @@ -6,7 +6,6 @@ extern crate ron; extern crate file; use std::path::PathBuf; -use std::ascii::AsciiExt; use std::fmt::Write; fn main() { diff --git a/src/parser/event_parser/grammar.rs b/src/parser/event_parser/grammar.rs index be61483ecd..77596fea6d 100644 --- a/src/parser/event_parser/grammar.rs +++ b/src/parser/event_parser/grammar.rs @@ -1,4 +1,3 @@ -use super::Event; use super::parser::Parser; use syntax_kinds::*; @@ -50,10 +49,26 @@ fn item(p: &mut Parser) -> Result { ERR } -fn struct_item(p: &mut Parser) -> Result{ +fn struct_item(p: &mut Parser) -> Result { p.expect(IDENT)?; - p.expect(L_CURLY)?; - p.expect(R_CURLY) + p.curly_block(|p| { + comma_list(p, struct_field) + }) +} + +fn struct_field(p: &mut Parser) -> Result { + if !p.current_is(IDENT) { + return ERR; + } + p.start(STRUCT_FIELD); + p.bump(); + ignore_errors(|| { + p.expect(COLON)?; + p.expect(IDENT)?; + OK + }); + p.finish(); + OK } // Paths, types, attributes, and stuff // @@ -78,4 +93,19 @@ fn skip_one_token(p: &mut Parser) { p.start(ERROR); p.bump().unwrap(); p.finish(); +} + +fn ignore_errors Result>(f: F) { + drop(f()); +} + +fn comma_list Result>(p: &mut Parser, element: F) { + loop { + if element(p).is_err() { + return + } + if p.expect(COMMA).is_err() { + return + } + } } \ No newline at end of file diff --git a/src/parser/event_parser/mod.rs b/src/parser/event_parser/mod.rs index 1228236a96..3c3654b6b3 100644 --- a/src/parser/event_parser/mod.rs +++ b/src/parser/event_parser/mod.rs @@ -1,6 +1,5 @@ -use {Token, TextUnit, SyntaxKind}; +use {Token, SyntaxKind}; -use syntax_kinds::*; mod grammar; mod parser; diff --git a/src/parser/event_parser/parser.rs b/src/parser/event_parser/parser.rs index 36452ef671..04ef4fb284 100644 --- a/src/parser/event_parser/parser.rs +++ b/src/parser/event_parser/parser.rs @@ -1,7 +1,7 @@ use {Token, SyntaxKind, TextUnit}; use super::{Event}; use super::super::is_insignificant; -use syntax_kinds::{WHITESPACE, COMMENT}; +use syntax_kinds::{L_CURLY, R_CURLY, ERROR}; pub struct Parser<'t> { text: &'t str, @@ -10,6 +10,7 @@ pub struct Parser<'t> { pos: usize, events: Vec, + curly_level: i32, } impl<'t> Parser<'t> { @@ -30,6 +31,7 @@ impl<'t> Parser<'t> { pos: 0, events: Vec::new(), + curly_level: 0, } } @@ -64,6 +66,11 @@ impl<'t> Parser<'t> { pub(crate) fn bump(&mut self) -> Option { let kind = self.current()?; + match kind { + L_CURLY => self.curly_level += 1, + R_CURLY => self.curly_level -= 1, + _ => (), + } self.pos += 1; self.event(Event::Token { kind, n_raw_tokens: 1 }); Some(kind) @@ -78,6 +85,24 @@ impl<'t> Parser<'t> { } } + pub(crate) fn curly_block(&mut self, f: F) -> Result<(), ()> { + let level = self.curly_level; + self.expect(L_CURLY)?; + f(self); + assert!(self.curly_level > level); + if self.expect(R_CURLY).is_ok() { + return Ok(()); + } + self.start(ERROR); + while self.curly_level > level { + if self.bump().is_none() { + break; + } + } + self.finish(); + Ok(()) //??? + } + fn event(&mut self, event: Event) { self.events.push(event) } diff --git a/src/syntax_kinds.rs b/src/syntax_kinds.rs index d9b1462a7f..4a27b0eae6 100644 --- a/src/syntax_kinds.rs +++ b/src/syntax_kinds.rs @@ -60,8 +60,9 @@ pub const DOC_COMMENT: SyntaxKind = SyntaxKind(55); pub const SHEBANG: SyntaxKind = SyntaxKind(56); pub const FILE: SyntaxKind = SyntaxKind(57); pub const STRUCT_ITEM: SyntaxKind = SyntaxKind(58); +pub const STRUCT_FIELD: SyntaxKind = SyntaxKind(59); -static INFOS: [SyntaxInfo; 59] = [ +static INFOS: [SyntaxInfo; 60] = [ SyntaxInfo { name: "USE_KW" }, SyntaxInfo { name: "FN_KW" }, SyntaxInfo { name: "STRUCT_KW" }, @@ -121,6 +122,7 @@ static INFOS: [SyntaxInfo; 59] = [ SyntaxInfo { name: "SHEBANG" }, SyntaxInfo { name: "FILE" }, SyntaxInfo { name: "STRUCT_ITEM" }, + SyntaxInfo { name: "STRUCT_FIELD" }, ]; pub(crate) fn syntax_info(kind: SyntaxKind) -> &'static SyntaxInfo { diff --git a/tests/data/parser/0002_struct_item_field.rs b/tests/data/parser/0002_struct_item_field.rs new file mode 100644 index 0000000000..cc3866d251 --- /dev/null +++ b/tests/data/parser/0002_struct_item_field.rs @@ -0,0 +1,3 @@ +struct S { + foo: u32 +} \ No newline at end of file diff --git a/tests/data/parser/0002_struct_item_field.txt b/tests/data/parser/0002_struct_item_field.txt new file mode 100644 index 0000000000..b1673ade3e --- /dev/null +++ b/tests/data/parser/0002_struct_item_field.txt @@ -0,0 +1,15 @@ +FILE@[0; 25) + STRUCT_ITEM@[0; 25) + STRUCT_KW@[0; 6) + WHITESPACE@[6; 7) + IDENT@[7; 8) + WHITESPACE@[8; 9) + L_CURLY@[9; 10) + STRUCT_FIELD@[10; 24) + WHITESPACE@[10; 15) + IDENT@[15; 18) + COLON@[18; 19) + WHITESPACE@[19; 20) + IDENT@[20; 23) + WHITESPACE@[23; 24) + R_CURLY@[24; 25) \ No newline at end of file diff --git a/tests/parser.rs b/tests/parser.rs index e71b488523..5c63be3be1 100644 --- a/tests/parser.rs +++ b/tests/parser.rs @@ -61,7 +61,8 @@ fn dump_tree(file: &File) -> String { fn go(node: Node, buff: &mut String, level: usize) { buff.push_str(&String::from(" ").repeat(level)); - write!(buff, "{:?}\n", node); + write!(buff, "{:?}\n", node) + .unwrap(); for child in node.children() { go(child, buff, level + 1) }