use {parser::Parser, symbol::*, Symbol};
struct Mark(Symbol);
impl Drop for Mark {
fn drop(&mut self) {
if !::std::thread::panicking() {
panic!("Mark dropped")
}
}
}
impl<'t, 's, 'a> Parser<'t, 's, 'a> {
fn start(&mut self, s: Symbol) -> Mark {
self.sink.start(s);
Mark(s)
}
fn finish(&mut self, m: Mark) {
self.sink.finish(m.0);
::std::mem::forget(m)
}
fn error(&mut self, msg: &str) {
self.sink.error(msg);
}
fn at(&self, lookahead: usize) -> Symbol {
let pos = self.pos + lookahead;
if pos >= self.tokens.significant.len() {
return EOF;
}
let pos = self.tokens.significant[pos];
self.tokens.raw_tokens[pos].symbol
}
fn current(&self) -> Symbol {
self.at(0)
}
fn eat(&mut self, s: Symbol) {
let msg = match s {
COMMA => "expected `,`",
EQ => "expected `=`",
DOT => "expected `.`",
R_BRACK => "expected `]`",
R_CURLY => "expected `}`",
_ => unimplemented!("msg for {:?}", s),
};
if self.current() == s {
self.bump()
} else {
self.bump_error(msg)
}
}
fn bump(&mut self) {
if self.pos == self.tokens.significant.len() {
panic!("bumping past EOF");
}
let pos = self.tokens.significant[self.pos];
self.sink.token(pos, None);
self.pos += 1;
}
fn bump_remap(&mut self, s: Symbol) {
if self.pos == self.tokens.significant.len() {
panic!("bumping past EOF");
}
let pos = self.tokens.significant[self.pos];
self.sink.token(pos, Some(s));
self.pos += 1;
}
fn bump_error(&mut self, msg: &str) {
match self.current() {
EOF => {
self.error(msg);
return;
}
_ => {
let m = self.start(ERROR);
self.error(msg);
self.bump();
self.finish(m);
}
}
}
}
impl<'s, 't, 'a> Parser<'s, 't, 'a> {
pub(crate) fn parse(&mut self) {
self.doc();
}
fn doc(&mut self) {
let m = self.start(DOC);
self.entries();
while self.current() != EOF {
match self.current() {
L_BRACK => {
if self.at(1) == L_BRACK {
self.array_table()
} else {
self.table()
}
}
_ => self.bump_error("expected `[`"),
}
}
self.finish(m);
}
fn entries(&mut self) {
while self.current() != EOF && self.current() != L_BRACK {
match self.current() {
| BARE_KEY | BARE_KEY_OR_NUMBER | BARE_KEY_OR_DATE | BASIC_STRING
| LITERAL_STRING => self.entry(),
_ => self.bump_error("expected a key"),
}
}
}
fn entry(&mut self) {
let m = self.start(ENTRY);
self.keys();
self.eat(EQ);
self.val();
self.finish(m);
}
fn keys(&mut self) {
let mut first = true;
while self.current() != EOF && self.current() != R_BRACK && self.current() != EQ {
if !first {
self.eat(DOT);
}
first = false;
self.key();
}
}
fn key(&mut self) {
let m = self.start(KEY);
match self.current() {
BARE_KEY | BARE_KEY_OR_NUMBER | BARE_KEY_OR_DATE => self.bump_remap(BARE_KEY),
BASIC_STRING | LITERAL_STRING => self.bump(),
_ => self.bump_error("expected a key"),
}
self.finish(m);
}
fn val(&mut self) {
let m = self.start(VALUE);
match self.current() {
BARE_KEY_OR_NUMBER | NUMBER => self.bump_remap(NUMBER),
BOOL => self.bump(),
BARE_KEY_OR_DATE | DATE_TIME => self.bump_remap(DATE_TIME),
BASIC_STRING | MULTILINE_BASIC_STRING => self.bump(),
LITERAL_STRING | MULTILINE_LITERAL_STRING => self.bump(),
L_BRACK => self.array(),
L_CURLY => self.dict(),
_ => self.bump_error("expected a value"),
}
self.finish(m);
}
fn array(&mut self) {
assert_eq!(self.current(), L_BRACK);
let m = self.start(ARRAY);
self.bump();
while self.current() != EOF && self.current() != R_BRACK {
self.val();
if self.current() != R_BRACK {
self.eat(COMMA)
}
}
self.eat(R_BRACK);
self.finish(m);
}
fn dict(&mut self) {
assert_eq!(self.current(), L_CURLY);
let m = self.start(DICT);
self.bump();
while self.current() != EOF && self.current() != R_CURLY {
self.entry();
if self.current() != R_CURLY {
self.eat(COMMA)
}
}
self.eat(R_CURLY);
self.finish(m);
}
fn table(&mut self) {
assert_eq!(self.current(), L_BRACK);
let m = self.start(TABLE);
self.table_header(false);
self.entries();
self.finish(m)
}
fn array_table(&mut self) {
assert!(self.at(0) == L_BRACK && self.at(1) == L_BRACK);
let m = self.start(ARRAY_TABLE);
self.table_header(true);
self.entries();
self.finish(m)
}
fn table_header(&mut self, array: bool) {
assert_eq!(self.current(), L_BRACK);
let m = self.start(TABLE_HEADER);
self.bump();
if array {
assert_eq!(self.current(), L_BRACK);
self.bump();
}
self.keys();
self.eat(R_BRACK);
if array {
self.eat(R_BRACK);
}
self.finish(m);
}
}