Markers API

This commit is contained in:
Aleksey Kladov 2018-01-20 23:25:34 +03:00
parent be60d5aa66
commit 0b5d39f2a2
10 changed files with 189 additions and 145 deletions

View file

@ -19,13 +19,13 @@ fn attribute(p: &mut Parser, kind: AttrKind) -> bool {
if kind == AttrKind::Inner && p.raw_lookahead(1) != EXCL { if kind == AttrKind::Inner && p.raw_lookahead(1) != EXCL {
return false; return false;
} }
p.start(ATTR); let attr = p.start();
p.bump(); p.bump();
if kind == AttrKind::Inner { if kind == AttrKind::Inner {
p.bump(); p.bump();
} }
p.expect(L_BRACK) && meta_item(p) && p.expect(R_BRACK); p.expect(L_BRACK) && meta_item(p) && p.expect(R_BRACK);
p.finish(); attr.complete(p, ATTR);
true true
} else { } else {
false false
@ -34,7 +34,7 @@ fn attribute(p: &mut Parser, kind: AttrKind) -> bool {
fn meta_item(p: &mut Parser) -> bool { fn meta_item(p: &mut Parser) -> bool {
if p.at(IDENT) { if p.at(IDENT) {
p.start(META_ITEM); let meta_item = p.start();
p.bump(); p.bump();
if p.eat(EQ) { if p.eat(EQ) {
if !expressions::literal(p) { if !expressions::literal(p) {
@ -46,7 +46,7 @@ fn meta_item(p: &mut Parser) -> bool {
comma_list(p, R_PAREN, meta_item_inner); comma_list(p, R_PAREN, meta_item_inner);
p.expect(R_PAREN); p.expect(R_PAREN);
} }
p.finish(); meta_item.complete(p, META_ITEM);
true true
} else { } else {
false false

View file

@ -6,9 +6,9 @@ pub(super) fn literal(p: &mut Parser) -> bool {
INT_NUMBER | FLOAT_NUMBER | INT_NUMBER | FLOAT_NUMBER |
BYTE | CHAR | BYTE | CHAR |
STRING | RAW_STRING | BYTE_STRING | RAW_BYTE_STRING => { STRING | RAW_STRING | BYTE_STRING | RAW_BYTE_STRING => {
p.start(LITERAL); let lit = p.start();
p.bump(); p.bump();
p.finish(); lit.complete(p, LITERAL);
true true
} }
_ => false _ => false

View file

@ -8,19 +8,34 @@ pub(super) fn mod_contents(p: &mut Parser) {
} }
fn item(p: &mut Parser) { fn item(p: &mut Parser) {
let attrs_start = p.mark(); let item = p.start();
attributes::outer_attributes(p); attributes::outer_attributes(p);
visibility(p); visibility(p);
let la = p.raw_lookahead(1); let la = p.raw_lookahead(1);
let item_start = p.mark(); let item_kind = match p.current() {
match p.current() { EXTERN_KW if la == CRATE_KW => {
EXTERN_KW if la == CRATE_KW => extern_crate_item(p), extern_crate_item(p);
MOD_KW => mod_item(p), EXTERN_CRATE_ITEM
USE_KW => use_item(p), }
STRUCT_KW => struct_item(p), MOD_KW => {
FN_KW => fn_item(p), mod_item(p);
MOD_ITEM
}
USE_KW => {
use_item(p);
USE_ITEM
}
STRUCT_KW => {
struct_item(p);
STRUCT_ITEM
}
FN_KW => {
fn_item(p);
FN_ITEM
}
err_token => { err_token => {
p.start(ERROR); item.abandon(p);
let err = p.start();
let message = if err_token == SEMI { let message = if err_token == SEMI {
//TODO: if the item is incomplete, this message is misleading //TODO: if the item is incomplete, this message is misleading
"expected item, found `;`\n\ "expected item, found `;`\n\
@ -32,60 +47,52 @@ fn item(p: &mut Parser) {
.message(message) .message(message)
.emit(); .emit();
p.bump(); p.bump();
p.finish(); err.complete(p, ERROR);
return; return;
} }
}; };
p.forward_parent(attrs_start, item_start); item.complete(p, item_kind);
} }
fn struct_item(p: &mut Parser) { fn struct_item(p: &mut Parser) {
p.start(STRUCT_ITEM);
assert!(p.at(STRUCT_KW)); assert!(p.at(STRUCT_KW));
p.bump(); p.bump();
struct_inner(p); if !p.expect(IDENT) {
p.finish(); return;
}
fn struct_inner(p: &mut Parser) { generic_parameters(p);
if !p.expect(IDENT) { match p.current() {
p.finish(); WHERE_KW => {
return; where_clause(p);
} match p.current() {
generic_parameters(p); SEMI => {
match p.current() { p.bump();
WHERE_KW => { return;
where_clause(p); }
match p.current() { L_CURLY => named_fields(p),
SEMI => { _ => { //TODO: special case `(` error message
p.bump(); p.error()
return; .message("expected `;` or `{`")
} .emit();
L_CURLY => named_fields(p), return;
_ => { //TODO: special case `(` error message
p.error()
.message("expected `;` or `{`")
.emit();
return;
}
} }
} }
SEMI => { }
p.bump(); SEMI => {
return; p.bump();
} return;
L_CURLY => named_fields(p), }
L_PAREN => { L_CURLY => named_fields(p),
tuple_fields(p); L_PAREN => {
p.expect(SEMI); pos_fields(p);
} p.expect(SEMI);
_ => { }
p.error() _ => {
.message("expected `;`, `{`, or `(`") p.error()
.emit(); .message("expected `;`, `{`, or `(`")
return; .emit();
} return;
} }
} }
} }
@ -97,30 +104,30 @@ fn named_fields(p: &mut Parser) {
})); }));
fn named_field(p: &mut Parser) { fn named_field(p: &mut Parser) {
p.start(NAMED_FIELD); let field = p.start();
visibility(p); visibility(p);
if p.expect(IDENT) && p.expect(COLON) { if p.expect(IDENT) && p.expect(COLON) {
types::type_ref(p); types::type_ref(p);
}; };
p.finish() field.complete(p, NAMED_FIELD);
} }
} }
fn tuple_fields(p: &mut Parser) { fn pos_fields(p: &mut Parser) {
if !p.expect(L_PAREN) { if !p.expect(L_PAREN) {
return; return;
} }
comma_list(p, R_PAREN, |p| { comma_list(p, R_PAREN, |p| {
tuple_field(p); pos_field(p);
true true
}); });
p.expect(R_PAREN); p.expect(R_PAREN);
fn tuple_field(p: &mut Parser) { fn pos_field(p: &mut Parser) {
p.start(POS_FIELD); let pos_field = p.start();
visibility(p); visibility(p);
types::type_ref(p); types::type_ref(p);
p.finish(); pos_field.complete(p, POS_FIELD);
} }
} }
@ -129,28 +136,21 @@ fn generic_parameters(_: &mut Parser) {}
fn where_clause(_: &mut Parser) {} fn where_clause(_: &mut Parser) {}
fn extern_crate_item(p: &mut Parser) { fn extern_crate_item(p: &mut Parser) {
p.start(EXTERN_CRATE_ITEM);
assert!(p.at(EXTERN_KW)); assert!(p.at(EXTERN_KW));
p.bump(); p.bump();
assert!(p.at(CRATE_KW)); assert!(p.at(CRATE_KW));
p.bump(); p.bump();
p.expect(IDENT) && alias(p) && p.expect(SEMI); p.expect(IDENT) && alias(p) && p.expect(SEMI);
p.finish();
} }
fn mod_item(p: &mut Parser) { fn mod_item(p: &mut Parser) {
p.start(MOD_ITEM);
assert!(p.at(MOD_KW)); assert!(p.at(MOD_KW));
p.bump(); p.bump();
if p.expect(IDENT) && !p.eat(SEMI) { if p.expect(IDENT) && !p.eat(SEMI) {
p.curly_block(mod_contents); p.curly_block(mod_contents);
} }
p.finish()
} }
pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool { pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool {
@ -158,28 +158,24 @@ pub(super) fn is_use_tree_start(kind: SyntaxKind) -> bool {
} }
fn use_item(p: &mut Parser) { fn use_item(p: &mut Parser) {
p.start(USE_ITEM);
assert!(p.at(USE_KW)); assert!(p.at(USE_KW));
p.bump(); p.bump();
use_tree(p); use_tree(p);
p.expect(SEMI); p.expect(SEMI);
p.finish();
fn use_tree(p: &mut Parser) -> bool { fn use_tree(p: &mut Parser) -> bool {
let la = p.raw_lookahead(1); let la = p.raw_lookahead(1);
let m = p.start();
match (p.current(), la) { match (p.current(), la) {
(STAR, _) => { (STAR, _) => {
p.start(USE_TREE);
p.bump(); p.bump();
} }
(COLONCOLON, STAR) => { (COLONCOLON, STAR) => {
p.start(USE_TREE);
p.bump(); p.bump();
p.bump(); p.bump();
} }
(L_CURLY, _) | (COLONCOLON, L_CURLY) => { (L_CURLY, _) | (COLONCOLON, L_CURLY) => {
p.start(USE_TREE);
if p.at(COLONCOLON) { if p.at(COLONCOLON) {
p.bump(); p.bump();
} }
@ -188,7 +184,6 @@ fn use_item(p: &mut Parser) {
}); });
} }
_ if paths::is_path_start(p) => { _ if paths::is_path_start(p) => {
p.start(USE_TREE);
paths::use_path(p); paths::use_path(p);
match p.current() { match p.current() {
AS_KW => { AS_KW => {
@ -216,23 +211,23 @@ fn use_item(p: &mut Parser) {
_ => (), _ => (),
} }
} }
_ => return false, _ => {
m.abandon(p);
return false
},
} }
p.finish(); m.complete(p, USE_TREE);
return true; return true;
} }
} }
fn fn_item(p: &mut Parser) { fn fn_item(p: &mut Parser) {
p.start(FN_ITEM);
assert!(p.at(FN_KW)); assert!(p.at(FN_KW));
p.bump(); p.bump();
p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN) p.expect(IDENT) && p.expect(L_PAREN) && p.expect(R_PAREN)
&& p.curly_block(|_| ()); && p.curly_block(|_| ());
p.finish();
} }

View file

@ -10,15 +10,15 @@ mod types;
mod paths; mod paths;
pub(crate) fn file(p: &mut Parser) { pub(crate) fn file(p: &mut Parser) {
p.start(FILE); let file = p.start();
p.eat(SHEBANG); p.eat(SHEBANG);
items::mod_contents(p); items::mod_contents(p);
p.finish() file.complete(p, FILE);
} }
fn visibility(p: &mut Parser) { fn visibility(p: &mut Parser) {
if p.at(PUB_KW) { if p.at(PUB_KW) {
p.start(VISIBILITY); let vis = p.start();
p.bump(); p.bump();
if p.at(L_PAREN) { if p.at(L_PAREN) {
match p.raw_lookahead(1) { match p.raw_lookahead(1) {
@ -32,16 +32,16 @@ fn visibility(p: &mut Parser) {
_ => () _ => ()
} }
} }
p.finish(); vis.complete(p, VISIBILITY);
} }
} }
fn alias(p: &mut Parser) -> bool { fn alias(p: &mut Parser) -> bool {
if p.at(AS_KW) { if p.at(AS_KW) {
p.start(ALIAS); let alias = p.start();
p.bump(); p.bump();
p.expect(IDENT); p.expect(IDENT);
p.finish(); alias.complete(p, ALIAS);
} }
true //FIXME: return false if three are errors true //FIXME: return false if three are errors
} }

View file

@ -8,19 +8,16 @@ pub(crate) fn use_path(p: &mut Parser) {
if !is_path_start(p) { if !is_path_start(p) {
return; return;
} }
let mut prev = p.mark(); let path = p.start();
p.start(PATH);
path_segment(p, true); path_segment(p, true);
p.finish(); let mut qual = path.complete(p, PATH);
loop { loop {
let curr = p.mark();
if p.at(COLONCOLON) && !items::is_use_tree_start(p.raw_lookahead(1)) { if p.at(COLONCOLON) && !items::is_use_tree_start(p.raw_lookahead(1)) {
p.start(PATH); let path = qual.precede(p);
p.bump(); p.bump();
path_segment(p, false); path_segment(p, false);
p.forward_parent(prev, curr); let path = path.complete(p, PATH);
prev = curr; qual = path;
p.finish();
} else { } else {
break; break;
} }
@ -28,7 +25,7 @@ pub(crate) fn use_path(p: &mut Parser) {
} }
fn path_segment(p: &mut Parser, first: bool) { fn path_segment(p: &mut Parser, first: bool) {
p.start(PATH_SEGMENT); let segment = p.start();
if first { if first {
p.eat(COLONCOLON); p.eat(COLONCOLON);
} }
@ -42,5 +39,5 @@ fn path_segment(p: &mut Parser, first: bool) {
.emit(); .emit();
} }
}; };
p.finish(); segment.complete(p, PATH_SEGMENT);
} }

View file

@ -1,8 +1,71 @@
use {Token, SyntaxKind, TextUnit}; use {Token, SyntaxKind, TextUnit};
use super::{Event}; use super::Event;
use super::super::is_insignificant; use super::super::is_insignificant;
use syntax_kinds::{L_CURLY, R_CURLY, ERROR}; use syntax_kinds::{L_CURLY, R_CURLY, ERROR};
use tree::EOF; use tree::{EOF, TOMBSTONE};
pub(crate) struct Marker {
pos: u32
}
impl Marker {
pub fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompleteMarker {
match self.event(p) {
&mut Event::Start { kind: ref mut slot, ..} => {
*slot = kind;
}
_ => unreachable!(),
}
p.event(Event::Finish);
let result = CompleteMarker { pos: self.pos };
::std::mem::forget(self);
result
}
pub fn abandon(self, p: &mut Parser) {
let idx = self.pos as usize;
if idx == p.events.len() - 1 {
match p.events.pop() {
Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (),
_ => unreachable!()
}
}
::std::mem::forget(self);
}
fn event<'p>(&self, p: &'p mut Parser) -> &'p mut Event {
&mut p.events[self.idx()]
}
fn idx(&self) -> usize {
self.pos as usize
}
}
impl Drop for Marker {
fn drop(&mut self) {
if !::std::thread::panicking() {
panic!("Each marker should be eithe completed or abandoned");
}
}
}
pub(crate) struct CompleteMarker {
pos: u32
}
impl CompleteMarker {
pub(crate) fn precede(self, p: &mut Parser) -> Marker {
let m = p.start();
match p.events[self.pos as usize] {
Event::Start { ref mut forward_parent, ..} => {
*forward_parent = Some(m.pos - self.pos);
}
_ => unreachable!(),
}
m
}
}
pub(crate) struct Parser<'t> { pub(crate) struct Parser<'t> {
@ -19,12 +82,9 @@ pub(crate) struct Parser<'t> {
curly_limit: Option<i32>, curly_limit: Option<i32>,
} }
#[derive(Debug, Clone, Copy,PartialEq, Eq)] #[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) struct Pos(u32); pub(crate) struct Pos(u32);
#[derive(Debug, Clone, Copy,PartialEq, Eq)]
pub(crate) struct Mark(u32);
impl<'t> Parser<'t> { impl<'t> Parser<'t> {
pub(crate) fn new(text: &'t str, raw_tokens: &'t [Token]) -> Parser<'t> { pub(crate) fn new(text: &'t str, raw_tokens: &'t [Token]) -> Parser<'t> {
let mut tokens = Vec::new(); let mut tokens = Vec::new();
@ -50,31 +110,13 @@ impl<'t> Parser<'t> {
} }
} }
pub(crate) fn mark(&self) -> Mark {
Mark(self.events.len() as u32)
}
pub(crate) fn forward_parent(&mut self, child: Mark, parent: Mark) {
if child == parent || parent == self.mark() {
return
}
assert!(child.0 < parent.0);
let diff = parent.0 - child.0;
match self.events[child.0 as usize] {
Event::Start { ref mut forward_parent, .. } => {
*forward_parent = Some(diff);
}
_ => unreachable!()
}
}
pub(crate) fn pos(&self) -> Pos { pub(crate) fn pos(&self) -> Pos {
Pos(self.pos as u32) Pos(self.pos as u32)
} }
pub(crate) fn into_events(self) -> Vec<Event> { pub(crate) fn into_events(self) -> Vec<Event> {
assert!(self.curly_limit.is_none()); assert!(self.curly_limit.is_none());
assert!(self.current() == EOF); assert_eq!(self.current(), EOF);
self.events self.events
} }
@ -85,18 +127,16 @@ impl<'t> Parser<'t> {
let token = self.tokens[self.pos]; let token = self.tokens[self.pos];
if let Some(limit) = self.curly_limit { if let Some(limit) = self.curly_limit {
if limit == self.curly_level && token.kind == R_CURLY { if limit == self.curly_level && token.kind == R_CURLY {
return EOF return EOF;
} }
} }
token.kind token.kind
} }
pub(crate) fn start(&mut self, kind: SyntaxKind) { pub(crate) fn start(&mut self) -> Marker {
self.event(Event::Start { kind, forward_parent: None }); let m = Marker { pos: self.events.len() as u32 };
} self.event(Event::Start { kind: TOMBSTONE, forward_parent: None });
m
pub(crate) fn finish(&mut self) {
self.event(Event::Finish);
} }
pub(crate) fn error<'p>(&'p mut self) -> ErrorBuilder<'p, 't> { pub(crate) fn error<'p>(&'p mut self) -> ErrorBuilder<'p, 't> {
@ -124,20 +164,20 @@ impl<'t> Parser<'t> {
let old_level = self.curly_level; let old_level = self.curly_level;
let old_limit = self.curly_limit; let old_limit = self.curly_limit;
if !self.expect(L_CURLY) { if !self.expect(L_CURLY) {
return false return false;
} }
self.curly_limit = Some(self.curly_level); self.curly_limit = Some(self.curly_level);
f(self); f(self);
assert!(self.curly_level > old_level); assert!(self.curly_level > old_level);
self.curly_limit = old_limit; self.curly_limit = old_limit;
if !self.expect(R_CURLY) { if !self.expect(R_CURLY) {
self.start(ERROR); let err = self.start();
while self.curly_level > old_level { while self.curly_level > old_level {
if self.bump() == EOF { if self.bump() == EOF {
break; break;
} }
} }
self.finish(); err.complete(self, ERROR);
} }
true true
} }
@ -149,7 +189,7 @@ impl<'t> Parser<'t> {
pub(crate) struct ErrorBuilder<'p, 't: 'p> { pub(crate) struct ErrorBuilder<'p, 't: 'p> {
message: Option<String>, message: Option<String>,
parser: &'p mut Parser<'t> parser: &'p mut Parser<'t>,
} }
impl<'t, 'p> ErrorBuilder<'p, 't> { impl<'t, 'p> ErrorBuilder<'p, 't> {

View file

@ -1,6 +1,7 @@
use {Token, File, FileBuilder, Sink, SyntaxKind}; use {Token, File, FileBuilder, Sink, SyntaxKind};
use syntax_kinds::*; use syntax_kinds::*;
use tree::TOMBSTONE;
mod event_parser; mod event_parser;
use self::event_parser::Event; use self::event_parser::Event;
@ -29,6 +30,8 @@ fn from_events_to_file(
} }
match event { match event {
&Event::Start { kind: TOMBSTONE, .. } => (),
&Event::Start { .. } => { &Event::Start { .. } => {
forward_parents.clear(); forward_parents.clear();
let mut idx = i; let mut idx = i;
@ -62,7 +65,7 @@ fn from_events_to_file(
} }
builder.finish_internal() builder.finish_internal()
}, },
&Event::Token { kind, mut n_raw_tokens } => loop { &Event::Token { kind: _, mut n_raw_tokens } => loop {
let token = tokens[idx]; let token = tokens[idx];
if !is_insignificant(token.kind) { if !is_insignificant(token.kind) {
n_raw_tokens -= 1; n_raw_tokens -= 1;

View file

@ -48,7 +48,9 @@ impl Sink for FileBuilder {
} }
fn finish_internal(&mut self) { fn finish_internal(&mut self) {
let (id, _) = self.in_progress.pop().unwrap(); let (id, _) = self.in_progress.pop().expect(
"trying to complete a node, but there are no in-progress nodes"
);
if !self.in_progress.is_empty() { if !self.in_progress.is_empty() {
self.add_len(id); self.add_len(id);
} }
@ -77,8 +79,8 @@ impl FileBuilder {
self.in_progress.iter().map(|&(idx, _)| self.nodes[idx].kind) self.in_progress.iter().map(|&(idx, _)| self.nodes[idx].kind)
.collect::<Vec<_>>() .collect::<Vec<_>>()
); );
assert!( assert_eq!(
self.pos == (self.text.len() as u32).into(), self.pos, (self.text.len() as u32).into(),
"nodes in FileBuilder do not cover the whole file" "nodes in FileBuilder do not cover the whole file"
); );
File { File {

View file

@ -10,17 +10,24 @@ pub use self::file_builder::{FileBuilder, Sink};
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyntaxKind(pub(crate) u32); pub struct SyntaxKind(pub(crate) u32);
pub(crate) const EOF: SyntaxKind = SyntaxKind(10000); pub(crate) const EOF: SyntaxKind = SyntaxKind(!0);
pub(crate) const EOF_INFO: SyntaxInfo = SyntaxInfo { pub(crate) const EOF_INFO: SyntaxInfo = SyntaxInfo {
name: "EOF" name: "EOF"
}; };
pub(crate) const TOMBSTONE: SyntaxKind = SyntaxKind(!0 - 1);
pub(crate) const TOMBSTONE_INFO: SyntaxInfo = SyntaxInfo {
name: "TOMBSTONE"
};
impl SyntaxKind { impl SyntaxKind {
fn info(self) -> &'static SyntaxInfo { fn info(self) -> &'static SyntaxInfo {
if self == EOF { match self {
return &EOF_INFO; EOF => &EOF_INFO,
TOMBSTONE => &TOMBSTONE_INFO,
_ => syntax_info(self),
} }
syntax_info(self)
} }
} }