1mod arena;
10pub(crate) mod ast;
11mod eval;
12mod grammar;
13mod ops;
14
15use std::marker::PhantomData;
16
17use arena::{convert_to_arena, AstArena};
18pub use ast::*;
20use eval::arena_evaluate_root;
21use grammar::build_parser;
22
23use crate::lexer::Token;
24use crate::{BoxError, CallbackMap, EnumMap, EvalContextFamily, OttlParser, PathResolverMap, Result, Value};
25
26pub struct Parser<F: EvalContextFamily> {
36 arena: AstArena<F>,
38 arena_root: Option<ArenaRootExpr>,
40 errors: Vec<String>,
42 _marker: PhantomData<F>,
44}
45
46impl<F: EvalContextFamily> Parser<F> {
47 pub fn new(
51 editors_map: &CallbackMap, converters_map: &CallbackMap, enums_map: &EnumMap,
52 path_resolvers: &PathResolverMap<F>, expression: &str,
53 ) -> Self {
54 let mut parser = Parser::<F> {
55 arena: AstArena::new(),
56 arena_root: None,
57 errors: Vec::new(),
58 _marker: PhantomData,
59 };
60
61 let tokens_with_spans = match crate::lexer::Lexer::collect_with_spans(expression) {
63 Ok(tokens) => tokens,
64 Err(e) => {
65 parser.errors.push(format!("Lexer error: {}", e));
66 return parser;
67 }
68 };
69
70 if tokens_with_spans.is_empty() && !expression.trim().is_empty() {
71 parser.errors.push("Lexer failed to tokenize input".into());
72 return parser;
73 }
74
75 let tokens: Vec<Token> = tokens_with_spans.into_iter().map(|(t, _)| t).collect();
77
78 let chumsky_parser = build_parser(editors_map, converters_map, enums_map);
80
81 use chumsky::Parser as ChumskyParser;
83 let result = chumsky_parser.parse(&tokens[..]);
84
85 match result.into_result() {
86 Ok(ast) => {
87 match convert_to_arena(&ast, &mut parser.arena, path_resolvers) {
90 Ok(arena_root) => {
91 parser.arena_root = Some(arena_root);
92 }
93 Err(e) => {
94 parser.errors.push(format!("Path resolution error: {}", e));
95 }
96 }
97 }
98 Err(errs) => {
99 for err in errs {
100 parser.errors.push(format!("Parse error: {:?}", err));
101 }
102 }
103 }
104
105 parser
106 }
107}
108
109impl<F: EvalContextFamily> OttlParser<F> for Parser<F> {
111 fn is_error(&self) -> Result<()> {
112 if self.errors.is_empty() {
113 Ok(())
114 } else {
115 Err(self.errors.join("; ").into())
116 }
117 }
118
119 fn execute<'a>(&self, ctx: &mut F::Context<'a>) -> Result<Value> {
120 let arena_root = self
121 .arena_root
122 .as_ref()
123 .ok_or_else(|| -> BoxError { "No AST available (parsing failed)".into() })?;
124
125 arena_evaluate_root(arena_root, &self.arena, ctx)
127 }
128}