mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 12:33:33 +00:00
Separate parser API from implementation
This commit is contained in:
parent
7a0ada860b
commit
9e2c056478
8 changed files with 254 additions and 232 deletions
|
@ -61,7 +61,7 @@ pub(crate) enum Event {
|
|||
},
|
||||
|
||||
Error {
|
||||
message: String,
|
||||
msg: String,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -140,8 +140,8 @@ pub(super) fn to_file(text: String, tokens: &[Token], events: Vec<Event>) -> Fil
|
|||
}
|
||||
builder.leaf(kind, len);
|
||||
}
|
||||
&Event::Error { ref message } => builder.error(ErrorMsg {
|
||||
message: message.clone(),
|
||||
&Event::Error { ref msg } => builder.error(ErrorMsg {
|
||||
msg: msg.clone(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use super::parser::{Parser, TokenSet};
|
||||
use parser::parser::{Parser};
|
||||
use parser::token_set::TokenSet;
|
||||
use SyntaxKind;
|
||||
use syntax_kinds::*;
|
||||
|
||||
|
|
|
@ -3,19 +3,20 @@ use {File, SyntaxKind, Token};
|
|||
use syntax_kinds::*;
|
||||
|
||||
#[macro_use]
|
||||
mod token_set;
|
||||
mod parser;
|
||||
mod input;
|
||||
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 = {
|
||||
let input = input::ParserInput::new(&text, tokens);
|
||||
let mut parser = parser::Parser::new(&input);
|
||||
let parser_impl = parser::imp::ParserImpl::new(&input);
|
||||
let mut parser = parser::Parser(parser_impl);
|
||||
grammar::file(&mut parser);
|
||||
parser.into_events()
|
||||
parser.0.into_events()
|
||||
};
|
||||
event::to_file(text, tokens, events)
|
||||
}
|
||||
|
@ -26,33 +27,3 @@ fn is_insignificant(kind: SyntaxKind) -> bool {
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> parser::Parser<'p> {
|
||||
fn at(&self, kind: SyntaxKind) -> bool {
|
||||
self.current() == kind
|
||||
}
|
||||
|
||||
fn err_and_bump(&mut self, message: &str) {
|
||||
let err = self.start();
|
||||
self.error(message);
|
||||
self.bump();
|
||||
err.complete(self, ERROR);
|
||||
}
|
||||
|
||||
fn expect(&mut self, kind: SyntaxKind) -> bool {
|
||||
if self.at(kind) {
|
||||
self.bump();
|
||||
true
|
||||
} else {
|
||||
self.error(format!("expected {:?}", kind));
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fn eat(&mut self, kind: SyntaxKind) -> bool {
|
||||
self.at(kind) && {
|
||||
self.bump();
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,193 +0,0 @@
|
|||
use super::Event;
|
||||
use super::input::{InputPosition, ParserInput};
|
||||
use SyntaxKind::{self, 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 TokenSet {
|
||||
pub tokens: &'static [SyntaxKind],
|
||||
}
|
||||
|
||||
impl TokenSet {
|
||||
pub fn contains(&self, kind: SyntaxKind) -> bool {
|
||||
self.tokens.contains(&kind)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! token_set {
|
||||
($($t:ident),*) => {
|
||||
TokenSet {
|
||||
tokens: &[$($t),*],
|
||||
}
|
||||
};
|
||||
|
||||
($($t:ident),* ,) => {
|
||||
token_set!($($t),*)
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) struct Parser<'t> {
|
||||
inp: &'t ParserInput<'t>,
|
||||
|
||||
pos: InputPosition,
|
||||
events: Vec<Event>,
|
||||
}
|
||||
|
||||
impl<'t> Parser<'t> {
|
||||
pub(crate) fn new(inp: &'t ParserInput<'t>) -> Parser<'t> {
|
||||
Parser {
|
||||
inp,
|
||||
|
||||
pos: InputPosition::new(),
|
||||
events: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_events(self) -> Vec<Event> {
|
||||
assert_eq!(self.current(), EOF);
|
||||
self.events
|
||||
}
|
||||
|
||||
pub(crate) fn start(&mut self) -> Marker {
|
||||
let m = Marker {
|
||||
pos: self.events.len() as u32,
|
||||
};
|
||||
self.event(Event::Start {
|
||||
kind: TOMBSTONE,
|
||||
forward_parent: None,
|
||||
});
|
||||
m
|
||||
}
|
||||
|
||||
pub(crate) fn error<'p, T: Into<String>>(&'p mut self, msg: T) -> ErrorBuilder<'p, 't> {
|
||||
ErrorBuilder::new(self, msg.into())
|
||||
}
|
||||
|
||||
pub(crate) fn bump(&mut self) {
|
||||
let kind = self.current();
|
||||
if kind == EOF {
|
||||
return;
|
||||
}
|
||||
self.pos += 1;
|
||||
self.event(Event::Token {
|
||||
kind,
|
||||
n_raw_tokens: 1,
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) {
|
||||
if self.current() == EOF {
|
||||
// TODO: panic!?
|
||||
return;
|
||||
}
|
||||
self.pos += 1;
|
||||
self.event(Event::Token {
|
||||
kind,
|
||||
n_raw_tokens: 1,
|
||||
});
|
||||
}
|
||||
|
||||
pub(crate) fn nth(&self, n: u32) -> SyntaxKind {
|
||||
self.inp.kind(self.pos + n)
|
||||
}
|
||||
|
||||
pub(crate) fn at_kw(&self, t: &str) -> bool {
|
||||
self.inp.text(self.pos) == t
|
||||
}
|
||||
|
||||
pub(crate) fn current(&self) -> SyntaxKind {
|
||||
self.nth(0)
|
||||
}
|
||||
|
||||
fn event(&mut self, event: Event) {
|
||||
self.events.push(event)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct ErrorBuilder<'p, 't: 'p> {
|
||||
message: String,
|
||||
parser: &'p mut Parser<'t>,
|
||||
}
|
||||
|
||||
impl<'p, 't: 'p> Drop for ErrorBuilder<'p, 't> {
|
||||
fn drop(&mut self) {
|
||||
let message = ::std::mem::replace(&mut self.message, String::new());
|
||||
self.parser.event(Event::Error { message });
|
||||
}
|
||||
}
|
||||
|
||||
impl<'t, 'p> ErrorBuilder<'p, 't> {
|
||||
fn new(parser: &'p mut Parser<'t>, message: String) -> Self {
|
||||
ErrorBuilder { message, parser }
|
||||
}
|
||||
}
|
118
src/parser/parser/imp.rs
Normal file
118
src/parser/parser/imp.rs
Normal file
|
@ -0,0 +1,118 @@
|
|||
use parser::input::{ParserInput, InputPosition};
|
||||
use parser::event::Event;
|
||||
|
||||
use SyntaxKind;
|
||||
use syntax_kinds::{TOMBSTONE, EOF};
|
||||
|
||||
pub(crate) struct ParserImpl<'t> {
|
||||
inp: &'t ParserInput<'t>,
|
||||
|
||||
pos: InputPosition,
|
||||
events: Vec<Event>,
|
||||
}
|
||||
|
||||
impl<'t> ParserImpl<'t> {
|
||||
pub(crate) fn new(inp: &'t ParserInput<'t>) -> ParserImpl<'t> {
|
||||
ParserImpl {
|
||||
inp,
|
||||
|
||||
pos: InputPosition::new(),
|
||||
events: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn into_events(self) -> Vec<Event> {
|
||||
assert_eq!(self.nth(0), EOF);
|
||||
self.events
|
||||
}
|
||||
|
||||
|
||||
pub(super) fn nth(&self, n: u32) -> SyntaxKind {
|
||||
self.inp.kind(self.pos + n)
|
||||
}
|
||||
|
||||
pub(super) fn at_kw(&self, t: &str) -> bool {
|
||||
self.inp.text(self.pos) == t
|
||||
}
|
||||
|
||||
pub(super) fn start(&mut self) -> u32 {
|
||||
let pos = self.events.len() as u32;
|
||||
self.event(Event::Start {
|
||||
kind: TOMBSTONE,
|
||||
forward_parent: None,
|
||||
});
|
||||
pos
|
||||
}
|
||||
|
||||
pub(super) fn bump(&mut self) {
|
||||
let kind = self.nth(0);
|
||||
if kind == EOF {
|
||||
return;
|
||||
}
|
||||
self.do_bump(kind);
|
||||
}
|
||||
|
||||
pub(super) fn bump_remap(&mut self, kind: SyntaxKind) {
|
||||
if self.nth(0) == EOF {
|
||||
// TODO: panic!?
|
||||
return;
|
||||
}
|
||||
self.do_bump(kind);
|
||||
}
|
||||
|
||||
fn do_bump(&mut self, kind: SyntaxKind) {
|
||||
self.pos += 1;
|
||||
self.event(Event::Token {
|
||||
kind,
|
||||
n_raw_tokens: 1,
|
||||
});
|
||||
}
|
||||
|
||||
pub(super) fn error(&mut self, msg: String) {
|
||||
self.event(Event::Error { msg })
|
||||
}
|
||||
|
||||
pub(super) fn complete(&mut self, pos: u32, kind: SyntaxKind) {
|
||||
match self.events[pos as usize] {
|
||||
Event::Start {
|
||||
kind: ref mut slot, ..
|
||||
} => {
|
||||
*slot = kind;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
self.event(Event::Finish);
|
||||
}
|
||||
|
||||
pub(super) fn abandon(&mut self, pos: u32) {
|
||||
let idx = pos as usize;
|
||||
if idx == self.events.len() - 1 {
|
||||
match self.events.pop() {
|
||||
Some(Event::Start {
|
||||
kind: TOMBSTONE,
|
||||
forward_parent: None,
|
||||
}) => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn precede(&mut self, pos: u32) -> u32 {
|
||||
let new_pos = self.start();
|
||||
match self.events[pos as usize] {
|
||||
Event::Start {
|
||||
ref mut forward_parent,
|
||||
..
|
||||
} => {
|
||||
*forward_parent = Some(new_pos - pos);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
new_pos
|
||||
}
|
||||
|
||||
|
||||
fn event(&mut self, event: Event) {
|
||||
self.events.push(event)
|
||||
}
|
||||
}
|
100
src/parser/parser/mod.rs
Normal file
100
src/parser/parser/mod.rs
Normal file
|
@ -0,0 +1,100 @@
|
|||
use SyntaxKind;
|
||||
use syntax_kinds::ERROR;
|
||||
|
||||
pub(super) mod imp;
|
||||
use self::imp::ParserImpl;
|
||||
|
||||
pub(crate) struct Parser<'t>(pub(super) ParserImpl<'t>);
|
||||
|
||||
|
||||
impl<'t> Parser<'t> {
|
||||
pub(crate) fn current(&self) -> SyntaxKind {
|
||||
self.nth(0)
|
||||
}
|
||||
|
||||
pub(crate) fn nth(&self, n: u32) -> SyntaxKind {
|
||||
self.0.nth(n)
|
||||
}
|
||||
|
||||
pub(crate) fn at(&self, kind: SyntaxKind) -> bool {
|
||||
self.current() == kind
|
||||
}
|
||||
|
||||
pub(crate) fn at_kw(&self, t: &str) -> bool {
|
||||
self.0.at_kw(t)
|
||||
}
|
||||
|
||||
pub(crate) fn start(&mut self) -> Marker {
|
||||
Marker(self.0.start())
|
||||
}
|
||||
|
||||
pub(crate) fn bump(&mut self) {
|
||||
self.0.bump();
|
||||
}
|
||||
|
||||
pub(crate) fn bump_remap(&mut self, kind: SyntaxKind) {
|
||||
self.0.bump_remap(kind);
|
||||
}
|
||||
|
||||
pub(crate) fn error<T: Into<String>>(&mut self, message: T) {
|
||||
self.0.error(message.into())
|
||||
}
|
||||
|
||||
pub(crate) fn expect(&mut self, kind: SyntaxKind) -> bool {
|
||||
if self.at(kind) {
|
||||
self.bump();
|
||||
return true;
|
||||
}
|
||||
self.error(format!("expected {:?}", kind));
|
||||
false
|
||||
}
|
||||
|
||||
pub(crate) fn eat(&mut self, kind: SyntaxKind) -> bool {
|
||||
if !self.at(kind) {
|
||||
return false;
|
||||
}
|
||||
self.bump();
|
||||
true
|
||||
}
|
||||
|
||||
pub(crate) fn err_and_bump(&mut self, message: &str) {
|
||||
let m = self.start();
|
||||
self.error(message);
|
||||
self.bump();
|
||||
m.complete(self, ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct Marker(u32);
|
||||
|
||||
impl Marker {
|
||||
pub(crate) fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompletedMarker {
|
||||
let pos = self.0;
|
||||
::std::mem::forget(self);
|
||||
p.0.complete(pos, kind);
|
||||
CompletedMarker(pos)
|
||||
}
|
||||
|
||||
pub(crate) fn abandon(self, p: &mut Parser) {
|
||||
let pos = self.0;
|
||||
::std::mem::forget(self);
|
||||
p.0.abandon(pos);
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Marker {
|
||||
fn drop(&mut self) {
|
||||
if !::std::thread::panicking() {
|
||||
panic!("Marker must be either completed or abandoned");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub(crate) struct CompletedMarker(u32);
|
||||
|
||||
impl CompletedMarker {
|
||||
pub(crate) fn precede(self, p: &mut Parser) -> Marker {
|
||||
Marker(p.0.precede(self.0))
|
||||
}
|
||||
}
|
25
src/parser/token_set.rs
Normal file
25
src/parser/token_set.rs
Normal file
|
@ -0,0 +1,25 @@
|
|||
use SyntaxKind;
|
||||
|
||||
pub(crate) struct TokenSet {
|
||||
pub tokens: &'static [SyntaxKind],
|
||||
}
|
||||
|
||||
impl TokenSet {
|
||||
pub fn contains(&self, kind: SyntaxKind) -> bool {
|
||||
self.tokens.contains(&kind)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! token_set {
|
||||
($($t:ident),*) => {
|
||||
TokenSet {
|
||||
tokens: &[$($t),*],
|
||||
}
|
||||
};
|
||||
|
||||
($($t:ident),* ,) => {
|
||||
token_set!($($t),*)
|
||||
};
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ impl Sink for FileBuilder {
|
|||
let &(node, after_child) = self.in_progress.last().unwrap();
|
||||
self.errors.push(SyntaxErrorData {
|
||||
node,
|
||||
message: err.message,
|
||||
message: err.msg,
|
||||
after_child,
|
||||
})
|
||||
}
|
||||
|
@ -157,5 +157,5 @@ fn grow(left: &mut TextRange, right: TextRange) {
|
|||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct ErrorMsg {
|
||||
pub(crate) message: String,
|
||||
pub(crate) msg: String,
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue