Add ! unwrap operator

This commit is contained in:
Olivier 'reivilibre' 2025-06-11 22:16:42 +01:00
parent 9098d72217
commit 2281a9bb50
4 changed files with 57 additions and 2 deletions

View File

@ -225,4 +225,9 @@ pub enum Expression {
args: Vec<Expression>,
loc: Locator,
},
Unwrap {
obj: Box<Expression>,
loc: Locator,
},
}

View File

@ -213,7 +213,7 @@ bnot = { "not" ~ ws+ }
// POSTFIX
postfix = _{ unwrap | MethodCall | FieldLookup | Indexing }
unwrap = { "?" } // Not sure I'm convinced about this one, but we can think about it.
unwrap = { "!" } // Not sure I'm convinced about this one, but we can think about it.
// Note that functions aren't first-class; we don't allow you to 'call' an arbitrary term.
// This is probably for the best since we might have multiple backends for the templating.
MethodCall = { "." ~ ws* ~ Identifier ~ "(" ~ commaSeparatedExprs ~ ")" }

View File

@ -432,7 +432,9 @@ impl HornbeamParser {
let node = Node::new_with_user_data(op, ud.clone());
let loc = nodeloc(&node);
Ok(match node.as_rule() {
Rule::unwrap => unimplemented!("unimp unwrap"),
Rule::unwrap => {
Expression::Unwrap { obj: Box::new(lhs?), loc }
},
Rule::FieldLookup => {
let ident = intern(node.into_children().single()?.as_str());
Expression::FieldLookup { obj: Box::new(lhs?), ident, loc }

View File

@ -855,6 +855,54 @@ impl<'a, O: OutputSystem + Send, LS: LocalisationSystem + Sync + Send> Interpret
Expression::FunctionCall { .. } => {
unimplemented!()
}
Expression::Unwrap { obj, loc } => {
let obj_value = self.evaluate_expression(scope_idx, obj, loc)?;
match &obj_value {
Value::Reflective(reflective) => match reflective.reflect_ref() {
ReflectRef::Enum(reflenum) => match reflenum.variant_name() {
"Some" => {
if reflenum.field_len() != 1 {
return Err(InterpreterError::TypeError {
context: "unwrap".to_owned(),
conflict: "wrong number of fields in Some".to_owned(),
location: loc.clone(),
});
}
if reflenum.variant_type() != VariantType::Tuple {
return Err(InterpreterError::TypeError {
context: "unwrap".to_owned(),
conflict: "Some is not a tuple variant".to_owned(),
location: loc.clone(),
});
}
Ok(Value::from_reflect(
reflenum.field_at(0).unwrap().clone_value(),
))
}
"None" => Err(InterpreterError::TypeError {
context: "unwrap".to_owned(),
conflict: "tried to unwrap None".to_owned(),
location: loc.clone(),
}),
_other => {
warn!("unnecessary unwrap (!) at {loc}");
Ok(obj_value)
}
},
_other => {
warn!("unnecessary unwrap (!) at {loc}");
Ok(obj_value)
}
},
_other => {
warn!("unnecessary unwrap (!) at {loc}");
Ok(obj_value)
}
}
}
}
}