Handle constants propagation.
This commit is contained in:
parent
cce2e02428
commit
d1fc362eec
@ -4,7 +4,6 @@ use crate::ast::{Expr, OpAssignment, Stmt};
|
|||||||
use crate::dynamic::AccessMode;
|
use crate::dynamic::AccessMode;
|
||||||
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF};
|
||||||
use crate::fn_builtin::get_builtin_binary_op_fn;
|
use crate::fn_builtin::get_builtin_binary_op_fn;
|
||||||
use crate::parser::map_dynamic_to_expr;
|
|
||||||
use crate::token::Token;
|
use crate::token::Token;
|
||||||
use crate::utils::get_hasher;
|
use crate::utils::get_hasher;
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -59,7 +58,7 @@ struct State<'a> {
|
|||||||
/// Has the [`AST`] been changed during this pass?
|
/// Has the [`AST`] been changed during this pass?
|
||||||
changed: bool,
|
changed: bool,
|
||||||
/// Collection of constants to use for eager function evaluations.
|
/// Collection of constants to use for eager function evaluations.
|
||||||
variables: Vec<(String, AccessMode, Expr)>,
|
variables: Vec<(String, AccessMode, Option<Dynamic>)>,
|
||||||
/// Activate constants propagation?
|
/// Activate constants propagation?
|
||||||
propagate_constants: bool,
|
propagate_constants: bool,
|
||||||
/// An [`Engine`] instance for eager function evaluation.
|
/// An [`Engine`] instance for eager function evaluation.
|
||||||
@ -109,21 +108,21 @@ impl<'a> State<'a> {
|
|||||||
}
|
}
|
||||||
/// Add a new constant to the list.
|
/// Add a new constant to the list.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push_var(&mut self, name: &str, access: AccessMode, value: Expr) {
|
pub fn push_var(&mut self, name: &str, access: AccessMode, value: Option<Dynamic>) {
|
||||||
self.variables.push((name.into(), access, value))
|
self.variables.push((name.into(), access, value))
|
||||||
}
|
}
|
||||||
/// Look up a constant from the list.
|
/// Look up a constant from the list.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn find_constant(&self, name: &str) -> Option<&Expr> {
|
pub fn find_constant(&self, name: &str) -> Option<&Dynamic> {
|
||||||
if !self.propagate_constants {
|
if !self.propagate_constants {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.variables.iter().rev().find_map(|(n, access, expr)| {
|
self.variables.iter().rev().find_map(|(n, access, value)| {
|
||||||
if n == name {
|
if n == name {
|
||||||
match access {
|
match access {
|
||||||
AccessMode::ReadWrite => None,
|
AccessMode::ReadWrite => None,
|
||||||
AccessMode::ReadOnly => Some(expr),
|
AccessMode::ReadOnly => value.as_ref(),
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
@ -217,13 +216,17 @@ fn optimize_stmt_block(
|
|||||||
optimize_expr(value_expr, state);
|
optimize_expr(value_expr, state);
|
||||||
|
|
||||||
if value_expr.is_constant() {
|
if value_expr.is_constant() {
|
||||||
state.push_var(&x.name, AccessMode::ReadOnly, value_expr.clone());
|
state.push_var(
|
||||||
|
&x.name,
|
||||||
|
AccessMode::ReadOnly,
|
||||||
|
value_expr.get_constant_value(),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Add variables into the state
|
// Add variables into the state
|
||||||
Stmt::Let(value_expr, x, _, _) => {
|
Stmt::Let(value_expr, x, _, _) => {
|
||||||
optimize_expr(value_expr, state);
|
optimize_expr(value_expr, state);
|
||||||
state.push_var(&x.name, AccessMode::ReadWrite, Expr::Unit(x.pos));
|
state.push_var(&x.name, AccessMode::ReadWrite, None);
|
||||||
}
|
}
|
||||||
// Optimize the statement
|
// Optimize the statement
|
||||||
_ => optimize_stmt(stmt, state, preserve_result),
|
_ => optimize_stmt(stmt, state, preserve_result),
|
||||||
@ -925,15 +928,16 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
|
|
||||||
// Search for overloaded operators (can override built-in).
|
// Search for overloaded operators (can override built-in).
|
||||||
if !has_native_fn(state, x.hashes.native_hash(), arg_types.as_ref()) {
|
if !has_native_fn(state, x.hashes.native_hash(), arg_types.as_ref()) {
|
||||||
if let Some(result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
if let Some(mut result) = get_builtin_binary_op_fn(x.name.as_ref(), &arg_values[0], &arg_values[1])
|
||||||
.and_then(|f| {
|
.and_then(|f| {
|
||||||
let ctx = (state.engine, x.name.as_ref(), state.lib).into();
|
let ctx = (state.engine, x.name.as_ref(), state.lib).into();
|
||||||
let (first, second) = arg_values.split_first_mut().unwrap();
|
let (first, second) = arg_values.split_first_mut().unwrap();
|
||||||
(f)(ctx, &mut [ first, &mut second[0] ]).ok()
|
(f)(ctx, &mut [ first, &mut second[0] ]).ok()
|
||||||
})
|
})
|
||||||
.and_then(|result| map_dynamic_to_expr(result, *pos))
|
.map(Expr::from)
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
result.set_position(*pos);
|
||||||
*expr = result;
|
*expr = result;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -977,18 +981,19 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
""
|
""
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(result) = call_fn_with_constant_arguments(&state, x.name.as_ref(), &mut arg_values)
|
if let Some(mut result) = call_fn_with_constant_arguments(&state, x.name.as_ref(), &mut arg_values)
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
if !arg_for_type_of.is_empty() {
|
if !arg_for_type_of.is_empty() {
|
||||||
// Handle `type_of()`
|
// Handle `type_of()`
|
||||||
Some(arg_for_type_of.to_string().into())
|
Some(arg_for_type_of.to_string().into())
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.and_then(|result| map_dynamic_to_expr(result, *pos))
|
.map(Expr::from)
|
||||||
{
|
{
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
result.set_position(*pos);
|
||||||
*expr = result;
|
*expr = result;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1014,12 +1019,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
|
|
||||||
// constant-name
|
// constant-name
|
||||||
Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => {
|
Expr::Variable(_, pos, x) if x.1.is_none() && state.find_constant(&x.2).is_some() => {
|
||||||
state.set_dirty();
|
|
||||||
|
|
||||||
// Replace constant with value
|
// Replace constant with value
|
||||||
let mut result = state.find_constant(&x.2).unwrap().clone();
|
let pos = *pos;
|
||||||
result.set_position(*pos);
|
*expr = Expr::from(state.find_constant(&x.2).unwrap().clone());
|
||||||
*expr = result;
|
expr.set_position(pos);
|
||||||
|
state.set_dirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Custom syntax
|
// Custom syntax
|
||||||
@ -1055,13 +1059,9 @@ fn optimize_top_level(
|
|||||||
// Add constants and variables from the scope
|
// Add constants and variables from the scope
|
||||||
scope.iter().for_each(|(name, constant, value)| {
|
scope.iter().for_each(|(name, constant, value)| {
|
||||||
if !constant {
|
if !constant {
|
||||||
state.push_var(name, AccessMode::ReadWrite, Expr::Unit(Position::NONE));
|
state.push_var(name, AccessMode::ReadWrite, None);
|
||||||
} else {
|
} else {
|
||||||
state.push_var(
|
state.push_var(name, AccessMode::ReadOnly, Some(value));
|
||||||
name,
|
|
||||||
AccessMode::ReadOnly,
|
|
||||||
Expr::DynamicConstant(Box::new(value), Position::NONE),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -3121,29 +3121,32 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map a `Dynamic` value to an expression.
|
impl From<Dynamic> for Expr {
|
||||||
///
|
fn from(value: Dynamic) -> Self {
|
||||||
/// Returns Some(expression) if conversion is successful. Otherwise None.
|
match value.0 {
|
||||||
pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
|
#[cfg(not(feature = "no_float"))]
|
||||||
match value.0 {
|
Union::Float(value, _, _) => Self::FloatConstant(value, Position::NONE),
|
||||||
#[cfg(not(feature = "no_float"))]
|
|
||||||
Union::Float(value, _, _) => Some(Expr::FloatConstant(value, pos)),
|
|
||||||
|
|
||||||
#[cfg(feature = "decimal")]
|
#[cfg(feature = "decimal")]
|
||||||
Union::Decimal(value, _, _) => Some(Expr::DynamicConstant(Box::new((*value).into()), pos)),
|
Union::Decimal(value, _, _) => {
|
||||||
|
Self::DynamicConstant(Box::new((*value).into()), Position::NONE)
|
||||||
|
}
|
||||||
|
|
||||||
Union::Unit(_, _, _) => Some(Expr::Unit(pos)),
|
Union::Unit(_, _, _) => Self::Unit(Position::NONE),
|
||||||
Union::Int(value, _, _) => Some(Expr::IntegerConstant(value, pos)),
|
Union::Int(value, _, _) => Self::IntegerConstant(value, Position::NONE),
|
||||||
Union::Char(value, _, _) => Some(Expr::CharConstant(value, pos)),
|
Union::Char(value, _, _) => Self::CharConstant(value, Position::NONE),
|
||||||
Union::Str(value, _, _) => Some(Expr::StringConstant(value, pos)),
|
Union::Str(value, _, _) => Self::StringConstant(value, Position::NONE),
|
||||||
Union::Bool(value, _, _) => Some(Expr::BoolConstant(value, pos)),
|
Union::Bool(value, _, _) => Self::BoolConstant(value, Position::NONE),
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Union::Array(array, _, _) => Some(Expr::DynamicConstant(Box::new((*array).into()), pos)),
|
Union::Array(array, _, _) => {
|
||||||
|
Self::DynamicConstant(Box::new((*array).into()), Position::NONE)
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Union::Map(map, _, _) => Some(Expr::DynamicConstant(Box::new((*map).into()), pos)),
|
Union::Map(map, _, _) => Self::DynamicConstant(Box::new((*map).into()), Position::NONE),
|
||||||
|
|
||||||
_ => None,
|
_ => Self::DynamicConstant(Box::new(value.into()), Position::NONE),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user