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)]
pub struct ForBlock {
pub binding: IStr,
pub binding: Binding,
pub iterable: Expression,
pub blocks: Vec<Block>,
pub empty_blocks: Vec<Block>,
pub loc: Locator,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub enum Binding {
Variable(IStr),
Ignore,
}
#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
pub struct DefineExpandSlot {
pub name: IStr,

View File

@ -185,8 +185,10 @@ MapLiteral = { "{" ~ commaSeparatedKVPairs ~ "}" }
// 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!
Binding = {
Identifier
VarBinding | IgnoreBinding
}
VarBinding = { "$" ~ Identifier }
IgnoreBinding = { "_" }
LocalisationIdentifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_" | "-")+ }
ParameterisedLocalisation = { "@" ~ LocalisationIdentifier ~ (!"{" | MapLiteral) }

View File

@ -1,8 +1,8 @@
#![allow(non_snake_case)]
use crate::ast::{
Block, ComponentElement, DefineExpandSlot, DefineFragment, Expression, ForBlock, HtmlElement,
IfBlock, StringExpr, StringPiece, Template,
Binding, Block, ComponentElement, DefineExpandSlot, DefineFragment, Expression, ForBlock,
HtmlElement, IfBlock, StringExpr, StringPiece, Template,
};
use crate::{intern, IStr, Locator};
use lazy_static::lazy_static;
@ -374,8 +374,20 @@ impl HornbeamParser {
}))
}
fn Binding(input: Node) -> PCResult<IStr> {
Ok(intern(input.as_str()))
fn Binding(input: Node) -> PCResult<Binding> {
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>> {
@ -515,8 +527,8 @@ else // peculiar.
fn for_blocks() {
assert_yaml_snapshot!(parse_template(
r#"
for x in $xs
for y in $ys
for $x in $xs
for $y in $ys
"Woot"
empty
"no ys"

View File

@ -1,27 +1,29 @@
---
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:
- ForBlock:
binding: x
iterator:
binding:
Variable: x
iterable:
Variable:
name: xs
loc:
filename: inp
line: 2
column: 10
column: 11
blocks:
- ForBlock:
binding: y
iterator:
binding:
Variable: y
iterable:
Variable:
name: ys
loc:
filename: inp
line: 3
column: 14
column: 15
blocks:
- Text:
pieces:

View File

@ -3,6 +3,7 @@ use crate::InterpreterError;
use async_recursion::async_recursion;
use bevy_reflect::{FromReflect, Reflect, ReflectRef};
use fluent_templates::lazy_static::lazy_static;
use hornbeam_grammar::ast::Binding;
use hornbeam_grammar::Locator;
use hornbeam_ir::ir::{Expression, Step, StepDef, StringPiece};
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?;
} else {
for val in list {
self.scopes[scope_idx]
.variables
.insert(String::from(binding as &str), val);
// TODO duplicated code
match binding {
Binding::Variable(var) => {
self.scopes[scope_idx]
.variables
.insert(String::from(var as &str), val);
}
Binding::Ignore => {}
}
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() {
@ -212,13 +227,26 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
// TODO(performance) I'd like to remove this clone!
// Can possibly do so with a Yoke or something...
let val = list.get(idx).expect("checked iter").clone_value();
self.scopes[scope_idx].variables.insert(
String::from(binding as &str),
Value::from_reflect(val),
);
// TODO duplicated code
match binding {
Binding::Variable(var) => {
self.scopes[scope_idx].variables.insert(
String::from(var as &str),
Value::from_reflect(val),
);
}
Binding::Ignore => {}
}
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 => {

View File

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