commit
c7cbe71142
@ -4,13 +4,17 @@ Rhai Release Notes
|
|||||||
Version 0.19.9
|
Version 0.19.9
|
||||||
==============
|
==============
|
||||||
|
|
||||||
This version removes the confusing differences between _packages_ and _modules_
|
This version fixes a bug introduced in `0.19.8` which breaks property access
|
||||||
|
within closures.
|
||||||
|
|
||||||
|
It also removes the confusing differences between _packages_ and _modules_
|
||||||
by unifying the terminology and API under the global umbrella of _modules_.
|
by unifying the terminology and API under the global umbrella of _modules_.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* Property access in
|
* Fix bug when accessing properties in closures.
|
||||||
|
* Fix bug when accessing a deep index with a function call.
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
@ -53,9 +53,10 @@ In this case, the first parameter should be `&mut T` of the custom type and the
|
|||||||
Script-defined [function] signatures contain parameter names. Since all parameters, as well as
|
Script-defined [function] signatures contain parameter names. Since all parameters, as well as
|
||||||
the return value, are [`Dynamic`] the types are simply not shown.
|
the return value, are [`Dynamic`] the types are simply not shown.
|
||||||
|
|
||||||
A script-defined function always takes dynamic arguments, and the return type is also dynamic:
|
A script-defined function always takes dynamic arguments, and the return type is also dynamic,
|
||||||
|
so no type information is needed:
|
||||||
|
|
||||||
> `foo(x, y, z) -> Dynamic`
|
> `foo(x, y, z)`
|
||||||
|
|
||||||
probably defined as:
|
probably defined as:
|
||||||
|
|
||||||
|
30
src/ast.rs
30
src/ast.rs
@ -91,7 +91,7 @@ impl fmt::Display for ScriptFnDef {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}({}) -> Dynamic",
|
"{}{}({})",
|
||||||
if self.access.is_private() {
|
if self.access.is_private() {
|
||||||
"private "
|
"private "
|
||||||
} else {
|
} else {
|
||||||
@ -133,7 +133,7 @@ impl fmt::Display for ScriptFnMetadata<'_> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}({}) -> Dynamic",
|
"{}{}({})",
|
||||||
if self.access.is_private() {
|
if self.access.is_private() {
|
||||||
"private "
|
"private "
|
||||||
} else {
|
} else {
|
||||||
@ -646,7 +646,7 @@ impl AsRef<Module> for AST {
|
|||||||
/// ## WARNING
|
/// ## WARNING
|
||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Ident {
|
pub struct Ident {
|
||||||
/// Identifier name.
|
/// Identifier name.
|
||||||
pub name: ImmutableString,
|
pub name: ImmutableString,
|
||||||
@ -654,6 +654,12 @@ pub struct Ident {
|
|||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Ident {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Ident({:?} @ {:?})", self.name, self.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement.
|
/// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
@ -824,7 +830,7 @@ impl Stmt {
|
|||||||
Self::Import(_, _, _) | Self::Export(_, _) => false,
|
Self::Import(_, _, _) | Self::Export(_, _) => false,
|
||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Self::Share(_) => unreachable!(),
|
Self::Share(_) => unreachable!("Stmt::Share should not be parsed"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this statement _pure_?
|
/// Is this statement _pure_?
|
||||||
@ -973,8 +979,6 @@ pub enum Expr {
|
|||||||
Property(Box<(ImmutableString, ImmutableString, Ident)>),
|
Property(Box<(ImmutableString, ImmutableString, Ident)>),
|
||||||
/// { [statement][Stmt] }
|
/// { [statement][Stmt] }
|
||||||
Stmt(Box<StaticVec<Stmt>>, Position),
|
Stmt(Box<StaticVec<Stmt>>, Position),
|
||||||
/// Wrapped [expression][Expr] - should not be optimized away.
|
|
||||||
Expr(Box<Expr>),
|
|
||||||
/// func `(` expr `,` ... `)`
|
/// func `(` expr `,` ... `)`
|
||||||
FnCall(Box<FnCallExpr>, Position),
|
FnCall(Box<FnCallExpr>, Position),
|
||||||
/// lhs `.` rhs
|
/// lhs `.` rhs
|
||||||
@ -1004,8 +1008,6 @@ impl Expr {
|
|||||||
/// Returns [`None`] if the expression is not constant.
|
/// Returns [`None`] if the expression is not constant.
|
||||||
pub fn get_constant_value(&self) -> Option<Dynamic> {
|
pub fn get_constant_value(&self) -> Option<Dynamic> {
|
||||||
Some(match self {
|
Some(match self {
|
||||||
Self::Expr(x) => return x.get_constant_value(),
|
|
||||||
|
|
||||||
Self::DynamicConstant(x, _) => x.as_ref().clone(),
|
Self::DynamicConstant(x, _) => x.as_ref().clone(),
|
||||||
Self::IntegerConstant(x, _) => (*x).into(),
|
Self::IntegerConstant(x, _) => (*x).into(),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -1055,8 +1057,6 @@ impl Expr {
|
|||||||
/// Get the [position][Position] of the expression.
|
/// Get the [position][Position] of the expression.
|
||||||
pub fn position(&self) -> Position {
|
pub fn position(&self) -> Position {
|
||||||
match self {
|
match self {
|
||||||
Self::Expr(x) => x.position(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, pos) => *pos,
|
Self::FloatConstant(_, pos) => *pos,
|
||||||
|
|
||||||
@ -1085,10 +1085,6 @@ impl Expr {
|
|||||||
/// Override the [position][Position] of the expression.
|
/// Override the [position][Position] of the expression.
|
||||||
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
pub fn set_position(&mut self, new_pos: Position) -> &mut Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Expr(x) => {
|
|
||||||
x.set_position(new_pos);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, pos) => *pos = new_pos,
|
Self::FloatConstant(_, pos) => *pos = new_pos,
|
||||||
|
|
||||||
@ -1117,8 +1113,6 @@ impl Expr {
|
|||||||
/// A pure expression has no side effects.
|
/// A pure expression has no side effects.
|
||||||
pub fn is_pure(&self) -> bool {
|
pub fn is_pure(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Expr(x) => x.is_pure(),
|
|
||||||
|
|
||||||
Self::Array(x, _) => x.iter().all(Self::is_pure),
|
Self::Array(x, _) => x.iter().all(Self::is_pure),
|
||||||
|
|
||||||
Self::Map(x, _) => x.iter().map(|(_, v)| v).all(Self::is_pure),
|
Self::Map(x, _) => x.iter().map(|(_, v)| v).all(Self::is_pure),
|
||||||
@ -1145,8 +1139,6 @@ impl Expr {
|
|||||||
/// Is the expression a constant?
|
/// Is the expression a constant?
|
||||||
pub fn is_constant(&self) -> bool {
|
pub fn is_constant(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Expr(x) => x.is_constant(),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, _) => true,
|
Self::FloatConstant(_, _) => true,
|
||||||
|
|
||||||
@ -1183,8 +1175,6 @@ impl Expr {
|
|||||||
}
|
}
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Expr(x) => x.is_valid_postfix(token),
|
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, _) => false,
|
Self::FloatConstant(_, _) => false,
|
||||||
|
|
||||||
|
@ -812,6 +812,7 @@ impl Dynamic {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(feature = "sync")]
|
#[cfg(feature = "sync")]
|
||||||
Union::Shared(cell, _) => return cell.read().unwrap().clone().try_cast(),
|
Union::Shared(cell, _) => return cell.read().unwrap().clone().try_cast(),
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -903,7 +904,7 @@ impl Dynamic {
|
|||||||
match self.0 {
|
match self.0 {
|
||||||
Union::Variant(value, _) => (*value).as_box_any().downcast().map(|x| *x).ok(),
|
Union::Variant(value, _) => (*value).as_box_any().downcast().map(|x| *x).ok(),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Union::Shared(_, _) => unreachable!(),
|
Union::Shared(_, _) => unreachable!("Union::Shared case should be already handled"),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -225,7 +225,7 @@ impl IndexChainValue {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
pub fn as_value(self) -> Dynamic {
|
pub fn as_value(self) -> Dynamic {
|
||||||
match self {
|
match self {
|
||||||
Self::None | Self::FnCallArgs(_) => unreachable!("expecting IndexChainValue::Value"),
|
Self::None | Self::FnCallArgs(_) => panic!("expecting IndexChainValue::Value"),
|
||||||
Self::Value(value) => value,
|
Self::Value(value) => value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -237,7 +237,7 @@ impl IndexChainValue {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
pub fn as_fn_call_args(self) -> StaticVec<Dynamic> {
|
||||||
match self {
|
match self {
|
||||||
Self::None | Self::Value(_) => unreachable!("expecting IndexChainValue::FnCallArgs"),
|
Self::None | Self::Value(_) => panic!("expecting IndexChainValue::FnCallArgs"),
|
||||||
Self::FnCallArgs(value) => value,
|
Self::FnCallArgs(value) => value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -382,7 +382,7 @@ impl<'a> Target<'a> {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Self::LockGuard((r, _)) => **r = new_val,
|
Self::LockGuard((r, _)) => **r = new_val,
|
||||||
Self::Value(_) => unreachable!(),
|
Self::Value(_) => panic!("cannot update a value"),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Self::StringChar(string, index, _) if string.is::<ImmutableString>() => {
|
Self::StringChar(string, index, _) if string.is::<ImmutableString>() => {
|
||||||
let mut s = string.write_lock::<ImmutableString>().unwrap();
|
let mut s = string.write_lock::<ImmutableString>().unwrap();
|
||||||
@ -896,7 +896,7 @@ impl Engine {
|
|||||||
// Normal variable access
|
// Normal variable access
|
||||||
_ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
_ => self.search_scope_only(scope, mods, state, lib, this_ptr, expr),
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!("Expr::Variable expected, but gets {:?}", expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -912,7 +912,7 @@ impl Engine {
|
|||||||
) -> Result<(Target<'s>, Position), Box<EvalAltResult>> {
|
) -> Result<(Target<'s>, Position), Box<EvalAltResult>> {
|
||||||
let (index, _, Ident { name, pos }) = match expr {
|
let (index, _, Ident { name, pos }) = match expr {
|
||||||
Expr::Variable(v) => v.as_ref(),
|
Expr::Variable(v) => v.as_ref(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!("Expr::Variable expected, but gets {:?}", expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the variable is `this`
|
// Check if the variable is `this`
|
||||||
@ -988,7 +988,7 @@ impl Engine {
|
|||||||
new_val: Option<(Dynamic, Position)>,
|
new_val: Option<(Dynamic, Position)>,
|
||||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||||
if chain_type == ChainType::None {
|
if chain_type == ChainType::None {
|
||||||
unreachable!();
|
unreachable!("should not be ChainType::None");
|
||||||
}
|
}
|
||||||
|
|
||||||
let is_ref = target.is_ref();
|
let is_ref = target.is_ref();
|
||||||
@ -1103,7 +1103,9 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => unreachable!(),
|
Expr::FnCall(_, _) => {
|
||||||
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
|
}
|
||||||
// {xxx:map}.id = ???
|
// {xxx:map}.id = ???
|
||||||
Expr::Property(x) if target_val.is::<Map>() && new_val.is_some() => {
|
Expr::Property(x) if target_val.is::<Map>() && new_val.is_some() => {
|
||||||
let Ident { name, pos } = &x.2;
|
let Ident { name, pos } = &x.2;
|
||||||
@ -1178,9 +1180,11 @@ impl Engine {
|
|||||||
val.into()
|
val.into()
|
||||||
}
|
}
|
||||||
// {xxx:map}.module::fn_name(...) - syntax error
|
// {xxx:map}.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => unreachable!(),
|
Expr::FnCall(_, _) => unreachable!(
|
||||||
|
"function call in dot chain should not be namespace-qualified"
|
||||||
|
),
|
||||||
// Others - syntax error
|
// Others - syntax error
|
||||||
_ => unreachable!(),
|
expr => unreachable!("invalid dot expression: {:?}", expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.eval_dot_index_chain_helper(
|
self.eval_dot_index_chain_helper(
|
||||||
@ -1266,9 +1270,11 @@ impl Engine {
|
|||||||
.map_err(|err| err.fill_position(*pos))
|
.map_err(|err| err.fill_position(*pos))
|
||||||
}
|
}
|
||||||
// xxx.module::fn_name(...) - syntax error
|
// xxx.module::fn_name(...) - syntax error
|
||||||
Expr::FnCall(_, _) => unreachable!(),
|
Expr::FnCall(_, _) => unreachable!(
|
||||||
|
"function call in dot chain should not be namespace-qualified"
|
||||||
|
),
|
||||||
// Others - syntax error
|
// Others - syntax error
|
||||||
_ => unreachable!(),
|
expr => unreachable!("invalid dot expression: {:?}", expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Syntax error
|
// Syntax error
|
||||||
@ -1276,7 +1282,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unreachable!(),
|
chain_type => unreachable!("invalid ChainType: {:?}", chain_type),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1296,7 +1302,7 @@ impl Engine {
|
|||||||
let (crate::ast::BinaryExpr { lhs, rhs }, chain_type, op_pos) = match expr {
|
let (crate::ast::BinaryExpr { lhs, rhs }, chain_type, op_pos) = match expr {
|
||||||
Expr::Index(x, pos) => (x.as_ref(), ChainType::Index, *pos),
|
Expr::Index(x, pos) => (x.as_ref(), ChainType::Index, *pos),
|
||||||
Expr::Dot(x, pos) => (x.as_ref(), ChainType::Dot, *pos),
|
Expr::Dot(x, pos) => (x.as_ref(), ChainType::Dot, *pos),
|
||||||
_ => unreachable!(),
|
_ => unreachable!("index or dot chain expected, but gets {:?}", expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
let idx_values = &mut Default::default();
|
let idx_values = &mut Default::default();
|
||||||
@ -1333,7 +1339,7 @@ impl Engine {
|
|||||||
.map_err(|err| err.fill_position(op_pos))
|
.map_err(|err| err.fill_position(op_pos))
|
||||||
}
|
}
|
||||||
// {expr}.??? = ??? or {expr}[???] = ???
|
// {expr}.??? = ??? or {expr}[???] = ???
|
||||||
_ if new_val.is_some() => unreachable!(),
|
_ if new_val.is_some() => unreachable!("cannot assign to an expression"),
|
||||||
// {expr}.??? or {expr}[???]
|
// {expr}.??? or {expr}[???]
|
||||||
expr => {
|
expr => {
|
||||||
let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
let val = self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?;
|
||||||
@ -1359,7 +1365,7 @@ impl Engine {
|
|||||||
lib: &[&Module],
|
lib: &[&Module],
|
||||||
this_ptr: &mut Option<&mut Dynamic>,
|
this_ptr: &mut Option<&mut Dynamic>,
|
||||||
expr: &Expr,
|
expr: &Expr,
|
||||||
chain_type: ChainType,
|
parent_chain_type: ChainType,
|
||||||
idx_values: &mut StaticVec<IndexChainValue>,
|
idx_values: &mut StaticVec<IndexChainValue>,
|
||||||
size: usize,
|
size: usize,
|
||||||
level: usize,
|
level: usize,
|
||||||
@ -1367,7 +1373,7 @@ impl Engine {
|
|||||||
self.inc_operations(state, expr.position())?;
|
self.inc_operations(state, expr.position())?;
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
Expr::FnCall(x, _) if x.namespace.is_none() => {
|
Expr::FnCall(x, _) if parent_chain_type == ChainType::Dot && x.namespace.is_none() => {
|
||||||
let arg_values = x
|
let arg_values = x
|
||||||
.args
|
.args
|
||||||
.iter()
|
.iter()
|
||||||
@ -1378,15 +1384,27 @@ impl Engine {
|
|||||||
|
|
||||||
idx_values.push(arg_values.into());
|
idx_values.push(arg_values.into());
|
||||||
}
|
}
|
||||||
Expr::FnCall(_, _) => unreachable!(),
|
Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => {
|
||||||
Expr::Property(_) => idx_values.push(IndexChainValue::None),
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
|
}
|
||||||
|
|
||||||
|
Expr::Property(_) if parent_chain_type == ChainType::Dot => {
|
||||||
|
idx_values.push(IndexChainValue::None)
|
||||||
|
}
|
||||||
|
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
||||||
|
|
||||||
Expr::Index(x, _) | Expr::Dot(x, _) => {
|
Expr::Index(x, _) | Expr::Dot(x, _) => {
|
||||||
let crate::ast::BinaryExpr { lhs, rhs, .. } = x.as_ref();
|
let crate::ast::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 {
|
||||||
Expr::Property(_) => IndexChainValue::None,
|
Expr::Property(_) if parent_chain_type == ChainType::Dot => {
|
||||||
Expr::FnCall(x, _) if chain_type == ChainType::Dot && x.namespace.is_none() => {
|
IndexChainValue::None
|
||||||
|
}
|
||||||
|
Expr::Property(_) => unreachable!("unexpected Expr::Property for indexing"),
|
||||||
|
Expr::FnCall(x, _)
|
||||||
|
if parent_chain_type == ChainType::Dot && x.namespace.is_none() =>
|
||||||
|
{
|
||||||
x.args
|
x.args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|arg_expr| {
|
.map(|arg_expr| {
|
||||||
@ -1395,7 +1413,9 @@ impl Engine {
|
|||||||
.collect::<Result<StaticVec<Dynamic>, _>>()?
|
.collect::<Result<StaticVec<Dynamic>, _>>()?
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
Expr::FnCall(_, _) => unreachable!(),
|
Expr::FnCall(_, _) if parent_chain_type == ChainType::Dot => {
|
||||||
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
|
}
|
||||||
_ => self
|
_ => self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?
|
.eval_expr(scope, mods, state, lib, this_ptr, lhs, level)?
|
||||||
.into(),
|
.into(),
|
||||||
@ -1405,7 +1425,7 @@ impl Engine {
|
|||||||
let chain_type = match expr {
|
let chain_type = match expr {
|
||||||
Expr::Index(_, _) => ChainType::Index,
|
Expr::Index(_, _) => ChainType::Index,
|
||||||
Expr::Dot(_, _) => ChainType::Dot,
|
Expr::Dot(_, _) => ChainType::Dot,
|
||||||
_ => unreachable!(),
|
_ => unreachable!("index or dot chain expected, but gets {:?}", expr),
|
||||||
};
|
};
|
||||||
self.eval_indexed_chain(
|
self.eval_indexed_chain(
|
||||||
scope, mods, state, lib, this_ptr, rhs, chain_type, idx_values, size, level,
|
scope, mods, state, lib, this_ptr, rhs, chain_type, idx_values, size, level,
|
||||||
@ -1413,6 +1433,7 @@ impl Engine {
|
|||||||
|
|
||||||
idx_values.push(lhs_val);
|
idx_values.push(lhs_val);
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => idx_values.push(
|
_ => idx_values.push(
|
||||||
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||||
.into(),
|
.into(),
|
||||||
@ -1622,7 +1643,7 @@ impl Engine {
|
|||||||
// var[...]
|
// var[...]
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs {
|
Expr::Index(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs {
|
||||||
Expr::Property(_) => unreachable!(),
|
Expr::Property(_) => unreachable!("unexpected Expr::Property in indexing"),
|
||||||
// var[...]...
|
// var[...]...
|
||||||
Expr::FnCall(_, _) | Expr::Index(_, _) | Expr::Dot(_, _) => self
|
Expr::FnCall(_, _) | Expr::Index(_, _) | Expr::Dot(_, _) => self
|
||||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)
|
||||||
@ -1655,7 +1676,9 @@ impl Engine {
|
|||||||
// var.prop
|
// var.prop
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs {
|
Expr::Dot(x, _) if x.lhs.get_variable_access(false).is_some() => match x.rhs {
|
||||||
Expr::Variable(_) => unreachable!(),
|
Expr::Variable(_) => unreachable!(
|
||||||
|
"unexpected Expr::Variable in dot access (should be Expr::Property)"
|
||||||
|
),
|
||||||
// var.prop
|
// var.prop
|
||||||
Expr::Property(ref p) => {
|
Expr::Property(ref p) => {
|
||||||
let (mut target, _) = self.eval_expr_as_target(
|
let (mut target, _) = self.eval_expr_as_target(
|
||||||
@ -1718,8 +1741,6 @@ impl Engine {
|
|||||||
self.inc_operations(state, expr.position())?;
|
self.inc_operations(state, expr.position())?;
|
||||||
|
|
||||||
let result = match expr {
|
let result = match expr {
|
||||||
Expr::Expr(x) => self.eval_expr(scope, mods, state, lib, this_ptr, x, level),
|
|
||||||
|
|
||||||
Expr::DynamicConstant(x, _) => Ok(x.as_ref().clone()),
|
Expr::DynamicConstant(x, _) => Ok(x.as_ref().clone()),
|
||||||
Expr::IntegerConstant(x, _) => Ok((*x).into()),
|
Expr::IntegerConstant(x, _) => Ok((*x).into()),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -1738,7 +1759,6 @@ impl Engine {
|
|||||||
let (val, _) = self.search_namespace(scope, mods, state, lib, this_ptr, expr)?;
|
let (val, _) = self.search_namespace(scope, mods, state, lib, this_ptr, expr)?;
|
||||||
Ok(val.take_or_clone())
|
Ok(val.take_or_clone())
|
||||||
}
|
}
|
||||||
Expr::Property(_) => unreachable!(),
|
|
||||||
|
|
||||||
// Statement block
|
// Statement block
|
||||||
Expr::Stmt(x, _) => {
|
Expr::Stmt(x, _) => {
|
||||||
@ -1867,7 +1887,7 @@ impl Engine {
|
|||||||
(custom.func)(&mut context, &expressions)
|
(custom.func)(&mut context, &expressions)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => unreachable!(),
|
_ => unreachable!("expression cannot be evaluated: {:?}", expr),
|
||||||
};
|
};
|
||||||
|
|
||||||
self.check_data_size(result, expr.position())
|
self.check_data_size(result, expr.position())
|
||||||
@ -2072,7 +2092,9 @@ impl Engine {
|
|||||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||||
match lhs_expr {
|
match lhs_expr {
|
||||||
// name op= rhs (handled above)
|
// name op= rhs (handled above)
|
||||||
Expr::Variable(_) => unreachable!(),
|
Expr::Variable(_) => {
|
||||||
|
unreachable!("Expr::Variable case should already been handled")
|
||||||
|
}
|
||||||
// idx_lhs[idx_expr] op= rhs
|
// idx_lhs[idx_expr] op= rhs
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Expr::Index(_, _) => {
|
Expr::Index(_, _) => {
|
||||||
@ -2090,7 +2112,7 @@ impl Engine {
|
|||||||
Ok(Dynamic::UNIT)
|
Ok(Dynamic::UNIT)
|
||||||
}
|
}
|
||||||
// Non-lvalue expression (should be caught during parsing)
|
// Non-lvalue expression (should be caught during parsing)
|
||||||
_ => unreachable!(),
|
_ => unreachable!("cannot assign to expression: {:?}", lhs_expr),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2334,7 +2356,7 @@ impl Engine {
|
|||||||
let entry_type = match stmt {
|
let entry_type = match stmt {
|
||||||
Stmt::Let(_, _, _, _) => AccessMode::ReadWrite,
|
Stmt::Let(_, _, _, _) => AccessMode::ReadWrite,
|
||||||
Stmt::Const(_, _, _, _) => AccessMode::ReadOnly,
|
Stmt::Const(_, _, _, _) => AccessMode::ReadOnly,
|
||||||
_ => unreachable!(),
|
_ => unreachable!("should be Stmt::Let or Stmt::Const, but gets {:?}", stmt),
|
||||||
};
|
};
|
||||||
|
|
||||||
let val = if let Some(expr) = expr {
|
let val = if let Some(expr) = expr {
|
||||||
@ -2353,7 +2375,7 @@ impl Engine {
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
} else if *export {
|
} else if *export {
|
||||||
unreachable!();
|
unreachable!("exported variable not on global level");
|
||||||
} else {
|
} else {
|
||||||
(unsafe_cast_var_name_to_lifetime(&var_def.name).into(), None)
|
(unsafe_cast_var_name_to_lifetime(&var_def.name).into(), None)
|
||||||
};
|
};
|
||||||
|
@ -118,7 +118,7 @@ impl Drop for ArgBackup<'_> {
|
|||||||
// Panic if the shorter lifetime leaks.
|
// Panic if the shorter lifetime leaks.
|
||||||
assert!(
|
assert!(
|
||||||
self.orig_mut.is_none(),
|
self.orig_mut.is_none(),
|
||||||
"MutBackup::restore has not been called prior to existing this scope"
|
"ArgBackup::restore_first_arg has not been called prior to existing this scope"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -672,7 +672,9 @@ impl Engine {
|
|||||||
})
|
})
|
||||||
.or_else(|err| match *err {
|
.or_else(|err| match *err {
|
||||||
EvalAltResult::Return(out, _) => Ok(out),
|
EvalAltResult::Return(out, _) => Ok(out),
|
||||||
EvalAltResult::LoopBreak(_, _) => unreachable!(),
|
EvalAltResult::LoopBreak(_, _) => {
|
||||||
|
unreachable!("no outer loop scope to break out of")
|
||||||
|
}
|
||||||
_ => Err(err),
|
_ => Err(err),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -1227,7 +1229,7 @@ impl Engine {
|
|||||||
|
|
||||||
f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut())
|
f.get_native_fn()((self, module.id_raw(), &*mods, lib).into(), args.as_mut())
|
||||||
}
|
}
|
||||||
Some(_) => unreachable!(),
|
Some(f) => unreachable!("unknown function type: {:?}", f),
|
||||||
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
None if def_val.is_some() => Ok(def_val.unwrap().clone()),
|
||||||
None => EvalAltResult::ErrorFunctionNotFound(
|
None => EvalAltResult::ErrorFunctionNotFound(
|
||||||
format!(
|
format!(
|
||||||
|
@ -535,10 +535,10 @@ impl CallableFunction {
|
|||||||
pub fn get_native_fn(&self) -> &FnAny {
|
pub fn get_native_fn(&self) -> &FnAny {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(f) | Self::Method(f) => f.as_ref(),
|
Self::Pure(f) | Self::Method(f) => f.as_ref(),
|
||||||
Self::Iterator(_) | Self::Plugin(_) => unreachable!(),
|
Self::Iterator(_) | Self::Plugin(_) => panic!("function should be native"),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => unreachable!(),
|
Self::Script(_) => panic!("function should be native"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get a shared reference to a script-defined function definition.
|
/// Get a shared reference to a script-defined function definition.
|
||||||
@ -549,7 +549,9 @@ impl CallableFunction {
|
|||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
pub fn get_fn_def(&self) -> &ScriptFnDef {
|
||||||
match self {
|
match self {
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) | Self::Plugin(_) => {
|
||||||
|
panic!("function should be scripted")
|
||||||
|
}
|
||||||
Self::Script(f) => f.as_ref(),
|
Self::Script(f) => f.as_ref(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -561,10 +563,12 @@ impl CallableFunction {
|
|||||||
pub fn get_iter_fn(&self) -> IteratorFn {
|
pub fn get_iter_fn(&self) -> IteratorFn {
|
||||||
match self {
|
match self {
|
||||||
Self::Iterator(f) => *f,
|
Self::Iterator(f) => *f,
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) | Self::Plugin(_) => {
|
||||||
|
panic!("function should an iterator")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => unreachable!(),
|
Self::Script(_) => panic!("function should be an iterator"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Get a shared reference to a plugin function.
|
/// Get a shared reference to a plugin function.
|
||||||
@ -575,10 +579,12 @@ impl CallableFunction {
|
|||||||
pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin {
|
pub fn get_plugin_fn<'s>(&'s self) -> &FnPlugin {
|
||||||
match self {
|
match self {
|
||||||
Self::Plugin(f) => f.as_ref(),
|
Self::Plugin(f) => f.as_ref(),
|
||||||
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => unreachable!(),
|
Self::Pure(_) | Self::Method(_) | Self::Iterator(_) => {
|
||||||
|
panic!("function should a plugin")
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_) => unreachable!(),
|
Self::Script(_) => panic!("function should a plugin"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Create a new [`CallableFunction::Pure`].
|
/// Create a new [`CallableFunction::Pure`].
|
||||||
@ -609,7 +615,7 @@ impl From<ScriptFnDef> for CallableFunction {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(_func: ScriptFnDef) -> Self {
|
fn from(_func: ScriptFnDef) -> Self {
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
unreachable!();
|
unreachable!("no_function active");
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_func.into())
|
Self::Script(_func.into())
|
||||||
@ -620,7 +626,7 @@ impl From<Shared<ScriptFnDef>> for CallableFunction {
|
|||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn from(_func: Shared<ScriptFnDef>) -> Self {
|
fn from(_func: Shared<ScriptFnDef>) -> Self {
|
||||||
#[cfg(feature = "no_function")]
|
#[cfg(feature = "no_function")]
|
||||||
unreachable!();
|
unreachable!("no_function active");
|
||||||
|
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
Self::Script(_func)
|
Self::Script(_func)
|
||||||
|
@ -101,8 +101,6 @@ impl FuncInfo {
|
|||||||
if return_type != "()" {
|
if return_type != "()" {
|
||||||
sig.push_str(") -> ");
|
sig.push_str(") -> ");
|
||||||
sig.push_str(&return_type);
|
sig.push_str(&return_type);
|
||||||
} else if self.func.is_script() {
|
|
||||||
sig.push_str(") -> Dynamic");
|
|
||||||
} else {
|
} else {
|
||||||
sig.push_str(")");
|
sig.push_str(")");
|
||||||
}
|
}
|
||||||
@ -115,7 +113,7 @@ impl FuncInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.func.is_script() {
|
if self.func.is_script() {
|
||||||
sig.push_str(") -> Dynamic");
|
sig.push_str(")");
|
||||||
} else {
|
} else {
|
||||||
sig.push_str(") -> ?");
|
sig.push_str(") -> ?");
|
||||||
}
|
}
|
||||||
@ -471,6 +469,7 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// By taking a mutable reference, it is assumed that some sub-modules will be modified.
|
/// By taking a mutable reference, it is assumed that some sub-modules will be modified.
|
||||||
/// Thus the module is automatically set to be non-indexed.
|
/// Thus the module is automatically set to be non-indexed.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
||||||
// We must assume that the user has changed the sub-modules
|
// We must assume that the user has changed the sub-modules
|
||||||
|
@ -39,7 +39,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileModuleResolver {
|
pub struct FileModuleResolver {
|
||||||
path: PathBuf,
|
base_path: PathBuf,
|
||||||
extension: String,
|
extension: String,
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
@ -99,7 +99,7 @@ impl FileModuleResolver {
|
|||||||
extension: impl Into<String>,
|
extension: impl Into<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
path: path.into(),
|
base_path: path.into(),
|
||||||
extension: extension.into(),
|
extension: extension.into(),
|
||||||
cache: Default::default(),
|
cache: Default::default(),
|
||||||
}
|
}
|
||||||
@ -127,13 +127,13 @@ impl FileModuleResolver {
|
|||||||
|
|
||||||
/// Get the base path for script files.
|
/// Get the base path for script files.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn path(&self) -> &Path {
|
pub fn base_path(&self) -> &Path {
|
||||||
self.path.as_ref()
|
self.base_path.as_ref()
|
||||||
}
|
}
|
||||||
/// Set the base path for script files.
|
/// Set the base path for script files.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_path(&mut self, path: impl Into<PathBuf>) -> &mut Self {
|
pub fn set_base_path(&mut self, path: impl Into<PathBuf>) -> &mut Self {
|
||||||
self.path = path.into();
|
self.base_path = path.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ impl ModuleResolver for FileModuleResolver {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
||||||
// Construct the script file path
|
// Construct the script file path
|
||||||
let mut file_path = self.path.clone();
|
let mut file_path = self.base_path.clone();
|
||||||
file_path.push(path);
|
file_path.push(path);
|
||||||
file_path.set_extension(&self.extension); // Force extension
|
file_path.set_extension(&self.extension); // Force extension
|
||||||
|
|
||||||
|
@ -483,8 +483,6 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
];
|
];
|
||||||
|
|
||||||
match expr {
|
match expr {
|
||||||
// expr - do not promote because there is a reason it is wrapped in an `Expr::Expr`
|
|
||||||
Expr::Expr(x) => optimize_expr(x, state),
|
|
||||||
// {}
|
// {}
|
||||||
Expr::Stmt(x, pos) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(*pos) }
|
Expr::Stmt(x, pos) if x.is_empty() => { state.set_dirty(); *expr = Expr::Unit(*pos) }
|
||||||
// { stmt; ... } - do not count promotion as dirty because it gets turned back into an array
|
// { stmt; ... } - do not count promotion as dirty because it gets turned back into an array
|
||||||
|
190
src/parser.rs
190
src/parser.rs
@ -280,12 +280,12 @@ fn parse_paren_expr(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
// ( ...
|
|
||||||
settings.pos = eat_token(input, Token::LeftParen);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// ( ...
|
||||||
|
settings.pos = eat_token(input, Token::LeftParen);
|
||||||
|
|
||||||
if match_token(input, Token::RightParen).0 {
|
if match_token(input, Token::RightParen).0 {
|
||||||
return Ok(Expr::Unit(settings.pos));
|
return Ok(Expr::Unit(settings.pos));
|
||||||
}
|
}
|
||||||
@ -316,11 +316,11 @@ fn parse_fn_call(
|
|||||||
mut namespace: Option<NamespaceRef>,
|
mut namespace: Option<NamespaceRef>,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
@ -603,28 +603,12 @@ fn parse_index_chain(
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
// Otherwise terminate the indexing chain
|
// Otherwise terminate the indexing chain
|
||||||
_ => {
|
|
||||||
match idx_expr {
|
|
||||||
// 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
|
|
||||||
// dot expression/function call to be mis-parsed as following the indexing chain.
|
|
||||||
Expr::Index(_, _) | Expr::Dot(_, _) | Expr::FnCall(_, _) => {
|
|
||||||
Ok(Expr::Index(
|
|
||||||
Box::new(BinaryExpr {
|
|
||||||
lhs,
|
|
||||||
rhs: Expr::Expr(Box::new(idx_expr)),
|
|
||||||
}),
|
|
||||||
settings.pos,
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => Ok(Expr::Index(
|
_ => Ok(Expr::Index(
|
||||||
Box::new(BinaryExpr { lhs, rhs: idx_expr }),
|
Box::new(BinaryExpr { lhs, rhs: idx_expr }),
|
||||||
settings.pos,
|
settings.pos,
|
||||||
)),
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
(Token::LexError(err), pos) => return Err(err.clone().into_err(*pos)),
|
||||||
(_, pos) => Err(PERR::MissingToken(
|
(_, pos) => Err(PERR::MissingToken(
|
||||||
Token::RightBracket.into(),
|
Token::RightBracket.into(),
|
||||||
@ -642,12 +626,12 @@ fn parse_array_literal(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
// [ ...
|
|
||||||
settings.pos = eat_token(input, Token::LeftBracket);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// [ ...
|
||||||
|
settings.pos = eat_token(input, Token::LeftBracket);
|
||||||
|
|
||||||
let mut arr = StaticVec::new();
|
let mut arr = StaticVec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -712,12 +696,12 @@ fn parse_map_literal(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
// #{ ...
|
|
||||||
settings.pos = eat_token(input, Token::MapStart);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// #{ ...
|
||||||
|
settings.pos = eat_token(input, Token::MapStart);
|
||||||
|
|
||||||
let mut map: StaticVec<(Ident, Expr)> = Default::default();
|
let mut map: StaticVec<(Ident, Expr)> = Default::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -823,13 +807,12 @@ fn parse_switch(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// switch ...
|
|
||||||
let token_pos = eat_token(input, Token::Switch);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// switch ...
|
||||||
|
settings.pos = eat_token(input, Token::Switch);
|
||||||
|
|
||||||
let item = parse_expr(input, state, lib, settings.level_up())?;
|
let item = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
match input.next().unwrap() {
|
match input.next().unwrap() {
|
||||||
@ -950,12 +933,12 @@ fn parse_primary(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
|
||||||
settings.pos = *token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
let mut root_expr = match token {
|
let mut root_expr = match token {
|
||||||
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
|
|
||||||
@ -971,7 +954,7 @@ fn parse_primary(
|
|||||||
}
|
}
|
||||||
Token::True => Expr::BoolConstant(true, settings.pos),
|
Token::True => Expr::BoolConstant(true, settings.pos),
|
||||||
Token::False => Expr::BoolConstant(false, settings.pos),
|
Token::False => Expr::BoolConstant(false, settings.pos),
|
||||||
_ => unreachable!(),
|
t => unreachable!("unexpected token: {:?}", t),
|
||||||
},
|
},
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Token::FloatConstant(x) => {
|
Token::FloatConstant(x) => {
|
||||||
@ -984,7 +967,7 @@ fn parse_primary(
|
|||||||
Token::LeftBrace if settings.allow_stmt_expr => {
|
Token::LeftBrace if settings.allow_stmt_expr => {
|
||||||
match parse_block(input, state, lib, settings.level_up())? {
|
match parse_block(input, state, lib, settings.level_up())? {
|
||||||
Stmt::Block(statements, pos) => Expr::Stmt(Box::new(statements.into()), pos),
|
Stmt::Block(statements, pos) => Expr::Stmt(Box::new(statements.into()), pos),
|
||||||
_ => unreachable!(),
|
stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// ( - grouped expression
|
// ( - grouped expression
|
||||||
@ -1051,7 +1034,7 @@ fn parse_primary(
|
|||||||
Token::Identifier(_) => {
|
Token::Identifier(_) => {
|
||||||
let s = match input.next().unwrap().0 {
|
let s = match input.next().unwrap().0 {
|
||||||
Token::Identifier(s) => s,
|
Token::Identifier(s) => s,
|
||||||
_ => unreachable!(),
|
t => unreachable!("expecting Token::Identifier, but gets {:?}", t),
|
||||||
};
|
};
|
||||||
|
|
||||||
match input.peek().unwrap().0 {
|
match input.peek().unwrap().0 {
|
||||||
@ -1098,7 +1081,7 @@ fn parse_primary(
|
|||||||
Token::Reserved(_) => {
|
Token::Reserved(_) => {
|
||||||
let s = match input.next().unwrap().0 {
|
let s = match input.next().unwrap().0 {
|
||||||
Token::Reserved(s) => s,
|
Token::Reserved(s) => s,
|
||||||
_ => unreachable!(),
|
t => unreachable!("expecting Token::Reserved, but gets {:?}", t),
|
||||||
};
|
};
|
||||||
|
|
||||||
match input.peek().unwrap().0 {
|
match input.peek().unwrap().0 {
|
||||||
@ -1141,7 +1124,7 @@ fn parse_primary(
|
|||||||
Token::LexError(_) => {
|
Token::LexError(_) => {
|
||||||
let err = match input.next().unwrap().0 {
|
let err = match input.next().unwrap().0 {
|
||||||
Token::LexError(err) => err,
|
Token::LexError(err) => err,
|
||||||
_ => unreachable!(),
|
t => unreachable!("expecting Token::LexError, but gets {:?}", t),
|
||||||
};
|
};
|
||||||
|
|
||||||
return Err(err.into_err(settings.pos));
|
return Err(err.into_err(settings.pos));
|
||||||
@ -1201,7 +1184,6 @@ fn parse_primary(
|
|||||||
let ns = namespace.map(|(_, ns)| ns);
|
let ns = namespace.map(|(_, ns)| ns);
|
||||||
parse_fn_call(input, state, lib, name, false, ns, settings.level_up())?
|
parse_fn_call(input, state, lib, name, false, ns, settings.level_up())?
|
||||||
}
|
}
|
||||||
(Expr::Property(_), _) => unreachable!(),
|
|
||||||
// module access
|
// module access
|
||||||
(Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() {
|
(Expr::Variable(x), Token::DoubleColon) => match input.next().unwrap() {
|
||||||
(Token::Identifier(id2), pos2) => {
|
(Token::Identifier(id2), pos2) => {
|
||||||
@ -1241,7 +1223,7 @@ fn parse_primary(
|
|||||||
state.allow_capture = false;
|
state.allow_capture = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rhs = parse_unary(input, state, lib, settings.level_up())?;
|
let rhs = parse_primary(input, state, lib, settings.level_up())?;
|
||||||
make_dot_expr(state, expr, rhs, tail_pos)?
|
make_dot_expr(state, expr, rhs, tail_pos)?
|
||||||
}
|
}
|
||||||
// Unknown postfix operator
|
// Unknown postfix operator
|
||||||
@ -1262,17 +1244,16 @@ fn parse_primary(
|
|||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.map(|x| {
|
.map(|x| match x.as_mut() {
|
||||||
if let (_, Some((ref mut hash, ref mut namespace)), Ident { name, .. }) = x.as_mut() {
|
(_, Some((ref mut hash, ref mut namespace)), Ident { name, .. }) => {
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
*hash =
|
*hash =
|
||||||
calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0).unwrap();
|
calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0).unwrap();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace.set_index(state.find_module(&namespace[0].name));
|
namespace.set_index(state.find_module(&namespace[0].name));
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
|
_ => unreachable!("expecting namespace-qualified variable access"),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure identifiers are valid
|
// Make sure identifiers are valid
|
||||||
@ -1458,12 +1439,12 @@ fn parse_op_assignment_stmt(
|
|||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
|
||||||
settings.pos = *token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
let op = match token {
|
let op = match token {
|
||||||
Token::Equals => "".into(),
|
Token::Equals => "".into(),
|
||||||
|
|
||||||
@ -1714,11 +1695,11 @@ fn parse_binary_op(
|
|||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
settings.pos = lhs.position();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = lhs.position();
|
||||||
|
|
||||||
let mut root = lhs;
|
let mut root = lhs;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -1868,12 +1849,6 @@ fn parse_binary_op(
|
|||||||
make_in_expr(current_lhs, rhs, pos)?
|
make_in_expr(current_lhs, rhs, pos)?
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(not(feature = "no_object"))]
|
|
||||||
// Token::Period => {
|
|
||||||
// let rhs = args.pop().unwrap();
|
|
||||||
// let current_lhs = args.pop().unwrap();
|
|
||||||
// make_dot_expr(state, current_lhs, rhs, pos)?
|
|
||||||
// }
|
|
||||||
Token::Custom(s)
|
Token::Custom(s)
|
||||||
if state
|
if state
|
||||||
.engine
|
.engine
|
||||||
@ -1981,7 +1956,7 @@ fn parse_custom_syntax(
|
|||||||
segments.push(keyword.clone());
|
segments.push(keyword.clone());
|
||||||
tokens.push(keyword);
|
tokens.push(keyword);
|
||||||
}
|
}
|
||||||
_ => unreachable!(),
|
stmt => unreachable!("expecting Stmt::Block, but gets {:?}", stmt),
|
||||||
},
|
},
|
||||||
s => match input.next().unwrap() {
|
s => match input.next().unwrap() {
|
||||||
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
(Token::LexError(err), pos) => return Err(err.into_err(pos)),
|
||||||
@ -2017,11 +1992,11 @@ fn parse_expr(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
settings.pos = input.peek().unwrap().1;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = input.peek().unwrap().1;
|
||||||
|
|
||||||
// Check if it is a custom syntax.
|
// Check if it is a custom syntax.
|
||||||
if !state.engine.custom_syntax.is_empty() {
|
if !state.engine.custom_syntax.is_empty() {
|
||||||
let (token, pos) = input.peek().unwrap();
|
let (token, pos) = input.peek().unwrap();
|
||||||
@ -2095,13 +2070,12 @@ fn parse_if(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// if ...
|
|
||||||
let token_pos = eat_token(input, Token::If);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// if ...
|
||||||
|
settings.pos = eat_token(input, Token::If);
|
||||||
|
|
||||||
// if guard { if_body }
|
// if guard { if_body }
|
||||||
ensure_not_statement_expr(input, "a boolean")?;
|
ensure_not_statement_expr(input, "a boolean")?;
|
||||||
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
@ -2121,7 +2095,11 @@ fn parse_if(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Stmt::If(guard, Box::new((if_body, else_body)), token_pos))
|
Ok(Stmt::If(
|
||||||
|
guard,
|
||||||
|
Box::new((if_body, else_body)),
|
||||||
|
settings.pos,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a while loop.
|
/// Parse a while loop.
|
||||||
@ -2141,7 +2119,7 @@ fn parse_while_loop(
|
|||||||
(parse_expr(input, state, lib, settings.level_up())?, pos)
|
(parse_expr(input, state, lib, settings.level_up())?, pos)
|
||||||
}
|
}
|
||||||
(Token::Loop, pos) => (Expr::BoolConstant(true, pos), pos),
|
(Token::Loop, pos) => (Expr::BoolConstant(true, pos), pos),
|
||||||
_ => unreachable!(),
|
(t, _) => unreachable!("expecting Token::While or Token::Loop, but gets {:?}", t),
|
||||||
};
|
};
|
||||||
settings.pos = token_pos;
|
settings.pos = token_pos;
|
||||||
|
|
||||||
@ -2149,7 +2127,7 @@ fn parse_while_loop(
|
|||||||
settings.is_breakable = true;
|
settings.is_breakable = true;
|
||||||
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
||||||
|
|
||||||
Ok(Stmt::While(guard, body, token_pos))
|
Ok(Stmt::While(guard, body, settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a do loop.
|
/// Parse a do loop.
|
||||||
@ -2159,13 +2137,12 @@ fn parse_do(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// do ...
|
|
||||||
let token_pos = eat_token(input, Token::Do);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// do ...
|
||||||
|
settings.pos = eat_token(input, Token::Do);
|
||||||
|
|
||||||
// do { body } [while|until] guard
|
// do { body } [while|until] guard
|
||||||
settings.is_breakable = true;
|
settings.is_breakable = true;
|
||||||
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
||||||
@ -2186,7 +2163,7 @@ fn parse_do(
|
|||||||
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
ensure_not_assignment(input)?;
|
ensure_not_assignment(input)?;
|
||||||
|
|
||||||
Ok(Stmt::Do(body, guard, is_while, token_pos))
|
Ok(Stmt::Do(body, guard, is_while, settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a for loop.
|
/// Parse a for loop.
|
||||||
@ -2196,13 +2173,12 @@ fn parse_for(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// for ...
|
|
||||||
let token_pos = eat_token(input, Token::For);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// for ...
|
||||||
|
settings.pos = eat_token(input, Token::For);
|
||||||
|
|
||||||
// for name ...
|
// for name ...
|
||||||
let name = match input.next().unwrap() {
|
let name = match input.next().unwrap() {
|
||||||
// Variable name
|
// Variable name
|
||||||
@ -2242,7 +2218,7 @@ fn parse_for(
|
|||||||
|
|
||||||
state.stack.truncate(prev_stack_len);
|
state.stack.truncate(prev_stack_len);
|
||||||
|
|
||||||
Ok(Stmt::For(expr, Box::new((name, body)), token_pos))
|
Ok(Stmt::For(expr, Box::new((name, body)), settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a variable definition statement.
|
/// Parse a variable definition statement.
|
||||||
@ -2254,13 +2230,12 @@ fn parse_let(
|
|||||||
export: bool,
|
export: bool,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// let/const... (specified in `var_type`)
|
|
||||||
let token_pos = input.next().unwrap().1;
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// let/const... (specified in `var_type`)
|
||||||
|
settings.pos = input.next().unwrap().1;
|
||||||
|
|
||||||
// let name ...
|
// let name ...
|
||||||
let (name, pos) = match input.next().unwrap() {
|
let (name, pos) = match input.next().unwrap() {
|
||||||
(Token::Identifier(s), pos) => (s, pos),
|
(Token::Identifier(s), pos) => (s, pos),
|
||||||
@ -2272,7 +2247,7 @@ fn parse_let(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// let name = ...
|
// let name = ...
|
||||||
let init_expr = if match_token(input, Token::Equals).0 {
|
let expr = if match_token(input, Token::Equals).0 {
|
||||||
// let name = expr
|
// let name = expr
|
||||||
Some(parse_expr(input, state, lib, settings.level_up())?)
|
Some(parse_expr(input, state, lib, settings.level_up())?)
|
||||||
} else {
|
} else {
|
||||||
@ -2285,14 +2260,14 @@ fn parse_let(
|
|||||||
let name = state.get_interned_string(name);
|
let name = state.get_interned_string(name);
|
||||||
state.stack.push((name.clone(), AccessMode::ReadWrite));
|
state.stack.push((name.clone(), AccessMode::ReadWrite));
|
||||||
let var_def = Ident { name, pos };
|
let var_def = Ident { name, pos };
|
||||||
Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos))
|
Ok(Stmt::Let(Box::new(var_def), expr, export, settings.pos))
|
||||||
}
|
}
|
||||||
// const name = { expr:constant }
|
// const name = { expr:constant }
|
||||||
AccessMode::ReadOnly => {
|
AccessMode::ReadOnly => {
|
||||||
let name = state.get_interned_string(name);
|
let name = state.get_interned_string(name);
|
||||||
state.stack.push((name.clone(), AccessMode::ReadOnly));
|
state.stack.push((name.clone(), AccessMode::ReadOnly));
|
||||||
let var_def = Ident { name, pos };
|
let var_def = Ident { name, pos };
|
||||||
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
|
Ok(Stmt::Const(Box::new(var_def), expr, export, settings.pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2305,23 +2280,22 @@ fn parse_import(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// import ...
|
|
||||||
let token_pos = eat_token(input, Token::Import);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// import ...
|
||||||
|
settings.pos = eat_token(input, Token::Import);
|
||||||
|
|
||||||
// import expr ...
|
// import expr ...
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
// import expr as ...
|
// import expr as ...
|
||||||
if !match_token(input, Token::As).0 {
|
if !match_token(input, Token::As).0 {
|
||||||
return Ok(Stmt::Import(expr, None, token_pos));
|
return Ok(Stmt::Import(expr, None, settings.pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// import expr as name ...
|
// import expr as name ...
|
||||||
let (name, _) = match input.next().unwrap() {
|
let (name, name_pos) = match input.next().unwrap() {
|
||||||
(Token::Identifier(s), pos) => (s, pos),
|
(Token::Identifier(s), pos) => (s, pos),
|
||||||
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
|
(Token::Reserved(s), pos) if is_valid_identifier(s.chars()) => {
|
||||||
return Err(PERR::Reserved(s).into_err(pos));
|
return Err(PERR::Reserved(s).into_err(pos));
|
||||||
@ -2337,9 +2311,9 @@ fn parse_import(
|
|||||||
expr,
|
expr,
|
||||||
Some(Box::new(Ident {
|
Some(Box::new(Ident {
|
||||||
name,
|
name,
|
||||||
pos: settings.pos,
|
pos: name_pos,
|
||||||
})),
|
})),
|
||||||
token_pos,
|
settings.pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2351,12 +2325,11 @@ fn parse_export(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
let token_pos = eat_token(input, Token::Export);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = eat_token(input, Token::Export);
|
||||||
|
|
||||||
match input.peek().unwrap() {
|
match input.peek().unwrap() {
|
||||||
(Token::Let, pos) => {
|
(Token::Let, pos) => {
|
||||||
let pos = *pos;
|
let pos = *pos;
|
||||||
@ -2424,7 +2397,7 @@ fn parse_export(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Stmt::Export(exports, token_pos))
|
Ok(Stmt::Export(exports, settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a statement block.
|
/// Parse a statement block.
|
||||||
@ -2513,11 +2486,11 @@ fn parse_expr_stmt(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
settings.pos = input.peek().unwrap().1;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = input.peek().unwrap().1;
|
||||||
|
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
|
let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
|
||||||
Ok(stmt)
|
Ok(stmt)
|
||||||
@ -2543,14 +2516,15 @@ fn parse_stmt(
|
|||||||
}
|
}
|
||||||
|
|
||||||
if !is_doc_comment(comment) {
|
if !is_doc_comment(comment) {
|
||||||
unreachable!();
|
unreachable!("expecting doc-comment, but gets {:?}", comment);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !settings.is_global {
|
if !settings.is_global {
|
||||||
return Err(PERR::WrongDocComment.into_err(comments_pos));
|
return Err(PERR::WrongDocComment.into_err(comments_pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Token::Comment(comment) = input.next().unwrap().0 {
|
match input.next().unwrap().0 {
|
||||||
|
Token::Comment(comment) => {
|
||||||
comments.push(comment);
|
comments.push(comment);
|
||||||
|
|
||||||
match input.peek().unwrap() {
|
match input.peek().unwrap() {
|
||||||
@ -2558,8 +2532,8 @@ fn parse_stmt(
|
|||||||
(Token::Comment(_), _) => (),
|
(Token::Comment(_), _) => (),
|
||||||
_ => return Err(PERR::WrongDocComment.into_err(comments_pos)),
|
_ => return Err(PERR::WrongDocComment.into_err(comments_pos)),
|
||||||
}
|
}
|
||||||
} else {
|
}
|
||||||
unreachable!();
|
t => unreachable!("expecting Token::Comment, but gets {:?}", t),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2659,7 +2633,10 @@ fn parse_stmt(
|
|||||||
match token {
|
match token {
|
||||||
Token::Return => ReturnType::Return,
|
Token::Return => ReturnType::Return,
|
||||||
Token::Throw => ReturnType::Exception,
|
Token::Throw => ReturnType::Exception,
|
||||||
_ => unreachable!(),
|
t => unreachable!(
|
||||||
|
"expecting Token::Return or Token::Throw, but gets {:?}",
|
||||||
|
t
|
||||||
|
),
|
||||||
},
|
},
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
@ -2715,13 +2692,12 @@ fn parse_try_catch(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// try ...
|
|
||||||
let token_pos = eat_token(input, Token::Try);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// try ...
|
||||||
|
settings.pos = eat_token(input, Token::Try);
|
||||||
|
|
||||||
// try { body }
|
// try { body }
|
||||||
let body = parse_block(input, state, lib, settings.level_up())?;
|
let body = parse_block(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
@ -2765,7 +2741,7 @@ fn parse_try_catch(
|
|||||||
|
|
||||||
Ok(Stmt::TryCatch(
|
Ok(Stmt::TryCatch(
|
||||||
Box::new((body, var_def, catch_body)),
|
Box::new((body, var_def, catch_body)),
|
||||||
token_pos,
|
settings.pos,
|
||||||
catch_pos,
|
catch_pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -190,13 +190,16 @@ impl fmt::Display for EvalAltResult {
|
|||||||
Self::ErrorAssignmentToConstant(s, _) => {
|
Self::ErrorAssignmentToConstant(s, _) => {
|
||||||
write!(f, "Cannot assign to constant '{}'", s)?
|
write!(f, "Cannot assign to constant '{}'", s)?
|
||||||
}
|
}
|
||||||
Self::ErrorMismatchOutputType(r, s, _) => {
|
Self::ErrorMismatchOutputType(s, r, _) => {
|
||||||
write!(f, "Output type is incorrect: {} (expecting {})", r, s)?
|
write!(f, "Output type is incorrect: {} (expecting {})", r, s)?
|
||||||
}
|
}
|
||||||
Self::ErrorMismatchDataType(r, s, _) if r.is_empty() => {
|
Self::ErrorMismatchDataType(s, r, _) if r.is_empty() => {
|
||||||
write!(f, "Data type is incorrect, expecting {}", s)?
|
write!(f, "Data type is incorrect, expecting {}", s)?
|
||||||
}
|
}
|
||||||
Self::ErrorMismatchDataType(r, s, _) => {
|
Self::ErrorMismatchDataType(s, r, _) if s.is_empty() => {
|
||||||
|
write!(f, "Data type is incorrect: {}", r)?
|
||||||
|
}
|
||||||
|
Self::ErrorMismatchDataType(s, r, _) => {
|
||||||
write!(f, "Data type is incorrect: {} (expecting {})", r, s)?
|
write!(f, "Data type is incorrect: {} (expecting {})", r, s)?
|
||||||
}
|
}
|
||||||
Self::ErrorArithmetic(s, _) => f.write_str(s)?,
|
Self::ErrorArithmetic(s, _) => f.write_str(s)?,
|
||||||
@ -263,10 +266,14 @@ impl<T: AsRef<str>> From<T> for Box<EvalAltResult> {
|
|||||||
|
|
||||||
impl EvalAltResult {
|
impl EvalAltResult {
|
||||||
/// Can this error be caught?
|
/// Can this error be caught?
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics when [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return].
|
||||||
pub fn is_catchable(&self) -> bool {
|
pub fn is_catchable(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(_, _) => false,
|
Self::ErrorSystem(_, _) => false,
|
||||||
Self::ErrorParsing(_, _) => unreachable!(),
|
Self::ErrorParsing(_, _) => false,
|
||||||
|
|
||||||
Self::ErrorFunctionNotFound(_, _)
|
Self::ErrorFunctionNotFound(_, _)
|
||||||
| Self::ErrorInFunctionCall(_, _, _)
|
| Self::ErrorInFunctionCall(_, _, _)
|
||||||
@ -293,14 +300,19 @@ impl EvalAltResult {
|
|||||||
| Self::ErrorDataTooLarge(_, _)
|
| Self::ErrorDataTooLarge(_, _)
|
||||||
| Self::ErrorTerminated(_, _) => false,
|
| Self::ErrorTerminated(_, _) => false,
|
||||||
|
|
||||||
Self::LoopBreak(_, _) | Self::Return(_, _) => unreachable!(),
|
Self::LoopBreak(_, _) => panic!("EvalAltResult::LoopBreak should not occur naturally"),
|
||||||
|
Self::Return(_, _) => panic!("EvalAltResult::Return should not occur naturally"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Is this error a system exception?
|
/// Is this error a system exception?
|
||||||
|
///
|
||||||
|
/// # Panics
|
||||||
|
///
|
||||||
|
/// Panics when [`LoopBreak`][EvalAltResult::LoopBreak] or [`Return`][EvalAltResult::Return].
|
||||||
pub fn is_system_exception(&self) -> bool {
|
pub fn is_system_exception(&self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::ErrorSystem(_, _) => true,
|
Self::ErrorSystem(_, _) => true,
|
||||||
Self::ErrorParsing(_, _) => unreachable!(),
|
Self::ErrorParsing(_, _) => true,
|
||||||
|
|
||||||
Self::ErrorTooManyOperations(_)
|
Self::ErrorTooManyOperations(_)
|
||||||
| Self::ErrorTooManyModules(_)
|
| Self::ErrorTooManyModules(_)
|
||||||
@ -309,7 +321,8 @@ impl EvalAltResult {
|
|||||||
|
|
||||||
Self::ErrorTerminated(_, _) => true,
|
Self::ErrorTerminated(_, _) => true,
|
||||||
|
|
||||||
Self::LoopBreak(_, _) | Self::Return(_, _) => unreachable!(),
|
Self::LoopBreak(_, _) => panic!("EvalAltResult::LoopBreak should not occur naturally"),
|
||||||
|
Self::Return(_, _) => panic!("EvalAltResult::Return should not occur naturally"),
|
||||||
|
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
|
@ -283,9 +283,9 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
make_variant(_variant, content)
|
make_variant(_variant, content)
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
"Dynamic".into(),
|
"".into(),
|
||||||
"map".into(),
|
"object maps are not supported with 'no_object'".into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
@ -295,9 +295,9 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(DynamicSerializer::new(Array::new().into()));
|
return Ok(DynamicSerializer::new(Array::new().into()));
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
return EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
"Dynamic".into(),
|
"".into(),
|
||||||
"array".into(),
|
"arrays are not supported with 'no_index'".into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
@ -322,33 +322,28 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
_variant: &'static str,
|
_variant: &'static str,
|
||||||
_len: usize,
|
_len: usize,
|
||||||
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
) -> Result<Self::SerializeTupleVariant, Box<EvalAltResult>> {
|
||||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(TupleVariantSerializer {
|
return Ok(TupleVariantSerializer {
|
||||||
variant: _variant,
|
variant: _variant,
|
||||||
array: Array::with_capacity(_len),
|
array: Array::with_capacity(_len),
|
||||||
});
|
});
|
||||||
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||||
{
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
#[cfg(feature = "no_object")]
|
"".into(),
|
||||||
let err_type = "map";
|
"tuples are not supported with 'no_index' or 'no_object'".into(),
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
let err_type = "array";
|
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
|
||||||
"Dynamic".into(),
|
|
||||||
err_type.into(),
|
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into()
|
.into();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Box<EvalAltResult>> {
|
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(DynamicSerializer::new(Map::new().into()));
|
return Ok(DynamicSerializer::new(Map::new().into()));
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
"Dynamic".into(),
|
"".into(),
|
||||||
"map".into(),
|
"object maps are not supported with 'no_object'".into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
@ -375,9 +370,9 @@ impl Serializer for &mut DynamicSerializer {
|
|||||||
map: Map::with_capacity(_len),
|
map: Map::with_capacity(_len),
|
||||||
});
|
});
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
return EvalAltResult::ErrorMismatchOutputType(
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
"Dynamic".into(),
|
"".into(),
|
||||||
"map".into(),
|
"object maps are not supported with 'no_object'".into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
)
|
)
|
||||||
.into();
|
.into();
|
||||||
@ -400,7 +395,12 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"arrays are not supported with 'no_index'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close the sequence.
|
// Close the sequence.
|
||||||
@ -408,7 +408,12 @@ impl SerializeSeq for DynamicSerializer {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self._value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"arrays are not supported with 'no_index'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -428,14 +433,24 @@ impl SerializeTuple for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"tuples are not supported with 'no_index'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self._value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"tuples are not supported with 'no_index'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -455,14 +470,24 @@ impl SerializeTupleStruct for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"tuples are not supported with 'no_index'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
return Ok(self._value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_index")]
|
#[cfg(feature = "no_index")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"tuples are not supported with 'no_index'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,7 +502,12 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"object maps are not supported with 'no_object'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_value<T: ?Sized + Serialize>(
|
fn serialize_value<T: ?Sized + Serialize>(
|
||||||
@ -489,7 +519,7 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
let key = crate::stdlib::mem::take(&mut self._key)
|
let key = crate::stdlib::mem::take(&mut self._key)
|
||||||
.take_immutable_string()
|
.take_immutable_string()
|
||||||
.map_err(|typ| {
|
.map_err(|typ| {
|
||||||
EvalAltResult::ErrorMismatchOutputType(
|
EvalAltResult::ErrorMismatchDataType(
|
||||||
"string".into(),
|
"string".into(),
|
||||||
typ.into(),
|
typ.into(),
|
||||||
Position::NONE,
|
Position::NONE,
|
||||||
@ -501,7 +531,12 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"object maps are not supported with 'no_object'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
fn serialize_entry<K: ?Sized + Serialize, T: ?Sized + Serialize>(
|
||||||
@ -513,7 +548,7 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
{
|
{
|
||||||
let _key: Dynamic = _key.serialize(&mut *self)?;
|
let _key: Dynamic = _key.serialize(&mut *self)?;
|
||||||
let _key = _key.take_immutable_string().map_err(|typ| {
|
let _key = _key.take_immutable_string().map_err(|typ| {
|
||||||
EvalAltResult::ErrorMismatchOutputType("string".into(), typ.into(), Position::NONE)
|
EvalAltResult::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
||||||
})?;
|
})?;
|
||||||
let _value = _value.serialize(&mut *self)?;
|
let _value = _value.serialize(&mut *self)?;
|
||||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||||
@ -521,14 +556,24 @@ impl SerializeMap for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"object maps are not supported with 'no_object'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self._value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"object maps are not supported with 'no_object'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -549,14 +594,24 @@ impl SerializeStruct for DynamicSerializer {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"object maps are not supported with 'no_object'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
fn end(self) -> Result<Self::Ok, Box<EvalAltResult>> {
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
return Ok(self._value);
|
return Ok(self._value);
|
||||||
#[cfg(feature = "no_object")]
|
#[cfg(feature = "no_object")]
|
||||||
unreachable!()
|
return EvalAltResult::ErrorMismatchDataType(
|
||||||
|
"".into(),
|
||||||
|
"object maps are not supported with 'no_object'".into(),
|
||||||
|
Position::NONE,
|
||||||
|
)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
12
src/token.rs
12
src/token.rs
@ -437,7 +437,7 @@ impl Token {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
As => "as",
|
As => "as",
|
||||||
EOF => "{EOF}",
|
EOF => "{EOF}",
|
||||||
_ => unreachable!("operator should be match in outer scope"),
|
_ => unreachable!("operator should be matched in outer scope"),
|
||||||
}
|
}
|
||||||
.into(),
|
.into(),
|
||||||
}
|
}
|
||||||
@ -837,7 +837,7 @@ pub fn parse_string_literal(
|
|||||||
'x' => 2,
|
'x' => 2,
|
||||||
'u' => 4,
|
'u' => 4,
|
||||||
'U' => 8,
|
'U' => 8,
|
||||||
_ => unreachable!(),
|
_ => unreachable!("expecting 'x', 'u' or 'U', but gets {}", ch),
|
||||||
};
|
};
|
||||||
|
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
@ -1126,14 +1126,14 @@ fn get_next_token_inner(
|
|||||||
'x' | 'X' => is_hex_char,
|
'x' | 'X' => is_hex_char,
|
||||||
'o' | 'O' => is_octal_char,
|
'o' | 'O' => is_octal_char,
|
||||||
'b' | 'B' => is_binary_char,
|
'b' | 'B' => is_binary_char,
|
||||||
_ => unreachable!(),
|
_ => unreachable!("expecting 'x', 'o' or 'B', but gets {}", ch),
|
||||||
};
|
};
|
||||||
|
|
||||||
radix_base = Some(match ch {
|
radix_base = Some(match ch {
|
||||||
'x' | 'X' => 16,
|
'x' | 'X' => 16,
|
||||||
'o' | 'O' => 8,
|
'o' | 'O' => 8,
|
||||||
'b' | 'B' => 2,
|
'b' | 'B' => 2,
|
||||||
_ => unreachable!(),
|
_ => unreachable!("expecting 'x', 'o' or 'B', but gets {}", ch),
|
||||||
});
|
});
|
||||||
|
|
||||||
while let Some(next_char_in_escape_seq) = stream.peek_next() {
|
while let Some(next_char_in_escape_seq) = stream.peek_next() {
|
||||||
@ -1494,8 +1494,6 @@ fn get_next_token_inner(
|
|||||||
|
|
||||||
('$', _) => return Some((Token::Reserved("$".into()), start_pos)),
|
('$', _) => return Some((Token::Reserved("$".into()), start_pos)),
|
||||||
|
|
||||||
('\0', _) => unreachable!(),
|
|
||||||
|
|
||||||
(ch, _) if ch.is_whitespace() => (),
|
(ch, _) if ch.is_whitespace() => (),
|
||||||
#[cfg(feature = "unicode-xid-ident")]
|
#[cfg(feature = "unicode-xid-ident")]
|
||||||
(ch, _) if unicode_xid::UnicodeXID::is_xid_start(ch) => {
|
(ch, _) if unicode_xid::UnicodeXID::is_xid_start(ch) => {
|
||||||
@ -1749,7 +1747,7 @@ impl<'a> Iterator for TokenIterator<'a, '_> {
|
|||||||
Some((Token::Custom(token.syntax().into()), pos))
|
Some((Token::Custom(token.syntax().into()), pos))
|
||||||
} else {
|
} else {
|
||||||
// Active standard keyword - should never be a custom keyword!
|
// Active standard keyword - should never be a custom keyword!
|
||||||
unreachable!("{:?}", token)
|
unreachable!("{:?} is an active keyword", token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Disabled symbol
|
// Disabled symbol
|
||||||
|
@ -55,7 +55,7 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let ast = engine.compile("{ const DECISION = false; if DECISION { 42 } else { 123 } }")?;
|
let ast = engine.compile("{ const DECISION = false; if DECISION { 42 } else { 123 } }")?;
|
||||||
|
|
||||||
assert!(format!("{:?}", ast).starts_with(r#"AST { source: None, statements: [Block([Const(Ident { name: "DECISION", pos: 1:9 }, Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#));
|
assert!(format!("{:?}", ast).starts_with(r#"AST { source: None, statements: [Block([Const(Ident("DECISION" @ 1:9), Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#));
|
||||||
|
|
||||||
let ast = engine.compile("if 1 == 2 { 42 }")?;
|
let ast = engine.compile("if 1 == 2 { 42 }")?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user