Skip to content

Commit

Permalink
optional chaining
Browse files Browse the repository at this point in the history
  • Loading branch information
todesking committed Apr 14, 2024
1 parent 14eeaa7 commit d650cd9
Show file tree
Hide file tree
Showing 5 changed files with 28 additions and 2 deletions.
2 changes: 2 additions & 0 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ pub enum Expr {
Paren { expr: Box<Expr> },
#[serde(rename = "expr_prop")]
Prop { expr: Box<Expr>, name: Ident },
#[serde(rename = "expr_prop_opt")]
PropOpt { expr: Box<Expr>, name: Ident },
#[serde(rename = "expr_index")]
Index { expr: Box<Expr>, index: Box<Expr> },
#[serde(rename = "expr_binop")]
Expand Down
8 changes: 8 additions & 0 deletions src/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,14 @@ impl Env {
let value = self.eval_expr(expr, local_env)?;
self.get_prop(&value, name)
}
Expr::PropOpt { expr, name } => {
let value = self.eval_expr(expr, local_env)?;
if value.is_null() {
Ok(Value::null())
} else {
self.get_prop(&value, name)
}
}
Expr::Index { expr, index } => {
let value = self.eval_expr(expr, local_env)?;
let index = self.eval_expr(index, local_env)?;
Expand Down
6 changes: 6 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,12 @@ mod test {
assert_eval_ok!("{foo: 123, bar: {baz: 999}}.bar.baz", 999);
}

#[test]
fn optional_chain() {
assert_eval_ok!("null?.foo", Value::null());
assert_eval_ok!("{foo: 1}?.foo", 1);
}

#[test]
fn array() {
assert_eval_ok!("[]", array_value![]);
Expand Down
8 changes: 6 additions & 2 deletions src/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,13 +51,13 @@ impl Value {

pub fn use_array<T, F: FnOnce(&[Value]) -> EvalResult<T>>(&self, f: F) -> EvalResult<T> {
match self {
Value::Atom(_) => Err(EvalError::TypeError("Array".into(), self.clone())),
Value::Atom(_) => Err(EvalError::type_error("Array", self.clone())),
Value::Ref(ref_value) => match &**ref_value {
RefValue::Array(arr) => {
let arr = arr.borrow();
f(&arr)
}
_ => Err(EvalError::TypeError("Array".into(), self.clone())),
_ => Err(EvalError::type_error("Array", self.clone())),
},
}
}
Expand Down Expand Up @@ -94,6 +94,10 @@ impl Value {
_ => Err(EvalError::type_error("Object", self.clone())),
}
}

pub fn is_null(&self) -> bool {
matches!(self, Value::Atom(AtomValue::Null))
}
}

impl Display for Value {
Expand Down
6 changes: 6 additions & 0 deletions tree-sitter-borlang/rules.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const common_rules = {
$.expr_fun,
$.expr_if,
$.expr_prop,
$.expr_prop_opt,
$.expr_index,
),
expr_int: _ => /[0-9]+/,
Expand Down Expand Up @@ -143,6 +144,11 @@ const common_rules = {
'.',
field('name', $.ident),
)),
expr_prop_opt: $ => prec(Prec.prop, seq(
field('expr', $._expr),
'?.',
field('name', $.ident),
)),
expr_index: $ => prec.left(Prec.index, seq(
field('expr', $._expr),
'[',
Expand Down

0 comments on commit d650cd9

Please sign in to comment.