From 70f616d60c77b87bfcf25c140b56bb9384de15f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Fri, 13 Mar 2026 08:38:58 +0100 Subject: [PATCH 1/6] Add tokenization of function pieces MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- src/parser/mod.rs | 61 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 60 insertions(+), 1 deletion(-) diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 37e2757..3e0d80c 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -210,6 +210,9 @@ pub enum TokenKind { TrimWhitespace, WantsOutput, Ident, + LeftArgList, + RightArgList, + ArgSeperator, Whitespace, Invalid, ConditionalIf, @@ -316,6 +319,9 @@ impl TemplateToken { trim_whitespace => TokenKind::TrimWhitespace, wants_output => TokenKind::WantsOutput, ident => TokenKind::Ident, + left_arg_list => TokenKind::LeftArgList, + right_arg_list => TokenKind::RightArgList, + arg_seperator => TokenKind::ArgSeperator, whitespace => TokenKind::Whitespace, invalid => TokenKind::Invalid, conditional_if => TokenKind::ConditionalIf, @@ -415,7 +421,13 @@ fn parse_interpolate<'input>(input: &mut Input<'input>) -> PResult<'input, Vec(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { trace( "parse_block_token", - alt((parse_ident, parse_keyword, parse_whitespace, parse_operator)), + alt(( + parse_ident, + parse_function, + parse_keyword, + parse_whitespace, + parse_operator, + )), ) .parse_next(input) } @@ -493,6 +505,18 @@ fn parse_whitespace<'input>(input: &mut Input<'input>) -> PResult<'input, Templa .parse_next(input) } +fn parse_function<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { + trace( + "parse_function", + alt(( + "(".map(TemplateToken::left_arg_list), + ")".map(TemplateToken::right_arg_list), + ",".map(TemplateToken::arg_seperator), + )), + ) + .parse_next(input) +} + fn parse_ident<'input>(input: &mut Input<'input>) -> PResult<'input, TemplateToken> { resume_after_cut( terminated( @@ -581,6 +605,7 @@ fn ident_terminator<'input>(input: &mut Input<'input>) -> PResult<'input, ()> { alt(( eof.void(), one_of(('{', '}')).void(), + one_of(('(', ',', ')')).void(), one_of((' ', '\t', '\r', '\n')).void(), )) .parse_next(input) @@ -846,4 +871,38 @@ mod tests { ) "#); } + + #[test] + fn parse_function() { + let input = "{{= foo(23, 4, 3 * 5) }}"; + let output = parse(input.into()); + + insta::assert_debug_snapshot!(output, @r#" + Ok( + ParsedTemplate { + tokens: [ + [LeftDelim]"{{" (0..2), + [WantsOutput]"=" (2..3), + [Whitespace]" " (3..4), + [Ident]"foo" (4..7), + [LeftArgList]"(" (7..8), + [Literal(Integer(23))]"23" (8..10), + [ArgSeperator]"," (10..11), + [Whitespace]" " (11..12), + [Literal(Integer(4))]"4" (12..13), + [ArgSeperator]"," (13..14), + [Whitespace]" " (14..15), + [Literal(Integer(3))]"3" (15..16), + [Whitespace]" " (16..17), + [Operator(Times)]"*" (17..18), + [Whitespace]" " (18..19), + [Literal(Integer(5))]"5" (19..20), + [RightArgList]")" (20..21), + [Whitespace]" " (21..22), + [RightDelim]"}}" (22..24), + ], + }, + ) + "#); + } } From cb55c0073906c6c928111672d474389b9005d671 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Fri, 13 Mar 2026 09:08:06 +0100 Subject: [PATCH 2/6] Add function asting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- src/ast/mod.rs | 44 ++++++++++++++- ...nomo__ast__tests__check_function_call.snap | 53 +++++++++++++++++++ src/emit/mod.rs | 2 + src/value.rs | 2 - 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 src/ast/snapshots/nomo__ast__tests__check_function_call.snap diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 55190b0..a9ca5ce 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -13,6 +13,7 @@ use winnow::combinator::peek; use winnow::combinator::preceded; use winnow::combinator::repeat; use winnow::combinator::repeat_till; +use winnow::combinator::separated; use winnow::combinator::trace; use winnow::error::AddContext; use winnow::error::FromRecoverableError; @@ -268,6 +269,10 @@ pub enum TemplateAstExpr<'input> { source: TemplateToken, value: NomoValue, }, + FunctionCall { + name: Box>, + args: Vec>, + }, } fn parse_asts<'input>(input: &mut Input<'input>) -> Result>, AstError> { @@ -559,6 +564,22 @@ fn parse_end<'input>(input: &mut Input<'input>) -> Result(input: &mut Input<'input>) -> Result, AstError> { + trace( + "variable_access", + ( + TokenKind::Ident + .map(TemplateAstExpr::VariableAccess) + .map(Box::new), + TokenKind::LeftArgList, + separated(0.., parse_expression, TokenKind::ArgSeperator), + TokenKind::RightArgList, + ) + .map(|(name, _left, args, _right)| TemplateAstExpr::FunctionCall { name, args }), + ) + .parse_next(input) +} + fn parse_variable_access<'input>( input: &mut Input<'input>, ) -> Result, AstError> { @@ -620,7 +641,11 @@ where } fn parse_operand<'input>(input: &mut Input<'input>) -> Result, AstError> { - trace("operand", alt((parse_variable_access, parse_literal))).parse_next(input) + trace( + "operand", + alt((parse_function, parse_variable_access, parse_literal)), + ) + .parse_next(input) } fn parse_literal<'input>(input: &mut Input<'input>) -> Result, AstError> { @@ -658,7 +683,11 @@ fn parse_expression<'input>( ($parser:expr => [ $($side:tt $val:tt => $prec:expr),* $(,)? ]) => { dispatch! { surrounded(ws, parse_operator); $( - TokenOperator::$val => $side($prec, |_, lhs, rhs| Ok(TemplateAstExpr::Operation { op: TokenOperator::$val, lhs: Box::new(lhs), rhs: Box::new(rhs) })) + TokenOperator::$val => $side($prec, |_, lhs, rhs| Ok(TemplateAstExpr::Operation { + op: TokenOperator::$val, + lhs: Box::new(lhs), + rhs: Box::new(rhs) + })) ),* } }; @@ -1008,4 +1037,15 @@ mod tests { insta::assert_debug_snapshot!(ast); } + + #[test] + fn check_function_call() { + let input = "{{= foo(2 * 3, bar(2 + baz)) }}"; + + let parsed = crate::parser::parse(input.into()).unwrap(); + + let ast = panic_pretty(input, parse(parsed.tokens())); + + insta::assert_debug_snapshot!(ast); + } } diff --git a/src/ast/snapshots/nomo__ast__tests__check_function_call.snap b/src/ast/snapshots/nomo__ast__tests__check_function_call.snap new file mode 100644 index 0000000..44eaec1 --- /dev/null +++ b/src/ast/snapshots/nomo__ast__tests__check_function_call.snap @@ -0,0 +1,53 @@ +--- +source: src/ast/mod.rs +expression: ast +--- +TemplateAst { + root: [ + Interpolation { + prev_whitespace_content: None, + expression: FunctionCall { + name: VariableAccess( + [Ident]"foo" (4..7), + ), + args: [ + Operation { + op: Times, + lhs: Literal { + source: [Literal(Integer(2))]"2" (8..9), + value: Integer { + value: 2, + }, + }, + rhs: Literal { + source: [Literal(Integer(3))]"3" (12..13), + value: Integer { + value: 3, + }, + }, + }, + FunctionCall { + name: VariableAccess( + [Ident]"bar" (15..18), + ), + args: [ + Operation { + op: Plus, + lhs: Literal { + source: [Literal(Integer(2))]"2" (19..20), + value: Integer { + value: 2, + }, + }, + rhs: VariableAccess( + [Ident]"baz" (23..26), + ), + }, + ], + }, + ], + }, + post_whitespace_content: None, + }, + ], +} diff --git a/src/emit/mod.rs b/src/emit/mod.rs index aa3e6c0..1a8603a 100644 --- a/src/emit/mod.rs +++ b/src/emit/mod.rs @@ -417,6 +417,7 @@ fn emit_ast_expr( | TemplateAstExpr::ForElse | TemplateAstExpr::Invalid { .. } | TemplateAstExpr::Literal { .. } + | TemplateAstExpr::FunctionCall { .. } | TemplateAstExpr::Operation { .. } | TemplateAstExpr::VariableAccess { .. } => eval.push(Instruction::Abort), } @@ -459,6 +460,7 @@ fn emit_expr_load( TemplateAstExpr::StaticContent { .. } | TemplateAstExpr::Interpolation { .. } => { unreachable!("Invalid AST here") } + TemplateAstExpr::FunctionCall { .. } => todo!(), TemplateAstExpr::ConditionalChain { .. } => todo!(), TemplateAstExpr::ElseConditional { .. } => todo!(), TemplateAstExpr::EndBlock => todo!(), diff --git a/src/value.rs b/src/value.rs index 965cb2b..dd57a03 100644 --- a/src/value.rs +++ b/src/value.rs @@ -5,8 +5,6 @@ use std::collections::BTreeMap; use displaydoc::Display; use thiserror::Error; -use crate::Nomo; - #[derive(Clone)] pub enum NomoValue { String { From 52a63a706620a8b7e13c0c048a94cb49ef56303a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Sat, 14 Mar 2026 10:52:29 +0100 Subject: [PATCH 3/6] Add emitting of function calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- src/ast/mod.rs | 6 +- ...nomo__ast__tests__check_function_call.snap | 8 +- src/emit/mod.rs | 33 +++++++- ...omo__emit__tests__check_function_call.snap | 79 +++++++++++++++++++ src/eval/mod.rs | 1 + 5 files changed, 116 insertions(+), 11 deletions(-) create mode 100644 src/emit/snapshots/nomo__emit__tests__check_function_call.snap diff --git a/src/ast/mod.rs b/src/ast/mod.rs index a9ca5ce..3a94816 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -270,7 +270,7 @@ pub enum TemplateAstExpr<'input> { value: NomoValue, }, FunctionCall { - name: Box>, + name: TemplateToken, args: Vec>, }, } @@ -568,9 +568,7 @@ fn parse_function<'input>(input: &mut Input<'input>) -> Result, + slot: VariableSlot, + }, } #[derive(Debug, Clone)] @@ -456,11 +461,24 @@ fn emit_expr_load( result_slot: emit_slot, }); } + TemplateAstExpr::FunctionCall { name, args } => { + let mut arg_slots = vec![]; + for arg in args { + let slot = machine.reserve_slot(); + emit_expr_load(machine, eval, slot, arg); + arg_slots.push(slot); + } + + eval.push(Instruction::FunctionCall { + name: name.source(), + args: arg_slots, + slot: emit_slot, + }); + } TemplateAstExpr::Invalid { .. } => eval.push(Instruction::Abort), TemplateAstExpr::StaticContent { .. } | TemplateAstExpr::Interpolation { .. } => { unreachable!("Invalid AST here") } - TemplateAstExpr::FunctionCall { .. } => todo!(), TemplateAstExpr::ConditionalChain { .. } => todo!(), TemplateAstExpr::ElseConditional { .. } => todo!(), TemplateAstExpr::EndBlock => todo!(), @@ -526,4 +544,17 @@ mod tests { insta::assert_debug_snapshot!(emit); } + + #[test] + fn check_function_call() { + let input = "{{ if foo(23) }} bar {{ else }} foobar {{ end }}"; + + let parsed = crate::parser::parse(input.into()).unwrap(); + + let ast = crate::ast::parse(parsed.tokens()).unwrap(); + + let emit = emit_machine(ast); + + insta::assert_debug_snapshot!(emit); + } } diff --git a/src/emit/snapshots/nomo__emit__tests__check_function_call.snap b/src/emit/snapshots/nomo__emit__tests__check_function_call.snap new file mode 100644 index 0000000..3594efe --- /dev/null +++ b/src/emit/snapshots/nomo__emit__tests__check_function_call.snap @@ -0,0 +1,79 @@ +--- +source: src/emit/mod.rs +expression: emit +--- +VMInstructions { + labels: { + LabelSlot { + index: 0, + }: 13, + LabelSlot { + index: 3, + }: 8, + }, + instructions: [ + LoadLiteralToSlot { + source: [Literal(Integer(23))]"23" (10..12), + value: Integer { + value: 23, + }, + slot: VariableSlot { + index: 2, + }, + }, + FunctionCall { + name: "foo" (6..9), + args: [ + VariableSlot { + index: 2, + }, + ], + slot: VariableSlot { + index: 1, + }, + }, + JumpIfNotTrue { + emit_slot: VariableSlot { + index: 1, + }, + jump: LabelSlot { + index: 3, + }, + }, + AppendContent { + content: " " (16..17), + }, + AppendContent { + content: "bar" (17..20), + }, + AppendContent { + content: " " (20..21), + }, + Jump { + jump: LabelSlot { + index: 0, + }, + }, + AppendContent { + content: " " (16..17), + }, + AppendContent { + content: " " (31..32), + }, + AppendContent { + content: "foobar" (32..38), + }, + AppendContent { + content: " " (38..39), + }, + Jump { + jump: LabelSlot { + index: 0, + }, + }, + AppendContent { + content: " " (31..32), + }, + NoOp, + ], +} diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 8d32123..7617380 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -208,6 +208,7 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result todo!(), } ip += 1; From 10bcd770400834bd1338f8d1779c99c4b7201312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Sun, 15 Mar 2026 11:27:25 +0100 Subject: [PATCH 4/6] Add function calling MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- src/eval/mod.rs | 50 ++++++++++++- src/functions.rs | 175 ++++++++++++++++++++++++++++++++++++++++++++ src/lib.rs | 6 +- src/value.rs | 48 +++++++++++- tests/file_tests.rs | 3 +- 5 files changed, 275 insertions(+), 7 deletions(-) create mode 100644 src/functions.rs diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 7617380..1bb7425 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -7,6 +7,7 @@ use crate::Context; use crate::emit::Instruction; use crate::emit::VMInstructions; use crate::emit::VariableSlot; +use crate::functions::FunctionMap; use crate::input::NomoInput; use crate::value::NomoValue; @@ -69,7 +70,11 @@ impl Scope { clippy::unnecessary_to_owned, reason = "We cannot do the suggested way as the lifetimes would not match up" )] -pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result { +pub fn execute( + available_functions: &FunctionMap, + vm: &VMInstructions, + global_context: &Context, +) -> Result { let mut output = String::new(); let mut scopes = Scope { @@ -208,7 +213,17 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result todo!(), + Instruction::FunctionCall { name, args, slot } => { + let args = args.iter().map(|slot| scopes.get(slot)).cloned().collect(); + + let value = available_functions + .get(name.as_str()) + .unwrap() + .call(args) + .unwrap(); + + scopes.insert_into_slot(*slot, value); + } } ip += 1; @@ -221,6 +236,8 @@ pub fn execute(vm: &VMInstructions, global_context: &Context) -> Result Result { + Ok(arg.to_uppercase()) + }); + + let output = execute(&function_map, &emit, &context); + + insta::assert_debug_snapshot!(output, @r#" + Ok( + "Hello WORLD", + ) + "#); + } } diff --git a/src/functions.rs b/src/functions.rs new file mode 100644 index 0000000..c15031c --- /dev/null +++ b/src/functions.rs @@ -0,0 +1,175 @@ +use std::any::Any; +use std::collections::HashMap; + +use displaydoc::Display; +use thiserror::Error; + +use crate::NomoValueError; +use crate::value::NomoValue; + +#[derive(Debug, Error, Display)] +pub enum NomoFunctionError { + /// Received {received} arguments, but this function only takes {expected} + WrongArgumentCount { received: usize, expected: usize }, + + /// The argument at this position is of the wrong type + InvalidArgumentType { index: usize }, + + /// A user-provided error + #[error(transparent)] + CustomError { + custom: Box, + }, +} + +pub trait NomoFunction: 'static + Send + Sync { + fn call(&self, args: Vec) -> Result; +} + +#[derive(Default)] +pub struct FunctionMap { + funcs: HashMap, +} + +impl FunctionMap { + pub fn register, T>(&mut self, name: impl Into, func: NF) { + self.funcs + .insert(name.into(), ErasedNomoFunction::erase(func)); + } + + pub fn get(&self, name: impl AsRef) -> Option<&ErasedNomoFunction> { + self.funcs.get(name.as_ref()) + } +} + +pub struct ErasedNomoFunction { + func: Box, + call_fn: fn(&dyn Any, Vec) -> Result, +} + +impl ErasedNomoFunction { + pub fn call(&self, args: Vec) -> Result { + (self.call_fn)(&*self.func, args) + } + + pub fn erase(f: NF) -> ErasedNomoFunction + where + NF: NomoFunction, + { + ErasedNomoFunction { + func: Box::new(f), + call_fn: |nf, args| { + let nf: &NF = nf.downcast_ref().unwrap(); + + nf.call(args) + }, + } + } +} + +#[rustfmt::skip] +macro_rules! for_all_tuples { + ($name:ident) => { + $name!([], T1); + $name!([T1], T2); + $name!([T1, T2], T3); + $name!([T1, T2, T3], T4); + $name!([T1, T2, T3, T4], T5); + $name!([T1, T2, T3, T4, T5], T6); + $name!([T1, T2, T3, T4, T5, T6], T7); + $name!([T1, T2, T3, T4, T5, T6, T7], T8); + $name!([T1, T2, T3, T4, T5, T6, T7, T8], T9); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9], T10); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10], T11); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11], T12); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12], T13); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13], T14); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14], T15); + $name!([T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15], T16); + }; +} + +macro_rules! impl_nomo_function { + ([$($ty:ident),*], $last:ident) => { + impl NomoFunction<($($ty,)* $last,)> for F + where + F: Fn($($ty,)* $last,) -> Result, + F: Send + Sync + 'static, + Res: Into, + Error: Into, + $( $ty: TryFrom, )* + $last: TryFrom, + { + fn call(&self, args: Vec) -> Result { + let arg_count = args.len(); + + let total_count = 1 $(+ impl_nomo_function!(count $ty))*; + + if arg_count != total_count { + return Err(NomoFunctionError::WrongArgumentCount { + expected: total_count, + received: arg_count, + }); + } + + let mut args = args.into_iter(); + + #[allow(unused_mut)] + let mut idx = 0; + + let val = (self)( + $({ + let val = $ty::try_from(args.next().unwrap()).map_err(|_| NomoFunctionError::InvalidArgumentType { index: idx })?; + idx += 1; + val + },)* + $last::try_from(args.next().unwrap()).map_err(|_| NomoFunctionError::InvalidArgumentType { index: idx })?, + ); + + val.map(Into::into).map_err(Into::into) + } + } + }; + + (count $ty:ident) => { + 1 + } +} + +for_all_tuples!(impl_nomo_function); + +impl NomoFunction<()> for F +where + F: Fn() -> Result + Send + Sync + 'static, + Res: Into, + Error: Into, +{ + fn call(&self, args: Vec) -> Result { + let arg_count = args.len(); + + if arg_count != 0 { + return Err(NomoFunctionError::WrongArgumentCount { + received: arg_count, + expected: 0, + }); + } + + let val = (self)(); + + val.map(Into::into).map_err(Into::into) + } +} + +#[cfg(test)] +mod tests { + use crate::functions::ErasedNomoFunction; + use crate::functions::NomoFunctionError; + + #[expect(dead_code, reason = "This is a compile test")] + fn check_various_methods() { + ErasedNomoFunction::erase(|name: String| -> Result { Ok(name) }); + ErasedNomoFunction::erase(|left: u64, right: u64| -> Result { + Ok(left + right) + }); + } +} diff --git a/src/lib.rs b/src/lib.rs index 8d177ce..c9b8222 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ use displaydoc::Display; use thiserror::Error; use crate::emit::VMInstructions; +use crate::functions::FunctionMap; use crate::input::NomoInput; use crate::value::NomoValue; use crate::value::NomoValueError; @@ -11,6 +12,7 @@ use crate::value::NomoValueError; pub mod ast; pub mod emit; pub mod eval; +pub mod functions; pub mod input; pub mod parser; pub mod value; @@ -40,6 +42,7 @@ pub enum NomoError { pub struct Nomo { templates: HashMap, + function_map: FunctionMap, } impl Default for Nomo { @@ -52,6 +55,7 @@ impl Nomo { pub fn new() -> Nomo { Nomo { templates: HashMap::new(), + function_map: FunctionMap::default(), } } @@ -78,7 +82,7 @@ impl Nomo { .get(name) .ok_or_else(|| NomoError::UnknownTemplate(name.to_string()))?; - let res = eval::execute(&template.instructions, ctx)?; + let res = eval::execute(&self.function_map, &template.instructions, ctx)?; Ok(res) } diff --git a/src/value.rs b/src/value.rs index dd57a03..2d70084 100644 --- a/src/value.rs +++ b/src/value.rs @@ -310,6 +310,18 @@ impl From<&'static str> for NomoValue { } } +impl From for NomoValue { + fn from(val: u64) -> Self { + NomoValue::Integer { value: val } + } +} + +impl From for NomoValue { + fn from(val: i64) -> Self { + NomoValue::SignedInteger { value: val } + } +} + impl From> for NomoValue where V: Into, @@ -355,11 +367,43 @@ where } } -#[cfg(feature = "serde_json")] #[derive(Debug, Error, Display)] -/// Could not transform value to [`NomoValue`] +/// Could not transform value to/from [`NomoValue`] pub struct NomoValueError; +impl TryFrom for String { + type Error = NomoValueError; + + fn try_from(value: NomoValue) -> Result { + match value { + NomoValue::String { value } => Ok(value.to_string()), + _ => Err(NomoValueError), + } + } +} + +impl TryFrom for i64 { + type Error = NomoValueError; + + fn try_from(value: NomoValue) -> Result { + match value { + NomoValue::SignedInteger { value } => Ok(value), + _ => Err(NomoValueError), + } + } +} + +impl TryFrom for u64 { + type Error = NomoValueError; + + fn try_from(value: NomoValue) -> Result { + match value { + NomoValue::Integer { value } => Ok(value), + _ => Err(NomoValueError), + } + } +} + #[cfg(feature = "serde_json")] impl TryFrom for NomoValue { type Error = NomoValueError; diff --git a/tests/file_tests.rs b/tests/file_tests.rs index db3c666..28e88e9 100644 --- a/tests/file_tests.rs +++ b/tests/file_tests.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::path::Path; use nomo::Context; +use nomo::functions::FunctionMap; test_each_file::test_each_path! { for ["nomo"] in "./tests/cases/" as cases => check_for_input } @@ -58,7 +59,7 @@ fn check_for_input([path]: [&Path; 1]) { insta::assert_debug_snapshot!(format!("{basename}.3-instructions"), emit); - let output = nomo::eval::execute(&emit, &context).unwrap(); + let output = nomo::eval::execute(&FunctionMap::default(), &emit, &context).unwrap(); insta::assert_debug_snapshot!(format!("{basename}.4-output"), output); } From f87f4a0262553754e38ed8a5879cf139b6670d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Sun, 15 Mar 2026 11:31:40 +0100 Subject: [PATCH 5/6] Rename parser to lexer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- benches/asting.rs | 4 +- benches/parsing.rs | 4 +- fuzz/fuzz_targets/fuzz_target_1.rs | 2 +- src/ast/mod.rs | 40 +++++++++---------- src/emit/mod.rs | 12 +++--- src/eval/mod.rs | 16 ++++---- src/{parser => lexer}/mod.rs | 2 +- ...exer__tests__parse_interpolate_bad-2.snap} | 2 +- src/lib.rs | 6 +-- tests/checks.rs | 2 +- tests/file_tests.rs | 2 +- 11 files changed, 46 insertions(+), 46 deletions(-) rename src/{parser => lexer}/mod.rs (99%) rename src/{parser/snapshots/nomo__parser__tests__parse_interpolate_bad-2.snap => lexer/snapshots/nomo__lexer__tests__parse_interpolate_bad-2.snap} (93%) diff --git a/benches/asting.rs b/benches/asting.rs index 1528069..800942b 100644 --- a/benches/asting.rs +++ b/benches/asting.rs @@ -19,7 +19,7 @@ fn asting_benchmark(c: &mut Criterion) { parsing.throughput(criterion::Throughput::Bytes(input.len() as u64)); parsing.bench_with_input(BenchmarkId::from_parameter(size), &input, |b, input| { b.iter(|| { - let tokens = nomo::parser::parse(input.clone()).unwrap(); + let tokens = nomo::lexer::parse(input.clone()).unwrap(); let _ast = nomo::ast::parse(tokens.tokens()).unwrap(); }); }); @@ -43,7 +43,7 @@ fn asting_nested(c: &mut Criterion) { parsing.throughput(criterion::Throughput::Bytes(input.len() as u64)); parsing.bench_with_input(BenchmarkId::from_parameter(size), &input, |b, input| { b.iter(|| { - let tokens = nomo::parser::parse(input.clone()).unwrap(); + let tokens = nomo::lexer::parse(input.clone()).unwrap(); let _ast = nomo::ast::parse(tokens.tokens()).unwrap(); }); }); diff --git a/benches/parsing.rs b/benches/parsing.rs index 35de7ae..20548e6 100644 --- a/benches/parsing.rs +++ b/benches/parsing.rs @@ -18,7 +18,7 @@ fn parsing_benchmark(c: &mut Criterion) { parsing.throughput(criterion::Throughput::Bytes(input.len() as u64)); parsing.bench_with_input(BenchmarkId::from_parameter(size), &input, |b, input| { - b.iter(|| nomo::parser::parse(input.clone()).unwrap()); + b.iter(|| nomo::lexer::parse(input.clone()).unwrap()); }); } } @@ -39,7 +39,7 @@ fn parsing_nested(c: &mut Criterion) { parsing.throughput(criterion::Throughput::Bytes(input.len() as u64)); parsing.bench_with_input(BenchmarkId::from_parameter(size), &input, |b, input| { - b.iter(|| nomo::parser::parse(input.clone()).unwrap()); + b.iter(|| nomo::lexer::parse(input.clone()).unwrap()); }); } } diff --git a/fuzz/fuzz_targets/fuzz_target_1.rs b/fuzz/fuzz_targets/fuzz_target_1.rs index 56024b8..ebef862 100644 --- a/fuzz/fuzz_targets/fuzz_target_1.rs +++ b/fuzz/fuzz_targets/fuzz_target_1.rs @@ -4,7 +4,7 @@ use libfuzzer_sys::Corpus; use libfuzzer_sys::fuzz_target; fuzz_target!(|data: String| -> Corpus { - let Ok(parsed) = nomo::parser::parse(data.into()) else { + let Ok(parsed) = nomo::lexer::parse(data.into()) else { return Corpus::Reject; }; diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 3a94816..bdf3044 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -26,9 +26,9 @@ use winnow::stream::TokenSlice; use winnow::token::any; use crate::SourceSpan; -use crate::parser::TemplateToken; -use crate::parser::TokenKind; -use crate::parser::TokenOperator; +use crate::lexer::TemplateToken; +use crate::lexer::TokenKind; +use crate::lexer::TokenOperator; use crate::resume_after_cut; use crate::value::NomoValue; @@ -653,8 +653,8 @@ fn parse_literal<'input>(input: &mut Input<'input>) -> Result Some(TemplateAstExpr::Literal { source: token.clone(), value: match literal { - crate::parser::TokenLiteral::Bool(bool) => NomoValue::Bool { value: bool }, - crate::parser::TokenLiteral::Integer(int) => NomoValue::Integer { value: int }, + crate::lexer::TokenLiteral::Bool(bool) => NomoValue::Bool { value: bool }, + crate::lexer::TokenLiteral::Integer(int) => NomoValue::Integer { value: int }, }, }), _ => None, @@ -744,7 +744,7 @@ mod tests { use crate::ast::parse; use crate::ast::parse_block; use crate::ast::parse_end; - use crate::parser::TokenKind; + use crate::lexer::TokenKind; fn panic_pretty<'a>( input: &'_ str, @@ -762,7 +762,7 @@ mod tests { fn check_only_content() { let input = "Hello World"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = parse(parsed.tokens()).unwrap(); @@ -781,7 +781,7 @@ mod tests { fn check_simple_variable_interpolation() { let input = "Hello {{= world }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = parse(parsed.tokens()).unwrap(); @@ -809,7 +809,7 @@ mod tests { fn check_simple_if() { let input = "{{ if foo }} Hiii {{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -858,7 +858,7 @@ mod tests { {{ value }} {{ value }}"#; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = parse(parsed.tokens()).unwrap_err(); @@ -876,7 +876,7 @@ mod tests { {{= value }} "#; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); insta::assert_debug_snapshot!("simple_if_tokens", parsed); @@ -891,7 +891,7 @@ mod tests { let input = "{{ foo }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let result = alt(( parse_end, @@ -937,7 +937,7 @@ mod tests { fn check_empty_if_output() { let input = "{{ if foo }}{{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -974,7 +974,7 @@ mod tests { fn check_if_else() { let input = "{{ if foo }} foo {{ else }} bar {{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -985,7 +985,7 @@ mod tests { fn check_if_else_if() { let input = "{{ if foo }} foo {{ else if bar }} bar {{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -996,7 +996,7 @@ mod tests { fn check_trim_whitespace() { let input = "{{ if foo -}} foo {{- else if bar -}} bar {{- end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -1007,7 +1007,7 @@ mod tests { fn check_for_loop() { let input = "{{ for value in array }} Hi: {{= value }} {{ else }} No Content :C {{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -1018,7 +1018,7 @@ mod tests { fn check_math_expression() { let input = "{{= 5 * 3 + 2 / 3 }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -1029,7 +1029,7 @@ mod tests { fn check_logical_expression() { let input = "{{= true && false || 3 >= 2 && 5 == 2 }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); @@ -1040,7 +1040,7 @@ mod tests { fn check_function_call() { let input = "{{= foo(2 * 3, bar(2 + baz)) }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = panic_pretty(input, parse(parsed.tokens())); diff --git a/src/emit/mod.rs b/src/emit/mod.rs index 0e8b7af..9d1fdd9 100644 --- a/src/emit/mod.rs +++ b/src/emit/mod.rs @@ -2,8 +2,8 @@ use std::collections::BTreeMap; use crate::ast::TemplateAstExpr; use crate::input::NomoInput; -use crate::parser::TemplateToken; -use crate::parser::TokenOperator; +use crate::lexer::TemplateToken; +use crate::lexer::TokenOperator; use crate::value::NomoValue; pub struct EmitMachine { @@ -171,7 +171,7 @@ fn emit_ast_expr( let end_label = machine.reserve_label(); let mut end_indices = vec![]; - let mut previous_post_whitespace_content: &Option = &None; + let mut previous_post_whitespace_content: &Option = &None; let mut previous_jump: Option = None; loop { @@ -500,7 +500,7 @@ mod tests { fn check_simple_variable_interpolation() { let input = "Hello {{= world }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = crate::ast::parse(parsed.tokens()).unwrap(); @@ -536,7 +536,7 @@ mod tests { fn check_if_else_if() { let input = "{{ if foo }} foo {{ else if bar }} bar {{ else }} foobar {{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = crate::ast::parse(parsed.tokens()).unwrap(); @@ -549,7 +549,7 @@ mod tests { fn check_function_call() { let input = "{{ if foo(23) }} bar {{ else }} foobar {{ end }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = crate::ast::parse(parsed.tokens()).unwrap(); diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 1bb7425..ee8bfc7 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -202,12 +202,12 @@ pub fn execute( let right_value = scopes.get(right_slot); let result = match op { - crate::parser::TokenOperator::Plus => left_value.try_add(right_value), - crate::parser::TokenOperator::Minus => left_value.try_sub(right_value), - crate::parser::TokenOperator::Times => left_value.try_mul(right_value), - crate::parser::TokenOperator::Divide => left_value.try_div(right_value), - crate::parser::TokenOperator::And => left_value.try_and(right_value), - crate::parser::TokenOperator::Or => left_value.try_or(right_value), + crate::lexer::TokenOperator::Plus => left_value.try_add(right_value), + crate::lexer::TokenOperator::Minus => left_value.try_sub(right_value), + crate::lexer::TokenOperator::Times => left_value.try_mul(right_value), + crate::lexer::TokenOperator::Divide => left_value.try_div(right_value), + crate::lexer::TokenOperator::And => left_value.try_and(right_value), + crate::lexer::TokenOperator::Or => left_value.try_or(right_value), _ => todo!(), }; @@ -243,7 +243,7 @@ mod tests { fn check_simple_variable_interpolation() { let input = "Hello {{= world }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = crate::ast::parse(parsed.tokens()).unwrap(); @@ -264,7 +264,7 @@ mod tests { fn check_method_call() { let input = "Hello {{= foo(world) }}"; - let parsed = crate::parser::parse(input.into()).unwrap(); + let parsed = crate::lexer::parse(input.into()).unwrap(); let ast = crate::ast::parse(parsed.tokens()).unwrap(); diff --git a/src/parser/mod.rs b/src/lexer/mod.rs similarity index 99% rename from src/parser/mod.rs rename to src/lexer/mod.rs index 3e0d80c..a35e096 100644 --- a/src/parser/mod.rs +++ b/src/lexer/mod.rs @@ -613,7 +613,7 @@ fn ident_terminator<'input>(input: &mut Input<'input>) -> PResult<'input, ()> { #[cfg(test)] mod tests { - use crate::parser::parse; + use crate::lexer::parse; #[test] fn parse_simple() { diff --git a/src/parser/snapshots/nomo__parser__tests__parse_interpolate_bad-2.snap b/src/lexer/snapshots/nomo__lexer__tests__parse_interpolate_bad-2.snap similarity index 93% rename from src/parser/snapshots/nomo__parser__tests__parse_interpolate_bad-2.snap rename to src/lexer/snapshots/nomo__lexer__tests__parse_interpolate_bad-2.snap index 9dd6238..9b30aec 100644 --- a/src/parser/snapshots/nomo__parser__tests__parse_interpolate_bad-2.snap +++ b/src/lexer/snapshots/nomo__lexer__tests__parse_interpolate_bad-2.snap @@ -1,5 +1,5 @@ --- -source: src/parser/mod.rs +source: src/lexer/mod.rs expression: error.to_report() --- error: Invalid variable identifier diff --git a/src/lib.rs b/src/lib.rs index c9b8222..7c7ad86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ pub mod emit; pub mod eval; pub mod functions; pub mod input; -pub mod parser; +pub mod lexer; pub mod value; #[derive(Debug, Error, Display)] @@ -22,7 +22,7 @@ pub enum NomoError { /// Could not parse the given template ParseError { #[from] - source: parser::ParseFailure, + source: lexer::ParseFailure, }, /// Invalid Template AstError { @@ -65,7 +65,7 @@ impl Nomo { value: impl Into, ) -> Result<(), NomoError> { let source = value.into(); - let parse = parser::parse(source.clone())?; + let parse = lexer::parse(source.clone())?; let ast = ast::parse(parse.tokens())?; let instructions = emit::emit_machine(ast); diff --git a/tests/checks.rs b/tests/checks.rs index 56c736a..893b022 100644 --- a/tests/checks.rs +++ b/tests/checks.rs @@ -5,7 +5,7 @@ fn check_files() { for file in files { let input = std::fs::read_to_string(file.unwrap().path()).unwrap(); - let Ok(parsed) = nomo::parser::parse(input.into()) else { + let Ok(parsed) = nomo::lexer::parse(input.into()) else { continue; }; diff --git a/tests/file_tests.rs b/tests/file_tests.rs index 28e88e9..e01a8e8 100644 --- a/tests/file_tests.rs +++ b/tests/file_tests.rs @@ -39,7 +39,7 @@ fn check_for_input([path]: [&Path; 1]) { context.try_insert(k, v).unwrap(); } - let parsed = nomo::parser::parse(input.into()).unwrap(); + let parsed = nomo::lexer::parse(input.into()).unwrap(); let _guard = settings.bind_to_scope(); From 705c6a8818f493edd20b46a406e382bc662e98ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcel=20M=C3=BCller?= Date: Sun, 15 Mar 2026 11:33:40 +0100 Subject: [PATCH 6/6] Rename ast to parser MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marcel Müller --- benches/asting.rs | 4 ++-- fuzz/fuzz_targets/fuzz_target_1.rs | 2 +- src/emit/mod.rs | 10 +++++----- src/eval/mod.rs | 4 ++-- src/lib.rs | 6 +++--- src/{ast => parser}/mod.rs | 14 +++++++------- .../nomo__parser__tests__check_for_loop.snap} | 2 +- .../nomo__parser__tests__check_function_call.snap} | 2 +- .../nomo__parser__tests__check_if_else.snap} | 2 +- .../nomo__parser__tests__check_if_else_if.snap} | 2 +- ...nomo__parser__tests__check_invalid_action.snap} | 2 +- ...__parser__tests__check_logical_expression.snap} | 2 +- ...omo__parser__tests__check_math_expression.snap} | 2 +- ...omo__parser__tests__check_trim_whitespace.snap} | 2 +- .../nomo__parser__tests__simple_if_ast.snap} | 2 +- .../nomo__parser__tests__simple_if_tokens.snap} | 2 +- tests/checks.rs | 2 +- tests/file_tests.rs | 2 +- 18 files changed, 32 insertions(+), 32 deletions(-) rename src/{ast => parser}/mod.rs (99%) rename src/{ast/snapshots/nomo__ast__tests__check_for_loop.snap => parser/snapshots/nomo__parser__tests__check_for_loop.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_function_call.snap => parser/snapshots/nomo__parser__tests__check_function_call.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_if_else.snap => parser/snapshots/nomo__parser__tests__check_if_else.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_if_else_if.snap => parser/snapshots/nomo__parser__tests__check_if_else_if.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_invalid_action.snap => parser/snapshots/nomo__parser__tests__check_invalid_action.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_logical_expression.snap => parser/snapshots/nomo__parser__tests__check_logical_expression.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_math_expression.snap => parser/snapshots/nomo__parser__tests__check_math_expression.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__check_trim_whitespace.snap => parser/snapshots/nomo__parser__tests__check_trim_whitespace.snap} (98%) rename src/{ast/snapshots/nomo__ast__tests__simple_if_ast.snap => parser/snapshots/nomo__parser__tests__simple_if_ast.snap} (99%) rename src/{ast/snapshots/nomo__ast__tests__simple_if_tokens.snap => parser/snapshots/nomo__parser__tests__simple_if_tokens.snap} (98%) diff --git a/benches/asting.rs b/benches/asting.rs index 800942b..3e8d755 100644 --- a/benches/asting.rs +++ b/benches/asting.rs @@ -20,7 +20,7 @@ fn asting_benchmark(c: &mut Criterion) { parsing.bench_with_input(BenchmarkId::from_parameter(size), &input, |b, input| { b.iter(|| { let tokens = nomo::lexer::parse(input.clone()).unwrap(); - let _ast = nomo::ast::parse(tokens.tokens()).unwrap(); + let _ast = nomo::parser::parse(tokens.tokens()).unwrap(); }); }); } @@ -44,7 +44,7 @@ fn asting_nested(c: &mut Criterion) { parsing.bench_with_input(BenchmarkId::from_parameter(size), &input, |b, input| { b.iter(|| { let tokens = nomo::lexer::parse(input.clone()).unwrap(); - let _ast = nomo::ast::parse(tokens.tokens()).unwrap(); + let _ast = nomo::parser::parse(tokens.tokens()).unwrap(); }); }); } diff --git a/fuzz/fuzz_targets/fuzz_target_1.rs b/fuzz/fuzz_targets/fuzz_target_1.rs index ebef862..da1e6e2 100644 --- a/fuzz/fuzz_targets/fuzz_target_1.rs +++ b/fuzz/fuzz_targets/fuzz_target_1.rs @@ -8,7 +8,7 @@ fuzz_target!(|data: String| -> Corpus { return Corpus::Reject; }; - let Ok(ast) = nomo::ast::parse(parsed.tokens()) else { + let Ok(ast) = nomo::parser::parse(parsed.tokens()) else { return Corpus::Keep; }; diff --git a/src/emit/mod.rs b/src/emit/mod.rs index 9d1fdd9..cf33cfa 100644 --- a/src/emit/mod.rs +++ b/src/emit/mod.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use crate::ast::TemplateAstExpr; +use crate::parser::TemplateAstExpr; use crate::input::NomoInput; use crate::lexer::TemplateToken; use crate::lexer::TokenOperator; @@ -115,7 +115,7 @@ pub struct VMInstructions { pub instructions: Vec, } -pub fn emit_machine(input: crate::ast::TemplateAst<'_>) -> VMInstructions { +pub fn emit_machine(input: crate::parser::TemplateAst<'_>) -> VMInstructions { let mut eval = vec![]; let mut machine = EmitMachine { @@ -502,7 +502,7 @@ mod tests { let parsed = crate::lexer::parse(input.into()).unwrap(); - let ast = crate::ast::parse(parsed.tokens()).unwrap(); + let ast = crate::parser::parse(parsed.tokens()).unwrap(); let emit = emit_machine(ast); @@ -538,7 +538,7 @@ mod tests { let parsed = crate::lexer::parse(input.into()).unwrap(); - let ast = crate::ast::parse(parsed.tokens()).unwrap(); + let ast = crate::parser::parse(parsed.tokens()).unwrap(); let emit = emit_machine(ast); @@ -551,7 +551,7 @@ mod tests { let parsed = crate::lexer::parse(input.into()).unwrap(); - let ast = crate::ast::parse(parsed.tokens()).unwrap(); + let ast = crate::parser::parse(parsed.tokens()).unwrap(); let emit = emit_machine(ast); diff --git a/src/eval/mod.rs b/src/eval/mod.rs index ee8bfc7..e0d864b 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -245,7 +245,7 @@ mod tests { let parsed = crate::lexer::parse(input.into()).unwrap(); - let ast = crate::ast::parse(parsed.tokens()).unwrap(); + let ast = crate::parser::parse(parsed.tokens()).unwrap(); let emit = crate::emit::emit_machine(ast); @@ -266,7 +266,7 @@ mod tests { let parsed = crate::lexer::parse(input.into()).unwrap(); - let ast = crate::ast::parse(parsed.tokens()).unwrap(); + let ast = crate::parser::parse(parsed.tokens()).unwrap(); let emit = crate::emit::emit_machine(ast); diff --git a/src/lib.rs b/src/lib.rs index 7c7ad86..fbe8ecf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,7 +9,7 @@ use crate::input::NomoInput; use crate::value::NomoValue; use crate::value::NomoValueError; -pub mod ast; +pub mod parser; pub mod emit; pub mod eval; pub mod functions; @@ -27,7 +27,7 @@ pub enum NomoError { /// Invalid Template AstError { #[from] - source: ast::AstFailure, + source: parser::AstFailure, }, /// An error occurred while evaluating @@ -66,7 +66,7 @@ impl Nomo { ) -> Result<(), NomoError> { let source = value.into(); let parse = lexer::parse(source.clone())?; - let ast = ast::parse(parse.tokens())?; + let ast = parser::parse(parse.tokens())?; let instructions = emit::emit_machine(ast); diff --git a/src/ast/mod.rs b/src/parser/mod.rs similarity index 99% rename from src/ast/mod.rs rename to src/parser/mod.rs index bdf3044..ed4456f 100644 --- a/src/ast/mod.rs +++ b/src/parser/mod.rs @@ -737,13 +737,13 @@ mod tests { use winnow::combinator::fail; use winnow::stream::TokenSlice; - use crate::ast::AstError; - use crate::ast::AstFailure; - use crate::ast::TemplateAst; - use crate::ast::TemplateAstExpr; - use crate::ast::parse; - use crate::ast::parse_block; - use crate::ast::parse_end; + use crate::parser::AstError; + use crate::parser::AstFailure; + use crate::parser::TemplateAst; + use crate::parser::TemplateAstExpr; + use crate::parser::parse; + use crate::parser::parse_block; + use crate::parser::parse_end; use crate::lexer::TokenKind; fn panic_pretty<'a>( diff --git a/src/ast/snapshots/nomo__ast__tests__check_for_loop.snap b/src/parser/snapshots/nomo__parser__tests__check_for_loop.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_for_loop.snap rename to src/parser/snapshots/nomo__parser__tests__check_for_loop.snap index 737e2c0..521c5fb 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_for_loop.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_for_loop.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__check_function_call.snap b/src/parser/snapshots/nomo__parser__tests__check_function_call.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_function_call.snap rename to src/parser/snapshots/nomo__parser__tests__check_function_call.snap index de41088..40e920c 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_function_call.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_function_call.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__check_if_else.snap b/src/parser/snapshots/nomo__parser__tests__check_if_else.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_if_else.snap rename to src/parser/snapshots/nomo__parser__tests__check_if_else.snap index 0a3b739..b989ca3 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_if_else.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_if_else.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap b/src/parser/snapshots/nomo__parser__tests__check_if_else_if.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap rename to src/parser/snapshots/nomo__parser__tests__check_if_else_if.snap index 3912e60..0c2eef2 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_if_else_if.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__check_invalid_action.snap b/src/parser/snapshots/nomo__parser__tests__check_invalid_action.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_invalid_action.snap rename to src/parser/snapshots/nomo__parser__tests__check_invalid_action.snap index c8f8f50..0587130 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_invalid_action.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_invalid_action.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast.to_report(input) --- error: Standlone action block diff --git a/src/ast/snapshots/nomo__ast__tests__check_logical_expression.snap b/src/parser/snapshots/nomo__parser__tests__check_logical_expression.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_logical_expression.snap rename to src/parser/snapshots/nomo__parser__tests__check_logical_expression.snap index e9caca2..aca365a 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_logical_expression.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_logical_expression.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__check_math_expression.snap b/src/parser/snapshots/nomo__parser__tests__check_math_expression.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_math_expression.snap rename to src/parser/snapshots/nomo__parser__tests__check_math_expression.snap index 7265e0a..7ba6415 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_math_expression.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_math_expression.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__check_trim_whitespace.snap b/src/parser/snapshots/nomo__parser__tests__check_trim_whitespace.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__check_trim_whitespace.snap rename to src/parser/snapshots/nomo__parser__tests__check_trim_whitespace.snap index bce8aa2..7308528 100644 --- a/src/ast/snapshots/nomo__ast__tests__check_trim_whitespace.snap +++ b/src/parser/snapshots/nomo__parser__tests__check_trim_whitespace.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap b/src/parser/snapshots/nomo__parser__tests__simple_if_ast.snap similarity index 99% rename from src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap rename to src/parser/snapshots/nomo__parser__tests__simple_if_ast.snap index 3701cc2..ef4803b 100644 --- a/src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap +++ b/src/parser/snapshots/nomo__parser__tests__simple_if_ast.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: ast --- TemplateAst { diff --git a/src/ast/snapshots/nomo__ast__tests__simple_if_tokens.snap b/src/parser/snapshots/nomo__parser__tests__simple_if_tokens.snap similarity index 98% rename from src/ast/snapshots/nomo__ast__tests__simple_if_tokens.snap rename to src/parser/snapshots/nomo__parser__tests__simple_if_tokens.snap index ffc7d97..e485e6b 100644 --- a/src/ast/snapshots/nomo__ast__tests__simple_if_tokens.snap +++ b/src/parser/snapshots/nomo__parser__tests__simple_if_tokens.snap @@ -1,5 +1,5 @@ --- -source: src/ast/mod.rs +source: src/parser/mod.rs expression: parsed --- ParsedTemplate { diff --git a/tests/checks.rs b/tests/checks.rs index 893b022..98480d8 100644 --- a/tests/checks.rs +++ b/tests/checks.rs @@ -9,7 +9,7 @@ fn check_files() { continue; }; - let Ok(ast) = nomo::ast::parse(parsed.tokens()) else { + let Ok(ast) = nomo::parser::parse(parsed.tokens()) else { continue; }; diff --git a/tests/file_tests.rs b/tests/file_tests.rs index e01a8e8..6163922 100644 --- a/tests/file_tests.rs +++ b/tests/file_tests.rs @@ -45,7 +45,7 @@ fn check_for_input([path]: [&Path; 1]) { insta::assert_debug_snapshot!(format!("{basename}.1-parsed"), parsed); - let ast = match nomo::ast::parse(parsed.tokens()) { + let ast = match nomo::parser::parse(parsed.tokens()) { Ok(ast) => ast, Err(err) => { eprintln!("{}", err.to_report(input));