Skip to main content

rune_cfg/parser/
mod.rs

1// Author: Dustin Pilgrim
2// License: GPL-3.0-or-later
3
4use std::collections::HashMap;
5
6use crate::RuneError;
7use crate::ast::{Document, Value};
8use crate::lexer::{Lexer, Token};
9
10mod conditional;
11mod document;
12mod reference;
13mod value;
14
15pub struct Parser<'a> {
16    lexer: Lexer<'a>,
17    peek: Option<Token>,
18    peek_start: usize,
19    peek_escaped_dollars: Vec<usize>,
20    lines: crate::source::LineIndex,
21    pub(crate) options: crate::ParseOptions,
22    pub imports: HashMap<String, Document>,
23}
24
25impl<'a> Parser<'a> {
26    pub fn new(input: &'a str) -> Result<Self, RuneError> {
27        Self::with_options(input, crate::ParseOptions::default())
28    }
29
30    pub fn with_options(input: &'a str, options: crate::ParseOptions) -> Result<Self, RuneError> {
31        let mut lexer = Lexer::new(input);
32        let token = lexer.next_token_spanned()?;
33        let peek_escaped_dollars = lexer.escaped_dollars.clone();
34        let peek_start = token.span.start;
35        let peek = Some(token.token);
36        Ok(Self {
37            lexer,
38            peek,
39            peek_start,
40            peek_escaped_dollars,
41            lines: crate::source::LineIndex::new(input),
42            options,
43            imports: HashMap::new(),
44        })
45    }
46
47    pub fn inject_import(&mut self, alias: String, document: Document) {
48        self.imports.insert(alias, document);
49    }
50
51    pub(crate) fn bump(&mut self) -> Result<Token, RuneError> {
52        let curr = self.peek.take().ok_or(RuneError::UnexpectedEof {
53            message: "Unexpected end of input".into(),
54            line: self.lexer.line(),
55            column: self.lexer.column(),
56            hint: None,
57            code: Some(201),
58        })?;
59        let token = self.lexer.next_token_spanned()?;
60        self.peek_start = token.span.start;
61        self.peek_escaped_dollars = self.lexer.escaped_dollars.clone();
62        self.peek = Some(token.token);
63        Ok(curr)
64    }
65
66    pub(crate) fn token_position(&self) -> (usize, usize) {
67        let position = self.lines.byte_to_position(self.peek_start);
68        (position.line as usize + 1, position.character as usize + 1)
69    }
70
71    pub(crate) fn peek(&self) -> Option<&Token> {
72        self.peek.as_ref()
73    }
74
75    #[allow(dead_code)]
76    pub(crate) fn expect(&mut self, expected: Token) -> Result<Token, RuneError> {
77        let token = self.bump()?;
78        if token != expected {
79            return Err(RuneError::SyntaxError {
80                message: format!("Expected {:?}, got {:?}", expected, token),
81                line: self.lexer.line(),
82                column: self.lexer.column(),
83                hint: Some("Check your syntax".into()),
84                code: Some(202),
85            });
86        }
87        Ok(token)
88    }
89
90    pub(crate) fn line(&self) -> usize {
91        self.lexer.line()
92    }
93
94    pub(crate) fn column(&self) -> usize {
95        self.lexer.column()
96    }
97
98    // Re-export main public methods
99    pub fn parse_document(&mut self) -> Result<Document, RuneError> {
100        document::parse_document(self)
101    }
102
103    pub fn resolve_reference<'b>(
104        &'b self,
105        path: &[String],
106        doc: &'b Document,
107    ) -> Option<&'b Value> {
108        reference::resolve_reference(self, path, doc)
109    }
110}
111
112#[cfg(test)]
113mod tests;