Compare commits
4 commits
c9314a3d9b
...
6a233e978f
| Author | SHA1 | Date | |
|---|---|---|---|
| 6a233e978f | |||
| ae379df9db | |||
| ff308649b9 | |||
| ef02e94591 |
14 changed files with 578 additions and 100 deletions
|
|
@ -227,7 +227,7 @@ pub enum TemplateAstExpr<'input> {
|
||||||
chain: Vec<TemplateAstExpr<'input>>,
|
chain: Vec<TemplateAstExpr<'input>>,
|
||||||
},
|
},
|
||||||
IfConditional {
|
IfConditional {
|
||||||
if_block: Box<TemplateAstExpr<'input>>,
|
expression: Box<TemplateAstExpr<'input>>,
|
||||||
},
|
},
|
||||||
ConditionalContent {
|
ConditionalContent {
|
||||||
content: Vec<TemplateAstExpr<'input>>,
|
content: Vec<TemplateAstExpr<'input>>,
|
||||||
|
|
@ -316,10 +316,10 @@ fn parse_conditional_chain<'input>(
|
||||||
input: &mut Input<'input>,
|
input: &mut Input<'input>,
|
||||||
) -> Result<TemplateAstExpr<'input>, AstError> {
|
) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||||
trace("conditional_chain", |input: &mut Input<'input>| {
|
trace("conditional_chain", |input: &mut Input<'input>| {
|
||||||
let if_block = parse_conditional_if.map(Box::new).parse_next(input)?;
|
let if_block = parse_conditional_if.parse_next(input)?;
|
||||||
let mut chain = vec![];
|
let mut chain = vec![];
|
||||||
|
|
||||||
chain.push(TemplateAstExpr::IfConditional { if_block });
|
chain.push(if_block);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let (content, end_block): (Vec<_>, _) = repeat_till(
|
let (content, end_block): (Vec<_>, _) = repeat_till(
|
||||||
|
|
@ -344,7 +344,7 @@ fn parse_conditional_chain<'input>(
|
||||||
|
|
||||||
chain.push(end_block);
|
chain.push(end_block);
|
||||||
|
|
||||||
if dbg!(is_end) {
|
if is_end {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -359,13 +359,17 @@ fn parse_conditional_if<'input>(
|
||||||
) -> Result<TemplateAstExpr<'input>, AstError> {
|
) -> Result<TemplateAstExpr<'input>, AstError> {
|
||||||
trace(
|
trace(
|
||||||
"conditional",
|
"conditional",
|
||||||
parse_block(preceded(
|
parse_block(
|
||||||
|
preceded(
|
||||||
TokenKind::ConditionalIf,
|
TokenKind::ConditionalIf,
|
||||||
cut_err(
|
cut_err(
|
||||||
surrounded(ws, parse_value_expression)
|
surrounded(ws, parse_value_expression)
|
||||||
|
.map(Box::new)
|
||||||
.context(AstError::ctx().msg("Expected an expression after 'if'")),
|
.context(AstError::ctx().msg("Expected an expression after 'if'")),
|
||||||
),
|
),
|
||||||
)),
|
)
|
||||||
|
.map(|expression| TemplateAstExpr::IfConditional { expression }),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
.parse_next(input)
|
.parse_next(input)
|
||||||
}
|
}
|
||||||
|
|
@ -559,17 +563,17 @@ mod tests {
|
||||||
root: [
|
root: [
|
||||||
ConditionalChain {
|
ConditionalChain {
|
||||||
chain: [
|
chain: [
|
||||||
IfConditional {
|
Block {
|
||||||
if_block: Block {
|
|
||||||
prev_whitespace_content: None,
|
prev_whitespace_content: None,
|
||||||
|
expression: IfConditional {
|
||||||
expression: VariableAccess(
|
expression: VariableAccess(
|
||||||
[Ident]"foo" (6..9),
|
[Ident]"foo" (6..9),
|
||||||
),
|
),
|
||||||
|
},
|
||||||
post_whitespace_content: Some(
|
post_whitespace_content: Some(
|
||||||
[Whitespace]" " (12..13),
|
[Whitespace]" " (12..13),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
ConditionalContent {
|
ConditionalContent {
|
||||||
content: [
|
content: [
|
||||||
StaticContent(
|
StaticContent(
|
||||||
|
|
@ -675,11 +679,61 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn check_empty_output() {
|
fn check_empty_if_output() {
|
||||||
let input = "{{ if foo }}{{ end }}";
|
let input = "{{ if foo }}{{ end }}";
|
||||||
|
|
||||||
let parsed = crate::parser::parse(input.into()).unwrap();
|
let parsed = crate::parser::parse(input.into()).unwrap();
|
||||||
|
|
||||||
panic_pretty(input, parse(parsed.tokens()));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
55
src/ast/snapshots/nomo__ast__tests__check_if_else.snap
Normal file
55
src/ast/snapshots/nomo__ast__tests__check_if_else.snap
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
---
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
59
src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap
Normal file
59
src/ast/snapshots/nomo__ast__tests__check_if_else_if.snap
Normal file
|
|
@ -0,0 +1,59 @@
|
||||||
|
---
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
@ -6,32 +6,32 @@ TemplateAst {
|
||||||
root: [
|
root: [
|
||||||
ConditionalChain {
|
ConditionalChain {
|
||||||
chain: [
|
chain: [
|
||||||
IfConditional {
|
Block {
|
||||||
if_block: Block {
|
|
||||||
prev_whitespace_content: None,
|
prev_whitespace_content: None,
|
||||||
|
expression: IfConditional {
|
||||||
expression: VariableAccess(
|
expression: VariableAccess(
|
||||||
[Ident]"foo" (6..9),
|
[Ident]"foo" (6..9),
|
||||||
),
|
),
|
||||||
|
},
|
||||||
post_whitespace_content: Some(
|
post_whitespace_content: Some(
|
||||||
[Whitespace]"\n " (12..25),
|
[Whitespace]"\n " (12..25),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
ConditionalContent {
|
ConditionalContent {
|
||||||
content: [
|
content: [
|
||||||
ConditionalChain {
|
ConditionalChain {
|
||||||
chain: [
|
chain: [
|
||||||
IfConditional {
|
Block {
|
||||||
if_block: Block {
|
|
||||||
prev_whitespace_content: None,
|
prev_whitespace_content: None,
|
||||||
|
expression: IfConditional {
|
||||||
expression: VariableAccess(
|
expression: VariableAccess(
|
||||||
[Ident]"bar" (31..34),
|
[Ident]"bar" (31..34),
|
||||||
),
|
),
|
||||||
|
},
|
||||||
post_whitespace_content: Some(
|
post_whitespace_content: Some(
|
||||||
[Whitespace]"\n " (37..54),
|
[Whitespace]"\n " (37..54),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
ConditionalContent {
|
ConditionalContent {
|
||||||
content: [
|
content: [
|
||||||
StaticContent(
|
StaticContent(
|
||||||
|
|
|
||||||
135
src/emit/mod.rs
135
src/emit/mod.rs
|
|
@ -42,6 +42,9 @@ pub enum Instruction {
|
||||||
emit_slot: VariableSlot,
|
emit_slot: VariableSlot,
|
||||||
jump: isize,
|
jump: isize,
|
||||||
},
|
},
|
||||||
|
Jump {
|
||||||
|
jump: isize,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn emit_machine(input: crate::ast::TemplateAst<'_>) -> Vec<Instruction> {
|
pub fn emit_machine(input: crate::ast::TemplateAst<'_>) -> Vec<Instruction> {
|
||||||
|
|
@ -90,76 +93,105 @@ fn emit_ast_expr(
|
||||||
}
|
}
|
||||||
TemplateAstExpr::ConditionalChain { chain } => {
|
TemplateAstExpr::ConditionalChain { chain } => {
|
||||||
let mut chain = chain.iter();
|
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 TemplateAstExpr::Block {
|
let mut end_indices = vec![];
|
||||||
prev_whitespace_content,
|
|
||||||
expression,
|
|
||||||
post_whitespace_content,
|
|
||||||
} = expression.as_ref()
|
|
||||||
else {
|
|
||||||
unreachable!("The end of an IfConditional must be a Block");
|
|
||||||
};
|
|
||||||
|
|
||||||
let Some(TemplateAstExpr::ConditionalContent { content }) = chain.next() else {
|
let mut previous_post_whitespace_content: &Option<crate::parser::TemplateToken> = &None;
|
||||||
unreachable!("The end of an IfConditional must be a Block");
|
let mut previous_jump: Option<usize> = None;
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(ws) = prev_whitespace_content {
|
loop {
|
||||||
eval.push(Instruction::AppendContent {
|
let next = chain.next().unwrap();
|
||||||
content: ws.source().clone(),
|
if let Some(ws) = previous_post_whitespace_content {
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
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 {
|
eval.push(Instruction::AppendContent {
|
||||||
content: ws.source().clone(),
|
content: ws.source().clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let TemplateAstExpr::ConditionalContent { content } = &next {
|
||||||
for ast in content {
|
for ast in content {
|
||||||
emit_ast_expr(machine, eval, ast);
|
emit_ast_expr(machine, eval, ast);
|
||||||
}
|
}
|
||||||
|
|
||||||
let Some(TemplateAstExpr::Block {
|
end_indices.push(eval.len());
|
||||||
|
eval.push(Instruction::Jump { jump: isize::MAX });
|
||||||
|
} else if let TemplateAstExpr::Block {
|
||||||
prev_whitespace_content,
|
prev_whitespace_content,
|
||||||
post_whitespace_content,
|
post_whitespace_content,
|
||||||
..
|
expression,
|
||||||
}) = chain.last()
|
} = &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 {
|
else {
|
||||||
unreachable!("The end of an IfConditional must be a End Block");
|
panic!("Jump slot had something that is not a jump?!");
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ws) = prev_whitespace_content {
|
*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 {
|
||||||
eval.push(Instruction::AppendContent {
|
eval.push(Instruction::AppendContent {
|
||||||
content: ws.source().clone(),
|
content: ws.source().clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for index in end_indices {
|
||||||
let jump = eval.len() - index - 1;
|
let jump = eval.len() - index - 1;
|
||||||
eval[index] = Instruction::JumpIfNotTrue {
|
eval[index] = Instruction::Jump {
|
||||||
emit_slot,
|
|
||||||
jump: jump as isize,
|
jump: jump as isize,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(ws) = post_whitespace_content {
|
|
||||||
eval.push(Instruction::AppendContent {
|
|
||||||
content: ws.source().clone(),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -235,4 +267,17 @@ 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);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
src/emit/snapshots/nomo__emit__tests__check_if_else_if.snap
Normal file
75
src/emit/snapshots/nomo__emit__tests__check_if_else_if.snap
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
---
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
]
|
||||||
|
|
@ -67,6 +67,16 @@ 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;
|
ip += 1;
|
||||||
|
|
|
||||||
36
tests/cases/1-parsed@if_else_if.snap
Normal file
36
tests/cases/1-parsed@if_else_if.snap
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
---
|
||||||
|
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),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
@ -7,17 +7,17 @@ TemplateAst {
|
||||||
root: [
|
root: [
|
||||||
ConditionalChain {
|
ConditionalChain {
|
||||||
chain: [
|
chain: [
|
||||||
IfConditional {
|
Block {
|
||||||
if_block: Block {
|
|
||||||
prev_whitespace_content: None,
|
prev_whitespace_content: None,
|
||||||
|
expression: IfConditional {
|
||||||
expression: VariableAccess(
|
expression: VariableAccess(
|
||||||
[Ident]"test" (6..10),
|
[Ident]"test" (6..10),
|
||||||
),
|
),
|
||||||
|
},
|
||||||
post_whitespace_content: Some(
|
post_whitespace_content: Some(
|
||||||
[Whitespace]"\n " (13..18),
|
[Whitespace]"\n " (13..18),
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
},
|
|
||||||
ConditionalContent {
|
ConditionalContent {
|
||||||
content: [
|
content: [
|
||||||
StaticContent(
|
StaticContent(
|
||||||
|
|
|
||||||
60
tests/cases/2-ast@if_else_if.snap
Normal file
60
tests/cases/2-ast@if_else_if.snap
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
---
|
||||||
|
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,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@ input_file: tests/cases/condition.nomo
|
||||||
emit_slot: VariableSlot {
|
emit_slot: VariableSlot {
|
||||||
index: 0,
|
index: 0,
|
||||||
},
|
},
|
||||||
jump: 3,
|
jump: 5,
|
||||||
},
|
},
|
||||||
AppendContent {
|
AppendContent {
|
||||||
content: "\n " (13..18),
|
content: "\n " (13..18),
|
||||||
|
|
@ -25,6 +25,12 @@ input_file: tests/cases/condition.nomo
|
||||||
AppendContent {
|
AppendContent {
|
||||||
content: "\n" (30..31),
|
content: "\n" (30..31),
|
||||||
},
|
},
|
||||||
|
Jump {
|
||||||
|
jump: 2,
|
||||||
|
},
|
||||||
|
AppendContent {
|
||||||
|
content: "\n " (13..18),
|
||||||
|
},
|
||||||
AppendContent {
|
AppendContent {
|
||||||
content: "\n\n" (40..42),
|
content: "\n\n" (40..42),
|
||||||
},
|
},
|
||||||
|
|
|
||||||
61
tests/cases/3-instructions@if_else_if.snap
Normal file
61
tests/cases/3-instructions@if_else_if.snap
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
---
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
]
|
||||||
6
tests/cases/4-output@if_else_if.snap
Normal file
6
tests/cases/4-output@if_else_if.snap
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
---
|
||||||
|
source: tests/file_tests.rs
|
||||||
|
expression: output
|
||||||
|
input_file: tests/cases/if_else_if.nomo
|
||||||
|
---
|
||||||
|
"\n \n Hello World!\n\n "
|
||||||
11
tests/cases/if_else_if.nomo
Normal file
11
tests/cases/if_else_if.nomo
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
{
|
||||||
|
"test": false,
|
||||||
|
"another_test": true,
|
||||||
|
"stuff": "more"
|
||||||
|
}
|
||||||
|
---
|
||||||
|
{{ if test }}
|
||||||
|
Not Hello World! :C
|
||||||
|
{{ else if another_test }}
|
||||||
|
Hello World!
|
||||||
|
{{ end }}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue