Allow using non-Some-wrapped values in optional KV attributes

This commit is contained in:
Olivier 'reivilibre' 2025-05-18 10:43:48 +01:00
parent dc8447f08e
commit 16f3488d20
3 changed files with 47 additions and 17 deletions

View File

@ -83,6 +83,11 @@ pub enum MatchBinding {
/// `None =>` /// `None =>`
UnitVariant { name: IStr }, UnitVariant { name: IStr },
/// `$var`
/// (A fallback case)
/// TODO this is not implemented in the grammar yet, but is used in generated rules
Variable { name: IStr },
/// `_ =>` /// `_ =>`
Ignore, Ignore,
} }

View File

@ -363,10 +363,10 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
} }
}, },
_ => { _ => {
warn!( // warn!(
"trying to `match` non-reflective vs {name} at {}", // "trying to `match` non-reflective vs {name} at {}",
step.locator // step.locator
); // );
continue; continue;
} }
} }
@ -416,14 +416,19 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
} }
}, },
_ => { _ => {
warn!( // warn!(
"trying to `match` non-reflective vs {name}(...) at {}", // "trying to `match` non-reflective vs {name}(...) at {}",
step.locator // step.locator
); // );
continue; continue;
} }
} }
} }
MatchBinding::Variable { name } => binder.bind(
&mut self.scopes[scope_idx].variables,
&Binding::Variable(name.clone()),
matchable_evaled,
),
MatchBinding::Ignore => { MatchBinding::Ignore => {
// always matches: no variable to bind, no conditions to check! // always matches: no variable to bind, no conditions to check!
} }
@ -782,11 +787,7 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
Expression::Variable { name, loc } => { Expression::Variable { name, loc } => {
let locals = &self.scopes[scope_idx].variables; let locals = &self.scopes[scope_idx].variables;
match locals.get(name as &str) { match locals.get(name as &str) {
Some(variable_value) => { Some(variable_value) => Ok(variable_value.clone()),
let new = variable_value.clone();
eprintln!("{variable_value:?} -> {new:?}");
Ok(variable_value.clone())
}
None => { None => {
let locals_list = locals.keys().join(", "); let locals_list = locals.keys().join(", ");
Err(InterpreterError::TypeError { Err(InterpreterError::TypeError {

View File

@ -215,20 +215,30 @@ fn compile_ast_block_to_steps(
let extra_inject = (attr_name.as_str() == "class" && !he.classes.is_empty()) let extra_inject = (attr_name.as_str() == "class" && !he.classes.is_empty())
.then(|| intern(he.classes.iter().map(|istr| istr.as_str()).join(" ") + " ")); .then(|| intern(he.classes.iter().map(|istr| istr.as_str()).join(" ") + " "));
if attr_flags.optional { if attr_flags.optional {
// For optional fields:
// - if it matches Some($x), unwrap to $x and emit $x
// - if it matches None, skip
// - if it matches neither, assume it's already unwrapped and emit directly
// A little bit ugly to say the least...
let mut some_stage = Vec::new(); let mut some_stage = Vec::new();
let virtual_varname = intern("___attrval");
gen_steps_to_write_attribute( gen_steps_to_write_attribute(
he, he,
attr_name, attr_name,
attr_expr, &Expression::Variable {
name: virtual_varname.clone(),
loc: he.loc.clone(),
},
extra_inject.clone(), extra_inject.clone(),
&mut some_stage, &mut some_stage,
); );
let binding = MatchBinding::TupleVariant { let binding = MatchBinding::TupleVariant {
name: intern("Some"), name: intern("Some"),
pieces: vec![Binding::Variable(intern("___attrval"))], pieces: vec![Binding::Variable(virtual_varname.clone())],
}; };
let mut arms = vec![(binding, some_stage)]; let mut arms = vec![(binding, some_stage.clone())];
if let Some(extra_inject) = extra_inject { if let Some(extra_inject) = extra_inject {
let mut none_stage = Vec::new(); let mut none_stage = Vec::new();
@ -244,15 +254,29 @@ fn compile_ast_block_to_steps(
}, },
none_stage, none_stage,
)); ));
} else {
arms.push((
MatchBinding::UnitVariant {
name: intern("None"),
},
Vec::new(),
));
} }
arms.push((
MatchBinding::Variable {
name: virtual_varname.clone(),
},
some_stage,
));
instructions.push(Step { instructions.push(Step {
def: StepDef::Match { def: StepDef::Match {
matchable: attr_expr.clone(), matchable: attr_expr.clone(),
arms, arms,
}, },
locator: he.loc.clone(), locator: he.loc.clone(),
}) });
} else { } else {
gen_steps_to_write_attribute( gen_steps_to_write_attribute(
he, he,