Skip to content

Commit aa36ad0

Browse files
committed
Merge #41
41: G: unsafe impl & trait r=matklad a=matklad bors r+
2 parents 5e5313a + d417955 commit aa36ad0

22 files changed

+228
-161
lines changed

grammar.ron

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,8 @@ Grammar(
9191
"USE_ITEM",
9292
"STATIC_ITEM",
9393
"CONST_ITEM",
94+
"TRAIT_ITEM",
95+
"IMPL_ITEM",
9496

9597
"EXTERN_BLOCK",
9698
"ENUM_VARIANT",

src/parser/event.rs

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
use {File, FileBuilder, Sink, SyntaxKind, Token};
2+
use syntax_kinds::TOMBSTONE;
3+
use super::is_insignificant;
4+
5+
/// `Parser` produces a flat list of `Event`s.
6+
/// They are converted to a tree-structure in
7+
/// a separate pass, via `TreeBuilder`.
8+
#[derive(Debug)]
9+
pub(crate) enum Event {
10+
/// This event signifies the start of the node.
11+
/// It should be either abandoned (in which case the
12+
/// `kind` is `TOMBSTONE`, and the event is ignored),
13+
/// or completed via a `Finish` event.
14+
///
15+
/// All tokens between a `Start` and a `Finish` would
16+
/// become the children of the respective node.
17+
///
18+
/// For left-recursive syntactic constructs, the parser produces
19+
/// a child node before it sees a parent. `forward_parent`
20+
/// exists to allow to tweak parent-child relationships.
21+
///
22+
/// Consider this path
23+
///
24+
/// foo::bar
25+
///
26+
/// The events for it would look like this:
27+
///
28+
///
29+
/// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
30+
/// | /\
31+
/// | |
32+
/// +------forward-parent------+
33+
///
34+
/// And the tree would look like this
35+
///
36+
/// +--PATH---------+
37+
/// | | |
38+
/// | | |
39+
/// | '::' 'bar'
40+
/// |
41+
/// PATH
42+
/// |
43+
/// 'foo'
44+
///
45+
/// See also `CompleteMarker::precede`.
46+
Start {
47+
kind: SyntaxKind,
48+
forward_parent: Option<u32>,
49+
},
50+
51+
/// Complete the previous `Start` event
52+
Finish,
53+
54+
/// Produce a single leaf-element.
55+
/// `n_raw_tokens` is used to glue complex contextual tokens.
56+
/// For example, lexer tokenizes `>>` as `>`, `>`, and
57+
/// `n_raw_tokens = 2` is used to produced a single `>>`.
58+
Token {
59+
kind: SyntaxKind,
60+
n_raw_tokens: u8,
61+
},
62+
63+
Error {
64+
message: String,
65+
},
66+
}
67+
68+
pub(super) fn to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File {
69+
let mut builder = FileBuilder::new(text);
70+
let mut idx = 0;
71+
72+
let mut holes = Vec::new();
73+
let mut forward_parents = Vec::new();
74+
75+
for (i, event) in events.iter().enumerate() {
76+
if holes.last() == Some(&i) {
77+
holes.pop();
78+
continue;
79+
}
80+
81+
match event {
82+
&Event::Start {
83+
kind: TOMBSTONE, ..
84+
} => (),
85+
86+
&Event::Start { .. } => {
87+
forward_parents.clear();
88+
let mut idx = i;
89+
loop {
90+
let (kind, fwd) = match events[idx] {
91+
Event::Start {
92+
kind,
93+
forward_parent,
94+
} => (kind, forward_parent),
95+
_ => unreachable!(),
96+
};
97+
forward_parents.push((idx, kind));
98+
if let Some(fwd) = fwd {
99+
idx += fwd as usize;
100+
} else {
101+
break;
102+
}
103+
}
104+
for &(idx, kind) in forward_parents.iter().into_iter().rev() {
105+
builder.start_internal(kind);
106+
holes.push(idx);
107+
}
108+
holes.pop();
109+
}
110+
&Event::Finish => {
111+
while idx < tokens.len() {
112+
let token = tokens[idx];
113+
if is_insignificant(token.kind) {
114+
idx += 1;
115+
builder.leaf(token.kind, token.len);
116+
} else {
117+
break;
118+
}
119+
}
120+
builder.finish_internal()
121+
}
122+
&Event::Token {
123+
kind: _,
124+
mut n_raw_tokens,
125+
} => loop {
126+
let token = tokens[idx];
127+
if !is_insignificant(token.kind) {
128+
n_raw_tokens -= 1;
129+
}
130+
idx += 1;
131+
builder.leaf(token.kind, token.len);
132+
if n_raw_tokens == 0 {
133+
break;
134+
}
135+
},
136+
&Event::Error { ref message } => builder.error().message(message.clone()).emit(),
137+
}
138+
}
139+
builder.finish()
140+
}

src/parser/event_parser/mod.rs

Lines changed: 0 additions & 74 deletions
This file was deleted.

src/parser/event_parser/grammar/items/mod.rs renamed to src/parser/grammar/items/mod.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use super::*;
33
mod structs;
44
mod use_item;
55
mod consts;
6+
mod traits;
67

78
pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
89
attributes::inner_attributes(p);
@@ -80,6 +81,22 @@ fn item(p: &mut Parser) {
8081
CONST_ITEM
8182
}
8283
},
84+
// TODO: auto trait
85+
// test unsafe_trait
86+
// unsafe trait T {}
87+
UNSAFE_KW if la == TRAIT_KW => {
88+
p.bump();
89+
traits::trait_item(p);
90+
TRAIT_ITEM
91+
}
92+
// TODO: default impl
93+
// test unsafe_impl
94+
// unsafe impl Foo {}
95+
UNSAFE_KW if la == IMPL_KW => {
96+
p.bump();
97+
traits::impl_item(p);
98+
IMPL_ITEM
99+
}
83100
MOD_KW => {
84101
mod_item(p);
85102
MOD_ITEM
@@ -131,6 +148,7 @@ fn extern_block(p: &mut Parser) {
131148
p.bump();
132149
p.expect(R_CURLY);
133150
}
151+
134152
fn mod_item(p: &mut Parser) {
135153
assert!(p.at(MOD_KW));
136154
p.bump();

src/parser/grammar/items/traits.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use super::*;
2+
3+
pub(super) fn trait_item(p: &mut Parser) {
4+
assert!(p.at(TRAIT_KW));
5+
p.bump();
6+
p.expect(IDENT);
7+
p.expect(L_CURLY);
8+
p.expect(R_CURLY);
9+
}
10+
11+
pub(super) fn impl_item(p: &mut Parser) {
12+
assert!(p.at(IMPL_KW));
13+
p.bump();
14+
p.expect(IDENT);
15+
p.expect(L_CURLY);
16+
p.expect(R_CURLY);
17+
}
File renamed without changes.

src/parser/mod.rs

Lines changed: 12 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,88 +1,21 @@
1-
use {File, FileBuilder, Sink, SyntaxKind, Token};
1+
use {File, SyntaxKind, Token};
22

33
use syntax_kinds::*;
44

5-
mod event_parser;
6-
use self::event_parser::Event;
5+
#[macro_use]
6+
mod parser;
7+
mod event;
8+
mod grammar;
9+
use self::event::Event;
710

811
/// Parse a sequence of tokens into the representative node tree
912
pub fn parse(text: String, tokens: &[Token]) -> File {
10-
let events = event_parser::parse(&text, tokens);
11-
from_events_to_file(text, tokens, events)
12-
}
13-
14-
fn from_events_to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File {
15-
let mut builder = FileBuilder::new(text);
16-
let mut idx = 0;
17-
18-
let mut holes = Vec::new();
19-
let mut forward_parents = Vec::new();
20-
21-
for (i, event) in events.iter().enumerate() {
22-
if holes.last() == Some(&i) {
23-
holes.pop();
24-
continue;
25-
}
26-
27-
match event {
28-
&Event::Start {
29-
kind: TOMBSTONE, ..
30-
} => (),
31-
32-
&Event::Start { .. } => {
33-
forward_parents.clear();
34-
let mut idx = i;
35-
loop {
36-
let (kind, fwd) = match events[idx] {
37-
Event::Start {
38-
kind,
39-
forward_parent,
40-
} => (kind, forward_parent),
41-
_ => unreachable!(),
42-
};
43-
forward_parents.push((idx, kind));
44-
if let Some(fwd) = fwd {
45-
idx += fwd as usize;
46-
} else {
47-
break;
48-
}
49-
}
50-
for &(idx, kind) in forward_parents.iter().into_iter().rev() {
51-
builder.start_internal(kind);
52-
holes.push(idx);
53-
}
54-
holes.pop();
55-
}
56-
&Event::Finish => {
57-
while idx < tokens.len() {
58-
let token = tokens[idx];
59-
if is_insignificant(token.kind) {
60-
idx += 1;
61-
builder.leaf(token.kind, token.len);
62-
} else {
63-
break;
64-
}
65-
}
66-
builder.finish_internal()
67-
}
68-
&Event::Token {
69-
kind: _,
70-
mut n_raw_tokens,
71-
} => loop {
72-
let token = tokens[idx];
73-
if !is_insignificant(token.kind) {
74-
n_raw_tokens -= 1;
75-
}
76-
idx += 1;
77-
builder.leaf(token.kind, token.len);
78-
if n_raw_tokens == 0 {
79-
break;
80-
}
81-
},
82-
&Event::Error { ref message } => builder.error().message(message.clone()).emit(),
83-
}
84-
}
85-
builder.finish()
13+
let events = {
14+
let mut parser = parser::Parser::new(&text, tokens);
15+
grammar::file(&mut parser);
16+
parser.into_events()
17+
};
18+
event::to_file(text, tokens, events)
8619
}
8720

8821
fn is_insignificant(kind: SyntaxKind) -> bool {

src/parser/event_parser/parser.rs renamed to src/parser/parser.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use {SyntaxKind, TextUnit, Token};
22
use super::Event;
3-
use super::super::is_insignificant;
3+
use super::is_insignificant;
44
use SyntaxKind::{EOF, TOMBSTONE};
55

66
pub(crate) struct Marker {

0 commit comments

Comments
 (0)