Replace cows with arc-interned strings
This commit is contained in:
parent
b5d424eb1c
commit
67545f9e8e
92
Cargo.lock
generated
92
Cargo.lock
generated
@ -2,6 +2,15 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.3.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8fd72866655d1904d6b0997d0b07ba561047d070fbe29de039031c641b61217"
|
||||
dependencies = [
|
||||
"const-random",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ahash"
|
||||
version = "0.7.6"
|
||||
@ -22,6 +31,18 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-interner"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "655ae79d4a7661f2f9a8f6daf95af32897eafdea938df06aeb127cea02b5f4ac"
|
||||
dependencies = [
|
||||
"ahash 0.3.8",
|
||||
"dashmap",
|
||||
"once_cell",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "arc-swap"
|
||||
version = "1.6.0"
|
||||
@ -109,7 +130,7 @@ version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6e9aa1866c1cf7ee000f281ce9e90d02d701f5c7380a107252017e58e2f5246"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
"getrandom",
|
||||
"hashbrown",
|
||||
"instant",
|
||||
@ -166,6 +187,28 @@ dependencies = [
|
||||
"windows-sys 0.42.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "368a7a772ead6ce7e1de82bfb04c485f3db8ec744f72925af5735e29a22cc18e"
|
||||
dependencies = [
|
||||
"const-random-macro",
|
||||
"proc-macro-hack",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "const-random-macro"
|
||||
version = "0.1.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9d7d6ab3c3a2282db210df5f02c4dab6e0a7057af0fb7ebd4070f30fe05c0ddb"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
"once_cell",
|
||||
"proc-macro-hack",
|
||||
"tiny-keccak",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.5"
|
||||
@ -175,6 +218,12 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "crunchy"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
|
||||
|
||||
[[package]]
|
||||
name = "crypto-common"
|
||||
version = "0.1.6"
|
||||
@ -185,6 +234,16 @@ dependencies = [
|
||||
"typenum",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dashmap"
|
||||
version = "4.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"num_cpus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.10.6"
|
||||
@ -379,7 +438,7 @@ version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
dependencies = [
|
||||
"ahash",
|
||||
"ahash 0.7.6",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -389,6 +448,15 @@ version = "0.4.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hornbeam"
|
||||
version = "0.1.0"
|
||||
@ -400,6 +468,7 @@ dependencies = [
|
||||
name = "hornbeam_grammar"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"arc-interner",
|
||||
"insta",
|
||||
"lazy_static",
|
||||
"pest",
|
||||
@ -578,6 +647,16 @@ version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b"
|
||||
dependencies = [
|
||||
"hermit-abi",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.17.1"
|
||||
@ -894,6 +973,15 @@ dependencies = [
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tiny-keccak"
|
||||
version = "2.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2c9d3793400a45f954c52e73d068316d76b6f4e36977e3fcebb13a2721e80237"
|
||||
dependencies = [
|
||||
"crunchy",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tinystr"
|
||||
version = "0.7.1"
|
||||
|
@ -11,6 +11,7 @@ pest_derive = "2.5.5"
|
||||
pest_consume = "1.1.3"
|
||||
lazy_static = "1.4.0"
|
||||
serde = { version = "1.0.152", features = ["derive"] }
|
||||
arc-interner = "0.7.0"
|
||||
|
||||
[dev-dependencies]
|
||||
insta = { version = "1.28.0", features = ["yaml"] }
|
||||
|
@ -1,146 +1,146 @@
|
||||
use crate::IStr;
|
||||
use serde::Serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct Template<'a> {
|
||||
pub blocks: Vec<Block<'a>>,
|
||||
pub struct Template {
|
||||
pub blocks: Vec<Block>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum Block<'a> {
|
||||
HtmlElement(HtmlElement<'a>),
|
||||
ComponentElement(ComponentElement<'a>),
|
||||
IfBlock(IfBlock<'a>),
|
||||
Text(StringExpr<'a>),
|
||||
DefineExpandSlot(DefineExpandSlot<'a>),
|
||||
DefineFragment(DefineFragment<'a>),
|
||||
pub enum Block {
|
||||
HtmlElement(HtmlElement),
|
||||
ComponentElement(ComponentElement),
|
||||
IfBlock(IfBlock),
|
||||
Text(StringExpr),
|
||||
DefineExpandSlot(DefineExpandSlot),
|
||||
DefineFragment(DefineFragment),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct HtmlElement<'a> {
|
||||
pub name: Cow<'a, str>,
|
||||
pub children: Vec<Block<'a>>,
|
||||
pub classes: Vec<Cow<'a, str>>,
|
||||
pub dom_id: Option<Cow<'a, str>>,
|
||||
pub attributes: BTreeMap<Cow<'a, str>, Expression<'a>>,
|
||||
pub struct HtmlElement {
|
||||
pub name: IStr,
|
||||
pub children: Vec<Block>,
|
||||
pub classes: Vec<IStr>,
|
||||
pub dom_id: Option<IStr>,
|
||||
pub attributes: BTreeMap<IStr, Expression>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct ComponentElement<'a> {
|
||||
pub name: Cow<'a, str>,
|
||||
pub slots: BTreeMap<Cow<'a, str>, Vec<Block<'a>>>,
|
||||
pub attributes: BTreeMap<Cow<'a, str>, Expression<'a>>,
|
||||
pub struct ComponentElement {
|
||||
pub name: IStr,
|
||||
pub slots: BTreeMap<IStr, Vec<Block>>,
|
||||
pub attributes: BTreeMap<IStr, Expression>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct IfBlock<'a> {
|
||||
pub condition: Expression<'a>,
|
||||
pub blocks: Vec<Block<'a>>,
|
||||
pub else_blocks: Vec<Block<'a>>,
|
||||
pub struct IfBlock {
|
||||
pub condition: Expression,
|
||||
pub blocks: Vec<Block>,
|
||||
pub else_blocks: Vec<Block>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct DefineExpandSlot<'a> {
|
||||
pub name: Cow<'a, str>,
|
||||
pub struct DefineExpandSlot {
|
||||
pub name: IStr,
|
||||
pub optional: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct DefineFragment<'a> {
|
||||
pub name: Cow<'a, str>,
|
||||
pub blocks: Vec<Block<'a>>,
|
||||
pub struct DefineFragment {
|
||||
pub name: IStr,
|
||||
pub blocks: Vec<Block>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct StringExpr<'a> {
|
||||
pub pieces: Vec<StringPiece<'a>>,
|
||||
pub struct StringExpr {
|
||||
pub pieces: Vec<StringPiece>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum StringPiece<'a> {
|
||||
Literal(Cow<'a, str>),
|
||||
Interpolation(Expression<'a>),
|
||||
pub enum StringPiece {
|
||||
Literal(IStr),
|
||||
Interpolation(Expression),
|
||||
Localise {
|
||||
trans_key: Cow<'a, str>,
|
||||
parameters: BTreeMap<Cow<'a, str>, Expression<'a>>,
|
||||
trans_key: IStr,
|
||||
parameters: BTreeMap<IStr, Expression>,
|
||||
},
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum Expression<'a> {
|
||||
pub enum Expression {
|
||||
// Arithmetic Operators
|
||||
Add {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
Sub {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
Mul {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
Div {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
Negate {
|
||||
sub: Box<Expression<'a>>,
|
||||
sub: Box<Expression>,
|
||||
},
|
||||
|
||||
// Boolean Operators
|
||||
BAnd {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
BOr {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
BNot {
|
||||
sub: Box<Expression<'a>>,
|
||||
sub: Box<Expression>,
|
||||
},
|
||||
|
||||
// Comparators
|
||||
Equals {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
|
||||
// Other Operators
|
||||
ListAdd {
|
||||
left: Box<Expression<'a>>,
|
||||
right: Box<Expression<'a>>,
|
||||
left: Box<Expression>,
|
||||
right: Box<Expression>,
|
||||
},
|
||||
|
||||
// Literals
|
||||
List {
|
||||
elements: Vec<Expression<'a>>,
|
||||
elements: Vec<Expression>,
|
||||
},
|
||||
IntLiteral {
|
||||
val: i64,
|
||||
},
|
||||
StringExpr(StringExpr<'a>),
|
||||
StringExpr(StringExpr),
|
||||
|
||||
// Relatives
|
||||
FieldLookup {
|
||||
obj: Box<Expression<'a>>,
|
||||
ident: Cow<'a, str>,
|
||||
obj: Box<Expression>,
|
||||
ident: IStr,
|
||||
},
|
||||
MethodCall {
|
||||
obj: Box<Expression<'a>>,
|
||||
ident: Cow<'a, str>,
|
||||
args: Vec<Expression<'a>>,
|
||||
obj: Box<Expression>,
|
||||
ident: IStr,
|
||||
args: Vec<Expression>,
|
||||
},
|
||||
|
||||
// Other Primaries
|
||||
Variable {
|
||||
name: Cow<'a, str>,
|
||||
name: IStr,
|
||||
},
|
||||
FunctionCall {
|
||||
name: Cow<'a, str>,
|
||||
args: Vec<Expression<'a>>,
|
||||
name: IStr,
|
||||
args: Vec<Expression>,
|
||||
},
|
||||
}
|
||||
|
@ -1,7 +1,14 @@
|
||||
pub mod ast;
|
||||
mod parser;
|
||||
|
||||
use arc_interner::ArcIntern;
|
||||
pub use parser::parse_template;
|
||||
|
||||
use parser::Rule;
|
||||
pub type ParseError = pest::error::Error<Rule>;
|
||||
|
||||
pub type IStr = ArcIntern<String>;
|
||||
|
||||
pub fn intern(s: impl Into<String>) -> ArcIntern<String> {
|
||||
ArcIntern::new(s.into())
|
||||
}
|
||||
|
@ -4,12 +4,12 @@ use crate::ast::{
|
||||
Block, ComponentElement, DefineExpandSlot, DefineFragment, Expression, HtmlElement, IfBlock,
|
||||
StringExpr, StringPiece, Template,
|
||||
};
|
||||
use crate::{intern, IStr};
|
||||
use lazy_static::lazy_static;
|
||||
use pest::error::ErrorVariant;
|
||||
use pest::pratt_parser::{Assoc, Op, PrattParser};
|
||||
use pest::Span;
|
||||
use pest_consume::{match_nodes, Error as PCError, Parser};
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
@ -100,7 +100,7 @@ impl HornbeamParser {
|
||||
if !supply_slots.is_empty() {
|
||||
let mut slots = BTreeMap::new();
|
||||
for (slot_name, slot_content_blocks, _slot_span) in supply_slots {
|
||||
slots.insert(Cow::from(slot_name), slot_content_blocks);
|
||||
slots.insert(slot_name, slot_content_blocks);
|
||||
}
|
||||
Block::ComponentElement(ComponentElement {
|
||||
name,
|
||||
@ -109,7 +109,7 @@ impl HornbeamParser {
|
||||
})
|
||||
} else {
|
||||
let mut slots = BTreeMap::new();
|
||||
slots.insert(Cow::from("main"), blocks);
|
||||
slots.insert(intern("main"), blocks);
|
||||
Block::ComponentElement(ComponentElement {
|
||||
name,
|
||||
slots,
|
||||
@ -145,11 +145,11 @@ impl HornbeamParser {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn ElementName(input: Node) -> PCResult<Cow<str>> {
|
||||
Ok(Cow::from(input.as_str()))
|
||||
fn ElementName(input: Node) -> PCResult<IStr> {
|
||||
Ok(intern(input.as_str()))
|
||||
}
|
||||
|
||||
fn SupplySlot(input: Node) -> PCResult<(Cow<str>, Vec<Block>, Span)> {
|
||||
fn SupplySlot(input: Node) -> PCResult<(IStr, Vec<Block>, Span)> {
|
||||
let in_span = input.as_span();
|
||||
match_nodes!(input.into_children();
|
||||
[Identifier(ident), blocks..] => {
|
||||
@ -159,17 +159,17 @@ impl HornbeamParser {
|
||||
)
|
||||
}
|
||||
|
||||
fn Identifier(input: Node) -> PCResult<Cow<str>> {
|
||||
Ok(Cow::from(input.as_str()))
|
||||
fn Identifier(input: Node) -> PCResult<IStr> {
|
||||
Ok(intern(input.as_str()))
|
||||
}
|
||||
fn LocalisationIdentifier(input: Node) -> PCResult<Cow<str>> {
|
||||
Ok(Cow::from(input.as_str()))
|
||||
fn LocalisationIdentifier(input: Node) -> PCResult<IStr> {
|
||||
Ok(intern(input.as_str()))
|
||||
}
|
||||
fn CssClass(input: Node) -> PCResult<Cow<str>> {
|
||||
Ok(Cow::from(input.as_str()))
|
||||
fn CssClass(input: Node) -> PCResult<IStr> {
|
||||
Ok(intern(input.as_str()))
|
||||
}
|
||||
fn DomId(input: Node) -> PCResult<Cow<str>> {
|
||||
Ok(Cow::from(input.as_str()))
|
||||
fn DomId(input: Node) -> PCResult<IStr> {
|
||||
Ok(intern(input.as_str()))
|
||||
}
|
||||
|
||||
fn Text(input: Node) -> PCResult<Block> {
|
||||
@ -189,10 +189,10 @@ impl HornbeamParser {
|
||||
Rule::SingleStringContent
|
||||
| Rule::DoubleStringContent
|
||||
| Rule::BlockStringContent => {
|
||||
pieces.push(StringPiece::Literal(Cow::from(node.as_str())));
|
||||
pieces.push(StringPiece::Literal(intern(node.as_str())));
|
||||
}
|
||||
Rule::BlockStringNewline => {
|
||||
pieces.push(StringPiece::Literal(Cow::from("\n")));
|
||||
pieces.push(StringPiece::Literal(intern("\n")));
|
||||
}
|
||||
Rule::ParameterisedLocalisation => {
|
||||
let (trans_key, parameters) = match_nodes!(node.into_children();
|
||||
@ -210,28 +210,28 @@ impl HornbeamParser {
|
||||
Ok(StringExpr { pieces })
|
||||
}
|
||||
|
||||
fn KVPair(input: Node) -> PCResult<(Cow<str>, Expression)> {
|
||||
fn KVPair(input: Node) -> PCResult<(IStr, Expression)> {
|
||||
Ok(match_nodes!(input.into_children();
|
||||
[Identifier(key), Expr(value)] => (key, value),
|
||||
))
|
||||
}
|
||||
|
||||
fn MapLiteral(input: Node) -> PCResult<BTreeMap<Cow<str>, Expression>> {
|
||||
fn MapLiteral(input: Node) -> PCResult<BTreeMap<IStr, Expression>> {
|
||||
Ok(match_nodes!(input.into_children();
|
||||
[KVPair(kv_pair)..] => kv_pair.collect()
|
||||
))
|
||||
}
|
||||
|
||||
fn SEscape(input: Node) -> PCResult<Cow<str>> {
|
||||
fn SEscape(input: Node) -> PCResult<IStr> {
|
||||
let esc = input.as_str();
|
||||
Ok(match esc {
|
||||
"\\\\" | "\\'" | "\\\"" | "\\$" => Cow::from(&esc[1..2]),
|
||||
"\\\\" | "\\'" | "\\\"" | "\\$" => intern(&esc[1..2]),
|
||||
other => unimplemented!("Unimplemented escape sequence {other:?}! This is a bug."),
|
||||
})
|
||||
}
|
||||
|
||||
fn Variable(input: Node) -> PCResult<Expression> {
|
||||
let name = Cow::from(input.into_children().single()?.as_str());
|
||||
let name = intern(input.into_children().single()?.as_str());
|
||||
Ok(Expression::Variable { name })
|
||||
}
|
||||
|
||||
@ -261,7 +261,7 @@ impl HornbeamParser {
|
||||
.map_postfix(|lhs, op| Ok(match op.as_rule() {
|
||||
Rule::unwrap => unimplemented!("unimp unwrap"),
|
||||
Rule::FieldLookup => {
|
||||
let ident = Cow::from(Node::new(op).into_children().single()?.as_str());
|
||||
let ident = intern(Node::new(op).into_children().single()?.as_str());
|
||||
Expression::FieldLookup { obj: Box::new(lhs?), ident }
|
||||
},
|
||||
Rule::MethodCall => {
|
||||
@ -316,7 +316,7 @@ impl HornbeamParser {
|
||||
}
|
||||
|
||||
impl HornbeamParser {
|
||||
fn helper_blocks<'a>(input: impl Iterator<Item = Node<'a>>) -> PCResult<Vec<Block<'a>>> {
|
||||
fn helper_blocks<'a>(input: impl Iterator<Item = Node<'a>>) -> PCResult<Vec<Block>> {
|
||||
let mut result = Vec::with_capacity(input.size_hint().0);
|
||||
for child in input {
|
||||
if let Some(block) = HornbeamParser::helper_block(child)? {
|
||||
|
@ -14,7 +14,7 @@ use std::sync::Arc;
|
||||
|
||||
pub(crate) struct FilledSlot<'a, L> {
|
||||
pub scope_idx: usize,
|
||||
pub steps: &'a [Step<'a, L>],
|
||||
pub steps: &'a [Step<L>],
|
||||
}
|
||||
|
||||
pub(crate) struct Scope<'a, L> {
|
||||
@ -24,7 +24,7 @@ pub(crate) struct Scope<'a, L> {
|
||||
|
||||
pub(crate) struct Interpreter<'a, L, O, LS> {
|
||||
pub(crate) entrypoint: String,
|
||||
pub(crate) program: &'a BTreeMap<String, Arc<Vec<Step<'a, L>>>>,
|
||||
pub(crate) program: &'a BTreeMap<String, Arc<Vec<Step<L>>>>,
|
||||
pub(crate) output: O,
|
||||
pub(crate) localisation: Arc<LS>,
|
||||
pub(crate) scopes: Vec<Scope<'a, L>>,
|
||||
@ -97,7 +97,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
||||
pub async fn run_steps(
|
||||
&mut self,
|
||||
scope_idx: usize,
|
||||
steps: &'a [Step<'a, L>],
|
||||
steps: &'a [Step<L>],
|
||||
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
||||
for step in steps {
|
||||
self.run_step(scope_idx, step).await?;
|
||||
@ -108,14 +108,14 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
||||
pub async fn run_step(
|
||||
&mut self,
|
||||
scope_idx: usize,
|
||||
step: &'a Step<'a, L>,
|
||||
step: &'a Step<L>,
|
||||
) -> Result<(), InterpreterError<LS::Error, O::Error>> {
|
||||
match &step.def {
|
||||
StepDef::WriteLiteral { escape, text } => {
|
||||
if *escape {
|
||||
// Unlikely to be hit: peephole optimisation should escape literals wherever
|
||||
// possible.
|
||||
let escaped = html_escape::encode_safe(text);
|
||||
let escaped = html_escape::encode_safe(text as &str);
|
||||
self.output
|
||||
.write(&escaped)
|
||||
.await
|
||||
@ -265,7 +265,7 @@ impl<'a, L: Sync + Send, O: OutputSystem + Send, LS: LocalisationSystem + Sync +
|
||||
pub fn evaluate_expression(
|
||||
&self,
|
||||
scope_idx: usize,
|
||||
expr: &'a Expression<'a>,
|
||||
expr: &'a Expression,
|
||||
) -> Result<Value, InterpreterError<LS::Error, O::Error>> {
|
||||
match expr {
|
||||
Expression::Add { left, right } => {
|
||||
|
@ -37,10 +37,10 @@ pub trait OutputSystem {
|
||||
pub use crate::engine::Value;
|
||||
use crate::InterpreterError;
|
||||
|
||||
pub struct LoadedTemplates<'a, L, LS> {
|
||||
pub struct LoadedTemplates<L, LS> {
|
||||
// todo might be tempted to use e.g. ouroboros here, to keep the file source adjacent?
|
||||
// or do we just staticify?
|
||||
template_functions: BTreeMap<String, Arc<Vec<Step<'a, L>>>>,
|
||||
template_functions: BTreeMap<String, Arc<Vec<Step<L>>>>,
|
||||
|
||||
localisation: Arc<LS>,
|
||||
}
|
||||
@ -56,7 +56,7 @@ impl Params {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, LS> LoadedTemplates<'a, (), LS> {
|
||||
impl<'a, LS> LoadedTemplates<(), LS> {
|
||||
pub fn new(localisation_system: LS) -> Self {
|
||||
LoadedTemplates {
|
||||
template_functions: Default::default(),
|
||||
@ -72,7 +72,7 @@ impl<'a, LS> LoadedTemplates<'a, (), LS> {
|
||||
let keys_to_remove: Vec<String> = self
|
||||
.template_functions
|
||||
.range(prefix.to_owned()..)
|
||||
.map(|(k, v)| k)
|
||||
.map(|(k, _v)| k)
|
||||
.take_while(|k| k.starts_with(&prefix))
|
||||
.cloned()
|
||||
.collect();
|
||||
@ -120,7 +120,7 @@ impl<'a, LS> LoadedTemplates<'a, (), LS> {
|
||||
}
|
||||
|
||||
pub struct PreparedTemplate<'a, L, LS> {
|
||||
pub(crate) all_instructions: Arc<BTreeMap<String, Arc<Vec<Step<'a, L>>>>>,
|
||||
pub(crate) all_instructions: Arc<BTreeMap<String, Arc<Vec<Step<L>>>>>,
|
||||
pub(crate) entrypoint: String,
|
||||
pub(crate) scope: Scope<'a, L>,
|
||||
pub localisation: Arc<LS>,
|
||||
|
@ -1,8 +1,10 @@
|
||||
use crate::ir::{Step, StepDef};
|
||||
use hornbeam_grammar::ast::{Block, Expression, StringExpr, StringPiece, Template};
|
||||
use hornbeam_grammar::intern;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::btree_map::Entry;
|
||||
use std::collections::BTreeMap;
|
||||
use std::ops::Deref;
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Error, Debug, Clone)]
|
||||
@ -23,9 +25,9 @@ pub enum AstToIrError {
|
||||
/// Fragments are extracted to `{template_name}__{fragment_name}`.
|
||||
/// The top-level template is extracted to `{template_name}`.
|
||||
pub(crate) fn pull_out_entrypoints<'a>(
|
||||
mut template: Template<'a>,
|
||||
mut template: Template,
|
||||
template_name: &str,
|
||||
) -> Result<BTreeMap<String, Vec<Block<'a>>>, AstToIrError> {
|
||||
) -> Result<BTreeMap<String, Vec<Block>>, AstToIrError> {
|
||||
let mut functions = BTreeMap::new();
|
||||
|
||||
for child in &mut template.blocks {
|
||||
@ -51,9 +53,9 @@ pub(crate) fn pull_out_entrypoints<'a>(
|
||||
}
|
||||
|
||||
fn pull_out_entrypoints_from_block<'a>(
|
||||
block: &mut Block<'a>,
|
||||
block: &mut Block,
|
||||
template_name: &str,
|
||||
target: &mut BTreeMap<String, Vec<Block<'a>>>,
|
||||
target: &mut BTreeMap<String, Vec<Block>>,
|
||||
) -> Result<(), AstToIrError> {
|
||||
match block {
|
||||
Block::HtmlElement(he) => {
|
||||
@ -86,7 +88,7 @@ fn pull_out_entrypoints_from_block<'a>(
|
||||
let new_func_name = format!("{template_name}__{}", frag.name);
|
||||
|
||||
// Canonicalise the fragment name that is left in the AST nodes.
|
||||
frag.name = Cow::from(new_func_name.clone());
|
||||
frag.name = intern(new_func_name.clone());
|
||||
|
||||
match target.entry(new_func_name) {
|
||||
Entry::Vacant(ve) => {
|
||||
@ -112,8 +114,8 @@ fn pull_out_entrypoints_from_block<'a>(
|
||||
|
||||
/// Step 2. Compile the AST to IR steps.
|
||||
pub(crate) fn compile_functions<'a>(
|
||||
functions: &BTreeMap<String, Vec<Block<'a>>>,
|
||||
) -> Result<BTreeMap<String, Vec<Step<'a, ()>>>, AstToIrError> {
|
||||
functions: &BTreeMap<String, Vec<Block>>,
|
||||
) -> Result<BTreeMap<String, Vec<Step<()>>>, AstToIrError> {
|
||||
let mut result = BTreeMap::new();
|
||||
for (func_name, func_blocks) in functions {
|
||||
let mut steps = Vec::new();
|
||||
@ -126,12 +128,12 @@ pub(crate) fn compile_functions<'a>(
|
||||
}
|
||||
|
||||
fn compile_ast_block_to_steps<'a>(
|
||||
block: &Block<'a>,
|
||||
instructions: &mut Vec<Step<'a, ()>>,
|
||||
block: &Block,
|
||||
instructions: &mut Vec<Step<()>>,
|
||||
) -> Result<(), AstToIrError> {
|
||||
match block {
|
||||
Block::HtmlElement(he) => {
|
||||
let text = if he.name == "html" {
|
||||
let text = if he.name.deref() == "html" {
|
||||
Cow::from("<!DOCTYPE html><html")
|
||||
} else {
|
||||
Cow::from(format!("<{}", he.name))
|
||||
@ -143,7 +145,7 @@ fn compile_ast_block_to_steps<'a>(
|
||||
instructions.push(Step {
|
||||
def: StepDef::WriteLiteral {
|
||||
escape: false,
|
||||
text,
|
||||
text: intern(text),
|
||||
},
|
||||
locator: (),
|
||||
});
|
||||
@ -153,7 +155,7 @@ fn compile_ast_block_to_steps<'a>(
|
||||
instructions.push(Step {
|
||||
def: StepDef::WriteLiteral {
|
||||
escape: false,
|
||||
text: Cow::from(format!(" {attr_name}=\"")),
|
||||
text: intern(format!(" {attr_name}=\"")),
|
||||
},
|
||||
locator: (),
|
||||
});
|
||||
@ -169,7 +171,7 @@ fn compile_ast_block_to_steps<'a>(
|
||||
instructions.push(Step {
|
||||
def: StepDef::WriteLiteral {
|
||||
escape: false,
|
||||
text: Cow::from("\""),
|
||||
text: intern("\""),
|
||||
},
|
||||
locator: (),
|
||||
});
|
||||
@ -179,7 +181,7 @@ fn compile_ast_block_to_steps<'a>(
|
||||
instructions.push(Step {
|
||||
def: StepDef::WriteLiteral {
|
||||
escape: false,
|
||||
text: Cow::from(">"),
|
||||
text: intern(">"),
|
||||
},
|
||||
locator: (),
|
||||
});
|
||||
@ -191,7 +193,7 @@ fn compile_ast_block_to_steps<'a>(
|
||||
instructions.push(Step {
|
||||
def: StepDef::WriteLiteral {
|
||||
escape: false,
|
||||
text: Cow::from(format!("</{}>", he.name)),
|
||||
text: intern(format!("</{}>", he.name)),
|
||||
},
|
||||
locator: (),
|
||||
});
|
||||
|
@ -1,51 +1,51 @@
|
||||
pub use hornbeam_grammar::ast::{Expression, StringPiece};
|
||||
use hornbeam_grammar::IStr;
|
||||
use serde::Serialize;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::BTreeMap;
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct Function<'a, L> {
|
||||
pub name: Cow<'a, str>,
|
||||
pub struct Function<L> {
|
||||
pub name: IStr,
|
||||
pub locator: L,
|
||||
pub steps: Vec<Step<'a, L>>,
|
||||
pub steps: Vec<Step<L>>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub struct Step<'a, L> {
|
||||
pub struct Step<L> {
|
||||
#[serde(flatten)]
|
||||
pub def: StepDef<'a, L>,
|
||||
pub def: StepDef<L>,
|
||||
pub locator: L,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
|
||||
pub enum StepDef<'a, L> {
|
||||
pub enum StepDef<L> {
|
||||
WriteLiteral {
|
||||
escape: bool,
|
||||
text: Cow<'a, str>,
|
||||
text: IStr,
|
||||
},
|
||||
WriteEval {
|
||||
escape: bool,
|
||||
expr: Expression<'a>,
|
||||
expr: Expression,
|
||||
},
|
||||
If {
|
||||
condition: Expression<'a>,
|
||||
true_steps: Vec<Step<'a, L>>,
|
||||
false_steps: Vec<Step<'a, L>>,
|
||||
condition: Expression,
|
||||
true_steps: Vec<Step<L>>,
|
||||
false_steps: Vec<Step<L>>,
|
||||
},
|
||||
For {
|
||||
iterable: Expression<'a>,
|
||||
iterable: Expression,
|
||||
// TODO!
|
||||
binding: Cow<'a, str>,
|
||||
body_steps: Vec<Step<'a, L>>,
|
||||
empty_steps: Vec<Step<'a, L>>,
|
||||
binding: IStr,
|
||||
body_steps: Vec<Step<L>>,
|
||||
empty_steps: Vec<Step<L>>,
|
||||
},
|
||||
Call {
|
||||
name: Cow<'a, str>,
|
||||
args: BTreeMap<Cow<'a, str>, Expression<'a>>,
|
||||
slots: BTreeMap<Cow<'a, str>, Vec<Step<'a, L>>>,
|
||||
name: IStr,
|
||||
args: BTreeMap<IStr, Expression>,
|
||||
slots: BTreeMap<IStr, Vec<Step<L>>>,
|
||||
},
|
||||
CallSlotWithParentScope {
|
||||
name: Cow<'a, str>,
|
||||
name: IStr,
|
||||
optional: bool,
|
||||
},
|
||||
}
|
||||
|
@ -19,10 +19,10 @@ mod peephole;
|
||||
|
||||
pub use ast_to_ir::AstToIrError;
|
||||
|
||||
pub fn ast_to_optimised_ir<'a>(
|
||||
pub fn ast_to_optimised_ir(
|
||||
template_name: &str,
|
||||
template: Template<'a>,
|
||||
) -> Result<BTreeMap<String, Vec<Step<'a, ()>>>, AstToIrError> {
|
||||
template: Template,
|
||||
) -> Result<BTreeMap<String, Vec<Step<()>>>, AstToIrError> {
|
||||
let entrypoints = pull_out_entrypoints(template, template_name)?;
|
||||
let mut compiled_funcs = ast_to_ir::compile_functions(&entrypoints)?;
|
||||
for steps in compiled_funcs.values_mut() {
|
||||
|
@ -3,8 +3,8 @@
|
||||
// - WriteLiteral, WriteLiteral -> combine
|
||||
|
||||
use crate::ir::{Step, StepDef};
|
||||
use hornbeam_grammar::ast::{Expression, StringExpr, StringPiece};
|
||||
use std::borrow::Cow;
|
||||
use hornbeam_grammar::ast::{Expression, StringPiece};
|
||||
use hornbeam_grammar::intern;
|
||||
|
||||
//// Peephole Machinery
|
||||
|
||||
@ -48,10 +48,7 @@ fn peephole_opt<T, F: FnMut(&mut [Option<T>]) -> ()>(
|
||||
*steps = result;
|
||||
}
|
||||
|
||||
fn apply_peephole_pass<'a, L, F: Fn(&mut Vec<Step<'a, L>>)>(
|
||||
steps: &mut Vec<Step<'a, L>>,
|
||||
pass: &F,
|
||||
) {
|
||||
fn apply_peephole_pass<'a, L, F: Fn(&mut Vec<Step<L>>)>(steps: &mut Vec<Step<L>>, pass: &F) {
|
||||
pass(steps);
|
||||
for step in steps {
|
||||
match &mut step.def {
|
||||
@ -106,7 +103,7 @@ fn pass_write_eval_literal_to_write_literal<L>(steps: &mut Vec<Step<L>>) {
|
||||
}
|
||||
step.def = StepDef::WriteLiteral {
|
||||
escape: *escape,
|
||||
text: Cow::from(buf),
|
||||
text: intern(buf),
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -118,9 +115,9 @@ fn pass_write_literal_preescape<L>(steps: &mut Vec<Step<L>>) {
|
||||
if let StepDef::WriteLiteral { escape, text } = &mut step.def {
|
||||
if *escape {
|
||||
*escape = false;
|
||||
let safe = html_escape::encode_safe(text);
|
||||
if *text != safe {
|
||||
*text = Cow::from(String::from(safe));
|
||||
let safe = html_escape::encode_safe(text as &str);
|
||||
if text as &str != &safe as &str {
|
||||
*text = intern(safe);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -146,7 +143,7 @@ fn pass_combine_write_literals<L>(steps: &mut Vec<Step<L>>) {
|
||||
) = (&mut left.def, &mut right.def)
|
||||
{
|
||||
if *escape_left == *escape_right {
|
||||
let combined_text = Cow::from(String::from(text_left as &str) + text_right);
|
||||
let combined_text = intern(String::from(text_left as &str) + text_right);
|
||||
*text_left = combined_text;
|
||||
r[0] = None;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user