mod choice;
mod content;
mod declaration;
mod divert;
mod expression;
mod gather;
mod inline;
mod knot;
mod logic;
mod story;
mod tag;
use crate::SyntaxKind::{self, COLON, EOF, ERROR, IDENT, L_BRACE, NEWLINE, PIPE, R_BRACE};
use crate::lexer;
use rowan::GreenNode;
pub struct Parse {
green: GreenNode,
errors: Vec<ParseError>,
}
impl Parse {
#[must_use]
pub fn green(&self) -> &GreenNode {
&self.green
}
#[must_use]
pub fn syntax(&self) -> crate::SyntaxNode {
crate::SyntaxNode::new_root(self.green.clone())
}
#[must_use]
pub fn errors(&self) -> &[ParseError] {
&self.errors
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct ParseError {
pub message: String,
pub range: rowan::TextRange,
}
#[must_use]
pub fn parse(source: &str) -> Parse {
let raw_tokens = lexer::lex(source);
let mut p = Parser::new(&raw_tokens);
story::source_file(&mut p);
let green = p.builder.finish();
Parse {
green,
errors: p.errors,
}
}
pub fn parse_with_cache(source: &str, cache: &mut rowan::NodeCache) -> Parse {
let raw_tokens = lexer::lex(source);
let mut p = Parser::with_cache(&raw_tokens, cache);
story::source_file(&mut p);
let green = p.builder.finish();
Parse {
green,
errors: p.errors,
}
}
const MAX_DEPTH: u32 = 256;
pub(crate) struct Parser<'t, 'c> {
tokens: &'t [(SyntaxKind, &'t str)],
pos: usize,
depth: u32,
brace_scan: Vec<SyntaxKind>,
non_trivia: Vec<usize>,
builder: rowan::GreenNodeBuilder<'c>,
errors: Vec<ParseError>,
}
impl<'t> Parser<'t, 'static> {
fn new(tokens: &'t [(SyntaxKind, &'t str)]) -> Self {
let brace_scan = Self::build_brace_scan(tokens);
let non_trivia = Self::build_non_trivia(tokens);
Self {
tokens,
pos: 0,
depth: 0,
brace_scan,
non_trivia,
builder: rowan::GreenNodeBuilder::new(),
errors: Vec::new(),
}
}
}
impl<'t, 'c> Parser<'t, 'c> {
fn with_cache(tokens: &'t [(SyntaxKind, &'t str)], cache: &'c mut rowan::NodeCache) -> Self {
let brace_scan = Self::build_brace_scan(tokens);
let non_trivia = Self::build_non_trivia(tokens);
Self {
tokens,
pos: 0,
depth: 0,
brace_scan,
non_trivia,
builder: rowan::GreenNodeBuilder::with_cache(cache),
errors: Vec::new(),
}
}
fn build_non_trivia(tokens: &[(SyntaxKind, &str)]) -> Vec<usize> {
tokens
.iter()
.enumerate()
.filter(|(_, (k, _))| !k.is_trivia())
.map(|(i, _)| i)
.collect()
}
fn build_brace_scan(tokens: &[(SyntaxKind, &str)]) -> Vec<SyntaxKind> {
struct Entry {
brace_pos: usize,
has_colon: bool,
has_pipe: bool,
single_pipe_before_colon: bool,
}
fn classify(e: &Entry) -> SyntaxKind {
if e.single_pipe_before_colon {
PIPE } else if e.has_colon {
COLON } else if e.has_pipe {
PIPE } else {
EOF }
}
let n = tokens.len();
let mut result = vec![EOF; n];
let next_nt = {
let mut v = vec![n; n];
let mut last = n;
for i in (0..n).rev() {
v[i] = last;
if !tokens[i].0.is_trivia() {
last = i;
}
}
v
};
let mut stack: Vec<Entry> = Vec::new();
let mut prev_nt = EOF;
for (i, &(kind, _)) in tokens.iter().enumerate() {
if kind.is_trivia() {
continue;
}
match kind {
L_BRACE => {
stack.push(Entry {
brace_pos: i,
has_colon: false,
has_pipe: false,
single_pipe_before_colon: false,
});
prev_nt = L_BRACE;
}
R_BRACE => {
if let Some(entry) = stack.pop() {
result[entry.brace_pos] = classify(&entry);
}
prev_nt = R_BRACE;
}
COLON => {
if let Some(e) = stack.last_mut() {
e.has_colon = true;
}
prev_nt = COLON;
}
PIPE => {
if let Some(e) = stack.last_mut() {
e.has_pipe = true;
let next_is_pipe = next_nt[i] < n && tokens[next_nt[i]].0 == PIPE;
let prev_is_pipe = prev_nt == PIPE;
let is_single = !next_is_pipe && !prev_is_pipe;
if is_single && !e.has_colon {
e.single_pipe_before_colon = true;
}
}
prev_nt = PIPE;
}
NEWLINE => {
while let Some(entry) = stack.pop() {
result[entry.brace_pos] = classify(&entry);
}
prev_nt = NEWLINE;
}
_ => {
prev_nt = kind;
}
}
}
for entry in stack {
result[entry.brace_pos] = classify(&entry);
}
result
}
fn at_depth_limit(&self) -> bool {
self.depth >= MAX_DEPTH
}
fn brace_scan_at(&self, raw_pos: usize) -> SyntaxKind {
self.brace_scan.get(raw_pos).copied().unwrap_or(EOF)
}
fn current(&self) -> SyntaxKind {
self.nth(0)
}
fn nth(&self, n: usize) -> SyntaxKind {
let start = self.non_trivia.partition_point(|&idx| idx < self.pos);
let target = start + n;
if target < self.non_trivia.len() {
self.tokens[self.non_trivia[target]].0
} else {
EOF
}
}
fn nth_raw(&self, n: usize) -> SyntaxKind {
self.tokens.get(self.pos + n).map_or(EOF, |&(k, _)| k)
}
fn at(&self, kind: SyntaxKind) -> bool {
self.current() == kind
}
fn at_eof(&self) -> bool {
self.pos >= self.tokens.len()
}
fn pos(&self) -> usize {
self.pos
}
fn bump(&mut self) {
if self.pos < self.tokens.len() {
let (kind, text) = self.tokens[self.pos];
self.builder.token(rowan::SyntaxKind(kind as u16), text);
self.pos += 1;
}
}
fn bump_assert(&mut self, kind: SyntaxKind) {
debug_assert_eq!(self.nth_raw(0), kind);
self.bump();
}
fn eat(&mut self, kind: SyntaxKind) -> bool {
if self.current() == kind {
self.skip_ws();
self.bump();
true
} else {
false
}
}
fn expect(&mut self, kind: SyntaxKind) {
if !self.eat(kind) {
self.error(format!("expected {kind:?}"));
}
}
fn at_ident_or_keyword(&self) -> bool {
self.current() == IDENT || self.current().is_keyword()
}
fn eat_ident_or_keyword(&mut self) -> bool {
if self.at_ident_or_keyword() {
self.skip_ws();
self.bump();
true
} else {
false
}
}
fn expect_ident_or_keyword(&mut self) {
if !self.eat_ident_or_keyword() {
self.error("expected IDENT".into());
}
}
fn skip_ws(&mut self) {
while self.pos < self.tokens.len() && self.tokens[self.pos].0.is_trivia() {
self.bump();
}
}
fn start_node(&mut self, kind: SyntaxKind) {
self.builder.start_node(rowan::SyntaxKind(kind as u16));
}
fn start_node_at(&mut self, checkpoint: rowan::Checkpoint, kind: SyntaxKind) {
self.builder
.start_node_at(checkpoint, rowan::SyntaxKind(kind as u16));
}
fn finish_node(&mut self) {
self.builder.finish_node();
}
fn checkpoint(&self) -> rowan::Checkpoint {
self.builder.checkpoint()
}
fn error(&mut self, message: String) {
let upto = self.pos.min(self.tokens.len());
let start: usize = self.tokens[..upto].iter().map(|(_, t)| t.len()).sum();
let len: usize = self.tokens.get(self.pos).map_or(0, |(_, t)| t.len());
let start = rowan::TextSize::from(u32::try_from(start).unwrap_or(u32::MAX));
let len = rowan::TextSize::from(u32::try_from(len).unwrap_or(u32::MAX));
self.errors.push(ParseError {
message,
range: rowan::TextRange::at(start, len),
});
}
fn error_recover(&mut self, message: &str) {
self.error(message.to_owned());
self.start_node(ERROR);
self.bump();
self.finish_node();
}
}
#[cfg(test)]
mod tests;