diff --git a/src/ast/mod.rs b/src/ast/mod.rs index 9f18f45..8e2a1a7 100644 --- a/src/ast/mod.rs +++ b/src/ast/mod.rs @@ -227,7 +227,7 @@ pub enum TemplateAstExpr<'input> { chain: Vec>, }, IfConditional { - expression: Box>, + if_block: Box>, }, ConditionalContent { content: Vec>, @@ -316,10 +316,10 @@ fn parse_conditional_chain<'input>( input: &mut Input<'input>, ) -> Result, AstError> { trace("conditional_chain", |input: &mut Input<'input>| { - let if_block = parse_conditional_if.parse_next(input)?; + let if_block = parse_conditional_if.map(Box::new).parse_next(input)?; let mut chain = vec![]; - chain.push(if_block); + chain.push(TemplateAstExpr::IfConditional { if_block }); loop { let (content, end_block): (Vec<_>, _) = repeat_till( @@ -344,7 +344,7 @@ fn parse_conditional_chain<'input>( chain.push(end_block); - if is_end { + if dbg!(is_end) { break; } } @@ -359,17 +359,13 @@ fn parse_conditional_if<'input>( ) -> Result, AstError> { trace( "conditional", - parse_block( - preceded( - TokenKind::ConditionalIf, - cut_err( - surrounded(ws, parse_value_expression) - .map(Box::new) - .context(AstError::ctx().msg("Expected an expression after 'if'")), - ), - ) - .map(|expression| TemplateAstExpr::IfConditional { expression }), - ), + parse_block(preceded( + TokenKind::ConditionalIf, + cut_err( + surrounded(ws, parse_value_expression) + .context(AstError::ctx().msg("Expected an expression after 'if'")), + ), + )), ) .parse_next(input) } @@ -563,16 +559,16 @@ mod tests { root: [ ConditionalChain { chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { + IfConditional { + if_block: Block { + prev_whitespace_content: None, expression: VariableAccess( [Ident]"foo" (6..9), ), + post_whitespace_content: Some( + [Whitespace]" " (12..13), + ), }, - post_whitespace_content: Some( - [Whitespace]" " (12..13), - ), }, ConditionalContent { content: [ @@ -679,61 +675,11 @@ mod tests { } #[test] - fn check_empty_if_output() { + fn check_empty_output() { let input = "{{ if foo }}{{ end }}"; let parsed = crate::parser::parse(input.into()).unwrap(); - let ast = panic_pretty(input, parse(parsed.tokens())); - - insta::assert_debug_snapshot!(ast, @r#" - TemplateAst { - root: [ - ConditionalChain { - chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { - expression: VariableAccess( - [Ident]"foo" (6..9), - ), - }, - post_whitespace_content: None, - }, - ConditionalContent { - content: [], - }, - Block { - prev_whitespace_content: None, - expression: EndBlock, - post_whitespace_content: None, - }, - ], - }, - ], - } - "#); - } - - #[test] - fn check_if_else() { - let input = "{{ if foo }} foo {{ else }} bar {{ end }}"; - - let parsed = crate::parser::parse(input.into()).unwrap(); - - let ast = panic_pretty(input, parse(parsed.tokens())); - - insta::assert_debug_snapshot!(ast); - } - - #[test] - fn check_if_else_if() { - let input = "{{ if foo }} foo {{ else if bar }} bar {{ end }}"; - - let parsed = crate::parser::parse(input.into()).unwrap(); - - let ast = panic_pretty(input, parse(parsed.tokens())); - - insta::assert_debug_snapshot!(ast); + panic_pretty(input, parse(parsed.tokens())); } } diff --git a/src/ast/snapshots/nomo__ast__tests__check_if_else.snap b/src/ast/snapshots/nomo__ast__tests__check_if_else.snap deleted file mode 100644 index 0a3b739..0000000 --- a/src/ast/snapshots/nomo__ast__tests__check_if_else.snap +++ /dev/null @@ -1,55 +0,0 @@ ---- -source: src/ast/mod.rs -expression: ast ---- -TemplateAst { - root: [ - ConditionalChain { - chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { - expression: VariableAccess( - [Ident]"foo" (6..9), - ), - }, - post_whitespace_content: Some( - [Whitespace]" " (12..13), - ), - }, - ConditionalContent { - content: [ - StaticContent( - [Content]"foo" (13..16), - ), - ], - }, - Block { - prev_whitespace_content: Some( - [Whitespace]" " (16..17), - ), - expression: ElseConditional { - expression: None, - }, - post_whitespace_content: Some( - [Whitespace]" " (27..28), - ), - }, - ConditionalContent { - content: [ - StaticContent( - [Content]"bar" (28..31), - ), - ], - }, - Block { - prev_whitespace_content: Some( - [Whitespace]" " (31..32), - ), - expression: EndBlock, - post_whitespace_content: None, - }, - ], - }, - ], -} diff --git a/src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap b/src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap deleted file mode 100644 index 3912e60..0000000 --- a/src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap +++ /dev/null @@ -1,59 +0,0 @@ ---- -source: src/ast/mod.rs -expression: ast ---- -TemplateAst { - root: [ - ConditionalChain { - chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { - expression: VariableAccess( - [Ident]"foo" (6..9), - ), - }, - post_whitespace_content: Some( - [Whitespace]" " (12..13), - ), - }, - ConditionalContent { - content: [ - StaticContent( - [Content]"foo" (13..16), - ), - ], - }, - Block { - prev_whitespace_content: Some( - [Whitespace]" " (16..17), - ), - expression: ElseConditional { - expression: Some( - VariableAccess( - [Ident]"bar" (28..31), - ), - ), - }, - post_whitespace_content: Some( - [Whitespace]" " (34..35), - ), - }, - ConditionalContent { - content: [ - StaticContent( - [Content]"bar" (35..38), - ), - ], - }, - Block { - prev_whitespace_content: Some( - [Whitespace]" " (38..39), - ), - expression: EndBlock, - post_whitespace_content: None, - }, - ], - }, - ], -} diff --git a/src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap b/src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap index 3701cc2..59d5426 100644 --- a/src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap +++ b/src/ast/snapshots/nomo__ast__tests__simple_if_ast.snap @@ -6,31 +6,31 @@ TemplateAst { root: [ ConditionalChain { chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { + IfConditional { + if_block: Block { + prev_whitespace_content: None, expression: VariableAccess( [Ident]"foo" (6..9), ), + post_whitespace_content: Some( + [Whitespace]"\n " (12..25), + ), }, - post_whitespace_content: Some( - [Whitespace]"\n " (12..25), - ), }, ConditionalContent { content: [ ConditionalChain { chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { + IfConditional { + if_block: Block { + prev_whitespace_content: None, expression: VariableAccess( [Ident]"bar" (31..34), ), + post_whitespace_content: Some( + [Whitespace]"\n " (37..54), + ), }, - post_whitespace_content: Some( - [Whitespace]"\n " (37..54), - ), }, ConditionalContent { content: [ diff --git a/src/emit/mod.rs b/src/emit/mod.rs index 95a92e6..6f38a91 100644 --- a/src/emit/mod.rs +++ b/src/emit/mod.rs @@ -42,9 +42,6 @@ pub enum Instruction { emit_slot: VariableSlot, jump: isize, }, - Jump { - jump: isize, - }, } pub fn emit_machine(input: crate::ast::TemplateAst<'_>) -> Vec { @@ -93,105 +90,76 @@ fn emit_ast_expr( } TemplateAstExpr::ConditionalChain { chain } => { let mut chain = chain.iter(); + let Some(TemplateAstExpr::IfConditional { + if_block: expression, + }) = chain.next() + else { + unreachable!("First element in conditional chain should be an IfConditional"); + }; - let mut end_indices = vec![]; + let TemplateAstExpr::Block { + prev_whitespace_content, + expression, + post_whitespace_content, + } = expression.as_ref() + else { + unreachable!("The end of an IfConditional must be a Block"); + }; - let mut previous_post_whitespace_content: &Option = &None; - let mut previous_jump: Option = None; + let Some(TemplateAstExpr::ConditionalContent { content }) = chain.next() else { + unreachable!("The end of an IfConditional must be a Block"); + }; - loop { - let next = chain.next().unwrap(); - if let Some(ws) = previous_post_whitespace_content { - eval.push(Instruction::AppendContent { - content: ws.source().clone(), - }); - } - - if let TemplateAstExpr::ConditionalContent { content } = &next { - for ast in content { - emit_ast_expr(machine, eval, ast); - } - - end_indices.push(eval.len()); - eval.push(Instruction::Jump { jump: isize::MAX }); - } else if let TemplateAstExpr::Block { - prev_whitespace_content, - post_whitespace_content, - expression, - } = &next - { - previous_post_whitespace_content = post_whitespace_content; - if let Some(ws) = prev_whitespace_content { - eval.insert( - eval.len() - 2, - Instruction::AppendContent { - content: ws.source().clone(), - }, - ); - let index_index = end_indices.len() - 1; - end_indices[index_index] += 1; - } - - if let TemplateAstExpr::IfConditional { expression } = &**expression { - let emit_slot = machine.reserve_slot(); - emit_expr_load(machine, eval, emit_slot, expression); - - previous_jump = Some(eval.len()); - eval.push(Instruction::JumpIfNotTrue { - emit_slot, - jump: isize::MAX, - }); - } else if let TemplateAstExpr::ElseConditional { expression } = &**expression { - if let Some(previous_jump) = previous_jump.take() { - let new_jump = eval.len() - previous_jump - 1; - let Instruction::JumpIfNotTrue { jump, .. } = &mut eval[previous_jump] - else { - panic!("Jump slot had something that is not a jump?!"); - }; - - *jump = new_jump as isize; - } else { - panic!("Got an else without a previous if?"); - } - - if let Some(expression) = expression { - let emit_slot = machine.reserve_slot(); - emit_expr_load(machine, eval, emit_slot, expression); - - previous_jump = Some(eval.len()); - eval.push(Instruction::JumpIfNotTrue { - emit_slot, - jump: isize::MAX, - }); - } else { - // We don't have to do anything in the else case - } - } else if let TemplateAstExpr::EndBlock = &**expression { - break; - } - } - } - - if let Some(previous_jump) = previous_jump.take() { - let new_jump = eval.len() - previous_jump - 1; - let Instruction::JumpIfNotTrue { jump, .. } = &mut eval[previous_jump] else { - panic!("Jump slot had something that is not a jump?!"); - }; - - *jump = new_jump as isize; - } - - if let Some(ws) = previous_post_whitespace_content { + if let Some(ws) = prev_whitespace_content { eval.push(Instruction::AppendContent { content: ws.source().clone(), }); } - for index in end_indices { - let jump = eval.len() - index - 1; - eval[index] = Instruction::Jump { - jump: jump as isize, - }; + let emit_slot = machine.reserve_slot(); + emit_expr_load(machine, eval, emit_slot, expression); + + let index = eval.len(); + eval.push(Instruction::JumpIfNotTrue { + emit_slot, + jump: isize::MAX, + }); + + if let Some(ws) = post_whitespace_content { + eval.push(Instruction::AppendContent { + content: ws.source().clone(), + }); + } + + for ast in content { + emit_ast_expr(machine, eval, ast); + } + + let Some(TemplateAstExpr::Block { + prev_whitespace_content, + post_whitespace_content, + .. + }) = chain.last() + else { + unreachable!("The end of an IfConditional must be a End Block"); + }; + + if let Some(ws) = prev_whitespace_content { + eval.push(Instruction::AppendContent { + content: ws.source().clone(), + }); + } + + let jump = eval.len() - index - 1; + eval[index] = Instruction::JumpIfNotTrue { + emit_slot, + jump: jump as isize, + }; + + if let Some(ws) = post_whitespace_content { + eval.push(Instruction::AppendContent { + content: ws.source().clone(), + }); } } @@ -267,17 +235,4 @@ mod tests { ] "#); } - - #[test] - 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 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_if_else_if.snap b/src/emit/snapshots/nomo__emit__tests__check_if_else_if.snap deleted file mode 100644 index ee52b87..0000000 --- a/src/emit/snapshots/nomo__emit__tests__check_if_else_if.snap +++ /dev/null @@ -1,75 +0,0 @@ ---- -source: src/emit/mod.rs -expression: emit ---- -[ - LoadFromContextToSlot { - name: "foo" (6..9), - slot: VariableSlot { - index: 0, - }, - }, - JumpIfNotTrue { - emit_slot: VariableSlot { - index: 0, - }, - jump: 5, - }, - AppendContent { - content: " " (12..13), - }, - AppendContent { - content: "foo" (13..16), - }, - AppendContent { - content: " " (16..17), - }, - Jump { - jump: 13, - }, - AppendContent { - content: " " (12..13), - }, - LoadFromContextToSlot { - name: "bar" (28..31), - slot: VariableSlot { - index: 1, - }, - }, - JumpIfNotTrue { - emit_slot: VariableSlot { - index: 1, - }, - jump: 5, - }, - AppendContent { - content: " " (34..35), - }, - AppendContent { - content: "bar" (35..38), - }, - AppendContent { - content: " " (38..39), - }, - Jump { - jump: 6, - }, - AppendContent { - content: " " (34..35), - }, - AppendContent { - content: " " (49..50), - }, - AppendContent { - content: "foobar" (50..56), - }, - AppendContent { - content: " " (56..57), - }, - Jump { - jump: 1, - }, - AppendContent { - content: " " (49..50), - }, -] diff --git a/src/eval/mod.rs b/src/eval/mod.rs index 0b0b6f9..f94ed8c 100644 --- a/src/eval/mod.rs +++ b/src/eval/mod.rs @@ -67,16 +67,6 @@ pub fn execute( } } } - Instruction::Jump { jump } => { - let (new_ip, overflow) = ip.overflowing_add_signed(*jump); - - if overflow { - return Err(EvaluationError::InstructionPointerOverflow); - } else { - ip = new_ip; - continue; - } - } } ip += 1; diff --git a/tests/cases/1-parsed@if_else_if.snap b/tests/cases/1-parsed@if_else_if.snap deleted file mode 100644 index 287fce6..0000000 --- a/tests/cases/1-parsed@if_else_if.snap +++ /dev/null @@ -1,36 +0,0 @@ ---- -source: tests/file_tests.rs -expression: parsed -input_file: tests/cases/if_else_if.nomo ---- -ParsedTemplate { - tokens: [ - [LeftDelim]"{{" (0..2), - [Whitespace]" " (2..3), - [ConditionalIf]"if" (3..5), - [Whitespace]" " (5..6), - [Ident]"test" (6..10), - [Whitespace]" " (10..11), - [RightDelim]"}}" (11..13), - [Whitespace]"\n " (13..18), - [Content]"Not Hello World! :C" (18..37), - [Whitespace]"\n" (37..38), - [LeftDelim]"{{" (38..40), - [Whitespace]" " (40..41), - [ConditionalElse]"else" (41..45), - [Whitespace]" " (45..46), - [ConditionalIf]"if" (46..48), - [Whitespace]" " (48..49), - [Ident]"another_test" (49..61), - [Whitespace]" " (61..62), - [RightDelim]"}}" (62..64), - [Whitespace]"\n " (64..69), - [Content]"Hello World!" (69..81), - [Whitespace]"\n" (81..82), - [LeftDelim]"{{" (82..84), - [Whitespace]" " (84..85), - [End]"end" (85..88), - [Whitespace]" " (88..89), - [RightDelim]"}}" (89..91), - ], -} diff --git a/tests/cases/2-ast@condition.snap b/tests/cases/2-ast@condition.snap index ae3a62e..22d6b93 100644 --- a/tests/cases/2-ast@condition.snap +++ b/tests/cases/2-ast@condition.snap @@ -7,16 +7,16 @@ TemplateAst { root: [ ConditionalChain { chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { + IfConditional { + if_block: Block { + prev_whitespace_content: None, expression: VariableAccess( [Ident]"test" (6..10), ), + post_whitespace_content: Some( + [Whitespace]"\n " (13..18), + ), }, - post_whitespace_content: Some( - [Whitespace]"\n " (13..18), - ), }, ConditionalContent { content: [ diff --git a/tests/cases/2-ast@if_else_if.snap b/tests/cases/2-ast@if_else_if.snap deleted file mode 100644 index 3bc850b..0000000 --- a/tests/cases/2-ast@if_else_if.snap +++ /dev/null @@ -1,60 +0,0 @@ ---- -source: tests/file_tests.rs -expression: ast -input_file: tests/cases/if_else_if.nomo ---- -TemplateAst { - root: [ - ConditionalChain { - chain: [ - Block { - prev_whitespace_content: None, - expression: IfConditional { - expression: VariableAccess( - [Ident]"test" (6..10), - ), - }, - post_whitespace_content: Some( - [Whitespace]"\n " (13..18), - ), - }, - ConditionalContent { - content: [ - StaticContent( - [Content]"Not Hello World! :C" (18..37), - ), - ], - }, - Block { - prev_whitespace_content: Some( - [Whitespace]"\n" (37..38), - ), - expression: ElseConditional { - expression: Some( - VariableAccess( - [Ident]"another_test" (49..61), - ), - ), - }, - post_whitespace_content: Some( - [Whitespace]"\n " (64..69), - ), - }, - ConditionalContent { - content: [ - StaticContent( - [Content]"Hello World!" (69..81), - ), - ], - }, - Block { - prev_whitespace_content: Some( - [Whitespace]"\n" (81..82), - ), - expression: EndBlock, - post_whitespace_content: None, - }, - ], - }, - ], -} diff --git a/tests/cases/3-instructions@condition.snap b/tests/cases/3-instructions@condition.snap index c2901f7..f79800d 100644 --- a/tests/cases/3-instructions@condition.snap +++ b/tests/cases/3-instructions@condition.snap @@ -14,7 +14,7 @@ input_file: tests/cases/condition.nomo emit_slot: VariableSlot { index: 0, }, - jump: 5, + jump: 3, }, AppendContent { content: "\n " (13..18), @@ -25,12 +25,6 @@ input_file: tests/cases/condition.nomo AppendContent { content: "\n" (30..31), }, - Jump { - jump: 2, - }, - AppendContent { - content: "\n " (13..18), - }, AppendContent { content: "\n\n" (40..42), }, diff --git a/tests/cases/3-instructions@if_else_if.snap b/tests/cases/3-instructions@if_else_if.snap deleted file mode 100644 index d19a4ed..0000000 --- a/tests/cases/3-instructions@if_else_if.snap +++ /dev/null @@ -1,61 +0,0 @@ ---- -source: tests/file_tests.rs -expression: emit -input_file: tests/cases/if_else_if.nomo ---- -[ - LoadFromContextToSlot { - name: "test" (6..10), - slot: VariableSlot { - index: 0, - }, - }, - JumpIfNotTrue { - emit_slot: VariableSlot { - index: 0, - }, - jump: 5, - }, - AppendContent { - content: "\n " (13..18), - }, - AppendContent { - content: "Not Hello World! :C" (18..37), - }, - AppendContent { - content: "\n" (37..38), - }, - Jump { - jump: 8, - }, - AppendContent { - content: "\n " (13..18), - }, - LoadFromContextToSlot { - name: "another_test" (49..61), - slot: VariableSlot { - index: 1, - }, - }, - JumpIfNotTrue { - emit_slot: VariableSlot { - index: 1, - }, - jump: 5, - }, - AppendContent { - content: "\n " (64..69), - }, - AppendContent { - content: "Hello World!" (69..81), - }, - AppendContent { - content: "\n" (81..82), - }, - Jump { - jump: 1, - }, - AppendContent { - content: "\n " (64..69), - }, -] diff --git a/tests/cases/4-output@if_else_if.snap b/tests/cases/4-output@if_else_if.snap deleted file mode 100644 index efb547b..0000000 --- a/tests/cases/4-output@if_else_if.snap +++ /dev/null @@ -1,6 +0,0 @@ ---- -source: tests/file_tests.rs -expression: output -input_file: tests/cases/if_else_if.nomo ---- -"\n \n Hello World!\n\n " diff --git a/tests/cases/if_else_if.nomo b/tests/cases/if_else_if.nomo deleted file mode 100644 index befa0fe..0000000 --- a/tests/cases/if_else_if.nomo +++ /dev/null @@ -1,11 +0,0 @@ -{ - "test": false, - "another_test": true, - "stuff": "more" -} ---- -{{ if test }} - Not Hello World! :C -{{ else if another_test }} - Hello World! -{{ end }} \ No newline at end of file