Remove Expr::get_constant_str and change Expr::get_constant_value not to panic.

This commit is contained in:
Stephen Chung 2020-10-06 22:09:26 +08:00
parent 8809d25d3c
commit ae1157a140
3 changed files with 52 additions and 48 deletions

View File

@ -1454,8 +1454,9 @@ impl Engine {
Some((result, rhs_expr.position())) Some((result, rhs_expr.position()))
}; };
// Must be either `var[index] op= val` or `var.prop op= val`
match lhs_expr { match lhs_expr {
// name op= rhs // name op= rhs (handled above)
Expr::Variable(_) => unreachable!(), Expr::Variable(_) => unreachable!(),
// idx_lhs[idx_expr] op= rhs // idx_lhs[idx_expr] op= rhs
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -1473,12 +1474,8 @@ impl Engine {
)?; )?;
Ok(Default::default()) Ok(Default::default())
} }
// Error assignment to constant // Constant expression (should be caught during parsing)
expr if expr.is_constant() => EvalAltResult::ErrorAssignmentToConstant( expr if expr.is_constant() => unreachable!(),
expr.get_constant_str(),
expr.position(),
)
.into(),
// Syntax error // Syntax error
expr => EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(), expr => EvalAltResult::ErrorAssignmentToUnknownLHS(expr.position()).into(),
} }

View File

@ -585,7 +585,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
=> { => {
let ((name, _, _, pos), _, _, args, _) = x.as_mut(); let ((name, _, _, pos), _, _, args, _) = x.as_mut();
let arg_values: StaticVec<_> = args.iter().map(Expr::get_constant_value).collect(); let arg_values: StaticVec<_> = args.iter().map(|e| e.get_constant_value().unwrap()).collect();
let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect(); let arg_types: StaticVec<_> = arg_values.iter().map(Dynamic::type_id).collect();
// Search for overloaded operators (can override built-in). // Search for overloaded operators (can override built-in).
@ -618,7 +618,7 @@ fn optimize_expr(expr: Expr, state: &mut State) -> Expr {
let has_script_fn = false; let has_script_fn = false;
if !has_script_fn { if !has_script_fn {
let mut arg_values: StaticVec<_> = args.iter().map(Expr::get_constant_value).collect(); let mut arg_values: StaticVec<_> = args.iter().map(|e| e.get_constant_value().unwrap()).collect();
// Save the typename of the first argument if it is `type_of()` // Save the typename of the first argument if it is `type_of()`
// This is to avoid `call_args` being passed into the closure // This is to avoid `call_args` being passed into the closure

View File

@ -12,13 +12,17 @@ use crate::syntax::FnCustomSyntaxEval;
use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream}; use crate::token::{is_keyword_function, is_valid_identifier, Position, Token, TokenStream};
use crate::utils::{StaticVec, StraightHasherBuilder}; use crate::utils::{StaticVec, StraightHasherBuilder};
#[cfg(not(feature = "no_index"))]
use crate::engine::Array;
#[cfg(not(feature = "no_object"))]
use crate::engine::{make_getter, make_setter, Map};
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY}; use crate::engine::{FN_ANONYMOUS, KEYWORD_FN_PTR_CURRY};
#[cfg(not(feature = "no_object"))]
use crate::engine::{make_getter, make_setter};
use crate::stdlib::{ use crate::stdlib::{
any::TypeId,
borrow::Cow, borrow::Cow,
boxed::Box, boxed::Box,
char, char,
@ -847,14 +851,40 @@ impl Default for Expr {
} }
impl Expr { impl Expr {
/// Get the type of an expression.
///
/// Returns `None` if the expression's result type is not constant.
pub fn get_type_id(&self) -> Option<TypeId> {
Some(match self {
Self::Expr(x) => return x.get_type_id(),
Self::IntegerConstant(_) => TypeId::of::<INT>(),
#[cfg(not(feature = "no_float"))]
Self::FloatConstant(_) => TypeId::of::<FLOAT>(),
Self::CharConstant(_) => TypeId::of::<char>(),
Self::StringConstant(_) => TypeId::of::<ImmutableString>(),
Self::FnPointer(_) => TypeId::of::<FnPtr>(),
Self::True(_) | Self::False(_) | Self::In(_) | Self::And(_) | Self::Or(_) => {
TypeId::of::<bool>()
}
Self::Unit(_) => TypeId::of::<()>(),
#[cfg(not(feature = "no_index"))]
Self::Array(_) => TypeId::of::<Array>(),
#[cfg(not(feature = "no_object"))]
Self::Map(_) => TypeId::of::<Map>(),
_ => return None,
})
}
/// Get the `Dynamic` value of a constant expression. /// Get the `Dynamic` value of a constant expression.
/// ///
/// # Panics /// Returns `None` if the expression is not constant.
/// pub fn get_constant_value(&self) -> Option<Dynamic> {
/// Panics when the expression is not constant. Some(match self {
pub fn get_constant_value(&self) -> Dynamic { Self::Expr(x) => return x.get_constant_value(),
match self {
Self::Expr(x) => x.get_constant_value(),
Self::IntegerConstant(x) => x.0.into(), Self::IntegerConstant(x) => x.0.into(),
#[cfg(not(feature = "no_float"))] #[cfg(not(feature = "no_float"))]
@ -871,45 +901,22 @@ impl Expr {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Self::Array(x) if x.0.iter().all(Self::is_constant) => Dynamic(Union::Array(Box::new( Self::Array(x) if x.0.iter().all(Self::is_constant) => Dynamic(Union::Array(Box::new(
x.0.iter().map(Self::get_constant_value).collect::<Vec<_>>(), x.0.iter()
.map(|v| v.get_constant_value().unwrap())
.collect(),
))), ))),
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Self::Map(x) if x.0.iter().all(|(_, v)| v.is_constant()) => { Self::Map(x) if x.0.iter().all(|(_, v)| v.is_constant()) => {
Dynamic(Union::Map(Box::new( Dynamic(Union::Map(Box::new(
x.0.iter() x.0.iter()
.map(|((k, _), v)| (k.clone(), v.get_constant_value())) .map(|((k, _), v)| (k.clone(), v.get_constant_value().unwrap()))
.collect::<HashMap<_, _>>(), .collect(),
))) )))
} }
_ => unreachable!("cannot get value of non-constant expression"), _ => return None,
} })
}
/// Get the display value of a constant expression.
///
/// # Panics
///
/// Panics when the expression is not constant.
pub fn get_constant_str(&self) -> String {
match self {
Self::Expr(x) => x.get_constant_str(),
#[cfg(not(feature = "no_float"))]
Self::FloatConstant(x) => x.0.to_string(),
Self::IntegerConstant(x) => x.0.to_string(),
Self::CharConstant(x) => x.0.to_string(),
Self::StringConstant(_) => "string".to_string(),
Self::True(_) => "true".to_string(),
Self::False(_) => "false".to_string(),
Self::Unit(_) => "()".to_string(),
Self::Array(x) if x.0.iter().all(Self::is_constant) => "array".to_string(),
_ => unreachable!("cannot get value of non-constant expression"),
}
} }
/// Get the `Position` of the expression. /// Get the `Position` of the expression.