1use 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 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;