Introduce TemplateFunction as wrapper of Vec<Step>

This commit is contained in:
Olivier 'reivilibre' 2025-05-18 11:19:18 +01:00
parent 16f3488d20
commit 659f3a88e4
10 changed files with 483 additions and 435 deletions

View File

@ -6,7 +6,7 @@ use bevy_reflect::{FromReflect, Reflect, ReflectRef, VariantType};
use fluent_templates::lazy_static::lazy_static; use fluent_templates::lazy_static::lazy_static;
use hornbeam_grammar::ast::{Binding, MatchBinding}; use hornbeam_grammar::ast::{Binding, MatchBinding};
use hornbeam_grammar::Locator; use hornbeam_grammar::Locator;
use hornbeam_ir::ir::{Expression, Step, StepDef, StringPiece}; use hornbeam_ir::ir::{Expression, Step, StepDef, StringPiece, TemplateFunction};
use itertools::Itertools; use itertools::Itertools;
use std::any::TypeId; use std::any::TypeId;
use std::borrow::Cow; use std::borrow::Cow;
@ -28,7 +28,7 @@ pub(crate) struct Scope<'a> {
pub(crate) struct Interpreter<'a, O, LS> { pub(crate) struct Interpreter<'a, O, LS> {
pub(crate) entrypoint: String, pub(crate) entrypoint: String,
pub(crate) program: &'a BTreeMap<String, Arc<Vec<Step>>>, pub(crate) program: &'a BTreeMap<String, Arc<TemplateFunction>>,
pub(crate) output: O, pub(crate) output: O,
pub(crate) localisation: Arc<LS>, pub(crate) localisation: Arc<LS>,
pub(crate) locale: String, pub(crate) locale: String,
@ -445,6 +445,14 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
} }
} }
StepDef::Call { name, args, slots } => { StepDef::Call { name, args, slots } => {
let Some(module) = self.program.get(name as &str) else {
return Err(InterpreterError::TypeError {
context: "Call".to_string(),
conflict: format!("no entrypoint for {name:?}."),
location: step.locator.clone(),
});
};
let mut evaled_args = BTreeMap::new(); let mut evaled_args = BTreeMap::new();
for (key, expr) in args { for (key, expr) in args {
evaled_args.insert( evaled_args.insert(
@ -464,23 +472,18 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
); );
} }
// TODO check slots
// ...
// check params
self.scopes.push(Scope { self.scopes.push(Scope {
variables: evaled_args, variables: evaled_args,
slots: filled_in_slots, slots: filled_in_slots,
}); });
let next_scope_idx = self.scopes.len() - 1; let next_scope_idx = self.scopes.len() - 1;
let steps = if let Some(steps) = self.program.get(name as &str) { self.run_steps(next_scope_idx, &module.steps).await?;
steps
} else {
return Err(InterpreterError::TypeError {
context: "Call".to_string(),
conflict: format!("no entrypoint for {name:?}."),
location: step.locator.clone(),
});
};
self.run_steps(next_scope_idx, steps).await?;
self.scopes.pop(); self.scopes.pop();
assert_eq!(self.scopes.len(), next_scope_idx); assert_eq!(self.scopes.len(), next_scope_idx);
@ -892,16 +895,15 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
} }
pub async fn run(mut self) -> Result<(), InterpreterError<LS::Error, O::Error>> { pub async fn run(mut self) -> Result<(), InterpreterError<LS::Error, O::Error>> {
let main = if let Some(main) = self.program.get(&self.entrypoint) { let Some(main) = self.program.get(&self.entrypoint) else {
main
} else {
return Err(InterpreterError::TypeError { return Err(InterpreterError::TypeError {
context: format!("No entrypoint called {:?}", self.entrypoint), context: format!("No entrypoint called {:?}", self.entrypoint),
conflict: "".to_string(), conflict: "".to_string(),
location: Locator::empty(), location: Locator::empty(),
}); });
}; };
self.run_steps(0, main).await?; // TODO slot + params check
self.run_steps(0, &main.steps).await?;
Ok(()) Ok(())
} }
} }

