Enforce rustfmt format

This commit is contained in:
Christopher Durham 2018-01-27 18:31:23 -05:00
parent 357cd33581
commit 4de3c97b2a
26 changed files with 281 additions and 257 deletions

View file

@ -1,3 +1,14 @@
language: rust language: rust
rust: rust:
- stable - stable
matrix:
include:
- rust: nightly-2018-01-26
before_script:
- rustup component add rustfmt-preview
script:
- cargo fmt -- --write-mode=diff
script:
- cargo test

View file

@ -13,4 +13,4 @@ file = "1.1.1"
ron = "0.1.5" ron = "0.1.5"
[dev-dependencies] [dev-dependencies]
testutils = { path = "./tests/testutils" } testutils = { path = "./tests/testutils" }

0
rustfmt.toml Normal file
View file

View file

@ -2,8 +2,8 @@ extern crate serde;
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
extern crate ron;
extern crate file; extern crate file;
extern crate ron;
use std::path::PathBuf; use std::path::PathBuf;
use std::fmt::Write; use std::fmt::Write;
@ -33,11 +33,12 @@ impl Grammar {
acc.push_str("use tree::{SyntaxKind, SyntaxInfo};\n"); acc.push_str("use tree::{SyntaxKind, SyntaxInfo};\n");
acc.push_str("\n"); acc.push_str("\n");
let syntax_kinds: Vec<String> = let syntax_kinds: Vec<String> = self.keywords
self.keywords.iter().map(|kw| kw_token(kw)) .iter()
.chain(self.tokens.iter().cloned()) .map(|kw| kw_token(kw))
.chain(self.nodes.iter().cloned()) .chain(self.tokens.iter().cloned())
.collect(); .chain(self.nodes.iter().cloned())
.collect();
for (idx, kind) in syntax_kinds.iter().enumerate() { for (idx, kind) in syntax_kinds.iter().enumerate() {
let sname = scream(kind); let sname = scream(kind);
@ -48,7 +49,11 @@ impl Grammar {
).unwrap(); ).unwrap();
} }
acc.push_str("\n"); acc.push_str("\n");
write!(acc, "static INFOS: [SyntaxInfo; {}] = [\n", syntax_kinds.len()).unwrap(); write!(
acc,
"static INFOS: [SyntaxInfo; {}] = [\n",
syntax_kinds.len()
).unwrap();
for kind in syntax_kinds.iter() { for kind in syntax_kinds.iter() {
let sname = scream(kind); let sname = scream(kind);
write!( write!(
@ -91,4 +96,4 @@ fn scream(word: &str) -> String {
fn kw_token(keyword: &str) -> String { fn kw_token(keyword: &str) -> String {
format!("{}_KW", scream(keyword)) format!("{}_KW", scream(keyword))
} }

View file

@ -2,7 +2,7 @@ extern crate libsyntax2;
use std::io::Read; use std::io::Read;
use libsyntax2::{tokenize, parse}; use libsyntax2::{parse, tokenize};
use libsyntax2::utils::dump_tree; use libsyntax2::utils::dump_tree;
fn main() { fn main() {

View file

@ -1,17 +1,12 @@
use unicode_xid::UnicodeXID; use unicode_xid::UnicodeXID;
pub fn is_ident_start(c: char) -> bool { pub fn is_ident_start(c: char) -> bool {
(c >= 'a' && c <= 'z') (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_'
|| (c >= 'A' && c <= 'Z')
|| c == '_'
|| (c > '\x7f' && UnicodeXID::is_xid_start(c)) || (c > '\x7f' && UnicodeXID::is_xid_start(c))
} }
pub fn is_ident_continue(c: char) -> bool { pub fn is_ident_continue(c: char) -> bool {
(c >= 'a' && c <= 'z') (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || c == '_'
|| (c >= 'A' && c <= 'Z')
|| (c >= '0' && c <= '9')
|| c == '_'
|| (c > '\x7f' && UnicodeXID::is_xid_continue(c)) || (c > '\x7f' && UnicodeXID::is_xid_continue(c))
} }

View file

@ -1,6 +1,6 @@
use lexer::ptr::Ptr; use lexer::ptr::Ptr;
use {SyntaxKind}; use SyntaxKind;
use syntax_kinds::*; use syntax_kinds::*;
pub(crate) fn scan_shebang(ptr: &mut Ptr) -> bool { pub(crate) fn scan_shebang(ptr: &mut Ptr) -> bool {
@ -23,7 +23,6 @@ pub(crate) fn scan_comment(ptr: &mut Ptr) -> Option<SyntaxKind> {
} }
} }
fn bump_until_eol(ptr: &mut Ptr) { fn bump_until_eol(ptr: &mut Ptr) {
loop { loop {
if ptr.next_is('\n') || ptr.next_is('\r') && ptr.nnext_is('\n') { if ptr.next_is('\n') || ptr.next_is('\r') && ptr.nnext_is('\n') {
@ -33,4 +32,4 @@ fn bump_until_eol(ptr: &mut Ptr) {
break; break;
} }
} }
} }

View file

@ -1,4 +1,4 @@
use {Token, SyntaxKind}; use {SyntaxKind, Token};
use syntax_kinds::*; use syntax_kinds::*;
mod ptr; mod ptr;
@ -11,10 +11,11 @@ mod numbers;
use self::numbers::scan_number; use self::numbers::scan_number;
mod strings; mod strings;
use self::strings::{is_string_literal_start, scan_char, scan_byte_char_or_string, scan_string, scan_raw_string}; use self::strings::{is_string_literal_start, scan_byte_char_or_string, scan_char, scan_raw_string,
scan_string};
mod comments; mod comments;
use self::comments::{scan_shebang, scan_comment}; use self::comments::{scan_comment, scan_shebang};
pub fn tokenize(text: &str) -> Vec<Token> { pub fn tokenize(text: &str) -> Vec<Token> {
let mut text = text; let mut text = text;
@ -45,10 +46,10 @@ fn next_token_inner(c: char, ptr: &mut Ptr) -> SyntaxKind {
match c { match c {
'#' => if scan_shebang(ptr) { '#' => if scan_shebang(ptr) {
return SHEBANG; return SHEBANG;
} },
'/' => if let Some(kind) = scan_comment(ptr) { '/' => if let Some(kind) = scan_comment(ptr) {
return kind; return kind;
} },
_ => (), _ => (),
} }
@ -89,79 +90,91 @@ fn next_token_inner(c: char, ptr: &mut Ptr) -> SyntaxKind {
'%' => return PERCENT, '%' => return PERCENT,
// Multi-byte tokens. // Multi-byte tokens.
'.' => return match (ptr.next(), ptr.nnext()) { '.' => {
(Some('.'), Some('.')) => { return match (ptr.next(), ptr.nnext()) {
ptr.bump(); (Some('.'), Some('.')) => {
ptr.bump(); ptr.bump();
DOTDOTDOT ptr.bump();
}, DOTDOTDOT
(Some('.'), Some('=')) => { }
ptr.bump(); (Some('.'), Some('=')) => {
ptr.bump(); ptr.bump();
DOTDOTEQ ptr.bump();
}, DOTDOTEQ
(Some('.'), _) => { }
ptr.bump(); (Some('.'), _) => {
DOTDOT ptr.bump();
}, DOTDOT
_ => DOT }
}, _ => DOT,
':' => return match ptr.next() {
Some(':') => {
ptr.bump();
COLONCOLON
} }
_ => COLON }
}, ':' => {
'=' => return match ptr.next() { return match ptr.next() {
Some('=') => { Some(':') => {
ptr.bump(); ptr.bump();
EQEQ COLONCOLON
}
_ => COLON,
} }
Some('>') => { }
ptr.bump(); '=' => {
FAT_ARROW return match ptr.next() {
Some('=') => {
ptr.bump();
EQEQ
}
Some('>') => {
ptr.bump();
FAT_ARROW
}
_ => EQ,
} }
_ => EQ, }
}, '!' => {
'!' => return match ptr.next() { return match ptr.next() {
Some('=') => { Some('=') => {
ptr.bump(); ptr.bump();
NEQ NEQ
}
_ => EXCL,
} }
_ => EXCL, }
}, '-' => {
'-' => return if ptr.next_is('>') { return if ptr.next_is('>') {
ptr.bump(); ptr.bump();
THIN_ARROW THIN_ARROW
} else { } else {
MINUS MINUS
}, }
}
// If the character is an ident start not followed by another single // If the character is an ident start not followed by another single
// quote, then this is a lifetime name: // quote, then this is a lifetime name:
'\'' => return if ptr.next_is_p(is_ident_start) && !ptr.nnext_is('\'') { '\'' => {
ptr.bump(); return if ptr.next_is_p(is_ident_start) && !ptr.nnext_is('\'') {
while ptr.next_is_p(is_ident_continue) {
ptr.bump(); ptr.bump();
while ptr.next_is_p(is_ident_continue) {
ptr.bump();
}
// lifetimes shouldn't end with a single quote
// if we find one, then this is an invalid character literal
if ptr.next_is('\'') {
ptr.bump();
return CHAR; // TODO: error reporting
}
LIFETIME
} else {
scan_char(ptr);
scan_literal_suffix(ptr);
CHAR
} }
// lifetimes shouldn't end with a single quote }
// if we find one, then this is an invalid character literal
if ptr.next_is('\'') {
ptr.bump();
return CHAR; // TODO: error reporting
}
LIFETIME
} else {
scan_char(ptr);
scan_literal_suffix(ptr);
CHAR
},
'b' => { 'b' => {
let kind = scan_byte_char_or_string(ptr); let kind = scan_byte_char_or_string(ptr);
scan_literal_suffix(ptr); scan_literal_suffix(ptr);
return kind return kind;
}, }
'"' => { '"' => {
scan_string(ptr); scan_string(ptr);
scan_literal_suffix(ptr); scan_literal_suffix(ptr);

View file

@ -1,7 +1,7 @@
use lexer::ptr::Ptr; use lexer::ptr::Ptr;
use lexer::classes::*; use lexer::classes::*;
use {SyntaxKind}; use SyntaxKind;
use syntax_kinds::*; use syntax_kinds::*;
pub(crate) fn scan_number(c: char, ptr: &mut Ptr) -> SyntaxKind { pub(crate) fn scan_number(c: char, ptr: &mut Ptr) -> SyntaxKind {
@ -49,10 +49,10 @@ fn scan_digits(ptr: &mut Ptr, allow_hex: bool) {
'_' | '0'...'9' => { '_' | '0'...'9' => {
ptr.bump(); ptr.bump();
} }
'a'...'f' | 'A' ... 'F' if allow_hex => { 'a'...'f' | 'A'...'F' if allow_hex => {
ptr.bump(); ptr.bump();
} }
_ => return _ => return,
} }
} }
} }

View file

@ -1,4 +1,4 @@
use {TextUnit}; use TextUnit;
use std::str::Chars; use std::str::Chars;
@ -9,7 +9,10 @@ pub(crate) struct Ptr<'s> {
impl<'s> Ptr<'s> { impl<'s> Ptr<'s> {
pub fn new(text: &'s str) -> Ptr<'s> { pub fn new(text: &'s str) -> Ptr<'s> {
Ptr { text, len: TextUnit::new(0) } Ptr {
text,
len: TextUnit::new(0),
}
} }
pub fn into_len(self) -> TextUnit { pub fn into_len(self) -> TextUnit {
@ -53,7 +56,7 @@ impl<'s> Ptr<'s> {
match self.next() { match self.next() {
Some(c) if pred(c) => { Some(c) if pred(c) => {
self.bump(); self.bump();
}, }
_ => return, _ => return,
} }
} }
@ -66,6 +69,6 @@ impl<'s> Ptr<'s> {
fn chars(&self) -> Chars { fn chars(&self) -> Chars {
let len: u32 = self.len.into(); let len: u32 = self.len.into();
self.text[len as usize ..].chars() self.text[len as usize..].chars()
} }
} }

View file

@ -1,17 +1,17 @@
use {SyntaxKind}; use SyntaxKind;
use syntax_kinds::*; use syntax_kinds::*;
use lexer::ptr::Ptr; use lexer::ptr::Ptr;
pub(crate) fn is_string_literal_start(c: char, c1: Option<char>, c2: Option<char>) -> bool { pub(crate) fn is_string_literal_start(c: char, c1: Option<char>, c2: Option<char>) -> bool {
match (c, c1, c2) { match (c, c1, c2) {
('r', Some('"'), _) | ('r', Some('"'), _)
('r', Some('#'), _) | | ('r', Some('#'), _)
('b', Some('"'), _) | | ('b', Some('"'), _)
('b', Some('\''), _) | | ('b', Some('\''), _)
('b', Some('r'), Some('"')) | | ('b', Some('r'), Some('"'))
('b', Some('r'), Some('#')) => true, | ('b', Some('r'), Some('#')) => true,
_ => false _ => false,
} }
} }
@ -50,20 +50,20 @@ pub(crate) fn scan_byte_char_or_string(ptr: &mut Ptr) -> SyntaxKind {
pub(crate) fn scan_string(ptr: &mut Ptr) { pub(crate) fn scan_string(ptr: &mut Ptr) {
while let Some(c) = ptr.bump() { while let Some(c) = ptr.bump() {
if c == '"' { if c == '"' {
return return;
} }
} }
} }
pub(crate) fn scan_raw_string(ptr: &mut Ptr) { pub(crate) fn scan_raw_string(ptr: &mut Ptr) {
if !ptr.next_is('"') { if !ptr.next_is('"') {
return return;
} }
ptr.bump(); ptr.bump();
while let Some(c) = ptr.bump() { while let Some(c) = ptr.bump() {
if c == '"' { if c == '"' {
return return;
} }
} }
} }
@ -71,32 +71,32 @@ pub(crate) fn scan_raw_string(ptr: &mut Ptr) {
fn scan_byte(ptr: &mut Ptr) { fn scan_byte(ptr: &mut Ptr) {
if ptr.next_is('\'') { if ptr.next_is('\'') {
ptr.bump(); ptr.bump();
return return;
} }
ptr.bump(); ptr.bump();
if ptr.next_is('\'') { if ptr.next_is('\'') {
ptr.bump(); ptr.bump();
return return;
} }
} }
fn scan_byte_string(ptr: &mut Ptr) { fn scan_byte_string(ptr: &mut Ptr) {
while let Some(c) = ptr.bump() { while let Some(c) = ptr.bump() {
if c == '"' { if c == '"' {
return return;
} }
} }
} }
fn scan_raw_byte_string(ptr: &mut Ptr) { fn scan_raw_byte_string(ptr: &mut Ptr) {
if !ptr.next_is('"') { if !ptr.next_is('"') {
return return;
} }
ptr.bump(); ptr.bump();
while let Some(c) = ptr.bump() { while let Some(c) = ptr.bump() {
if c == '"' { if c == '"' {
return return;
} }
} }
} }
@ -105,4 +105,3 @@ fn scan_char_or_byte(ptr: &mut Ptr) {
//FIXME: deal with escape sequencies //FIXME: deal with escape sequencies
ptr.bump(); ptr.bump();
} }

View file

@ -5,9 +5,10 @@ mod tree;
mod lexer; mod lexer;
mod parser; mod parser;
#[cfg_attr(rustfmt, rustfmt_skip)]
pub mod syntax_kinds; pub mod syntax_kinds;
pub use text::{TextUnit, TextRange}; pub use text::{TextRange, TextUnit};
pub use tree::{SyntaxKind, Token, FileBuilder, Sink, File, Node}; pub use tree::{File, FileBuilder, Node, Sink, SyntaxKind, Token};
pub use lexer::{next_token, tokenize}; pub use lexer::{next_token, tokenize};
pub use parser::parse; pub use parser::parse;
@ -25,7 +26,8 @@ pub mod utils {
buff.push_str(&String::from(" ").repeat(level)); buff.push_str(&String::from(" ").repeat(level));
write!(buff, "{:?}\n", node).unwrap(); write!(buff, "{:?}\n", node).unwrap();
let my_errors = node.errors().filter(|e| e.after_child().is_none()); let my_errors = node.errors().filter(|e| e.after_child().is_none());
let parent_errors = node.parent().into_iter() let parent_errors = node.parent()
.into_iter()
.flat_map(|n| n.errors()) .flat_map(|n| n.errors())
.filter(|e| e.after_child() == Some(node)); .filter(|e| e.after_child() == Some(node));

View file

@ -12,8 +12,7 @@ pub(super) fn outer_attributes(p: &mut Parser) {
} }
} }
fn attribute(p: &mut Parser, inner: bool) {
fn attribute(p: &mut Parser, inner: bool){
let attr = p.start(); let attr = p.start();
assert!(p.at(POUND)); assert!(p.at(POUND));
p.bump(); p.bump();
@ -38,9 +37,7 @@ fn meta_item(p: &mut Parser) {
EQ => { EQ => {
p.bump(); p.bump();
if !expressions::literal(p) { if !expressions::literal(p) {
p.error() p.error().message("expected literal").emit();
.message("expected literal")
.emit();
} }
} }
L_PAREN => meta_item_arg_list(p), L_PAREN => meta_item_arg_list(p),
@ -48,9 +45,7 @@ fn meta_item(p: &mut Parser) {
} }
meta_item.complete(p, META_ITEM); meta_item.complete(p, META_ITEM);
} else { } else {
p.error() p.error().message("expected attribute value").emit()
.message("expected attribute value")
.emit()
} }
} }
@ -73,8 +68,8 @@ fn meta_item_arg_list(p: &mut Parser) {
p.error().message(message).emit(); p.error().message(message).emit();
p.bump(); p.bump();
err.complete(p, ERROR); err.complete(p, ERROR);
continue continue;
} },
} }
if !p.at(R_PAREN) { if !p.at(R_PAREN) {
p.expect(COMMA); p.expect(COMMA);

View file

@ -2,15 +2,13 @@ use super::*;
pub(super) fn literal(p: &mut Parser) -> bool { pub(super) fn literal(p: &mut Parser) -> bool {
match p.current() { match p.current() {
TRUE_KW | FALSE_KW | TRUE_KW | FALSE_KW | INT_NUMBER | FLOAT_NUMBER | BYTE | CHAR | STRING | RAW_STRING
INT_NUMBER | FLOAT_NUMBER | | BYTE_STRING | RAW_BYTE_STRING => {
BYTE | CHAR |
STRING | RAW_STRING | BYTE_STRING | RAW_BYTE_STRING => {
let lit = p.start(); let lit = p.start();
p.bump(); p.bump();
lit.complete(p, LITERAL); lit.complete(p, LITERAL);
true true
} }
_ => false _ => false,
} }
} }

View file

@ -7,15 +7,8 @@ pub(super) fn mod_contents(p: &mut Parser) {
} }
} }
pub(super) const ITEM_FIRST: TokenSet = token_set![ pub(super) const ITEM_FIRST: TokenSet =
EXTERN_KW, token_set![EXTERN_KW, MOD_KW, USE_KW, STRUCT_KW, FN_KW, PUB_KW, POUND,];
MOD_KW,
USE_KW,
STRUCT_KW,
FN_KW,
PUB_KW,
POUND,
];
fn item(p: &mut Parser) { fn item(p: &mut Parser) {
let item = p.start(); let item = p.start();
@ -48,7 +41,7 @@ fn item(p: &mut Parser) {
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\
consider removing this semicolon" consider removing this semicolon"
} else { } else {
"expected item" "expected item"
}; };
@ -76,10 +69,9 @@ fn struct_item(p: &mut Parser) {
return; return;
} }
L_CURLY => named_fields(p), L_CURLY => named_fields(p),
_ => { //TODO: special case `(` error message _ => {
p.error() //TODO: special case `(` error message
.message("expected `;` or `{`") p.error().message("expected `;` or `{`").emit();
.emit();
return; return;
} }
} }
@ -94,9 +86,7 @@ fn struct_item(p: &mut Parser) {
p.expect(SEMI); p.expect(SEMI);
} }
_ => { _ => {
p.error() p.error().message("expected `;`, `{`, or `(`").emit();
.message("expected `;`, `{`, or `(`")
.emit();
return; return;
} }
} }
@ -177,7 +167,7 @@ fn use_item(p: &mut Parser) {
use_tree(p); use_tree(p);
p.expect(SEMI); p.expect(SEMI);
fn use_tree(p: &mut Parser){ fn use_tree(p: &mut Parser) {
let la = p.raw_lookahead(1); let la = p.raw_lookahead(1);
let m = p.start(); let m = p.start();
match (p.current(), la) { match (p.current(), la) {
@ -209,9 +199,7 @@ fn use_item(p: &mut Parser) {
L_CURLY => nested_trees(p), L_CURLY => nested_trees(p),
_ => { _ => {
// is this unreachable? // is this unreachable?
p.error() p.error().message("expected `{` or `*`").emit();
.message("expected `{` or `*`")
.emit();
} }
} }
} }
@ -222,7 +210,7 @@ fn use_item(p: &mut Parser) {
m.abandon(p); m.abandon(p);
p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`"); p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super`, `indent`");
return; return;
}, }
} }
m.complete(p, USE_TREE); m.complete(p, USE_TREE);
} }
@ -240,13 +228,9 @@ fn use_item(p: &mut Parser) {
} }
} }
fn fn_item(p: &mut Parser) { fn fn_item(p: &mut Parser) {
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(|_| ());
} }

View file

@ -1,5 +1,5 @@
use super::parser::{Parser, TokenSet}; use super::parser::{Parser, TokenSet};
use {SyntaxKind}; use SyntaxKind;
use tree::EOF; use tree::EOF;
use syntax_kinds::*; use syntax_kinds::*;
@ -29,7 +29,7 @@ fn visibility(p: &mut Parser) {
} }
p.expect(R_PAREN); p.expect(R_PAREN);
} }
_ => () _ => (),
} }
} }
vis.complete(p, VISIBILITY); vis.complete(p, VISIBILITY);
@ -53,9 +53,7 @@ impl<'p> Parser<'p> {
fn err_and_bump(&mut self, message: &str) { fn err_and_bump(&mut self, message: &str) {
let err = self.start(); let err = self.start();
self.error() self.error().message(message).emit();
.message(message)
.emit();
self.bump(); self.bump();
err.complete(self, ERROR); err.complete(self, ERROR);
} }
@ -65,15 +63,16 @@ impl<'p> Parser<'p> {
self.bump(); self.bump();
true true
} else { } else {
self.error() self.error().message(format!("expected {:?}", kind)).emit();
.message(format!("expected {:?}", kind))
.emit();
false false
} }
} }
fn eat(&mut self, kind: SyntaxKind) -> bool { fn eat(&mut self, kind: SyntaxKind) -> bool {
self.current() == kind && { self.bump(); true } self.current() == kind && {
self.bump();
true
}
} }
} }
@ -94,8 +93,7 @@ impl Lookahead for SyntaxKind {
impl Lookahead for [SyntaxKind; 2] { impl Lookahead for [SyntaxKind; 2] {
fn is_ahead(self, p: &Parser) -> bool { fn is_ahead(self, p: &Parser) -> bool {
p.current() == self[0] p.current() == self[0] && p.raw_lookahead(1) == self[1]
&& p.raw_lookahead(1) == self[1]
} }
fn consume(p: &mut Parser) { fn consume(p: &mut Parser) {
@ -106,9 +104,7 @@ impl Lookahead for [SyntaxKind; 2] {
impl Lookahead for [SyntaxKind; 3] { impl Lookahead for [SyntaxKind; 3] {
fn is_ahead(self, p: &Parser) -> bool { fn is_ahead(self, p: &Parser) -> bool {
p.current() == self[0] p.current() == self[0] && p.raw_lookahead(1) == self[1] && p.raw_lookahead(2) == self[2]
&& p.raw_lookahead(1) == self[1]
&& p.raw_lookahead(2) == self[2]
} }
fn consume(p: &mut Parser) { fn consume(p: &mut Parser) {
@ -130,5 +126,4 @@ impl<'a> Lookahead for AnyOf<'a> {
fn consume(p: &mut Parser) { fn consume(p: &mut Parser) {
p.bump(); p.bump();
} }
} }

View file

@ -34,9 +34,7 @@ fn path_segment(p: &mut Parser, first: bool) {
p.bump(); p.bump();
} }
_ => { _ => {
p.error() p.error().message("expected identifier").emit();
.message("expected identifier")
.emit();
} }
}; };
segment.complete(p, PATH_SEGMENT); segment.complete(p, PATH_SEGMENT);

View file

@ -2,4 +2,4 @@ use super::*;
pub(super) fn type_ref(p: &mut Parser) { pub(super) fn type_ref(p: &mut Parser) {
p.expect(IDENT); p.expect(IDENT);
} }

View file

@ -1,4 +1,4 @@
use {Token, SyntaxKind}; use {SyntaxKind, Token};
#[macro_use] #[macro_use]
mod parser; mod parser;

View file

@ -1,17 +1,19 @@
use {Token, SyntaxKind, TextUnit}; use {SyntaxKind, TextUnit, Token};
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::{ERROR, L_CURLY, R_CURLY};
use tree::{EOF, TOMBSTONE}; use tree::{EOF, TOMBSTONE};
pub(crate) struct Marker { pub(crate) struct Marker {
pos: u32 pos: u32,
} }
impl Marker { impl Marker {
pub fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompleteMarker { pub fn complete(self, p: &mut Parser, kind: SyntaxKind) -> CompleteMarker {
match self.event(p) { match self.event(p) {
&mut Event::Start { kind: ref mut slot, ..} => { &mut Event::Start {
kind: ref mut slot, ..
} => {
*slot = kind; *slot = kind;
} }
_ => unreachable!(), _ => unreachable!(),
@ -26,8 +28,11 @@ impl Marker {
let idx = self.pos as usize; let idx = self.pos as usize;
if idx == p.events.len() - 1 { if idx == p.events.len() - 1 {
match p.events.pop() { match p.events.pop() {
Some(Event::Start { kind: TOMBSTONE, forward_parent: None }) => (), Some(Event::Start {
_ => unreachable!() kind: TOMBSTONE,
forward_parent: None,
}) => (),
_ => unreachable!(),
} }
} }
::std::mem::forget(self); ::std::mem::forget(self);
@ -51,14 +56,17 @@ impl Drop for Marker {
} }
pub(crate) struct CompleteMarker { pub(crate) struct CompleteMarker {
pos: u32 pos: u32,
} }
impl CompleteMarker { impl CompleteMarker {
pub(crate) fn precede(self, p: &mut Parser) -> Marker { pub(crate) fn precede(self, p: &mut Parser) -> Marker {
let m = p.start(); let m = p.start();
match p.events[self.pos as usize] { match p.events[self.pos as usize] {
Event::Start { ref mut forward_parent, ..} => { Event::Start {
ref mut forward_parent,
..
} => {
*forward_parent = Some(m.pos - self.pos); *forward_parent = Some(m.pos - self.pos);
} }
_ => unreachable!(), _ => unreachable!(),
@ -68,7 +76,7 @@ impl CompleteMarker {
} }
pub(crate) struct TokenSet { pub(crate) struct TokenSet {
pub tokens: &'static [SyntaxKind] pub tokens: &'static [SyntaxKind],
} }
impl TokenSet { impl TokenSet {
@ -90,7 +98,6 @@ macro_rules! token_set {
}; };
} }
pub(crate) struct Parser<'t> { pub(crate) struct Parser<'t> {
#[allow(unused)] #[allow(unused)]
text: &'t str, text: &'t str,
@ -150,8 +157,13 @@ impl<'t> Parser<'t> {
} }
pub(crate) fn start(&mut self) -> Marker { pub(crate) fn start(&mut self) -> Marker {
let m = Marker { pos: self.events.len() as u32 }; let m = Marker {
self.event(Event::Start { kind: TOMBSTONE, forward_parent: None }); pos: self.events.len() as u32,
};
self.event(Event::Start {
kind: TOMBSTONE,
forward_parent: None,
});
m m
} }
@ -168,7 +180,10 @@ impl<'t> Parser<'t> {
_ => (), _ => (),
} }
self.pos += 1; self.pos += 1;
self.event(Event::Token { kind, n_raw_tokens: 1 }); self.event(Event::Token {
kind,
n_raw_tokens: 1,
});
kind kind
} }
@ -210,7 +225,10 @@ pub(crate) struct ErrorBuilder<'p, 't: 'p> {
impl<'t, 'p> ErrorBuilder<'p, 't> { impl<'t, 'p> ErrorBuilder<'p, 't> {
fn new(parser: &'p mut Parser<'t>) -> Self { fn new(parser: &'p mut Parser<'t>) -> Self {
ErrorBuilder { message: None, parser } ErrorBuilder {
message: None,
parser,
}
} }
pub fn message<M: Into<String>>(mut self, m: M) -> Self { pub fn message<M: Into<String>>(mut self, m: M) -> Self {

View file

@ -1,4 +1,4 @@
use {Token, File, FileBuilder, Sink, SyntaxKind}; use {File, FileBuilder, Sink, SyntaxKind, Token};
use syntax_kinds::*; use syntax_kinds::*;
use tree::TOMBSTONE; use tree::TOMBSTONE;
@ -6,17 +6,12 @@ use tree::TOMBSTONE;
mod event_parser; mod event_parser;
use self::event_parser::Event; use self::event_parser::Event;
pub fn parse(text: String, tokens: &[Token]) -> File { pub fn parse(text: String, tokens: &[Token]) -> File {
let events = event_parser::parse(&text, tokens); let events = event_parser::parse(&text, tokens);
from_events_to_file(text, tokens, events) from_events_to_file(text, tokens, events)
} }
fn from_events_to_file( fn from_events_to_file(text: String, tokens: &[Token], events: Vec<Event>) -> File {
text: String,
tokens: &[Token],
events: Vec<Event>,
) -> File {
let mut builder = FileBuilder::new(text); let mut builder = FileBuilder::new(text);
let mut idx = 0; let mut idx = 0;
@ -26,18 +21,23 @@ fn from_events_to_file(
for (i, event) in events.iter().enumerate() { for (i, event) in events.iter().enumerate() {
if holes.last() == Some(&i) { if holes.last() == Some(&i) {
holes.pop(); holes.pop();
continue continue;
} }
match event { match event {
&Event::Start { kind: TOMBSTONE, .. } => (), &Event::Start {
kind: TOMBSTONE, ..
} => (),
&Event::Start { .. } => { &Event::Start { .. } => {
forward_parents.clear(); forward_parents.clear();
let mut idx = i; let mut idx = i;
loop { loop {
let (kind, fwd) = match events[idx] { let (kind, fwd) = match events[idx] {
Event::Start { kind, forward_parent } => (kind, forward_parent), Event::Start {
kind,
forward_parent,
} => (kind, forward_parent),
_ => unreachable!(), _ => unreachable!(),
}; };
forward_parents.push((idx, kind)); forward_parents.push((idx, kind));
@ -64,8 +64,11 @@ 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;
@ -76,8 +79,7 @@ fn from_events_to_file(
break; break;
} }
}, },
&Event::Error { ref message } => &Event::Error { ref message } => builder.error().message(message.clone()).emit(),
builder.error().message(message.clone()).emit(),
} }
} }
builder.finish() builder.finish()

View file

@ -64,7 +64,6 @@ impl ops::SubAssign<TextUnit> for TextUnit {
} }
} }
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
pub struct TextRange { pub struct TextRange {
start: TextUnit, start: TextUnit,
@ -83,7 +82,6 @@ impl fmt::Display for TextRange {
} }
} }
impl TextRange { impl TextRange {
pub fn empty() -> TextRange { pub fn empty() -> TextRange {
TextRange::from_to(TextUnit::new(0), TextUnit::new(0)) TextRange::from_to(TextUnit::new(0), TextUnit::new(0))
@ -91,7 +89,10 @@ impl TextRange {
pub fn from_to(from: TextUnit, to: TextUnit) -> TextRange { pub fn from_to(from: TextUnit, to: TextUnit) -> TextRange {
assert!(from <= to, "Invalid text range [{}; {})", from, to); assert!(from <= to, "Invalid text range [{}; {})", from, to);
TextRange { start: from, end: to } TextRange {
start: from,
end: to,
}
} }
pub fn from_len(from: TextUnit, len: TextUnit) -> TextRange { pub fn from_len(from: TextUnit, len: TextUnit) -> TextRange {
@ -121,4 +122,4 @@ impl ops::Index<TextRange> for str {
fn index(&self, index: TextRange) -> &str { fn index(&self, index: TextRange) -> &str {
&self[index.start().0 as usize..index.end().0 as usize] &self[index.start().0 as usize..index.end().0 as usize]
} }
} }

View file

@ -1,5 +1,5 @@
use {SyntaxKind, TextUnit, TextRange}; use {SyntaxKind, TextRange, TextUnit};
use super::{NodeData, SyntaxErrorData, NodeIdx, File}; use super::{File, NodeData, NodeIdx, SyntaxErrorData};
pub trait Sink { pub trait Sink {
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit); fn leaf(&mut self, kind: SyntaxKind, len: TextUnit);
@ -8,7 +8,6 @@ pub trait Sink {
fn error(&mut self) -> ErrorBuilder; fn error(&mut self) -> ErrorBuilder;
} }
pub struct FileBuilder { pub struct FileBuilder {
text: String, text: String,
nodes: Vec<NodeData>, nodes: Vec<NodeData>,
@ -48,9 +47,9 @@ impl Sink for FileBuilder {
} }
fn finish_internal(&mut self) { fn finish_internal(&mut self) {
let (id, _) = self.in_progress.pop().expect( let (id, _) = self.in_progress
"trying to complete a node, but there are no in-progress nodes" .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);
} }
@ -76,11 +75,14 @@ impl FileBuilder {
assert!( assert!(
self.in_progress.is_empty(), self.in_progress.is_empty(),
"some nodes in FileBuilder are unfinished: {:?}", "some nodes in FileBuilder are unfinished: {:?}",
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_eq!( 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 {
@ -100,7 +102,6 @@ impl FileBuilder {
child.parent = Some(self.current_id()); child.parent = Some(self.current_id());
let id = self.new_node(child); let id = self.new_node(child);
{ {
let (parent, sibling) = *self.in_progress.last().unwrap(); let (parent, sibling) = *self.in_progress.last().unwrap();
let slot = if let Some(idx) = sibling { let slot = if let Some(idx) = sibling {
&mut self.nodes[idx].next_sibling &mut self.nodes[idx].next_sibling
@ -140,12 +141,15 @@ fn grow(left: &mut TextRange, right: TextRange) {
pub struct ErrorBuilder<'f> { pub struct ErrorBuilder<'f> {
message: Option<String>, message: Option<String>,
builder: &'f mut FileBuilder builder: &'f mut FileBuilder,
} }
impl<'f> ErrorBuilder<'f> { impl<'f> ErrorBuilder<'f> {
fn new(builder: &'f mut FileBuilder) -> Self { fn new(builder: &'f mut FileBuilder) -> Self {
ErrorBuilder { message: None, builder } ErrorBuilder {
message: None,
builder,
}
} }
pub fn message<M: Into<String>>(mut self, m: M) -> Self { pub fn message<M: Into<String>>(mut self, m: M) -> Self {
@ -156,6 +160,10 @@ impl<'f> ErrorBuilder<'f> {
pub fn emit(self) { pub fn emit(self) {
let message = self.message.expect("Error message not set"); let message = self.message.expect("Error message not set");
let &(node, after_child) = self.builder.in_progress.last().unwrap(); let &(node, after_child) = self.builder.in_progress.last().unwrap();
self.builder.errors.push(SyntaxErrorData { node, message, after_child }) self.builder.errors.push(SyntaxErrorData {
node,
message,
after_child,
})
} }
} }

View file

@ -1,4 +1,4 @@
use text::{TextUnit, TextRange}; use text::{TextRange, TextUnit};
use syntax_kinds::syntax_info; use syntax_kinds::syntax_info;
use std::fmt; use std::fmt;
@ -11,15 +11,10 @@ pub use self::file_builder::{FileBuilder, Sink};
pub struct SyntaxKind(pub(crate) u32); pub struct SyntaxKind(pub(crate) u32);
pub(crate) const EOF: SyntaxKind = SyntaxKind(!0); 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: SyntaxKind = SyntaxKind(!0 - 1);
pub(crate) const TOMBSTONE_INFO: SyntaxInfo = SyntaxInfo { pub(crate) const TOMBSTONE_INFO: SyntaxInfo = SyntaxInfo { name: "TOMBSTONE" };
name: "TOMBSTONE"
};
impl SyntaxKind { impl SyntaxKind {
fn info(self) -> &'static SyntaxInfo { fn info(self) -> &'static SyntaxInfo {
@ -38,7 +33,6 @@ impl fmt::Debug for SyntaxKind {
} }
} }
pub(crate) struct SyntaxInfo { pub(crate) struct SyntaxInfo {
pub name: &'static str, pub name: &'static str,
} }
@ -58,7 +52,10 @@ pub struct File {
impl File { impl File {
pub fn root<'f>(&'f self) -> Node<'f> { pub fn root<'f>(&'f self) -> Node<'f> {
assert!(!self.nodes.is_empty()); assert!(!self.nodes.is_empty());
Node { file: self, idx: NodeIdx(0) } Node {
file: self,
idx: NodeIdx(0),
}
} }
} }
@ -86,14 +83,17 @@ impl<'f> Node<'f> {
} }
pub fn children(&self) -> Children<'f> { pub fn children(&self) -> Children<'f> {
Children { next: self.as_node(self.data().first_child) } Children {
next: self.as_node(self.data().first_child),
}
} }
pub fn errors(&self) -> SyntaxErrors<'f> { pub fn errors(&self) -> SyntaxErrors<'f> {
let pos = self.file.errors.iter().position(|e| e.node == self.idx); let pos = self.file.errors.iter().position(|e| e.node == self.idx);
let next = pos let next = pos.map(|i| ErrorIdx(i as u32)).map(|idx| SyntaxError {
.map(|i| ErrorIdx(i as u32)) file: self.file,
.map(|idx| SyntaxError { file: self.file, idx }); idx,
});
SyntaxErrors { next } SyntaxErrors { next }
} }
@ -102,7 +102,10 @@ impl<'f> Node<'f> {
} }
fn as_node(&self, idx: Option<NodeIdx>) -> Option<Node<'f>> { fn as_node(&self, idx: Option<NodeIdx>) -> Option<Node<'f>> {
idx.map(|idx| Node { file: self.file, idx }) idx.map(|idx| Node {
file: self.file,
idx,
})
} }
} }
@ -118,8 +121,7 @@ impl<'f> cmp::PartialEq<Node<'f>> for Node<'f> {
} }
} }
impl<'f> cmp::Eq for Node<'f> { impl<'f> cmp::Eq for Node<'f> {}
}
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct SyntaxError<'f> { pub struct SyntaxError<'f> {
@ -134,7 +136,10 @@ impl<'f> SyntaxError<'f> {
pub fn after_child(&self) -> Option<Node<'f>> { pub fn after_child(&self) -> Option<Node<'f>> {
let idx = self.data().after_child?; let idx = self.data().after_child?;
Some(Node { file: self.file, idx }) Some(Node {
file: self.file,
idx,
})
} }
fn data(&self) -> &'f SyntaxErrorData { fn data(&self) -> &'f SyntaxErrorData {
@ -148,7 +153,7 @@ impl<'f> SyntaxError<'f> {
} }
let result = SyntaxError { let result = SyntaxError {
file: self.file, file: self.file,
idx: ErrorIdx(next_idx) idx: ErrorIdx(next_idx),
}; };
if result.data().node != self.data().node { if result.data().node != self.data().node {
return None; return None;
@ -185,7 +190,6 @@ impl<'f> Iterator for SyntaxErrors<'f> {
} }
} }
#[derive(Clone, Copy, PartialEq, Eq)] #[derive(Clone, Copy, PartialEq, Eq)]
struct NodeIdx(u32); struct NodeIdx(u32);

View file

@ -4,18 +4,15 @@ extern crate testutils;
use std::fmt::Write; use std::fmt::Write;
use libsyntax2::{Token, tokenize}; use libsyntax2::{tokenize, Token};
use testutils::dir_tests; use testutils::dir_tests;
#[test] #[test]
fn lexer_tests() { fn lexer_tests() {
dir_tests( dir_tests(&["lexer"], |text| {
&["lexer"], let tokens = tokenize(text);
|text| { dump_tokens(&tokens, text)
let tokens = tokenize(text); })
dump_tokens(&tokens, text)
}
)
} }
fn dump_tokens(tokens: &[Token], text: &str) -> String { fn dump_tokens(tokens: &[Token], text: &str) -> String {
@ -29,4 +26,4 @@ fn dump_tokens(tokens: &[Token], text: &str) -> String {
write!(acc, "{:?} {} {:?}\n", token.kind, token.len, token_text).unwrap() write!(acc, "{:?} {} {:?}\n", token.kind, token.len, token_text).unwrap()
} }
acc acc
} }

View file

@ -2,18 +2,15 @@ extern crate file;
extern crate libsyntax2; extern crate libsyntax2;
extern crate testutils; extern crate testutils;
use libsyntax2::{tokenize, parse}; use libsyntax2::{parse, tokenize};
use libsyntax2::utils::dump_tree; use libsyntax2::utils::dump_tree;
use testutils::dir_tests; use testutils::dir_tests;
#[test] #[test]
fn parser_tests() { fn parser_tests() {
dir_tests( dir_tests(&["parser/ok", "parser/err"], |text| {
&["parser/ok", "parser/err"], let tokens = tokenize(text);
|text| { let file = parse(text.to_string(), &tokens);
let tokens = tokenize(text); dump_tree(&file)
let file = parse(text.to_string(), &tokens); })
dump_tree(&file)
}
)
} }