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 =>`
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,
}

View File

@ -363,10 +363,10 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
}
},
_ => {
warn!(
"trying to `match` non-reflective vs {name} at {}",
step.locator
);
// warn!(
// "trying to `match` non-reflective vs {name} at {}",
// step.locator
// );
continue;
}
}
@ -416,14 +416,19 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
}
},
_ => {
warn!(
"trying to `match` non-reflective vs {name}(...) at {}",
step.locator
);
// warn!(
// "trying to `match` non-reflective vs {name}(...) at {}",
// step.locator
// );
continue;
}
}
}
MatchBinding::Variable { name } => binder.bind(
&mut self.scopes[scope_idx].variables,
&Binding::Variable(name.clone()),
matchable_evaled,
),
MatchBinding::Ignore => {
// 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 } => {
let locals = &self.scopes[scope_idx].variables;
match locals.get(name as &str) {
Some(variable_value) => {
let new = variable_value.clone();
eprintln!("{variable_value:?} -> {new:?}");
Ok(variable_value.clone())
}
Some(variable_value) => Ok(variable_value.clone()),
None => {
let locals_list = locals.keys().join(", ");
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())
.then(|| intern(he.classes.iter().map(|istr| istr.as_str()).join(" ") + " "));
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 virtual_varname = intern("___attrval");
gen_steps_to_write_attribute(
he,
attr_name,
attr_expr,
&Expression::Variable {
name: virtual_varname.clone(),
loc: he.loc.clone(),
},
extra_inject.clone(),
&mut some_stage,
);
let binding = MatchBinding::TupleVariant {
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 {
let mut none_stage = Vec::new();
@ -244,15 +254,29 @@ fn compile_ast_block_to_steps(
},
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 {
def: StepDef::Match {
matchable: attr_expr.clone(),
arms,
},
locator: he.loc.clone(),
})
});
} else {
gen_steps_to_write_attribute(
he,