Allow more complicated types of bindings in For and use $ for var bindings

This commit is contained in:
Olivier 'reivilibre' 2023-08-07 22:31:02 +01:00
parent 1a1dc740e8
commit 062bd8abd7
6 changed files with 76 additions and 26 deletions

View File

@ -46,13 +46,19 @@ pub struct IfBlock {
#[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct ForBlock { pub struct ForBlock {
pub binding: IStr, pub binding: Binding,
pub iterable: Expression, pub iterable: Expression,
pub blocks: Vec<Block>, pub blocks: Vec<Block>,
pub empty_blocks: Vec<Block>, pub empty_blocks: Vec<Block>,
pub loc: Locator, pub loc: Locator,
} }
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Binding {
Variable(IStr),
Ignore,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)] #[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DefineExpandSlot { pub struct DefineExpandSlot {
pub name: IStr, pub name: IStr,

View File

@ -185,8 +185,10 @@ MapLiteral = { "{" ~ commaSeparatedKVPairs ~ "}" }
// As in a let binding or for binding. // As in a let binding or for binding.
// More options in the future, but for now you just get one identifier and that's it! // More options in the future, but for now you just get one identifier and that's it!
Binding = { Binding = {
Identifier VarBinding | IgnoreBinding
} }
VarBinding = { "$" ~ Identifier }
IgnoreBinding = { "_" }
LocalisationIdentifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_" | "-")+ } LocalisationIdentifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_" | "-")+ }
ParameterisedLocalisation = { "@" ~ LocalisationIdentifier ~ (!"{" | MapLiteral) } ParameterisedLocalisation = { "@" ~ LocalisationIdentifier ~ (!"{" | MapLiteral) }

View File

@ -1,8 +1,8 @@
#![allow(non_snake_case)] #![allow(non_snake_case)]
use crate::ast::{ use crate::ast::{
Block, ComponentElement, DefineExpandSlot, DefineFragment, Expression, ForBlock, HtmlElement, Binding, Block, ComponentElement, DefineExpandSlot, DefineFragment, Expression, ForBlock,
IfBlock, StringExpr, StringPiece, Template, HtmlElement, IfBlock, StringExpr, StringPiece, Template,
}; };
use crate::{intern, IStr, Locator}; use crate::{intern, IStr, Locator};
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -374,8 +374,20 @@ impl HornbeamParser {
})) }))
} }
fn Binding(input: Node) -> PCResult<IStr> { fn Binding(input: Node) -> PCResult<Binding> {
Ok(intern(input.as_str())) Ok(match_nodes!(input.into_children();
[VarBinding(b)] => b,
[IgnoreBinding(b)] => b,
))
}
fn VarBinding(input: Node) -> PCResult<Binding> {
let str = Self::Identifier(input.into_children().single()?)?;
Ok(Binding::Variable(str))
}
fn IgnoreBinding(input: Node) -> PCResult<Binding> {
Ok(Binding::Ignore)
} }
fn EmptyForBlock(input: Node) -> PCResult<Vec<Block>> { fn EmptyForBlock(input: Node) -> PCResult<Vec<Block>> {
@ -515,8 +527,8 @@ else // peculiar.
fn for_blocks() { fn for_blocks() {
assert_yaml_snapshot!(parse_template( assert_yaml_snapshot!(parse_template(
r#" r#"
for x in $xs for $x in $xs
for y in $ys for $y in $ys
"Woot" "Woot"
empty empty
"no ys" "no ys"

View File

@ -1,27 +1,29 @@
--- ---
source: hornbeam_grammar/src/parser.rs source: hornbeam_grammar/src/parser.rs
expression: "parse_template(r#\"\nfor x in $xs\n for y in $ys\n \"Woot\"\n empty\n \"no ys\"\nempty\n \"no xs\"\n \"#,\n \"inp\").unwrap()" expression: "parse_template(r#\"\nfor $x in $xs\n for $y in $ys\n \"Woot\"\n empty\n \"no ys\"\nempty\n \"no xs\"\n \"#,\n \"inp\").unwrap()"
--- ---
blocks: blocks:
- ForBlock: - ForBlock:
binding: x binding:
iterator: Variable: x
iterable:
Variable: Variable:
name: xs name: xs
loc: loc:
filename: inp filename: inp
line: 2 line: 2
column: 10 column: 11
blocks: blocks:
- ForBlock: - ForBlock:
binding: y binding:
iterator: Variable: y
iterable:
Variable: Variable:
name: ys name: ys
loc: loc:
filename: inp filename: inp
line: 3 line: 3
column: 14 column: 15
blocks: blocks:
- Text: - Text:
pieces: pieces:

View File

@ -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::ast::Binding;
use hornbeam_grammar::Locator; 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;
@ -195,12 +196,26 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
self.run_steps(scope_idx, empty_steps).await?; self.run_steps(scope_idx, empty_steps).await?;
} else { } else {
for val in list { for val in list {
// TODO duplicated code
match binding {
Binding::Variable(var) => {
self.scopes[scope_idx] self.scopes[scope_idx]
.variables .variables
.insert(String::from(binding as &str), val); .insert(String::from(var as &str), val);
}
Binding::Ignore => {}
}
self.run_steps(scope_idx, body_steps).await?; self.run_steps(scope_idx, body_steps).await?;
} }
self.scopes[scope_idx].variables.remove(binding as &str);
// TODO duplicated code
match binding {
Binding::Variable(var) => {
self.scopes[scope_idx].variables.remove(var as &str);
}
Binding::Ignore => {}
}
} }
} }
Value::Reflective(reflective) => match reflective.reflect_ref() { Value::Reflective(reflective) => match reflective.reflect_ref() {
@ -212,13 +227,26 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
// TODO(performance) I'd like to remove this clone! // TODO(performance) I'd like to remove this clone!
// Can possibly do so with a Yoke or something... // Can possibly do so with a Yoke or something...
let val = list.get(idx).expect("checked iter").clone_value(); let val = list.get(idx).expect("checked iter").clone_value();
// TODO duplicated code
match binding {
Binding::Variable(var) => {
self.scopes[scope_idx].variables.insert( self.scopes[scope_idx].variables.insert(
String::from(binding as &str), String::from(var as &str),
Value::from_reflect(val), Value::from_reflect(val),
); );
}
Binding::Ignore => {}
}
self.run_steps(scope_idx, body_steps).await?; self.run_steps(scope_idx, body_steps).await?;
} }
self.scopes[scope_idx].variables.remove(binding as &str);
// TODO duplicated code
match binding {
Binding::Variable(var) => {
self.scopes[scope_idx].variables.remove(var as &str);
}
Binding::Ignore => {}
}
} }
} }
other => { other => {

View File

@ -1,3 +1,4 @@
use hornbeam_grammar::ast::Binding;
pub use hornbeam_grammar::ast::{Expression, StringPiece}; pub use hornbeam_grammar::ast::{Expression, StringPiece};
use hornbeam_grammar::{IStr, Locator}; use hornbeam_grammar::{IStr, Locator};
use serde::Serialize; use serde::Serialize;
@ -34,8 +35,7 @@ pub enum StepDef {
}, },
For { For {
iterable: Expression, iterable: Expression,
// TODO! binding: Binding,
binding: IStr,
body_steps: Vec<Step>, body_steps: Vec<Step>,
empty_steps: Vec<Step>, empty_steps: Vec<Step>,
}, },