From 53bbb0be608cc016b20bcb0eb801935acf67df0c Mon Sep 17 00:00:00 2001 From: Ziyang Hu Date: Sat, 24 Sep 2022 21:14:16 +0800 Subject: [PATCH] "try" special form --- src/data/expr.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- src/data/program.rs | 27 +++++++++++++++++++++++++++ src/parse/expr.rs | 4 ++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/src/data/expr.rs b/src/data/expr.rs index 1dbb8582..9866fdbe 100644 --- a/src/data/expr.rs +++ b/src/data/expr.rs @@ -38,6 +38,11 @@ pub(crate) enum Expr { #[serde(skip)] span: SourceSpan, }, + Try { + clauses: Vec, + #[serde(skip)] + span: SourceSpan, + }, } #[derive(Debug, Error, Diagnostic)] @@ -60,7 +65,10 @@ impl Expr { pub(crate) fn span(&self) -> SourceSpan { match self { 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> { @@ -133,6 +141,11 @@ impl Expr { val.fill_binding_indices(binding_map)?; } } + Expr::Try { clauses, .. } => { + for clause in clauses { + clause.fill_binding_indices(binding_map)?; + } + } } Ok(()) } @@ -160,6 +173,11 @@ impl Expr { 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 { @@ -232,6 +250,11 @@ impl Expr { val.collect_bindings(coll) } } + Expr::Try { clauses, .. } => { + for clause in clauses { + clause.collect_bindings(coll); + } + } } } pub(crate) fn eval(&self, bindings: &Tuple) -> Result { @@ -278,6 +301,19 @@ impl Expr { } 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 { @@ -290,7 +326,9 @@ impl Expr { } pub(crate) fn extract_bound(&self, target: &Symbol) -> Result { 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 { n if n == OP_GE.name || n == OP_GT.name => { if let Some(symb) = args[0].get_binding() { diff --git a/src/data/program.rs b/src/data/program.rs index f9502316..da3becea 100644 --- a/src/data/program.rs +++ b/src/data/program.rs @@ -222,6 +222,33 @@ impl MagicAlgoApply { }, } } + pub(crate) fn string_option( + &self, + name: &str, + default: Option<&str>, + ) -> Result> { + 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) -> Result { match self.options.get(name) { Some(v) => match v.clone().eval_to_const() { diff --git a/src/parse/expr.rs b/src/parse/expr.rs index 12811081..6e46eba6 100644 --- a/src/parse/expr.rs +++ b/src/parse/expr.rs @@ -222,6 +222,10 @@ fn build_unary(pair: Pair<'_>, param_pool: &BTreeMap) -> Resu struct FuncNotFoundError(String, #[label] SourceSpan); match ident { + "try" => Expr::Try { + clauses: args, + span, + }, "cond" => { if args.len() & 1 == 1 { args.insert(