"try" special form

main
Ziyang Hu 2 years ago
parent 656311ed78
commit 53bbb0be60

@ -38,6 +38,11 @@ pub(crate) enum Expr {
#[serde(skip)] #[serde(skip)]
span: SourceSpan, span: SourceSpan,
}, },
Try {
clauses: Vec<Expr>,
#[serde(skip)]
span: SourceSpan,
},
} }
#[derive(Debug, Error, Diagnostic)] #[derive(Debug, Error, Diagnostic)]
@ -60,7 +65,10 @@ impl Expr {
pub(crate) fn span(&self) -> SourceSpan { pub(crate) fn span(&self) -> SourceSpan {
match self { match self {
Expr::Binding { var, .. } => var.span, Expr::Binding { var, .. } => var.span,
Expr::Const { span, .. } | Expr::Apply { span, .. } | Expr::Cond { span, .. } => *span, Expr::Const { span, .. }
| Expr::Apply { span, .. }
| Expr::Cond { span, .. }
| Expr::Try { span, .. } => *span,
} }
} }
pub(crate) fn get_binding(&self) -> Option<&Symbol> { pub(crate) fn get_binding(&self) -> Option<&Symbol> {
@ -133,6 +141,11 @@ impl Expr {
val.fill_binding_indices(binding_map)?; val.fill_binding_indices(binding_map)?;
} }
} }
Expr::Try { clauses, .. } => {
for clause in clauses {
clause.fill_binding_indices(binding_map)?;
}
}
} }
Ok(()) Ok(())
} }
@ -160,6 +173,11 @@ impl Expr {
val.do_binding_indices(coll) val.do_binding_indices(coll)
} }
} }
Expr::Try { clauses, .. } => {
for clause in clauses {
clause.do_binding_indices(coll)
}
}
} }
} }
pub(crate) fn eval_to_const(mut self) -> Result<DataValue> { pub(crate) fn eval_to_const(mut self) -> Result<DataValue> {
@ -232,6 +250,11 @@ impl Expr {
val.collect_bindings(coll) val.collect_bindings(coll)
} }
} }
Expr::Try { clauses, .. } => {
for clause in clauses {
clause.collect_bindings(coll);
}
}
} }
} }
pub(crate) fn eval(&self, bindings: &Tuple) -> Result<DataValue> { pub(crate) fn eval(&self, bindings: &Tuple) -> Result<DataValue> {
@ -278,6 +301,19 @@ impl Expr {
} }
return Ok(DataValue::Null); return Ok(DataValue::Null);
} }
Expr::Try { clauses, .. } => {
if clauses.is_empty() {
Ok(DataValue::Null)
} else {
for i in 0..clauses.len() - 1 {
let res = clauses[i].eval(bindings);
if res.is_ok() {
return res;
}
}
clauses[clauses.len() - 1].eval(bindings)
}
}
} }
} }
pub(crate) fn eval_pred(&self, bindings: &Tuple) -> Result<bool> { pub(crate) fn eval_pred(&self, bindings: &Tuple) -> Result<bool> {
@ -290,7 +326,9 @@ impl Expr {
} }
pub(crate) fn extract_bound(&self, target: &Symbol) -> Result<ValueRange> { pub(crate) fn extract_bound(&self, target: &Symbol) -> Result<ValueRange> {
Ok(match self { Ok(match self {
Expr::Binding { .. } | Expr::Const { .. } | Expr::Cond { .. } => ValueRange::default(), Expr::Binding { .. } | Expr::Const { .. } | Expr::Cond { .. } | Expr::Try { .. } => {
ValueRange::default()
}
Expr::Apply { op, args, .. } => match op.name { Expr::Apply { op, args, .. } => match op.name {
n if n == OP_GE.name || n == OP_GT.name => { n if n == OP_GE.name || n == OP_GT.name => {
if let Some(symb) = args[0].get_binding() { if let Some(symb) = args[0].get_binding() {

@ -222,6 +222,33 @@ impl MagicAlgoApply {
}, },
} }
} }
pub(crate) fn string_option(
&self,
name: &str,
default: Option<&str>,
) -> Result<SmartString<LazyCompact>> {
match self.options.get(name) {
Some(ex) => match ex.clone().eval_to_const()? {
DataValue::Str(s) => Ok(s),
_ => Err(WrongAlgoOptionError {
name: name.to_string(),
span: ex.span(),
algo_name: self.algo.name.to_string(),
help: "a string is required".to_string(),
}
.into()),
},
None => match default {
None => Err(AlgoOptionNotFoundError {
name: name.to_string(),
span: self.span,
algo_name: self.algo.name.to_string(),
}
.into()),
Some(s) => Ok(SmartString::from(s)),
},
}
}
pub(crate) fn pos_integer_option(&self, name: &str, default: Option<usize>) -> Result<usize> { pub(crate) fn pos_integer_option(&self, name: &str, default: Option<usize>) -> Result<usize> {
match self.options.get(name) { match self.options.get(name) {
Some(v) => match v.clone().eval_to_const() { Some(v) => match v.clone().eval_to_const() {

@ -222,6 +222,10 @@ fn build_unary(pair: Pair<'_>, param_pool: &BTreeMap<String, DataValue>) -> Resu
struct FuncNotFoundError(String, #[label] SourceSpan); struct FuncNotFoundError(String, #[label] SourceSpan);
match ident { match ident {
"try" => Expr::Try {
clauses: args,
span,
},
"cond" => { "cond" => {
if args.len() & 1 == 1 { if args.len() & 1 == 1 {
args.insert( args.insert(

Loading…
Cancel
Save