Simplify and use locators in the IR and interpreter
This commit is contained in:
parent
f54f2093de
commit
0370de40a1
@ -1,6 +1,8 @@
|
|||||||
pub mod ast;
|
pub mod ast;
|
||||||
mod parser;
|
mod parser;
|
||||||
|
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
use arc_interner::ArcIntern;
|
use arc_interner::ArcIntern;
|
||||||
pub use parser::parse_template;
|
pub use parser::parse_template;
|
||||||
@ -31,4 +33,30 @@ impl Locator {
|
|||||||
column: col.min(u16::MAX as usize) as u16,
|
column: col.min(u16::MAX as usize) as u16,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn empty() -> Locator {
|
||||||
|
Locator {
|
||||||
|
filename: intern(""),
|
||||||
|
line: 0,
|
||||||
|
column: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.filename.is_empty() && self.line == 0 && self.column == 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Locator {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
if self.is_empty() {
|
||||||
|
write!(f, "unknown location")
|
||||||
|
} else {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"file {:?} @ line {} (col {})",
|
||||||
|
self.filename, self.line, self.column
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\ndiv\n fragment BobbyDazzler\n span\n \"Wow!\"\n fragment MainPart\n slot :main\n div\n optional slot :footer\n \"#).unwrap()"
|
expression: "parse_template(r#\"\ndiv\n fragment BobbyDazzler\n span\n \"Wow!\"\n fragment MainPart\n slot :main\n div\n optional slot :footer\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- HtmlElement:
|
- HtmlElement:
|
||||||
@ -18,22 +18,50 @@ blocks:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 9
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
- DefineFragment:
|
- DefineFragment:
|
||||||
name: MainPart
|
name: MainPart
|
||||||
blocks:
|
blocks:
|
||||||
- DefineExpandSlot:
|
- DefineExpandSlot:
|
||||||
name: main
|
name: main
|
||||||
optional: false
|
optional: false
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 7
|
||||||
|
column: 9
|
||||||
- HtmlElement:
|
- HtmlElement:
|
||||||
name: div
|
name: div
|
||||||
children:
|
children:
|
||||||
- DefineExpandSlot:
|
- DefineExpandSlot:
|
||||||
name: footer
|
name: footer
|
||||||
optional: true
|
optional: true
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 9
|
||||||
|
column: 13
|
||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 8
|
||||||
|
column: 9
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 6
|
||||||
|
column: 5
|
||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\nif 1 + 1 == 2\n div\n \"Phew, safe!\"\nelse if 1 + 2 - 1 == 3 // not too far off, I suppose\n Warning\n \"Not quite, but fairly close. What kind of world is this?\"\nelse // peculiar.\n \"Not even close, eh?\"\n \"#).unwrap()"
|
expression: "parse_template(r#\"\nif 1 + 1 == 2\n div\n \"Phew, safe!\"\nelse if 1 + 2 - 1 == 3 // not too far off, I suppose\n Warning\n \"Not quite, but fairly close. What kind of world is this?\"\nelse // peculiar.\n \"Not even close, eh?\"\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- IfBlock:
|
- IfBlock:
|
||||||
@ -27,6 +27,10 @@ blocks:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 3
|
||||||
else_blocks:
|
else_blocks:
|
||||||
- IfBlock:
|
- IfBlock:
|
||||||
condition:
|
condition:
|
||||||
@ -56,8 +60,20 @@ blocks:
|
|||||||
pieces:
|
pieces:
|
||||||
- Literal: "Not quite, but fairly close. What kind of world is this?"
|
- Literal: "Not quite, but fairly close. What kind of world is this?"
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 6
|
||||||
|
column: 3
|
||||||
else_blocks:
|
else_blocks:
|
||||||
- Text:
|
- Text:
|
||||||
pieces:
|
pieces:
|
||||||
- Literal: "Not even close, eh?"
|
- Literal: "Not even close, eh?"
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 5
|
||||||
|
column: 6
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\nif 10 / 2 == 5 or $point.x == 42 // div for a div?\n div\n \"#).unwrap()"
|
expression: "parse_template(r#\"\nif 10 / 2 == 5 or $point.x == 42 // div for a div?\n div\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- IfBlock:
|
- IfBlock:
|
||||||
@ -26,7 +26,15 @@ blocks:
|
|||||||
obj:
|
obj:
|
||||||
Variable:
|
Variable:
|
||||||
name: point
|
name: point
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 19
|
||||||
ident: x
|
ident: x
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 25
|
||||||
right:
|
right:
|
||||||
IntLiteral:
|
IntLiteral:
|
||||||
val: 42
|
val: 42
|
||||||
@ -37,5 +45,13 @@ blocks:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
else_blocks: []
|
else_blocks: []
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\ndiv\n span\n @header-wow\n MainBody\n ''\n @body-welcome\n @body-msg{count = $messages.len()}\n ''\n Footer\n @footer-copyright{year = today().year}\n \"#).unwrap()"
|
expression: "parse_template(r#\"\ndiv\n span\n @header-wow\n MainBody\n ''\n @body-welcome\n @body-msg{count = $messages.len()}\n ''\n Footer\n @footer-copyright{year = today().year}\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- HtmlElement:
|
- HtmlElement:
|
||||||
@ -17,6 +17,10 @@ blocks:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
- ComponentElement:
|
- ComponentElement:
|
||||||
name: MainBody
|
name: MainBody
|
||||||
slots:
|
slots:
|
||||||
@ -35,9 +39,21 @@ blocks:
|
|||||||
obj:
|
obj:
|
||||||
Variable:
|
Variable:
|
||||||
name: messages
|
name: messages
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 8
|
||||||
|
column: 27
|
||||||
ident: len
|
ident: len
|
||||||
args: []
|
args: []
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 8
|
||||||
|
column: 36
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 5
|
||||||
|
column: 5
|
||||||
- ComponentElement:
|
- ComponentElement:
|
||||||
name: Footer
|
name: Footer
|
||||||
slots:
|
slots:
|
||||||
@ -53,9 +69,25 @@ blocks:
|
|||||||
FunctionCall:
|
FunctionCall:
|
||||||
name: today
|
name: today
|
||||||
args: []
|
args: []
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 11
|
||||||
|
column: 34
|
||||||
ident: year
|
ident: year
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 11
|
||||||
|
column: 41
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 10
|
||||||
|
column: 5
|
||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\n// This is a simple Hornbeam template that just shows a <div>\ndiv\n \"#).unwrap()"
|
expression: "parse_template(r#\"\n// This is a simple Hornbeam template that just shows a <div>\ndiv\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- HtmlElement:
|
- HtmlElement:
|
||||||
@ -9,4 +9,8 @@ blocks:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\nMyComponent\n :someslot\n ''\n ${\"abc\" + \"def${ 1 + 1 }\"}\n Not too bad now.\n ''\n \"#).unwrap()"
|
expression: "parse_template(r#\"\nMyComponent\n :someslot\n ''\n ${\"abc\" + \"def${ 1 + 1 }\"}\n Not too bad now.\n ''\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- ComponentElement:
|
- ComponentElement:
|
||||||
@ -30,4 +30,8 @@ blocks:
|
|||||||
- Literal: "\n"
|
- Literal: "\n"
|
||||||
- Literal: Not too bad now.
|
- Literal: Not too bad now.
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
source: hornbeam_grammar/src/parser.rs
|
source: hornbeam_grammar/src/parser.rs
|
||||||
expression: "parse_template(r#\"\nMyComponent\n :someslot\n \"That's better!\"\n \"#).unwrap()"
|
expression: "parse_template(r#\"\nMyComponent\n :someslot\n \"That's better!\"\n \"#,\n \"inp\").unwrap()"
|
||||||
---
|
---
|
||||||
blocks:
|
blocks:
|
||||||
- ComponentElement:
|
- ComponentElement:
|
||||||
@ -11,4 +11,8 @@ blocks:
|
|||||||
pieces:
|
pieces:
|
||||||
- Literal: "That's better!"
|
- Literal: "That's better!"
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ use crate::InterpreterError;
|
|||||||
use async_recursion::async_recursion;
|
use async_recursion::async_recursion;
|
||||||
use bevy_reflect::{FromReflect, Reflect, ReflectRef};
|
use bevy_reflect::{FromReflect, Reflect, ReflectRef};
|
||||||
use fluent_templates::lazy_static::lazy_static;
|
use fluent_templates::lazy_static::lazy_static;
|
||||||
|
use hornbeam_grammar::Locator;
|
||||||
use hornbeam_ir::ir::{Expression, Step, StepDef, StringPiece};
|
use hornbeam_ir::ir::{Expression, Step, StepDef, StringPiece};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use std::any::{Any, TypeId};
|
use std::any::{Any, TypeId};
|
||||||
@ -12,22 +13,22 @@ use std::fmt::Write;
|
|||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
pub(crate) struct FilledSlot<'a, L> {
|
pub(crate) struct FilledSlot<'a> {
|
||||||
pub scope_idx: usize,
|
pub scope_idx: usize,
|
||||||
pub steps: &'a [Step<L>],
|
pub steps: &'a [Step],
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Scope<'a, L> {
|
pub(crate) struct Scope<'a> {
|
||||||
pub variables: BTreeMap<String, Value>,
|
pub variables: BTreeMap<String, Value>,
|
||||||
pub slots: BTreeMap<String, FilledSlot<'a, L>>,
|
pub slots: BTreeMap<String, FilledSlot<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Interpreter<'a, L, 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<L>>>>,
|
pub(crate) program: &'a BTreeMap<String, Arc<Vec<Step>>>,
|
||||||
pub(crate) output: O,
|
pub(crate) output: O,
|
||||||
pub(crate) localisation: Arc<LS>,
|
pub(crate) localisation: Arc<LS>,
|
||||||
pub(crate) scopes: Vec<Scope<'a, L>>,
|
pub(crate) scopes: Vec<Scope<'a>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -90,14 +91,12 @@ impl Clone for Value {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send>
|
impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpreter<'a, O, LS> {
|
||||||
Interpreter<'a, L, O, LS>
|
|
||||||
{
|
|
||||||
#[async_recursion]
|
#[async_recursion]
|
||||||
pub async fn run_steps(
|
pub async fn run_steps(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope_idx: usize,
|
scope_idx: usize,
|
||||||
steps: &'a [Step<L>],
|
steps: &'a [Step],
|
||||||
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
||||||
for step in steps {
|
for step in steps {
|
||||||
self.run_step(scope_idx, step).await?;
|
self.run_step(scope_idx, step).await?;
|
||||||
@ -108,7 +107,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
pub async fn run_step(
|
pub async fn run_step(
|
||||||
&mut self,
|
&mut self,
|
||||||
scope_idx: usize,
|
scope_idx: usize,
|
||||||
step: &'a Step<L>,
|
step: &'a Step,
|
||||||
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
||||||
match &step.def {
|
match &step.def {
|
||||||
StepDef::WriteLiteral { escape, text } => {
|
StepDef::WriteLiteral { escape, text } => {
|
||||||
@ -128,9 +127,9 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
StepDef::WriteEval { escape, expr } => {
|
StepDef::WriteEval { escape, expr } => {
|
||||||
let val = self.evaluate_expression(scope_idx, expr)?;
|
let val = self.evaluate_expression(scope_idx, expr, &step.locator)?;
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
self.write_out_value_as_display_string(val, &mut buf)?;
|
self.write_out_value_as_display_string(val, &mut buf, &step.locator)?;
|
||||||
|
|
||||||
let to_write = if *escape {
|
let to_write = if *escape {
|
||||||
html_escape::encode_safe(&buf)
|
html_escape::encode_safe(&buf)
|
||||||
@ -148,7 +147,8 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
true_steps,
|
true_steps,
|
||||||
false_steps,
|
false_steps,
|
||||||
} => {
|
} => {
|
||||||
let evaled_condition = self.evaluate_expression(scope_idx, condition)?;
|
let evaled_condition =
|
||||||
|
self.evaluate_expression(scope_idx, condition, &step.locator)?;
|
||||||
let steps = match evaled_condition {
|
let steps = match evaled_condition {
|
||||||
Value::Bool(true) => true_steps,
|
Value::Bool(true) => true_steps,
|
||||||
Value::Bool(false) => false_steps,
|
Value::Bool(false) => false_steps,
|
||||||
@ -156,7 +156,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
return Err(InterpreterError::TypeError {
|
return Err(InterpreterError::TypeError {
|
||||||
context: "If".to_string(),
|
context: "If".to_string(),
|
||||||
conflict: format!("condition {other:?} is not a boolean."),
|
conflict: format!("condition {other:?} is not a boolean."),
|
||||||
location: "".to_string(),
|
location: step.locator.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -169,7 +169,8 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
body_steps,
|
body_steps,
|
||||||
empty_steps,
|
empty_steps,
|
||||||
} => {
|
} => {
|
||||||
let iterable_evaled = self.evaluate_expression(scope_idx, iterable)?;
|
let iterable_evaled =
|
||||||
|
self.evaluate_expression(scope_idx, iterable, &step.locator)?;
|
||||||
|
|
||||||
match iterable_evaled {
|
match iterable_evaled {
|
||||||
Value::List(list) => {
|
Value::List(list) => {
|
||||||
@ -191,7 +192,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
return Err(InterpreterError::TypeError {
|
return Err(InterpreterError::TypeError {
|
||||||
context: "For".to_string(),
|
context: "For".to_string(),
|
||||||
conflict: format!("not iterable: {other:?}."),
|
conflict: format!("not iterable: {other:?}."),
|
||||||
location: "".to_string(),
|
location: step.locator.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -201,7 +202,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
for (key, expr) in args {
|
for (key, expr) in args {
|
||||||
evaled_args.insert(
|
evaled_args.insert(
|
||||||
String::from(key as &str),
|
String::from(key as &str),
|
||||||
self.evaluate_expression(scope_idx, expr)?,
|
self.evaluate_expression(scope_idx, expr, &step.locator)?,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -228,7 +229,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
return Err(InterpreterError::TypeError {
|
return Err(InterpreterError::TypeError {
|
||||||
context: "Call".to_string(),
|
context: "Call".to_string(),
|
||||||
conflict: format!("no entrypoint for {name:?}."),
|
conflict: format!("no entrypoint for {name:?}."),
|
||||||
location: "".to_string(),
|
location: step.locator.clone(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -246,7 +247,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
Err(InterpreterError::TypeError {
|
Err(InterpreterError::TypeError {
|
||||||
context: format!("Required slot '{name}' not filled"),
|
context: format!("Required slot '{name}' not filled"),
|
||||||
conflict: format!("slot was left empty."),
|
conflict: format!("slot was left empty."),
|
||||||
location: "".to_string(),
|
location: step.locator.clone(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -266,113 +267,114 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
&self,
|
&self,
|
||||||
scope_idx: usize,
|
scope_idx: usize,
|
||||||
expr: &'a Expression,
|
expr: &'a Expression,
|
||||||
|
loc: &Locator,
|
||||||
) -> Result<Value, InterpreterError<LS::Error, O::Error>> {
|
) -> Result<Value, InterpreterError<LS::Error, O::Error>> {
|
||||||
match expr {
|
match expr {
|
||||||
Expression::Add { left, right } => {
|
Expression::Add { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint + rint)),
|
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint + rint)),
|
||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "Add".to_string(),
|
context: "Add".to_string(),
|
||||||
conflict: format!("can't add {lother:?} and {rother:?}!"),
|
conflict: format!("can't add {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Sub { left, right } => {
|
Expression::Sub { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint - rint)),
|
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint - rint)),
|
||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "Sub".to_string(),
|
context: "Sub".to_string(),
|
||||||
conflict: format!("can't sub {lother:?} and {rother:?}!"),
|
conflict: format!("can't sub {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Mul { left, right } => {
|
Expression::Mul { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint * rint)),
|
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint * rint)),
|
||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "Mul".to_string(),
|
context: "Mul".to_string(),
|
||||||
conflict: format!("can't mul {lother:?} and {rother:?}!"),
|
conflict: format!("can't mul {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Div { left, right } => {
|
Expression::Div { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint / rint)),
|
(Value::Int(lint), Value::Int(rint)) => Ok(Value::Int(lint / rint)),
|
||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "Div".to_string(),
|
context: "Div".to_string(),
|
||||||
conflict: format!("can't div {lother:?} and {rother:?}!"),
|
conflict: format!("can't div {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Negate { sub } => {
|
Expression::Negate { sub } => {
|
||||||
let sval = self.evaluate_expression(scope_idx, &sub)?;
|
let sval = self.evaluate_expression(scope_idx, &sub, loc)?;
|
||||||
|
|
||||||
match sval {
|
match sval {
|
||||||
Value::Int(sint) => Ok(Value::Int(-sint)),
|
Value::Int(sint) => Ok(Value::Int(-sint)),
|
||||||
sother => Err(InterpreterError::TypeError {
|
sother => Err(InterpreterError::TypeError {
|
||||||
context: "Negate".to_string(),
|
context: "Negate".to_string(),
|
||||||
conflict: format!("can't negate {sother:?}!"),
|
conflict: format!("can't negate {sother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::BAnd { left, right } => {
|
Expression::BAnd { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Bool(lbool), Value::Bool(rbool)) => Ok(Value::Bool(lbool && rbool)),
|
(Value::Bool(lbool), Value::Bool(rbool)) => Ok(Value::Bool(lbool && rbool)),
|
||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "BAnd".to_string(),
|
context: "BAnd".to_string(),
|
||||||
conflict: format!("can't and together {lother:?} and {rother:?}!"),
|
conflict: format!("can't and together {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::BOr { left, right } => {
|
Expression::BOr { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Bool(lbool), Value::Bool(rbool)) => Ok(Value::Bool(lbool || rbool)),
|
(Value::Bool(lbool), Value::Bool(rbool)) => Ok(Value::Bool(lbool || rbool)),
|
||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "BOr".to_string(),
|
context: "BOr".to_string(),
|
||||||
conflict: format!("can't or together {lother:?} and {rother:?}!"),
|
conflict: format!("can't or together {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::BNot { sub } => {
|
Expression::BNot { sub } => {
|
||||||
let sval = self.evaluate_expression(scope_idx, &sub)?;
|
let sval = self.evaluate_expression(scope_idx, &sub, loc)?;
|
||||||
|
|
||||||
match sval {
|
match sval {
|
||||||
Value::Bool(sbool) => Ok(Value::Bool(!sbool)),
|
Value::Bool(sbool) => Ok(Value::Bool(!sbool)),
|
||||||
sother => Err(InterpreterError::TypeError {
|
sother => Err(InterpreterError::TypeError {
|
||||||
context: "BNot".to_string(),
|
context: "BNot".to_string(),
|
||||||
conflict: format!("can't invert {sother:?}!"),
|
conflict: format!("can't invert {sother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::Equals { left, right } => {
|
Expression::Equals { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::Bool(lbool), Value::Bool(rbool)) => Ok(Value::Bool(lbool == rbool)),
|
(Value::Bool(lbool), Value::Bool(rbool)) => Ok(Value::Bool(lbool == rbool)),
|
||||||
@ -380,13 +382,13 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "Equals".to_string(),
|
context: "Equals".to_string(),
|
||||||
conflict: format!("can't test {lother:?} and {rother:?} for equality!"),
|
conflict: format!("can't test {lother:?} and {rother:?} for equality!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::ListAdd { left, right } => {
|
Expression::ListAdd { left, right } => {
|
||||||
let lval = self.evaluate_expression(scope_idx, &left)?;
|
let lval = self.evaluate_expression(scope_idx, &left, loc)?;
|
||||||
let rval = self.evaluate_expression(scope_idx, &right)?;
|
let rval = self.evaluate_expression(scope_idx, &right, loc)?;
|
||||||
|
|
||||||
match (lval, rval) {
|
match (lval, rval) {
|
||||||
(Value::List(mut llist), Value::List(rlist)) => {
|
(Value::List(mut llist), Value::List(rlist)) => {
|
||||||
@ -396,14 +398,14 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
(lother, rother) => Err(InterpreterError::TypeError {
|
(lother, rother) => Err(InterpreterError::TypeError {
|
||||||
context: "ListAdd".to_string(),
|
context: "ListAdd".to_string(),
|
||||||
conflict: format!("can't list-add {lother:?} and {rother:?}!"),
|
conflict: format!("can't list-add {lother:?} and {rother:?}!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expression::List { elements } => {
|
Expression::List { elements } => {
|
||||||
let mut result = Vec::with_capacity(elements.len());
|
let mut result = Vec::with_capacity(elements.len());
|
||||||
for expr in elements {
|
for expr in elements {
|
||||||
result.push(self.evaluate_expression(scope_idx, expr)?);
|
result.push(self.evaluate_expression(scope_idx, expr, loc)?);
|
||||||
}
|
}
|
||||||
Ok(Value::List(result))
|
Ok(Value::List(result))
|
||||||
}
|
}
|
||||||
@ -411,12 +413,12 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
Expression::StringExpr(sexpr) => {
|
Expression::StringExpr(sexpr) => {
|
||||||
let mut output = String::new();
|
let mut output = String::new();
|
||||||
for piece in &sexpr.pieces {
|
for piece in &sexpr.pieces {
|
||||||
self.evaluate_string_piece(scope_idx, piece, &mut output)?;
|
self.evaluate_string_piece(scope_idx, piece, &mut output, loc)?;
|
||||||
}
|
}
|
||||||
Ok(Value::Str(Arc::new(output)))
|
Ok(Value::Str(Arc::new(output)))
|
||||||
}
|
}
|
||||||
Expression::FieldLookup { obj, ident, loc } => {
|
Expression::FieldLookup { obj, ident, loc } => {
|
||||||
let obj_val = self.evaluate_expression(scope_idx, obj)?;
|
let obj_val = self.evaluate_expression(scope_idx, obj, loc)?;
|
||||||
match obj_val {
|
match obj_val {
|
||||||
Value::Reflective(reflective) => match reflective.reflect_ref() {
|
Value::Reflective(reflective) => match reflective.reflect_ref() {
|
||||||
ReflectRef::Struct(ss) => {
|
ReflectRef::Struct(ss) => {
|
||||||
@ -426,7 +428,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
Err(InterpreterError::TypeError {
|
Err(InterpreterError::TypeError {
|
||||||
context: format!("Field Lookup for '{ident}'"),
|
context: format!("Field Lookup for '{ident}'"),
|
||||||
conflict: format!("{reflective:?} is a reflective struct that does not have that field!"),
|
conflict: format!("{reflective:?} is a reflective struct that does not have that field!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -439,14 +441,14 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
Err(InterpreterError::TypeError {
|
Err(InterpreterError::TypeError {
|
||||||
context: format!("Field Lookup for '{ident}'"),
|
context: format!("Field Lookup for '{ident}'"),
|
||||||
conflict: format!("{reflective:?} is a reflective tuple struct that does not have that field!"),
|
conflict: format!("{reflective:?} is a reflective tuple struct that does not have that field!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Err(InterpreterError::TypeError {
|
Err(InterpreterError::TypeError {
|
||||||
context: format!("Field Lookup for '{ident}'"),
|
context: format!("Field Lookup for '{ident}'"),
|
||||||
conflict: format!("{reflective:?} is a reflective tuple struct that does not have names for field!"),
|
conflict: format!("{reflective:?} is a reflective tuple struct that does not have names for field!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -455,13 +457,13 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
conflict: format!(
|
conflict: format!(
|
||||||
"{reflective:?} is of a reflective type that has no fields!"
|
"{reflective:?} is of a reflective type that has no fields!"
|
||||||
),
|
),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
other => Err(InterpreterError::TypeError {
|
other => Err(InterpreterError::TypeError {
|
||||||
context: format!("Field Lookup for '{ident}'"),
|
context: format!("Field Lookup for '{ident}'"),
|
||||||
conflict: format!("{other:?} is of a type that has no fields!"),
|
conflict: format!("{other:?} is of a type that has no fields!"),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -479,7 +481,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
conflict: format!(
|
conflict: format!(
|
||||||
"No local by that name; the only locals are: {locals_list}."
|
"No local by that name; the only locals are: {locals_list}."
|
||||||
),
|
),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -494,6 +496,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
&self,
|
&self,
|
||||||
val: Value,
|
val: Value,
|
||||||
output: &mut String,
|
output: &mut String,
|
||||||
|
loc: &Locator,
|
||||||
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
||||||
match val {
|
match val {
|
||||||
Value::Str(s) => {
|
Value::Str(s) => {
|
||||||
@ -516,7 +519,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
conflict: format!(
|
conflict: format!(
|
||||||
"Don't know how to write {reflective:?} as a sensible string output."
|
"Don't know how to write {reflective:?} as a sensible string output."
|
||||||
),
|
),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Value::List(_) => {
|
Value::List(_) => {
|
||||||
@ -526,7 +529,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
conflict: format!(
|
conflict: format!(
|
||||||
"Don't know how to write List[...] as a sensible string output."
|
"Don't know how to write List[...] as a sensible string output."
|
||||||
),
|
),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,6 +540,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
scope_idx: usize,
|
scope_idx: usize,
|
||||||
piece: &StringPiece,
|
piece: &StringPiece,
|
||||||
output: &mut String,
|
output: &mut String,
|
||||||
|
loc: &Locator,
|
||||||
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
||||||
match piece {
|
match piece {
|
||||||
StringPiece::Literal(lit) => {
|
StringPiece::Literal(lit) => {
|
||||||
@ -544,8 +548,8 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
StringPiece::Interpolation(expr) => {
|
StringPiece::Interpolation(expr) => {
|
||||||
let val = self.evaluate_expression(scope_idx, expr)?;
|
let val = self.evaluate_expression(scope_idx, expr, loc)?;
|
||||||
self.write_out_value_as_display_string(val, output)?;
|
self.write_out_value_as_display_string(val, output, loc)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
StringPiece::Localise {
|
StringPiece::Localise {
|
||||||
@ -555,7 +559,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
let mut parameters_evaluated = BTreeMap::new();
|
let mut parameters_evaluated = BTreeMap::new();
|
||||||
for (key, expr) in parameters {
|
for (key, expr) in parameters {
|
||||||
parameters_evaluated
|
parameters_evaluated
|
||||||
.insert(key as &str, self.evaluate_expression(scope_idx, expr)?);
|
.insert(key as &str, self.evaluate_expression(scope_idx, expr, loc)?);
|
||||||
}
|
}
|
||||||
|
|
||||||
let localised_text = self
|
let localised_text = self
|
||||||
@ -564,7 +568,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
.map_err(|underlying| InterpreterError::Localisation {
|
.map_err(|underlying| InterpreterError::Localisation {
|
||||||
underlying,
|
underlying,
|
||||||
trans_key: (trans_key as &str).to_owned(),
|
trans_key: (trans_key as &str).to_owned(),
|
||||||
location: "".to_string(),
|
location: loc.clone(),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
output.push_str(&localised_text);
|
output.push_str(&localised_text);
|
||||||
@ -581,7 +585,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
|||||||
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: "".to_string(),
|
location: Locator::empty(),
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
self.run_steps(0, main).await?;
|
self.run_steps(0, main).await?;
|
||||||
|
@ -37,10 +37,10 @@ pub trait OutputSystem {
|
|||||||
pub use crate::engine::Value;
|
pub use crate::engine::Value;
|
||||||
use crate::InterpreterError;
|
use crate::InterpreterError;
|
||||||
|
|
||||||
pub struct LoadedTemplates<L, 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<L>>>>,
|
template_functions: BTreeMap<String, Arc<Vec<Step>>>,
|
||||||
|
|
||||||
localisation: Arc<LS>,
|
localisation: Arc<LS>,
|
||||||
}
|
}
|
||||||
@ -56,7 +56,7 @@ impl Params {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, LS> LoadedTemplates<(), LS> {
|
impl<'a, LS> LoadedTemplates<LS> {
|
||||||
pub fn new(localisation_system: LS) -> Self {
|
pub fn new(localisation_system: LS) -> Self {
|
||||||
LoadedTemplates {
|
LoadedTemplates {
|
||||||
template_functions: Default::default(),
|
template_functions: Default::default(),
|
||||||
@ -103,7 +103,7 @@ impl<'a, LS> LoadedTemplates<(), LS> {
|
|||||||
template_name: &str,
|
template_name: &str,
|
||||||
fragment_name: Option<&str>,
|
fragment_name: Option<&str>,
|
||||||
params: Params,
|
params: Params,
|
||||||
) -> PreparedTemplate<'a, (), LS> {
|
) -> PreparedTemplate<'a, LS> {
|
||||||
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 {
|
||||||
@ -120,14 +120,14 @@ impl<'a, LS> LoadedTemplates<(), LS> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PreparedTemplate<'a, L, LS> {
|
pub struct PreparedTemplate<'a, LS> {
|
||||||
pub(crate) all_instructions: Arc<BTreeMap<String, Arc<Vec<Step<L>>>>>,
|
pub(crate) all_instructions: Arc<BTreeMap<String, Arc<Vec<Step>>>>,
|
||||||
pub(crate) entrypoint: String,
|
pub(crate) entrypoint: String,
|
||||||
pub(crate) scope: Scope<'a, L>,
|
pub(crate) scope: Scope<'a>,
|
||||||
pub localisation: Arc<LS>,
|
pub localisation: Arc<LS>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, L: Sync + Send, LS: LocalisationSystem + Sync + Send> PreparedTemplate<'a, L, LS> {
|
impl<'a, LS: LocalisationSystem + Sync + Send> PreparedTemplate<'a, LS> {
|
||||||
pub async fn render_to_output<O: OutputSystem + Send>(
|
pub async fn render_to_output<O: OutputSystem + Send>(
|
||||||
self,
|
self,
|
||||||
output: O,
|
output: O,
|
||||||
|
@ -5,7 +5,7 @@ pub(crate) mod interface;
|
|||||||
|
|
||||||
pub mod localisation;
|
pub mod localisation;
|
||||||
|
|
||||||
use hornbeam_grammar::ParseError;
|
use hornbeam_grammar::{Locator, ParseError};
|
||||||
use hornbeam_ir::AstToIrError;
|
use hornbeam_ir::AstToIrError;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
@ -15,13 +15,13 @@ pub enum InterpreterError<LE: Debug + Clone, OE: Debug> {
|
|||||||
TypeError {
|
TypeError {
|
||||||
context: String,
|
context: String,
|
||||||
conflict: String,
|
conflict: String,
|
||||||
location: String,
|
location: Locator,
|
||||||
},
|
},
|
||||||
#[error("localisation lookup of {trans_key:?} at {location} failed: {underlying:?}")]
|
#[error("localisation lookup of {trans_key:?} at {location} failed: {underlying:?}")]
|
||||||
Localisation {
|
Localisation {
|
||||||
underlying: LE,
|
underlying: LE,
|
||||||
trans_key: String,
|
trans_key: String,
|
||||||
location: String,
|
location: Locator,
|
||||||
},
|
},
|
||||||
#[error("failed to write to output: {underlying:?}")]
|
#[error("failed to write to output: {underlying:?}")]
|
||||||
OutputError { underlying: OE },
|
OutputError { underlying: OE },
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
use crate::ir::{Step, StepDef};
|
use crate::ir::{Step, StepDef};
|
||||||
use hornbeam_grammar::ast::{Block, Expression, StringExpr, StringPiece, Template};
|
use hornbeam_grammar::ast::{Block, Expression, StringExpr, StringPiece, Template};
|
||||||
use hornbeam_grammar::intern;
|
use hornbeam_grammar::{intern, Locator};
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::collections::btree_map::Entry;
|
use std::collections::btree_map::Entry;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
@ -115,7 +115,7 @@ fn pull_out_entrypoints_from_block<'a>(
|
|||||||
/// Step 2. Compile the AST to IR steps.
|
/// Step 2. Compile the AST to IR steps.
|
||||||
pub(crate) fn compile_functions<'a>(
|
pub(crate) fn compile_functions<'a>(
|
||||||
functions: &BTreeMap<String, Vec<Block>>,
|
functions: &BTreeMap<String, Vec<Block>>,
|
||||||
) -> Result<BTreeMap<String, Vec<Step<()>>>, AstToIrError> {
|
) -> Result<BTreeMap<String, Vec<Step>>, 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();
|
||||||
@ -129,7 +129,7 @@ pub(crate) fn compile_functions<'a>(
|
|||||||
|
|
||||||
fn compile_ast_block_to_steps<'a>(
|
fn compile_ast_block_to_steps<'a>(
|
||||||
block: &Block,
|
block: &Block,
|
||||||
instructions: &mut Vec<Step<()>>,
|
instructions: &mut Vec<Step>,
|
||||||
) -> Result<(), AstToIrError> {
|
) -> Result<(), AstToIrError> {
|
||||||
match block {
|
match block {
|
||||||
Block::HtmlElement(he) => {
|
Block::HtmlElement(he) => {
|
||||||
@ -147,7 +147,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
escape: false,
|
escape: false,
|
||||||
text: intern(text),
|
text: intern(text),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: he.loc.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Write attributes
|
// Write attributes
|
||||||
@ -157,7 +157,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
escape: false,
|
escape: false,
|
||||||
text: intern(format!(" {attr_name}=\"")),
|
text: intern(format!(" {attr_name}=\"")),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: he.loc.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
instructions.push(Step {
|
instructions.push(Step {
|
||||||
@ -165,7 +165,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
escape: true,
|
escape: true,
|
||||||
expr: attr_expr.clone(),
|
expr: attr_expr.clone(),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: he.loc.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
instructions.push(Step {
|
instructions.push(Step {
|
||||||
@ -173,7 +173,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
escape: false,
|
escape: false,
|
||||||
text: intern("\""),
|
text: intern("\""),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: he.loc.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -183,7 +183,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
escape: false,
|
escape: false,
|
||||||
text: intern(">"),
|
text: intern(">"),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: he.loc.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for child in &he.children {
|
for child in &he.children {
|
||||||
@ -195,7 +195,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
escape: false,
|
escape: false,
|
||||||
text: intern(format!("</{}>", he.name)),
|
text: intern(format!("</{}>", he.name)),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: he.loc.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Block::ComponentElement(ce) => {
|
Block::ComponentElement(ce) => {
|
||||||
@ -214,7 +214,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
args: ce.attributes.clone(),
|
args: ce.attributes.clone(),
|
||||||
slots: all_slots_steps,
|
slots: all_slots_steps,
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: ce.loc.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
Block::IfBlock(ifb) => {
|
Block::IfBlock(ifb) => {
|
||||||
@ -235,7 +235,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
true_steps: true_instrs,
|
true_steps: true_instrs,
|
||||||
false_steps: false_instrs,
|
false_steps: false_instrs,
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: ifb.loc.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Block::Text(text) => {
|
Block::Text(text) => {
|
||||||
@ -247,7 +247,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
text: lit.clone(),
|
text: lit.clone(),
|
||||||
escape: true,
|
escape: true,
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: Locator::empty(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
StringPiece::Interpolation(expr) => {
|
StringPiece::Interpolation(expr) => {
|
||||||
@ -256,7 +256,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
expr: expr.clone(),
|
expr: expr.clone(),
|
||||||
escape: true,
|
escape: true,
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: Locator::empty(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
piece @ StringPiece::Localise { .. } => {
|
piece @ StringPiece::Localise { .. } => {
|
||||||
@ -267,7 +267,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
}),
|
}),
|
||||||
escape: true,
|
escape: true,
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: Locator::empty(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -279,7 +279,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
name: slot.name.clone(),
|
name: slot.name.clone(),
|
||||||
optional: slot.optional,
|
optional: slot.optional,
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: slot.loc.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Block::DefineFragment(frag) => {
|
Block::DefineFragment(frag) => {
|
||||||
@ -290,7 +290,7 @@ fn compile_ast_block_to_steps<'a>(
|
|||||||
args: Default::default(),
|
args: Default::default(),
|
||||||
slots: BTreeMap::new(),
|
slots: BTreeMap::new(),
|
||||||
},
|
},
|
||||||
locator: (),
|
locator: frag.loc.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,24 +1,24 @@
|
|||||||
pub use hornbeam_grammar::ast::{Expression, StringPiece};
|
pub use hornbeam_grammar::ast::{Expression, StringPiece};
|
||||||
use hornbeam_grammar::IStr;
|
use hornbeam_grammar::{IStr, Locator};
|
||||||
use serde::Serialize;
|
use serde::Serialize;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct Function<L> {
|
pub struct Function {
|
||||||
pub name: IStr,
|
pub name: IStr,
|
||||||
pub locator: L,
|
pub locator: Option<Locator>,
|
||||||
pub steps: Vec<Step<L>>,
|
pub steps: Vec<Step>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
pub struct Step<L> {
|
pub struct Step {
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
pub def: StepDef<L>,
|
pub def: StepDef,
|
||||||
pub locator: L,
|
pub locator: Locator,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||||
pub enum StepDef<L> {
|
pub enum StepDef {
|
||||||
WriteLiteral {
|
WriteLiteral {
|
||||||
escape: bool,
|
escape: bool,
|
||||||
text: IStr,
|
text: IStr,
|
||||||
@ -29,20 +29,20 @@ pub enum StepDef<L> {
|
|||||||
},
|
},
|
||||||
If {
|
If {
|
||||||
condition: Expression,
|
condition: Expression,
|
||||||
true_steps: Vec<Step<L>>,
|
true_steps: Vec<Step>,
|
||||||
false_steps: Vec<Step<L>>,
|
false_steps: Vec<Step>,
|
||||||
},
|
},
|
||||||
For {
|
For {
|
||||||
iterable: Expression,
|
iterable: Expression,
|
||||||
// TODO!
|
// TODO!
|
||||||
binding: IStr,
|
binding: IStr,
|
||||||
body_steps: Vec<Step<L>>,
|
body_steps: Vec<Step>,
|
||||||
empty_steps: Vec<Step<L>>,
|
empty_steps: Vec<Step>,
|
||||||
},
|
},
|
||||||
Call {
|
Call {
|
||||||
name: IStr,
|
name: IStr,
|
||||||
args: BTreeMap<IStr, Expression>,
|
args: BTreeMap<IStr, Expression>,
|
||||||
slots: BTreeMap<IStr, Vec<Step<L>>>,
|
slots: BTreeMap<IStr, Vec<Step>>,
|
||||||
},
|
},
|
||||||
CallSlotWithParentScope {
|
CallSlotWithParentScope {
|
||||||
name: IStr,
|
name: IStr,
|
||||||
|
@ -22,7 +22,7 @@ pub use ast_to_ir::AstToIrError;
|
|||||||
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, Vec<Step>>, 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 steps in compiled_funcs.values_mut() {
|
||||||
|
@ -48,7 +48,7 @@ fn peephole_opt<T, F: FnMut(&mut [Option<T>]) -> ()>(
|
|||||||
*steps = result;
|
*steps = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_peephole_pass<'a, L, F: Fn(&mut Vec<Step<L>>)>(steps: &mut Vec<Step<L>>, pass: &F) {
|
fn apply_peephole_pass<F: Fn(&mut Vec<Step>)>(steps: &mut Vec<Step>, pass: &F) {
|
||||||
pass(steps);
|
pass(steps);
|
||||||
for step in steps {
|
for step in steps {
|
||||||
match &mut step.def {
|
match &mut step.def {
|
||||||
@ -83,7 +83,7 @@ fn apply_peephole_pass<'a, L, F: Fn(&mut Vec<Step<L>>)>(steps: &mut Vec<Step<L>>
|
|||||||
//// Peephole Passes
|
//// Peephole Passes
|
||||||
|
|
||||||
/// Given a WriteEval step that just writes literals, convert it to a WriteLiteral step.
|
/// Given a WriteEval step that just writes literals, convert it to a WriteLiteral step.
|
||||||
fn pass_write_eval_literal_to_write_literal<L>(steps: &mut Vec<Step<L>>) {
|
fn pass_write_eval_literal_to_write_literal(steps: &mut Vec<Step>) {
|
||||||
'next_step: for step in steps {
|
'next_step: for step in steps {
|
||||||
if let StepDef::WriteEval {
|
if let StepDef::WriteEval {
|
||||||
escape,
|
escape,
|
||||||
@ -110,7 +110,7 @@ fn pass_write_eval_literal_to_write_literal<L>(steps: &mut Vec<Step<L>>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given a WriteLiteral step that escapes the HTML as it is written, precompute the escaped HTML.
|
/// Given a WriteLiteral step that escapes the HTML as it is written, precompute the escaped HTML.
|
||||||
fn pass_write_literal_preescape<L>(steps: &mut Vec<Step<L>>) {
|
fn pass_write_literal_preescape(steps: &mut Vec<Step>) {
|
||||||
for step in steps {
|
for step in steps {
|
||||||
if let StepDef::WriteLiteral { escape, text } = &mut step.def {
|
if let StepDef::WriteLiteral { escape, text } = &mut step.def {
|
||||||
if *escape {
|
if *escape {
|
||||||
@ -125,7 +125,7 @@ fn pass_write_literal_preescape<L>(steps: &mut Vec<Step<L>>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given two adjacent WriteLiteral steps, combine them together.
|
/// Given two adjacent WriteLiteral steps, combine them together.
|
||||||
fn pass_combine_write_literals<L>(steps: &mut Vec<Step<L>>) {
|
fn pass_combine_write_literals(steps: &mut Vec<Step>) {
|
||||||
peephole_opt(steps, 2, |steps| {
|
peephole_opt(steps, 2, |steps| {
|
||||||
let (l, r) = steps.split_at_mut(1);
|
let (l, r) = steps.split_at_mut(1);
|
||||||
let left = l[0].as_mut().unwrap();
|
let left = l[0].as_mut().unwrap();
|
||||||
@ -153,7 +153,7 @@ fn pass_combine_write_literals<L>(steps: &mut Vec<Step<L>>) {
|
|||||||
|
|
||||||
//// Apply all passes in the preferred order
|
//// Apply all passes in the preferred order
|
||||||
|
|
||||||
pub fn apply_all_peephole_passes<L>(steps: &mut Vec<Step<L>>) {
|
pub fn apply_all_peephole_passes(steps: &mut Vec<Step>) {
|
||||||
apply_peephole_pass(steps, &pass_write_eval_literal_to_write_literal);
|
apply_peephole_pass(steps, &pass_write_eval_literal_to_write_literal);
|
||||||
apply_peephole_pass(steps, &pass_write_literal_preescape);
|
apply_peephole_pass(steps, &pass_write_literal_preescape);
|
||||||
apply_peephole_pass(steps, &pass_combine_write_literals);
|
apply_peephole_pass(steps, &pass_combine_write_literals);
|
||||||
@ -167,7 +167,7 @@ mod tests {
|
|||||||
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, Vec<Step>> {
|
||||||
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();
|
||||||
|
@ -6,67 +6,112 @@ TemplateName:
|
|||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<div"
|
text: "<div"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: ">"
|
text: ">"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- Call:
|
- Call:
|
||||||
name: TemplateName__Frag1
|
name: TemplateName__Frag1
|
||||||
args: {}
|
args: {}
|
||||||
slots: {}
|
slots: {}
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
- Call:
|
- Call:
|
||||||
name: TemplateName__Footer
|
name: TemplateName__Footer
|
||||||
args: {}
|
args: {}
|
||||||
slots: {}
|
slots: {}
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 9
|
||||||
|
column: 5
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "</div>"
|
text: "</div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
TemplateName__Footer:
|
TemplateName__Footer:
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: true
|
escape: true
|
||||||
text: Or even adjacent ones
|
text: Or even adjacent ones
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: ""
|
||||||
|
line: 0
|
||||||
|
column: 0
|
||||||
TemplateName__Frag1:
|
TemplateName__Frag1:
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<span"
|
text: "<span"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 9
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: ">"
|
text: ">"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 9
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: true
|
escape: true
|
||||||
text: This is a fragment!!
|
text: This is a fragment!!
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: ""
|
||||||
|
line: 0
|
||||||
|
column: 0
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "</span>"
|
text: "</span>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 9
|
||||||
- Call:
|
- Call:
|
||||||
name: TemplateName__Frag2
|
name: TemplateName__Frag2
|
||||||
args: {}
|
args: {}
|
||||||
slots: {}
|
slots: {}
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 6
|
||||||
|
column: 9
|
||||||
TemplateName__Frag2:
|
TemplateName__Frag2:
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<div"
|
text: "<div"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 7
|
||||||
|
column: 13
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: ">"
|
text: ">"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 7
|
||||||
|
column: 13
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: true
|
escape: true
|
||||||
text: "There's no problem having nested fragments!"
|
text: "There's no problem having nested fragments!"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: ""
|
||||||
|
line: 0
|
||||||
|
column: 0
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "</div>"
|
text: "</div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 7
|
||||||
|
column: 13
|
||||||
|
|
||||||
|
@ -6,58 +6,98 @@ TemplateName:
|
|||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<div"
|
text: "<div"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: " arb=\""
|
text: " arb=\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteEval:
|
- WriteEval:
|
||||||
escape: true
|
escape: true
|
||||||
expr:
|
expr:
|
||||||
Variable:
|
Variable:
|
||||||
name: ritrary
|
name: ritrary
|
||||||
locator: ~
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 47
|
||||||
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "\""
|
text: "\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: " size=\""
|
text: " size=\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteEval:
|
- WriteEval:
|
||||||
escape: true
|
escape: true
|
||||||
expr:
|
expr:
|
||||||
IntLiteral:
|
IntLiteral:
|
||||||
val: 42
|
val: 42
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "\""
|
text: "\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: " stringy=\""
|
text: " stringy=\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteEval:
|
- WriteEval:
|
||||||
escape: true
|
escape: true
|
||||||
expr:
|
expr:
|
||||||
StringExpr:
|
StringExpr:
|
||||||
pieces:
|
pieces:
|
||||||
- Literal: yup
|
- Literal: yup
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "\""
|
text: "\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: ">"
|
text: ">"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: true
|
escape: true
|
||||||
text: This is a div with a few extras
|
text: This is a div with a few extras
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: ""
|
||||||
|
line: 0
|
||||||
|
column: 0
|
||||||
- Call:
|
- Call:
|
||||||
name: OtherComponent
|
name: OtherComponent
|
||||||
args:
|
args:
|
||||||
@ -71,11 +111,21 @@ TemplateName:
|
|||||||
param3:
|
param3:
|
||||||
Variable:
|
Variable:
|
||||||
name: three
|
name: three
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 52
|
||||||
slots:
|
slots:
|
||||||
main: []
|
main: []
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 5
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "</div>"
|
text: "</div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
@ -9,12 +9,24 @@ TemplateName:
|
|||||||
- DefineFragment:
|
- DefineFragment:
|
||||||
name: TemplateName__Frag1
|
name: TemplateName__Frag1
|
||||||
blocks: []
|
blocks: []
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
- DefineFragment:
|
- DefineFragment:
|
||||||
name: TemplateName__Footer
|
name: TemplateName__Footer
|
||||||
blocks: []
|
blocks: []
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 9
|
||||||
|
column: 5
|
||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
TemplateName__Footer:
|
TemplateName__Footer:
|
||||||
- Text:
|
- Text:
|
||||||
pieces:
|
pieces:
|
||||||
@ -29,9 +41,17 @@ TemplateName__Frag1:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 9
|
||||||
- DefineFragment:
|
- DefineFragment:
|
||||||
name: TemplateName__Frag2
|
name: TemplateName__Frag2
|
||||||
blocks: []
|
blocks: []
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 6
|
||||||
|
column: 9
|
||||||
TemplateName__Frag2:
|
TemplateName__Frag2:
|
||||||
- HtmlElement:
|
- HtmlElement:
|
||||||
name: div
|
name: div
|
||||||
@ -42,4 +62,8 @@ TemplateName__Frag2:
|
|||||||
classes: []
|
classes: []
|
||||||
dom_id: ~
|
dom_id: ~
|
||||||
attributes: {}
|
attributes: {}
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 7
|
||||||
|
column: 13
|
||||||
|
|
||||||
|
@ -6,39 +6,63 @@ TemplateName:
|
|||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<div>"
|
text: "<div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- Call:
|
- Call:
|
||||||
name: TemplateName__Frag1
|
name: TemplateName__Frag1
|
||||||
args: {}
|
args: {}
|
||||||
slots: {}
|
slots: {}
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 3
|
||||||
|
column: 5
|
||||||
- Call:
|
- Call:
|
||||||
name: TemplateName__Footer
|
name: TemplateName__Footer
|
||||||
args: {}
|
args: {}
|
||||||
slots: {}
|
slots: {}
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 9
|
||||||
|
column: 5
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "</div>"
|
text: "</div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
TemplateName__Footer:
|
TemplateName__Footer:
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: Or even adjacent ones
|
text: Or even adjacent ones
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: ""
|
||||||
|
line: 0
|
||||||
|
column: 0
|
||||||
TemplateName__Frag1:
|
TemplateName__Frag1:
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<span>This is a fragment!!</span>"
|
text: "<span>This is a fragment!!</span>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 9
|
||||||
- Call:
|
- Call:
|
||||||
name: TemplateName__Frag2
|
name: TemplateName__Frag2
|
||||||
args: {}
|
args: {}
|
||||||
slots: {}
|
slots: {}
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 6
|
||||||
|
column: 9
|
||||||
TemplateName__Frag2:
|
TemplateName__Frag2:
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<div>There's no problem having <<nested>> fragments!</div>"
|
text: "<div>There's no problem having <<nested>> fragments!</div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 7
|
||||||
|
column: 13
|
||||||
|
|
||||||
|
@ -6,27 +6,46 @@ TemplateName:
|
|||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "<div arb=\""
|
text: "<div arb=\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteEval:
|
- WriteEval:
|
||||||
escape: true
|
escape: true
|
||||||
expr:
|
expr:
|
||||||
Variable:
|
Variable:
|
||||||
name: ritrary
|
name: ritrary
|
||||||
locator: ~
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 47
|
||||||
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "\" size=\""
|
text: "\" size=\""
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteEval:
|
- WriteEval:
|
||||||
escape: true
|
escape: true
|
||||||
expr:
|
expr:
|
||||||
IntLiteral:
|
IntLiteral:
|
||||||
val: 42
|
val: 42
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "\" stringy=\"yup\">This is a div with a few extras"
|
text: "\" stringy=\"yup\">This is a div with a few extras"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
- Call:
|
- Call:
|
||||||
name: OtherComponent
|
name: OtherComponent
|
||||||
args:
|
args:
|
||||||
@ -40,11 +59,21 @@ TemplateName:
|
|||||||
param3:
|
param3:
|
||||||
Variable:
|
Variable:
|
||||||
name: three
|
name: three
|
||||||
|
loc:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 52
|
||||||
slots:
|
slots:
|
||||||
main: []
|
main: []
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 4
|
||||||
|
column: 5
|
||||||
- WriteLiteral:
|
- WriteLiteral:
|
||||||
escape: false
|
escape: false
|
||||||
text: "</div>"
|
text: "</div>"
|
||||||
locator: ~
|
locator:
|
||||||
|
filename: inp
|
||||||
|
line: 2
|
||||||
|
column: 1
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user