Introduce BinaryExpr.
This commit is contained in:
parent
f62f7908ab
commit
fd2ba54b49
@ -6,7 +6,7 @@ use crate::fn_native::{Callback, FnPtr, OnVarCallback};
|
|||||||
use crate::module::{Module, ModuleRef};
|
use crate::module::{Module, ModuleRef};
|
||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
use crate::packages::{Package, PackagesCollection, StandardPackage};
|
||||||
use crate::parser::{Expr, ReturnType, Stmt};
|
use crate::parser::{BinaryExpr, Expr, ReturnType, Stmt};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
@ -901,18 +901,17 @@ impl Engine {
|
|||||||
match rhs {
|
match rhs {
|
||||||
// xxx[idx].expr... | xxx[idx][expr]...
|
// xxx[idx].expr... | xxx[idx][expr]...
|
||||||
Expr::Dot(x) | Expr::Index(x) => {
|
Expr::Dot(x) | Expr::Index(x) => {
|
||||||
let (idx, expr, pos) = x.as_ref();
|
let idx_pos = x.lhs.position();
|
||||||
let idx_pos = idx.position();
|
|
||||||
let idx_val = idx_val.as_value();
|
let idx_val = idx_val.as_value();
|
||||||
let obj_ptr = &mut self.get_indexed_mut(
|
let obj_ptr = &mut self.get_indexed_mut(
|
||||||
state, lib, target, idx_val, idx_pos, false, true, level,
|
state, lib, target, idx_val, idx_pos, false, true, level,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
|
state, lib, this_ptr, obj_ptr, &x.rhs, idx_values, next_chain, level,
|
||||||
new_val,
|
new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(x.pos))
|
||||||
}
|
}
|
||||||
// xxx[rhs] = new_val
|
// xxx[rhs] = new_val
|
||||||
_ if new_val.is_some() => {
|
_ if new_val.is_some() => {
|
||||||
@ -1031,9 +1030,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
||||||
Expr::Index(x) | Expr::Dot(x) if target.is::<Map>() => {
|
Expr::Index(x) | Expr::Dot(x) if target.is::<Map>() => {
|
||||||
let (sub_lhs, expr, pos) = x.as_ref();
|
let mut val = match &x.lhs {
|
||||||
|
|
||||||
let mut val = match sub_lhs {
|
|
||||||
Expr::Property(p) => {
|
Expr::Property(p) => {
|
||||||
let ((prop, _, _), pos) = p.as_ref();
|
let ((prop, _, _), pos) = p.as_ref();
|
||||||
let index = prop.clone().into();
|
let index = prop.clone().into();
|
||||||
@ -1061,16 +1058,14 @@ impl Engine {
|
|||||||
};
|
};
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
|
state, lib, this_ptr, &mut val, &x.rhs, idx_values, next_chain, level,
|
||||||
new_val,
|
new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(x.pos))
|
||||||
}
|
}
|
||||||
// xxx.sub_lhs[expr] | xxx.sub_lhs.expr
|
// xxx.sub_lhs[expr] | xxx.sub_lhs.expr
|
||||||
Expr::Index(x) | Expr::Dot(x) => {
|
Expr::Index(x) | Expr::Dot(x) => {
|
||||||
let (sub_lhs, expr, _) = x.as_ref();
|
match &x.lhs {
|
||||||
|
|
||||||
match sub_lhs {
|
|
||||||
// xxx.prop[expr] | xxx.prop.expr
|
// xxx.prop[expr] | xxx.prop.expr
|
||||||
Expr::Property(p) => {
|
Expr::Property(p) => {
|
||||||
let ((_, getter, setter), pos) = p.as_ref();
|
let ((_, getter, setter), pos) = p.as_ref();
|
||||||
@ -1091,13 +1086,13 @@ impl Engine {
|
|||||||
lib,
|
lib,
|
||||||
this_ptr,
|
this_ptr,
|
||||||
&mut val.into(),
|
&mut val.into(),
|
||||||
expr,
|
&x.rhs,
|
||||||
idx_values,
|
idx_values,
|
||||||
next_chain,
|
next_chain,
|
||||||
level,
|
level,
|
||||||
new_val,
|
new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))?;
|
.map_err(|err| err.fill_position(x.pos))?;
|
||||||
|
|
||||||
// Feed the value back via a setter just in case it has been updated
|
// Feed the value back via a setter just in case it has been updated
|
||||||
if updated || may_be_changed {
|
if updated || may_be_changed {
|
||||||
@ -1113,7 +1108,7 @@ impl Engine {
|
|||||||
EvalAltResult::ErrorDotExpr(_, _) => {
|
EvalAltResult::ErrorDotExpr(_, _) => {
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
}
|
}
|
||||||
_ => Err(err.fill_position(*pos)),
|
_ => Err(err.fill_position(x.pos)),
|
||||||
},
|
},
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
@ -1121,8 +1116,8 @@ impl Engine {
|
|||||||
Ok((result, may_be_changed))
|
Ok((result, may_be_changed))
|
||||||
}
|
}
|
||||||
// xxx.fn_name(arg_expr_list)[expr] | xxx.fn_name(arg_expr_list).expr
|
// xxx.fn_name(arg_expr_list)[expr] | xxx.fn_name(arg_expr_list).expr
|
||||||
Expr::FnCall(x) if x.1.is_none() => {
|
Expr::FnCall(f) if f.1.is_none() => {
|
||||||
let ((name, native, _, pos), _, hash, _, def_val) = x.as_ref();
|
let ((name, native, _, pos), _, hash, _, def_val) = f.as_ref();
|
||||||
let def_val = def_val.map(Into::<Dynamic>::into);
|
let def_val = def_val.map(Into::<Dynamic>::into);
|
||||||
let args = idx_val.as_fn_call_args();
|
let args = idx_val.as_fn_call_args();
|
||||||
let (mut val, _) = self
|
let (mut val, _) = self
|
||||||
@ -1135,7 +1130,7 @@ impl Engine {
|
|||||||
let target = &mut val.into();
|
let target = &mut val.into();
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
state, lib, this_ptr, target, &x.rhs, idx_values, next_chain,
|
||||||
level, new_val,
|
level, new_val,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
@ -1168,7 +1163,14 @@ impl Engine {
|
|||||||
level: usize,
|
level: usize,
|
||||||
new_val: Option<(Dynamic, Position)>,
|
new_val: Option<(Dynamic, Position)>,
|
||||||
) -> Result<Dynamic, Box<EvalAltResult>> {
|
) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
let ((dot_lhs, dot_rhs, op_pos), chain_type) = match expr {
|
let (
|
||||||
|
BinaryExpr {
|
||||||
|
lhs: dot_lhs,
|
||||||
|
rhs: dot_rhs,
|
||||||
|
pos: op_pos,
|
||||||
|
},
|
||||||
|
chain_type,
|
||||||
|
) = match expr {
|
||||||
Expr::Index(x) => (x.as_ref(), ChainType::Index),
|
Expr::Index(x) => (x.as_ref(), ChainType::Index),
|
||||||
Expr::Dot(x) => (x.as_ref(), ChainType::Dot),
|
Expr::Dot(x) => (x.as_ref(), ChainType::Dot),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
@ -1266,7 +1268,7 @@ impl Engine {
|
|||||||
Expr::FnCall(_) => unreachable!(),
|
Expr::FnCall(_) => unreachable!(),
|
||||||
Expr::Property(_) => idx_values.push(IndexChainValue::None),
|
Expr::Property(_) => idx_values.push(IndexChainValue::None),
|
||||||
Expr::Index(x) | Expr::Dot(x) => {
|
Expr::Index(x) | Expr::Dot(x) => {
|
||||||
let (lhs, rhs, _) = x.as_ref();
|
let BinaryExpr { lhs, rhs, .. } = x.as_ref();
|
||||||
|
|
||||||
// Evaluate in left-to-right order
|
// Evaluate in left-to-right order
|
||||||
let lhs_val = match lhs {
|
let lhs_val = match lhs {
|
||||||
@ -1721,33 +1723,33 @@ impl Engine {
|
|||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::In(x) => self.eval_in_expr(scope, mods, state, lib, this_ptr, &x.0, &x.1, level),
|
Expr::In(x) => {
|
||||||
|
self.eval_in_expr(scope, mods, state, lib, this_ptr, &x.lhs, &x.rhs, level)
|
||||||
|
}
|
||||||
|
|
||||||
Expr::And(x) => {
|
Expr::And(x) => {
|
||||||
let (lhs, rhs, _) = x.as_ref();
|
|
||||||
Ok((self
|
Ok((self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, &x.lhs, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|err| self.make_type_mismatch_err::<bool>(err, lhs.position()))?
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, x.lhs.position()))?
|
||||||
&& // Short-circuit using &&
|
&& // Short-circuit using &&
|
||||||
self
|
self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, rhs, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, &x.rhs, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|err| self.make_type_mismatch_err::<bool>(err, rhs.position()))?)
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, x.rhs.position()))?)
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Or(x) => {
|
Expr::Or(x) => {
|
||||||
let (lhs, rhs, _) = x.as_ref();
|
|
||||||
Ok((self
|
Ok((self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, &x.lhs, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|err| self.make_type_mismatch_err::<bool>(err, lhs.position()))?
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, x.lhs.position()))?
|
||||||
|| // Short-circuit using ||
|
|| // Short-circuit using ||
|
||||||
self
|
self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, rhs, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, &x.rhs, level)?
|
||||||
.as_bool()
|
.as_bool()
|
||||||
.map_err(|err| self.make_type_mismatch_err::<bool>(err, rhs.position()))?)
|
.map_err(|err| self.make_type_mismatch_err::<bool>(err, x.rhs.position()))?)
|
||||||
.into())
|
.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1755,9 +1757,9 @@ impl Engine {
|
|||||||
Expr::False(_) => Ok(false.into()),
|
Expr::False(_) => Ok(false.into()),
|
||||||
Expr::Unit(_) => Ok(().into()),
|
Expr::Unit(_) => Ok(().into()),
|
||||||
|
|
||||||
Expr::Custom(x) => {
|
Expr::Custom(custom) => {
|
||||||
let func = (x.0).func();
|
let func = custom.func();
|
||||||
let expressions = (x.0)
|
let expressions = custom
|
||||||
.keywords()
|
.keywords()
|
||||||
.iter()
|
.iter()
|
||||||
.map(Into::into)
|
.map(Into::into)
|
||||||
|
@ -7,7 +7,7 @@ use crate::engine::{
|
|||||||
};
|
};
|
||||||
use crate::fn_call::run_builtin_binary_op;
|
use crate::fn_call::run_builtin_binary_op;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::parser::{map_dynamic_to_expr, Expr, ScriptFnDef, Stmt, AST};
|
use crate::parser::{map_dynamic_to_expr, BinaryExpr, Expr, ScriptFnDef, Stmt, AST};
|
||||||
use crate::scope::{Entry as ScopeEntry, Scope};
|
use crate::scope::{Entry as ScopeEntry, Scope};
|
||||||
use crate::token::{is_valid_identifier, Position};
|
use crate::token::{is_valid_identifier, Position};
|
||||||
use crate::{calc_fn_hash, StaticVec};
|
use crate::{calc_fn_hash, StaticVec};
|
||||||
@ -447,7 +447,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
|
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(x) => match (x.0, x.1) {
|
Expr::Dot(x) => match (x.lhs, x.rhs) {
|
||||||
// map.string
|
// map.string
|
||||||
(Expr::Map(m), Expr::Property(p)) if m.0.iter().all(|(_, x)| x.is_pure()) => {
|
(Expr::Map(m), Expr::Property(p)) if m.0.iter().all(|(_, x)| x.is_pure()) => {
|
||||||
let ((prop, _, _), _) = p.as_ref();
|
let ((prop, _, _), _) = p.as_ref();
|
||||||
@ -460,12 +460,16 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
.unwrap_or_else(|| Expr::Unit(pos))
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
}
|
}
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
(lhs, rhs) => Expr::Dot(Box::new((optimize_expr(lhs, state), optimize_expr(rhs, state), x.2)))
|
(lhs, rhs) => Expr::Dot(Box::new(BinaryExpr {
|
||||||
|
lhs: optimize_expr(lhs, state),
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
pos: x.pos
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
// lhs[rhs]
|
// lhs[rhs]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(x) => match (x.0, x.1) {
|
Expr::Index(x) => match (x.lhs, x.rhs) {
|
||||||
// array[int]
|
// array[int]
|
||||||
(Expr::Array(mut a), Expr::IntegerConstant(i))
|
(Expr::Array(mut a), Expr::IntegerConstant(i))
|
||||||
if i.0 >= 0 && (i.0 as usize) < a.0.len() && a.0.iter().all(Expr::is_pure) =>
|
if i.0 >= 0 && (i.0 as usize) < a.0.len() && a.0.iter().all(Expr::is_pure) =>
|
||||||
@ -494,7 +498,11 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
Expr::CharConstant(Box::new((s.0.chars().nth(i.0 as usize).unwrap(), s.1)))
|
Expr::CharConstant(Box::new((s.0.chars().nth(i.0 as usize).unwrap(), s.1)))
|
||||||
}
|
}
|
||||||
// lhs[rhs]
|
// lhs[rhs]
|
||||||
(lhs, rhs) => Expr::Index(Box::new((optimize_expr(lhs, state), optimize_expr(rhs, state), x.2))),
|
(lhs, rhs) => Expr::Index(Box::new(BinaryExpr {
|
||||||
|
lhs: optimize_expr(lhs, state),
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
pos: x.pos
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
// [ items .. ]
|
// [ items .. ]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
@ -507,7 +515,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
.into_iter().map(|((key, pos), expr)| ((key, pos), optimize_expr(expr, state)))
|
.into_iter().map(|((key, pos), expr)| ((key, pos), optimize_expr(expr, state)))
|
||||||
.collect(), m.1))),
|
.collect(), m.1))),
|
||||||
// lhs in rhs
|
// lhs in rhs
|
||||||
Expr::In(x) => match (x.0, x.1) {
|
Expr::In(x) => match (x.lhs, x.rhs) {
|
||||||
// "xxx" in "xxxxx"
|
// "xxx" in "xxxxx"
|
||||||
(Expr::StringConstant(a), Expr::StringConstant(b)) => {
|
(Expr::StringConstant(a), Expr::StringConstant(b)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -539,10 +547,14 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// lhs in rhs
|
// lhs in rhs
|
||||||
(lhs, rhs) => Expr::In(Box::new((optimize_expr(lhs, state), optimize_expr(rhs, state), x.2))),
|
(lhs, rhs) => Expr::In(Box::new(BinaryExpr {
|
||||||
|
lhs: optimize_expr(lhs, state),
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
pos: x.pos
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
// lhs && rhs
|
// lhs && rhs
|
||||||
Expr::And(x) => match (x.0, x.1) {
|
Expr::And(x) => match (x.lhs, x.rhs) {
|
||||||
// true && rhs -> rhs
|
// true && rhs -> rhs
|
||||||
(Expr::True(_), rhs) => {
|
(Expr::True(_), rhs) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -559,10 +571,14 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
optimize_expr(lhs, state)
|
optimize_expr(lhs, state)
|
||||||
}
|
}
|
||||||
// lhs && rhs
|
// lhs && rhs
|
||||||
(lhs, rhs) => Expr::And(Box::new((optimize_expr(lhs, state), optimize_expr(rhs, state), x.2))),
|
(lhs, rhs) => Expr::And(Box::new(BinaryExpr {
|
||||||
|
lhs: optimize_expr(lhs, state),
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
pos: x.pos
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
// lhs || rhs
|
// lhs || rhs
|
||||||
Expr::Or(x) => match (x.0, x.1) {
|
Expr::Or(x) => match (x.lhs, x.rhs) {
|
||||||
// false || rhs -> rhs
|
// false || rhs -> rhs
|
||||||
(Expr::False(_), rhs) => {
|
(Expr::False(_), rhs) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
@ -579,7 +595,11 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
|
|||||||
optimize_expr(lhs, state)
|
optimize_expr(lhs, state)
|
||||||
}
|
}
|
||||||
// lhs || rhs
|
// lhs || rhs
|
||||||
(lhs, rhs) => Expr::Or(Box::new((optimize_expr(lhs, state), optimize_expr(rhs, state), x.2))),
|
(lhs, rhs) => Expr::Or(Box::new(BinaryExpr {
|
||||||
|
lhs: optimize_expr(lhs, state),
|
||||||
|
rhs: optimize_expr(rhs, state),
|
||||||
|
pos: x.pos
|
||||||
|
})),
|
||||||
},
|
},
|
||||||
|
|
||||||
// Do not call some special keywords
|
// Do not call some special keywords
|
||||||
|
171
src/parser.rs
171
src/parser.rs
@ -924,19 +924,23 @@ impl Stmt {
|
|||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct CustomExpr(pub StaticVec<Expr>, pub Shared<FnCustomSyntaxEval>);
|
pub struct CustomExpr {
|
||||||
|
keywords: StaticVec<Expr>,
|
||||||
|
func: Shared<FnCustomSyntaxEval>,
|
||||||
|
pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
impl fmt::Debug for CustomExpr {
|
impl fmt::Debug for CustomExpr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
fmt::Debug::fmt(&self.0, f)
|
fmt::Debug::fmt(&self.keywords, f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hash for CustomExpr {
|
impl Hash for CustomExpr {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn hash<H: Hasher>(&self, state: &mut H) {
|
fn hash<H: Hasher>(&self, state: &mut H) {
|
||||||
self.0.hash(state);
|
self.keywords.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -944,12 +948,17 @@ impl CustomExpr {
|
|||||||
/// Get the keywords for this `CustomExpr`.
|
/// Get the keywords for this `CustomExpr`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn keywords(&self) -> &[Expr] {
|
pub fn keywords(&self) -> &[Expr] {
|
||||||
&self.0
|
&self.keywords
|
||||||
}
|
}
|
||||||
/// Get the implementation function for this `CustomExpr`.
|
/// Get the implementation function for this `CustomExpr`.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn func(&self) -> &FnCustomSyntaxEval {
|
pub fn func(&self) -> &FnCustomSyntaxEval {
|
||||||
self.1.as_ref()
|
self.func.as_ref()
|
||||||
|
}
|
||||||
|
/// Get the position of this `CustomExpr`.
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn position(&self) -> Position {
|
||||||
|
self.pos
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -975,6 +984,13 @@ impl Hash for FloatWrapper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Hash)]
|
||||||
|
pub struct BinaryExpr {
|
||||||
|
pub lhs: Expr,
|
||||||
|
pub rhs: Expr,
|
||||||
|
pub pos: Position,
|
||||||
|
}
|
||||||
|
|
||||||
/// _[INTERNALS]_ An expression sub-tree.
|
/// _[INTERNALS]_ An expression sub-tree.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
@ -1027,19 +1043,19 @@ pub enum Expr {
|
|||||||
/// expr op= expr
|
/// expr op= expr
|
||||||
Assignment(Box<(Expr, Cow<'static, str>, Expr, Position)>),
|
Assignment(Box<(Expr, Cow<'static, str>, Expr, Position)>),
|
||||||
/// lhs.rhs
|
/// lhs.rhs
|
||||||
Dot(Box<(Expr, Expr, Position)>),
|
Dot(Box<BinaryExpr>),
|
||||||
/// expr[expr]
|
/// expr[expr]
|
||||||
Index(Box<(Expr, Expr, Position)>),
|
Index(Box<BinaryExpr>),
|
||||||
/// [ expr, ... ]
|
/// [ expr, ... ]
|
||||||
Array(Box<(StaticVec<Expr>, Position)>),
|
Array(Box<(StaticVec<Expr>, Position)>),
|
||||||
/// #{ name:expr, ... }
|
/// #{ name:expr, ... }
|
||||||
Map(Box<(StaticVec<((ImmutableString, Position), Expr)>, Position)>),
|
Map(Box<(StaticVec<((ImmutableString, Position), Expr)>, Position)>),
|
||||||
/// lhs in rhs
|
/// lhs in rhs
|
||||||
In(Box<(Expr, Expr, Position)>),
|
In(Box<BinaryExpr>),
|
||||||
/// lhs && rhs
|
/// lhs && rhs
|
||||||
And(Box<(Expr, Expr, Position)>),
|
And(Box<BinaryExpr>),
|
||||||
/// lhs || rhs
|
/// lhs || rhs
|
||||||
Or(Box<(Expr, Expr, Position)>),
|
Or(Box<BinaryExpr>),
|
||||||
/// true
|
/// true
|
||||||
True(Position),
|
True(Position),
|
||||||
/// false
|
/// false
|
||||||
@ -1047,7 +1063,7 @@ pub enum Expr {
|
|||||||
/// ()
|
/// ()
|
||||||
Unit(Position),
|
Unit(Position),
|
||||||
/// Custom syntax
|
/// Custom syntax
|
||||||
Custom(Box<(CustomExpr, Position)>),
|
Custom(Box<CustomExpr>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Expr {
|
impl Default for Expr {
|
||||||
@ -1154,13 +1170,13 @@ impl Expr {
|
|||||||
Self::FnCall(x) => (x.0).3,
|
Self::FnCall(x) => (x.0).3,
|
||||||
Self::Assignment(x) => x.0.position(),
|
Self::Assignment(x) => x.0.position(),
|
||||||
|
|
||||||
Self::And(x) | Self::Or(x) | Self::In(x) => x.2,
|
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos,
|
||||||
|
|
||||||
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos,
|
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos,
|
||||||
|
|
||||||
Self::Dot(x) | Self::Index(x) => x.0.position(),
|
Self::Dot(x) | Self::Index(x) => x.lhs.position(),
|
||||||
|
|
||||||
Self::Custom(x) => x.1,
|
Self::Custom(x) => x.pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1184,16 +1200,11 @@ impl Expr {
|
|||||||
Self::Property(x) => x.1 = new_pos,
|
Self::Property(x) => x.1 = new_pos,
|
||||||
Self::Stmt(x) => x.1 = new_pos,
|
Self::Stmt(x) => x.1 = new_pos,
|
||||||
Self::FnCall(x) => (x.0).3 = new_pos,
|
Self::FnCall(x) => (x.0).3 = new_pos,
|
||||||
Self::And(x) => x.2 = new_pos,
|
Self::And(x) | Self::Or(x) | Self::In(x) => x.pos = new_pos,
|
||||||
Self::Or(x) => x.2 = new_pos,
|
Self::True(pos) | Self::False(pos) | Self::Unit(pos) => *pos = new_pos,
|
||||||
Self::In(x) => x.2 = new_pos,
|
|
||||||
Self::True(pos) => *pos = new_pos,
|
|
||||||
Self::False(pos) => *pos = new_pos,
|
|
||||||
Self::Unit(pos) => *pos = new_pos,
|
|
||||||
Self::Assignment(x) => x.3 = new_pos,
|
Self::Assignment(x) => x.3 = new_pos,
|
||||||
Self::Dot(x) => x.2 = new_pos,
|
Self::Dot(x) | Self::Index(x) => x.pos = new_pos,
|
||||||
Self::Index(x) => x.2 = new_pos,
|
Self::Custom(x) => x.pos = new_pos,
|
||||||
Self::Custom(x) => x.1 = new_pos,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
self
|
self
|
||||||
@ -1209,8 +1220,7 @@ impl Expr {
|
|||||||
Self::Array(x) => x.0.iter().all(Self::is_pure),
|
Self::Array(x) => x.0.iter().all(Self::is_pure),
|
||||||
|
|
||||||
Self::Index(x) | Self::And(x) | Self::Or(x) | Self::In(x) => {
|
Self::Index(x) | Self::And(x) | Self::Or(x) | Self::In(x) => {
|
||||||
let (lhs, rhs, _) = x.as_ref();
|
x.lhs.is_pure() && x.rhs.is_pure()
|
||||||
lhs.is_pure() && rhs.is_pure()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Self::Stmt(x) => x.0.is_pure(),
|
Self::Stmt(x) => x.0.is_pure(),
|
||||||
@ -1253,7 +1263,7 @@ impl Expr {
|
|||||||
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_literal),
|
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_literal),
|
||||||
|
|
||||||
// Check in expression
|
// Check in expression
|
||||||
Self::In(x) => match (&x.0, &x.1) {
|
Self::In(x) => match (&x.lhs, &x.rhs) {
|
||||||
(Self::StringConstant(_), Self::StringConstant(_))
|
(Self::StringConstant(_), Self::StringConstant(_))
|
||||||
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1286,7 +1296,7 @@ impl Expr {
|
|||||||
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
|
Self::Map(x) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
|
||||||
|
|
||||||
// Check in expression
|
// Check in expression
|
||||||
Self::In(x) => match (&x.0, &x.1) {
|
Self::In(x) => match (&x.lhs, &x.rhs) {
|
||||||
(Self::StringConstant(_), Self::StringConstant(_))
|
(Self::StringConstant(_), Self::StringConstant(_))
|
||||||
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
| (Self::CharConstant(_), Self::StringConstant(_)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
@ -1702,7 +1712,11 @@ fn parse_index_chain(
|
|||||||
let idx_expr =
|
let idx_expr =
|
||||||
parse_index_chain(input, state, lib, idx_expr, settings.level_up())?;
|
parse_index_chain(input, state, lib, idx_expr, settings.level_up())?;
|
||||||
// Indexing binds to right
|
// Indexing binds to right
|
||||||
Ok(Expr::Index(Box::new((lhs, idx_expr, prev_pos))))
|
Ok(Expr::Index(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs: idx_expr,
|
||||||
|
pos: prev_pos,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
// Otherwise terminate the indexing chain
|
// Otherwise terminate the indexing chain
|
||||||
_ => {
|
_ => {
|
||||||
@ -1710,10 +1724,18 @@ fn parse_index_chain(
|
|||||||
// Terminate with an `Expr::Expr` wrapper to prevent the last index expression
|
// Terminate with an `Expr::Expr` wrapper to prevent the last index expression
|
||||||
// inside brackets to be mis-parsed as another level of indexing, or a
|
// inside brackets to be mis-parsed as another level of indexing, or a
|
||||||
// dot expression/function call to be mis-parsed as following the indexing chain.
|
// dot expression/function call to be mis-parsed as following the indexing chain.
|
||||||
Expr::Index(_) | Expr::Dot(_) | Expr::FnCall(_) => Ok(Expr::Index(
|
Expr::Index(_) | Expr::Dot(_) | Expr::FnCall(_) => {
|
||||||
Box::new((lhs, Expr::Expr(Box::new(idx_expr)), settings.pos)),
|
Ok(Expr::Index(Box::new(BinaryExpr {
|
||||||
)),
|
lhs,
|
||||||
_ => Ok(Expr::Index(Box::new((lhs, idx_expr, settings.pos)))),
|
rhs: Expr::Expr(Box::new(idx_expr)),
|
||||||
|
pos: settings.pos,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
_ => Ok(Expr::Index(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs: idx_expr,
|
||||||
|
pos: settings.pos,
|
||||||
|
}))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2247,7 +2269,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// xxx[???] = rhs, xxx.??? = rhs
|
// xxx[???] = rhs, xxx.??? = rhs
|
||||||
Expr::Index(x) | Expr::Dot(x) => match &x.0 {
|
Expr::Index(x) | Expr::Dot(x) => match &x.lhs {
|
||||||
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
|
// var[???] (non-indexed) = rhs, var.??? (non-indexed) = rhs
|
||||||
Expr::Variable(x) if x.3.is_none() => {
|
Expr::Variable(x) if x.3.is_none() => {
|
||||||
Ok(Expr::Assignment(Box::new((lhs, fn_name.into(), rhs, pos))))
|
Ok(Expr::Assignment(Box::new((lhs, fn_name.into(), rhs, pos))))
|
||||||
@ -2266,7 +2288,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
// expr[???] = rhs, expr.??? = rhs
|
// expr[???] = rhs, expr.??? = rhs
|
||||||
_ => Err(PERR::AssignmentToCopy.into_err(x.0.position())),
|
_ => Err(PERR::AssignmentToCopy.into_err(x.lhs.position())),
|
||||||
},
|
},
|
||||||
// const_expr = rhs
|
// const_expr = rhs
|
||||||
expr if expr.is_constant() => {
|
expr if expr.is_constant() => {
|
||||||
@ -2324,13 +2346,9 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
|
|||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
// idx_lhs[idx_expr].rhs
|
// idx_lhs[idx_expr].rhs
|
||||||
// Attach dot chain to the bottom level of indexing chain
|
// Attach dot chain to the bottom level of indexing chain
|
||||||
(Expr::Index(x), rhs) => {
|
(Expr::Index(mut x), rhs) => {
|
||||||
let (idx_lhs, idx_expr, pos) = *x;
|
x.rhs = make_dot_expr(x.rhs, rhs, op_pos)?;
|
||||||
Expr::Index(Box::new((
|
Expr::Index(x)
|
||||||
idx_lhs,
|
|
||||||
make_dot_expr(idx_expr, rhs, op_pos)?,
|
|
||||||
pos,
|
|
||||||
)))
|
|
||||||
}
|
}
|
||||||
// lhs.id
|
// lhs.id
|
||||||
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
||||||
@ -2340,31 +2358,47 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
|
|||||||
let setter = make_setter(&name);
|
let setter = make_setter(&name);
|
||||||
let rhs = Expr::Property(Box::new(((name.into(), getter, setter), pos)));
|
let rhs = Expr::Property(Box::new(((name.into(), getter, setter), pos)));
|
||||||
|
|
||||||
Expr::Dot(Box::new((lhs, rhs, op_pos)))
|
Expr::Dot(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
pos: op_pos,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
// lhs.module::id - syntax error
|
// lhs.module::id - syntax error
|
||||||
(_, Expr::Variable(x)) if x.1.is_some() => {
|
(_, Expr::Variable(x)) if x.1.is_some() => {
|
||||||
return Err(PERR::PropertyExpected.into_err(x.1.unwrap()[0].1));
|
return Err(PERR::PropertyExpected.into_err(x.1.unwrap()[0].1));
|
||||||
}
|
}
|
||||||
// lhs.prop
|
// lhs.prop
|
||||||
(lhs, prop @ Expr::Property(_)) => Expr::Dot(Box::new((lhs, prop, op_pos))),
|
(lhs, prop @ Expr::Property(_)) => Expr::Dot(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs: prop,
|
||||||
|
pos: op_pos,
|
||||||
|
})),
|
||||||
// lhs.dot_lhs.dot_rhs
|
// lhs.dot_lhs.dot_rhs
|
||||||
(lhs, Expr::Dot(x)) => {
|
(lhs, Expr::Dot(x)) => {
|
||||||
let (dot_lhs, dot_rhs, pos) = *x;
|
let rhs = Expr::Dot(Box::new(BinaryExpr {
|
||||||
Expr::Dot(Box::new((
|
lhs: x.lhs.into_property(),
|
||||||
|
rhs: x.rhs,
|
||||||
|
pos: x.pos,
|
||||||
|
}));
|
||||||
|
Expr::Dot(Box::new(BinaryExpr {
|
||||||
lhs,
|
lhs,
|
||||||
Expr::Dot(Box::new((dot_lhs.into_property(), dot_rhs, pos))),
|
rhs,
|
||||||
op_pos,
|
pos: op_pos,
|
||||||
)))
|
}))
|
||||||
}
|
}
|
||||||
// lhs.idx_lhs[idx_rhs]
|
// lhs.idx_lhs[idx_rhs]
|
||||||
(lhs, Expr::Index(x)) => {
|
(lhs, Expr::Index(x)) => {
|
||||||
let (dot_lhs, dot_rhs, pos) = *x;
|
let rhs = Expr::Index(Box::new(BinaryExpr {
|
||||||
Expr::Dot(Box::new((
|
lhs: x.lhs.into_property(),
|
||||||
|
rhs: x.rhs,
|
||||||
|
pos: x.pos,
|
||||||
|
}));
|
||||||
|
Expr::Dot(Box::new(BinaryExpr {
|
||||||
lhs,
|
lhs,
|
||||||
Expr::Index(Box::new((dot_lhs.into_property(), dot_rhs, pos))),
|
rhs,
|
||||||
op_pos,
|
pos: op_pos,
|
||||||
)))
|
}))
|
||||||
}
|
}
|
||||||
// lhs.Fn() or lhs.eval()
|
// lhs.Fn() or lhs.eval()
|
||||||
(_, Expr::FnCall(x))
|
(_, Expr::FnCall(x))
|
||||||
@ -2385,7 +2419,11 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
|
|||||||
.into_err((x.0).3))
|
.into_err((x.0).3))
|
||||||
}
|
}
|
||||||
// lhs.func(...)
|
// lhs.func(...)
|
||||||
(lhs, func @ Expr::FnCall(_)) => Expr::Dot(Box::new((lhs, func, op_pos))),
|
(lhs, func @ Expr::FnCall(_)) => Expr::Dot(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs: func,
|
||||||
|
pos: op_pos,
|
||||||
|
})),
|
||||||
// lhs.rhs
|
// lhs.rhs
|
||||||
(_, rhs) => return Err(PERR::PropertyExpected.into_err(rhs.position())),
|
(_, rhs) => return Err(PERR::PropertyExpected.into_err(rhs.position())),
|
||||||
})
|
})
|
||||||
@ -2538,7 +2576,11 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Expr::In(Box::new((lhs, rhs, op_pos))))
|
Ok(Expr::In(Box::new(BinaryExpr {
|
||||||
|
lhs,
|
||||||
|
rhs,
|
||||||
|
pos: op_pos,
|
||||||
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a binary expression.
|
/// Parse a binary expression.
|
||||||
@ -2653,12 +2695,20 @@ fn parse_binary_op(
|
|||||||
Token::Or => {
|
Token::Or => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = args.pop().unwrap();
|
||||||
let current_lhs = args.pop().unwrap();
|
let current_lhs = args.pop().unwrap();
|
||||||
Expr::Or(Box::new((current_lhs, rhs, pos)))
|
Expr::Or(Box::new(BinaryExpr {
|
||||||
|
lhs: current_lhs,
|
||||||
|
rhs,
|
||||||
|
pos,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
Token::And => {
|
Token::And => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = args.pop().unwrap();
|
||||||
let current_lhs = args.pop().unwrap();
|
let current_lhs = args.pop().unwrap();
|
||||||
Expr::And(Box::new((current_lhs, rhs, pos)))
|
Expr::And(Box::new(BinaryExpr {
|
||||||
|
lhs: current_lhs,
|
||||||
|
rhs,
|
||||||
|
pos,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
Token::In => {
|
Token::In => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = args.pop().unwrap();
|
||||||
@ -2764,10 +2814,11 @@ fn parse_custom_syntax(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Expr::Custom(Box::new((
|
Ok(Expr::Custom(Box::new(CustomExpr {
|
||||||
CustomExpr(exprs, syntax.func.clone()),
|
keywords: exprs,
|
||||||
|
func: syntax.func.clone(),
|
||||||
pos,
|
pos,
|
||||||
))))
|
})))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse an expression.
|
/// Parse an expression.
|
||||||
|
Loading…
Reference in New Issue
Block a user