From 159457616a3919f5374858914675f43cbc609cc4 Mon Sep 17 00:00:00 2001 From: Olivier Date: Tue, 21 Nov 2023 23:16:58 +0000 Subject: [PATCH] Add a tuple binding --- hornbeam_grammar/src/ast.rs | 1 + hornbeam_grammar/src/hornbeam.pest | 3 ++- hornbeam_grammar/src/parser.rs | 9 +++++++++ hornbeam_interpreter/src/engine.rs | 30 +++++++++++++++++++++++++++++- 4 files changed, 41 insertions(+), 2 deletions(-) diff --git a/hornbeam_grammar/src/ast.rs b/hornbeam_grammar/src/ast.rs index 34f7474..6e06b66 100644 --- a/hornbeam_grammar/src/ast.rs +++ b/hornbeam_grammar/src/ast.rs @@ -76,6 +76,7 @@ pub enum MatchBinding { #[derive(Clone, Debug, Eq, PartialEq, Serialize)] pub enum Binding { Variable(IStr), + Tuple(Vec), Ignore, } diff --git a/hornbeam_grammar/src/hornbeam.pest b/hornbeam_grammar/src/hornbeam.pest index 7192f6c..40750e9 100644 --- a/hornbeam_grammar/src/hornbeam.pest +++ b/hornbeam_grammar/src/hornbeam.pest @@ -205,9 +205,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 = { - VarBinding | IgnoreBinding + VarBinding | TupleBinding | IgnoreBinding } VarBinding = { "$" ~ Identifier } +TupleBinding = { "(" ~ Binding ~ "," ~ ws* ~ (Binding ~ "," ~ ws*)+ ~ (Binding)? ~ ")" } IgnoreBinding = { "_" } LocalisationIdentifier = @{ ASCII_ALPHA ~ (ASCII_ALPHANUMERIC | "_" | "-")+ } diff --git a/hornbeam_grammar/src/parser.rs b/hornbeam_grammar/src/parser.rs index 5a89112..63255a8 100644 --- a/hornbeam_grammar/src/parser.rs +++ b/hornbeam_grammar/src/parser.rs @@ -422,6 +422,7 @@ impl HornbeamParser { Ok(match_nodes!(input.into_children(); [VarBinding(b)] => b, [IgnoreBinding(b)] => b, + [TupleBinding(b)] => b, )) } @@ -434,6 +435,14 @@ impl HornbeamParser { Ok(Binding::Ignore) } + fn TupleBinding(input: Node) -> PCResult { + Ok(match_nodes!(input.into_children(); + [Binding(bs)..] => { + Binding::Tuple(bs.collect()) + } + )) + } + fn EmptyForBlock(input: Node) -> PCResult> { HornbeamParser::helper_blocks(input.into_children()) } diff --git a/hornbeam_interpreter/src/engine.rs b/hornbeam_interpreter/src/engine.rs index d7b10dc..18aaa97 100644 --- a/hornbeam_interpreter/src/engine.rs +++ b/hornbeam_interpreter/src/engine.rs @@ -127,13 +127,41 @@ impl Binder { binding: &Binding, value: Value, ) { - // TODO duplicated code match binding { Binding::Variable(var_name) => { let var_name = String::from(var_name as &str); variables.insert(var_name.clone(), value); self.variables_to_unbind.push(var_name); } + Binding::Tuple(field_bindings) => { + match value { + Value::Str(_) | Value::Int(_) | Value::Bool(_) | Value::List(_) => { + // Error binding + todo!() + } + Value::Reflective(reflective) => match reflective.reflect_ref() { + ReflectRef::Tuple(tuple) => { + if tuple.field_len() != field_bindings.len() { + // Error binding + todo!(); + } + for (field_idx, field_binding) in field_bindings.iter().enumerate() { + self.bind( + variables, + field_binding, + Value::from_reflect( + tuple.field(field_idx).unwrap().clone_value(), + ), + ); + } + } + _ => { + // Error binding + todo!() + } + }, + } + } Binding::Ignore => {} } }