View File

@ -4,7 +4,7 @@ use async_trait::async_trait;
use bevy_reflect::Reflect; use bevy_reflect::Reflect;
use hornbeam_grammar::parse_template; use hornbeam_grammar::parse_template;
use hornbeam_ir::ast_to_optimised_ir; use hornbeam_ir::ast_to_optimised_ir;
use hornbeam_ir::ir::Step; use hornbeam_ir::ir::TemplateFunction;
use std::borrow::Cow; use std::borrow::Cow;
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::convert::Infallible; use std::convert::Infallible;
@ -46,7 +46,7 @@ use crate::{default_template_accessible_methods, InterpreterError};
pub struct LoadedTemplates<LS> { pub struct LoadedTemplates<LS> {
// todo might be tempted to use e.g. ouroboros here, to keep the file source adjacent? // todo might be tempted to use e.g. ouroboros here, to keep the file source adjacent?
// or do we just staticify? // or do we just staticify?
template_functions: BTreeMap<String, Arc<Vec<Step>>>, template_functions: BTreeMap<String, Arc<TemplateFunction>>,
methods: Arc<BTreeMap<String, TemplateAccessibleMethod>>, methods: Arc<BTreeMap<String, TemplateAccessibleMethod>>,
@ -170,6 +170,8 @@ impl<'a, LS> LoadedTemplates<LS> {
params: Params, params: Params,
locale: String, locale: String,
) -> PreparedTemplate<LS> { ) -> PreparedTemplate<LS> {
// TODO add support for running an `init` or `pre` fragment before running any fragment
// This would allow boilerplate `set` statements to be done ahead of time for example...
PreparedTemplate { PreparedTemplate {
all_instructions: Arc::new(self.template_functions.clone()), all_instructions: Arc::new(self.template_functions.clone()),
entrypoint: if let Some(frag) = fragment_name { entrypoint: if let Some(frag) = fragment_name {
@ -186,7 +188,8 @@ impl<'a, LS> LoadedTemplates<LS> {
} }
pub struct PreparedTemplate<LS> { pub struct PreparedTemplate<LS> {
pub(crate) all_instructions: Arc<BTreeMap<String, Arc<Vec<Step>>>>, // TODO rename to `template_functions`
pub(crate) all_instructions: Arc<BTreeMap<String, Arc<TemplateFunction>>>,
pub(crate) methods: Arc<BTreeMap<String, TemplateAccessibleMethod>>, pub(crate) methods: Arc<BTreeMap<String, TemplateAccessibleMethod>>,
pub(crate) entrypoint: String, pub(crate) entrypoint: String,
pub(crate) variables: Params, pub(crate) variables: Params,

View File

@ -1,4 +1,4 @@
use crate::ir::{Step, StepDef}; use crate::ir::{Step, StepDef, TemplateFunction};
use hornbeam_grammar::ast::{ use hornbeam_grammar::ast::{
Binding, Block, Expression, HtmlElement, MatchBinding, StringExpr, StringPiece, Template, Binding, Block, Expression, HtmlElement, MatchBinding, StringExpr, StringPiece, Template,
}; };
@ -144,14 +144,21 @@ fn pull_out_entrypoints_from_block(
/// Step 2. Compile the AST to IR steps. /// Step 2. Compile the AST to IR steps.
pub(crate) fn compile_functions( pub(crate) fn compile_functions(
functions: &BTreeMap<String, Vec<Block>>, functions: &BTreeMap<String, Vec<Block>>,
) -> Result<BTreeMap<String, Vec<Step>>, AstToIrError> { ) -> Result<BTreeMap<String, TemplateFunction>, AstToIrError> {
let mut result = BTreeMap::new(); let mut result = BTreeMap::new();
for (func_name, func_blocks) in functions { for (func_name, func_blocks) in functions {
let mut steps = Vec::new(); let mut steps = Vec::new();
for block in func_blocks { for block in func_blocks {
compile_ast_block_to_steps(block, &mut steps)?; compile_ast_block_to_steps(block, &mut steps)?;
} }
result.insert(func_name.clone(), steps); // TODO save more information
result.insert(
func_name.clone(),
TemplateFunction {
param_defs: None,
steps,
},
);
} }
Ok(result) Ok(result)
} }

View File

@ -11,6 +11,20 @@ pub struct Function {
pub steps: Vec<Step>, pub steps: Vec<Step>,
} }
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct TemplateFunction {
/// `None` if we don't have static parameter information.
pub param_defs: Option<Vec<ParamDef>>,
pub steps: Vec<Step>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ParamDef {
pub name: IStr,
// TODO type information
pub default: Option<Expression>,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct Step { pub struct Step {
#[serde(flatten)] #[serde(flatten)]

View File

@ -8,7 +8,6 @@
//! For using the IR, see `hornbeam_interpreter` (dynamic) or `hornbeam_macros` (code gen). //! For using the IR, see `hornbeam_interpreter` (dynamic) or `hornbeam_macros` (code gen).
use crate::ast_to_ir::pull_out_entrypoints; use crate::ast_to_ir::pull_out_entrypoints;
use crate::ir::Step;
use crate::peephole::apply_all_peephole_passes; use crate::peephole::apply_all_peephole_passes;
use hornbeam_grammar::ast::Template; use hornbeam_grammar::ast::Template;
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -19,14 +18,16 @@ mod peephole;
pub use ast_to_ir::AstToIrError; pub use ast_to_ir::AstToIrError;
use self::ir::TemplateFunction;
pub fn ast_to_optimised_ir( pub fn ast_to_optimised_ir(
template_name: &str, template_name: &str,
template: Template, template: Template,
) -> Result<BTreeMap<String, Vec<Step>>, AstToIrError> { ) -> Result<BTreeMap<String, TemplateFunction>, AstToIrError> {
let entrypoints = pull_out_entrypoints(template, template_name)?; let entrypoints = pull_out_entrypoints(template, template_name)?;
let mut compiled_funcs = ast_to_ir::compile_functions(&entrypoints)?; let mut compiled_funcs = ast_to_ir::compile_functions(&entrypoints)?;
for steps in compiled_funcs.values_mut() { for func in compiled_funcs.values_mut() {
apply_all_peephole_passes(steps); apply_all_peephole_passes(&mut func.steps);
} }
Ok(compiled_funcs) Ok(compiled_funcs)

View File

@ -167,16 +167,21 @@ pub fn apply_all_peephole_passes(steps: &mut Vec<Step>) {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; use super::*;
use crate::ast_to_ir::{compile_functions, pull_out_entrypoints}; use crate::{
ast_to_ir::{compile_functions, pull_out_entrypoints},
ir::TemplateFunction,
};
use hornbeam_grammar::parse_template; use hornbeam_grammar::parse_template;
use insta::assert_yaml_snapshot; use insta::assert_yaml_snapshot;
use std::collections::BTreeMap; use std::collections::BTreeMap;
fn parse_ir_and_peephole(text: &str) -> BTreeMap<String, Vec<Step>> { fn parse_ir_and_peephole(text: &str) -> BTreeMap<String, TemplateFunction> {
let template = parse_template(text, "inp").unwrap(); let template = parse_template(text, "inp").unwrap();
let entrypoints = pull_out_entrypoints(template, "TemplateName").unwrap(); let entrypoints = pull_out_entrypoints(template, "TemplateName").unwrap();
let mut compiled = compile_functions(&entrypoints).unwrap(); let mut compiled = compile_functions(&entrypoints).unwrap();
compiled.values_mut().for_each(apply_all_peephole_passes); compiled
.values_mut()
.for_each(|func| apply_all_peephole_passes(&mut func.steps));
compiled compiled
} }

View File

@ -3,115 +3,122 @@ source: hornbeam_ir/src/ast_to_ir.rs
expression: "compile_functions(&pull_out_entrypoints(template,\n \"TemplateName\").unwrap()).unwrap()" expression: "compile_functions(&pull_out_entrypoints(template,\n \"TemplateName\").unwrap()).unwrap()"
--- ---
TemplateName: TemplateName:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<div" - WriteLiteral:
locator: escape: false
filename: inp text: "<div"
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: false column: 1
text: ">" - WriteLiteral:
locator: escape: false
filename: inp text: ">"
line: 2 locator:
column: 1 filename: inp
- Call: line: 2
name: TemplateName__Frag1 column: 1
args: {} - Call:
slots: {} name: TemplateName__Frag1
locator: args: {}
filename: inp slots: {}
line: 3 locator:
column: 5 filename: inp
- Call: line: 3
name: TemplateName__Footer column: 5
args: {} - Call:
slots: {} name: TemplateName__Footer
locator: args: {}
filename: inp slots: {}
line: 9 locator:
column: 5 filename: inp
- WriteLiteral: line: 9
escape: false column: 5
text: "</div>" - WriteLiteral:
locator: escape: false
filename: inp text: "</div>"
line: 2 locator:
column: 1 filename: inp
line: 2
column: 1
TemplateName__Footer: TemplateName__Footer:
- WriteLiteral: param_defs: ~
escape: true steps:
text: Or even adjacent ones - WriteLiteral:
locator: escape: true
filename: "" text: Or even adjacent ones
line: 0 locator:
column: 0 filename: ""
line: 0
column: 0
TemplateName__Frag1: TemplateName__Frag1:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<span" - WriteLiteral:
locator: escape: false
filename: inp text: "<span"
line: 4 locator:
column: 9 filename: inp
- WriteLiteral: line: 4
escape: false column: 9
text: ">" - WriteLiteral:
locator: escape: false
filename: inp text: ">"
line: 4 locator:
column: 9 filename: inp
- WriteLiteral: line: 4
escape: true column: 9
text: This is a fragment!! - WriteLiteral:
locator: escape: true
filename: "" text: This is a fragment!!
line: 0 locator:
column: 0 filename: ""
- WriteLiteral: line: 0
escape: false column: 0
text: "</span>" - WriteLiteral:
locator: escape: false
filename: inp text: "</span>"
line: 4 locator:
column: 9 filename: inp
- Call: line: 4
name: TemplateName__Frag2 column: 9
args: {} - Call:
slots: {} name: TemplateName__Frag2
locator: args: {}
filename: inp slots: {}
line: 6 locator:
column: 9 filename: inp
line: 6
column: 9
TemplateName__Frag2: TemplateName__Frag2:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<div" - WriteLiteral:
locator: escape: false
filename: inp text: "<div"
line: 7 locator:
column: 13 filename: inp
- WriteLiteral: line: 7
escape: false column: 13
text: ">" - WriteLiteral:
locator: escape: false
filename: inp text: ">"
line: 7 locator:
column: 13 filename: inp
- WriteLiteral: line: 7
escape: true column: 13
text: "There's no problem having nested fragments!" - WriteLiteral:
locator: escape: true
filename: "" text: "There's no problem having nested fragments!"
line: 0 locator:
column: 0 filename: ""
- WriteLiteral: line: 0
escape: false column: 0
text: "</div>" - WriteLiteral:
locator: escape: false
filename: inp text: "</div>"
line: 7 locator:
column: 13 filename: inp
line: 7
column: 13

View File

@ -3,171 +3,172 @@ source: hornbeam_ir/src/ast_to_ir.rs
expression: "compile_functions(&pull_out_entrypoints(template,\n \"TemplateName\").unwrap()).unwrap()" expression: "compile_functions(&pull_out_entrypoints(template,\n \"TemplateName\").unwrap()).unwrap()"
--- ---
TemplateName: TemplateName:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<div" - WriteLiteral:
locator: escape: false
filename: inp text: "<div"
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: false column: 1
text: " id=\"" - WriteLiteral:
locator: escape: false
filename: inp text: " id=\""
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: true column: 1
text: myid - WriteLiteral:
locator: escape: true
filename: inp text: myid
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: false column: 1
text: "\"" - WriteLiteral:
locator: escape: false
filename: inp text: "\""
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: false column: 1
text: " class=\"" - WriteLiteral:
locator: escape: false
filename: inp text: " class=\""
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: true column: 1
text: stylish - WriteLiteral:
locator: escape: true
filename: inp text: stylish
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: false column: 1
text: "\"" - WriteLiteral:
locator: escape: false
filename: inp text: "\""
line: 2 locator:
column: 1 filename: inp
- WriteLiteral: line: 2
escape: false column: 1
text: " arb=\"" - WriteLiteral:
locator: escape: false
filename: inp text: " arb=\""
line: 2 locator:
column: 1 filename: inp
- WriteEval: line: 2
escape: true column: 1
expr: - WriteEval:
Variable: escape: true
name: ritrary expr:
loc:
filename: inp
line: 2
column: 47
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\""
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: " size=\""
locator:
filename: inp
line: 2
column: 1
- WriteEval:
escape: true
expr:
IntLiteral:
val: 42
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\""
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: " stringy=\""
locator:
filename: inp
line: 2
column: 1
- WriteEval:
escape: true
expr:
StringExpr:
pieces:
- Literal: yup
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\""
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: ">"
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: true
text: This is a div with a few extras
locator:
filename: ""
line: 0
column: 0
- Call:
name: OtherComponent
args:
param1:
IntLiteral:
val: 1
param2:
StringExpr:
pieces:
- Literal: two
param3:
Variable: Variable:
name: three name: ritrary
loc: loc:
filename: inp filename: inp
line: 4 line: 2
column: 52 column: 47
slots: locator:
main: [] filename: inp
locator: line: 2
filename: inp column: 1
line: 4 - WriteLiteral:
column: 5 escape: false
- WriteLiteral: text: "\""
escape: false locator:
text: "</div>" filename: inp
locator: line: 2
filename: inp column: 1
line: 2 - WriteLiteral:
column: 1 escape: false
text: " size=\""
locator:
filename: inp
line: 2
column: 1
- WriteEval:
escape: true
expr:
IntLiteral:
val: 42
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\""
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: " stringy=\""
locator:
filename: inp
line: 2
column: 1
- WriteEval:
escape: true
expr:
StringExpr:
pieces:
- Literal: yup
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\""
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: ">"
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: true
text: This is a div with a few extras
locator:
filename: ""
line: 0
column: 0
- Call:
name: OtherComponent
args:
param1:
IntLiteral:
val: 1
param2:
StringExpr:
pieces:
- Literal: two
param3:
Variable:
name: three
loc:
filename: inp
line: 4
column: 52
slots:
main: []
locator:
filename: inp
line: 4
column: 5
- WriteLiteral:
escape: false
text: "</div>"
locator:
filename: inp
line: 2
column: 1

View File

@ -3,66 +3,73 @@ source: hornbeam_ir/src/peephole.rs
expression: "parse_ir_and_peephole(r#\"\ndiv\n fragment Frag1\n span\n \"This is a fragment!!\"\n fragment Frag2\n div\n \"There's no problem having <<nested>> fragments!\"\n fragment Footer\n \"Or even adjacent ones\"\n \"#)" expression: "parse_ir_and_peephole(r#\"\ndiv\n fragment Frag1\n span\n \"This is a fragment!!\"\n fragment Frag2\n div\n \"There's no problem having <<nested>> fragments!\"\n fragment Footer\n \"Or even adjacent ones\"\n \"#)"
--- ---
TemplateName: TemplateName:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<div>" - WriteLiteral:
locator: escape: false
filename: inp text: "<div>"
line: 2 locator:
column: 1 filename: inp
- Call: line: 2
name: TemplateName__Frag1 column: 1
args: {} - Call:
slots: {} name: TemplateName__Frag1
locator: args: {}
filename: inp slots: {}
line: 3 locator:
column: 5 filename: inp
- Call: line: 3
name: TemplateName__Footer column: 5
args: {} - Call:
slots: {} name: TemplateName__Footer
locator: args: {}
filename: inp slots: {}
line: 9 locator:
column: 5 filename: inp
- WriteLiteral: line: 9
escape: false column: 5
text: "</div>" - WriteLiteral:
locator: escape: false
filename: inp text: "</div>"
line: 2 locator:
column: 1 filename: inp
line: 2
column: 1
TemplateName__Footer: TemplateName__Footer:
- WriteLiteral: param_defs: ~
escape: false steps:
text: Or even adjacent ones - WriteLiteral:
locator: escape: false
filename: "" text: Or even adjacent ones
line: 0 locator:
column: 0 filename: ""
line: 0
column: 0
TemplateName__Frag1: TemplateName__Frag1:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<span>This is a fragment!!</span>" - WriteLiteral:
locator: escape: false
filename: inp text: "<span>This is a fragment!!</span>"
line: 4 locator:
column: 9 filename: inp
- Call: line: 4
name: TemplateName__Frag2 column: 9
args: {} - Call:
slots: {} name: TemplateName__Frag2
locator: args: {}
filename: inp slots: {}
line: 6 locator:
column: 9 filename: inp
line: 6
column: 9
TemplateName__Frag2: TemplateName__Frag2:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<div>There&#x27;s no problem having &lt;&lt;nested&gt;&gt; fragments!</div>" - WriteLiteral:
locator: escape: false
filename: inp text: "<div>There&#x27;s no problem having &lt;&lt;nested&gt;&gt; fragments!</div>"
line: 7 locator:
column: 13 filename: inp
line: 7
column: 13

View File

@ -3,77 +3,78 @@ source: hornbeam_ir/src/peephole.rs
expression: "parse_ir_and_peephole(r#\"\ndiv.stylish#myid {size=42, stringy=\"yup\", arb=$ritrary}\n \"This is a div with a few extras\"\n OtherComponent {param1=1, param2=\"two\", param3=$three}\n \"#)" expression: "parse_ir_and_peephole(r#\"\ndiv.stylish#myid {size=42, stringy=\"yup\", arb=$ritrary}\n \"This is a div with a few extras\"\n OtherComponent {param1=1, param2=\"two\", param3=$three}\n \"#)"
--- ---
TemplateName: TemplateName:
- WriteLiteral: param_defs: ~
escape: false steps:
text: "<div id=\"myid\" class=\"stylish\" arb=\"" - WriteLiteral:
locator: escape: false
filename: inp text: "<div id=\"myid\" class=\"stylish\" arb=\""
line: 2 locator:
column: 1 filename: inp
- WriteEval: line: 2
escape: true column: 1
expr: - WriteEval:
Variable: escape: true
name: ritrary expr:
loc:
filename: inp
line: 2
column: 47
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\" size=\""
locator:
filename: inp
line: 2
column: 1
- WriteEval:
escape: true
expr:
IntLiteral:
val: 42
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\" stringy=\"yup\">This is a div with a few extras"
locator:
filename: inp
line: 2
column: 1
- Call:
name: OtherComponent
args:
param1:
IntLiteral:
val: 1
param2:
StringExpr:
pieces:
- Literal: two
param3:
Variable: Variable:
name: three name: ritrary
loc: loc:
filename: inp filename: inp
line: 4 line: 2
column: 52 column: 47
slots: locator:
main: [] filename: inp
locator: line: 2
filename: inp column: 1
line: 4 - WriteLiteral:
column: 5 escape: false
- WriteLiteral: text: "\" size=\""
escape: false locator:
text: "</div>" filename: inp
locator: line: 2
filename: inp column: 1
line: 2 - WriteEval:
column: 1 escape: true
expr:
IntLiteral:
val: 42
locator:
filename: inp
line: 2
column: 1
- WriteLiteral:
escape: false
text: "\" stringy=\"yup\">This is a div with a few extras"
locator:
filename: inp
line: 2
column: 1
- Call:
name: OtherComponent
args:
param1:
IntLiteral:
val: 1
param2:
StringExpr:
pieces:
- Literal: two
param3:
Variable:
name: three
loc:
filename: inp
line: 4
column: 52
slots:
main: []
locator:
filename: inp
line: 4
column: 5
- WriteLiteral:
escape: false
text: "</div>"
locator:
filename: inp
line: 2
column: 1