Skip to content

G: unsafe impl & trait #41

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Feb 4, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions grammar.ron
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,8 @@ Grammar(
"USE_ITEM",
"STATIC_ITEM",
"CONST_ITEM",
"TRAIT_ITEM",
"IMPL_ITEM",

"EXTERN_BLOCK",
"ENUM_VARIANT",
Expand Down
140 changes: 140 additions & 0 deletions src/parser/event.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
use {File, FileBuilder, Sink, SyntaxKind, Token};
use syntax_kinds::TOMBSTONE;
use super::is_insignificant;

/// `Parser` produces a flat list of `Event`s.
/// They are converted to a tree-structure in
/// a separate pass, via `TreeBuilder`.
#[derive(Debug)]
pub(crate) enum Event {
/// This event signifies the start of the node.
/// It should be either abandoned (in which case the
/// `kind` is `TOMBSTONE`, and the event is ignored),
/// or completed via a `Finish` event.
///
/// All tokens between a `Start` and a `Finish` would
/// become the children of the respective node.
///
/// For left-recursive syntactic constructs, the parser produces
/// a child node before it sees a parent. `forward_parent`
/// exists to allow to tweak parent-child relationships.
///
/// Consider this path
///
/// foo::bar
///
/// The events for it would look like this:
///
///
/// START(PATH) IDENT('foo') FINISH START(PATH) COLONCOLON IDENT('bar') FINISH
/// | /\
/// | |
/// +------forward-parent------+
///
/// And the tree would look like this
///
/// +--PATH---------+
/// | | |
/// | | |
/// | '::' 'bar'
/// |
/// PATH
/// |
/// 'foo'
///
/// See also `CompleteMarker::precede`.
Start {
kind: SyntaxKind,
forward_parent: Option<u32>,
},

/// Complete the previous `Start` event
Finish,

/// Produce a single leaf-element.
/// `n_raw_tokens` is used to glue complex contextual tokens.
/// For example, lexer tokenizes `>>` as `>`, `>`, and
/// `n_raw_tokens = 2` is used to produced a single `>>`.
Token {
kind: SyntaxKind,
n_raw_tokens: u8,
},

Error {
message: String,
},
}

pub(super) fn to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File {
let mut builder = FileBuilder::new(text);
let mut idx = 0;

let mut holes = Vec::new();
let mut forward_parents = Vec::new();

for (i, event) in events.iter().enumerate() {
if holes.last() == Some(&i) {
holes.pop();
continue;
}

match event {
&Event::Start {
kind: TOMBSTONE, ..
} => (),

&Event::Start { .. } => {
forward_parents.clear();
let mut idx = i;
loop {
let (kind, fwd) = match events[idx] {
Event::Start {
kind,
forward_parent,
} => (kind, forward_parent),
_ => unreachable!(),
};
forward_parents.push((idx, kind));
if let Some(fwd) = fwd {
idx += fwd as usize;
} else {
break;
}
}
for &(idx, kind) in forward_parents.iter().into_iter().rev() {
builder.start_internal(kind);
holes.push(idx);
}
holes.pop();
}
&Event::Finish => {
while idx < tokens.len() {
let token = tokens[idx];
if is_insignificant(token.kind) {
idx += 1;
builder.leaf(token.kind, token.len);
} else {
break;
}
}
builder.finish_internal()
}
&Event::Token {
kind: _,
mut n_raw_tokens,
} => loop {
let token = tokens[idx];
if !is_insignificant(token.kind) {
n_raw_tokens -= 1;
}
idx += 1;
builder.leaf(token.kind, token.len);
if n_raw_tokens == 0 {
break;
}
},
&Event::Error { ref message } => builder.error().message(message.clone()).emit(),
}
}
builder.finish()
}
74 changes: 0 additions & 74 deletions src/parser/event_parser/mod.rs

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use super::*;
mod structs;
mod use_item;
mod consts;
mod traits;

pub(super) fn mod_contents(p: &mut Parser, stop_on_r_curly: bool) {
attributes::inner_attributes(p);
Expand Down Expand Up @@ -80,6 +81,22 @@ fn item(p: &mut Parser) {
CONST_ITEM
}
},
// TODO: auto trait
// test unsafe_trait
// unsafe trait T {}
UNSAFE_KW if la == TRAIT_KW => {
p.bump();
traits::trait_item(p);
TRAIT_ITEM
}
// TODO: default impl
// test unsafe_impl
// unsafe impl Foo {}
UNSAFE_KW if la == IMPL_KW => {
p.bump();
traits::impl_item(p);
IMPL_ITEM
}
MOD_KW => {
mod_item(p);
MOD_ITEM
Expand Down Expand Up @@ -131,6 +148,7 @@ fn extern_block(p: &mut Parser) {
p.bump();
p.expect(R_CURLY);
}

fn mod_item(p: &mut Parser) {
assert!(p.at(MOD_KW));
p.bump();
Expand Down
17 changes: 17 additions & 0 deletions src/parser/grammar/items/traits.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
use super::*;

pub(super) fn trait_item(p: &mut Parser) {
assert!(p.at(TRAIT_KW));
p.bump();
p.expect(IDENT);
p.expect(L_CURLY);
p.expect(R_CURLY);
}

pub(super) fn impl_item(p: &mut Parser) {
assert!(p.at(IMPL_KW));
p.bump();
p.expect(IDENT);
p.expect(L_CURLY);
p.expect(R_CURLY);
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
91 changes: 12 additions & 79 deletions src/parser/mod.rs
Original file line number Diff line number Diff line change
@@ -1,88 +1,21 @@
use {File, FileBuilder, Sink, SyntaxKind, Token};
use {File, SyntaxKind, Token};

use syntax_kinds::*;

mod event_parser;
use self::event_parser::Event;
#[macro_use]
mod parser;
mod event;
mod grammar;
use self::event::Event;

/// Parse a sequence of tokens into the representative node tree
pub fn parse(text: String, tokens: &[Token]) -> File {
let events = event_parser::parse(&text, tokens);
from_events_to_file(text, tokens, events)
}

fn from_events_to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File {
let mut builder = FileBuilder::new(text);
let mut idx = 0;

let mut holes = Vec::new();
let mut forward_parents = Vec::new();

for (i, event) in events.iter().enumerate() {
if holes.last() == Some(&i) {
holes.pop();
continue;
}

match event {
&Event::Start {
kind: TOMBSTONE, ..
} => (),

&Event::Start { .. } => {
forward_parents.clear();
let mut idx = i;
loop {
let (kind, fwd) = match events[idx] {
Event::Start {
kind,
forward_parent,
} => (kind, forward_parent),
_ => unreachable!(),
};
forward_parents.push((idx, kind));
if let Some(fwd) = fwd {
idx += fwd as usize;
} else {
break;
}
}
for &(idx, kind) in forward_parents.iter().into_iter().rev() {
builder.start_internal(kind);
holes.push(idx);
}
holes.pop();
}
&Event::Finish => {
while idx < tokens.len() {
let token = tokens[idx];
if is_insignificant(token.kind) {
idx += 1;
builder.leaf(token.kind, token.len);
} else {
break;
}
}
builder.finish_internal()
}
&Event::Token {
kind: _,
mut n_raw_tokens,
} => loop {
let token = tokens[idx];
if !is_insignificant(token.kind) {
n_raw_tokens -= 1;
}
idx += 1;
builder.leaf(token.kind, token.len);
if n_raw_tokens == 0 {
break;
}
},
&Event::Error { ref message } => builder.error().message(message.clone()).emit(),
}
}
builder.finish()
let events = {
let mut parser = parser::Parser::new(&text, tokens);
grammar::file(&mut parser);
parser.into_events()
};
event::to_file(text, tokens, events)
}

fn is_insignificant(kind: SyntaxKind) -> bool {
Expand Down
2 changes: 1 addition & 1 deletion src/parser/event_parser/parser.rs → src/parser/parser.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use {SyntaxKind, TextUnit, Token};
use super::Event;
use super::super::is_insignificant;
use super::is_insignificant;
use SyntaxKind::{EOF, TOMBSTONE};

pub(crate) struct Marker {
Expand Down
Loading