Reduce unnecessary Cow's in Expr.
This commit is contained in:
parent
6351c07bc6
commit
9ad9dd52ab
@ -893,7 +893,7 @@ impl Engine {
|
|||||||
|
|
||||||
match dot_lhs {
|
match dot_lhs {
|
||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(id, pos) => {
|
Expr::Variable(id, _, pos) => {
|
||||||
let (target, typ) = search_scope(scope, id, *pos)?;
|
let (target, typ) = search_scope(scope, id, *pos)?;
|
||||||
|
|
||||||
// Constants cannot be modified
|
// Constants cannot be modified
|
||||||
@ -1129,7 +1129,7 @@ impl Engine {
|
|||||||
Expr::FloatConstant(f, _) => Ok((*f).into()),
|
Expr::FloatConstant(f, _) => Ok((*f).into()),
|
||||||
Expr::StringConstant(s, _) => Ok(s.to_string().into()),
|
Expr::StringConstant(s, _) => Ok(s.to_string().into()),
|
||||||
Expr::CharConstant(c, _) => Ok((*c).into()),
|
Expr::CharConstant(c, _) => Ok((*c).into()),
|
||||||
Expr::Variable(id, pos) => search_scope(scope, id, *pos).map(|(v, _)| v.clone()),
|
Expr::Variable(id, _, pos) => search_scope(scope, id, *pos).map(|(v, _)| v.clone()),
|
||||||
Expr::Property(_, _) => panic!("unexpected property."),
|
Expr::Property(_, _) => panic!("unexpected property."),
|
||||||
|
|
||||||
// Statement block
|
// Statement block
|
||||||
@ -1141,7 +1141,7 @@ impl Engine {
|
|||||||
|
|
||||||
match lhs.as_ref() {
|
match lhs.as_ref() {
|
||||||
// name = rhs
|
// name = rhs
|
||||||
Expr::Variable(name, pos) => match scope.get(name) {
|
Expr::Variable(name, _, pos) => match scope.get(name) {
|
||||||
None => {
|
None => {
|
||||||
return Err(Box::new(EvalAltResult::ErrorVariableNotFound(
|
return Err(Box::new(EvalAltResult::ErrorVariableNotFound(
|
||||||
name.to_string(),
|
name.to_string(),
|
||||||
|
@ -368,12 +368,12 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
//id = id2 = expr2
|
//id = id2 = expr2
|
||||||
Expr::Assignment(id2, expr2, pos2) => match (*id, *id2) {
|
Expr::Assignment(id2, expr2, pos2) => match (*id, *id2) {
|
||||||
// var = var = expr2 -> var = expr2
|
// var = var = expr2 -> var = expr2
|
||||||
(Expr::Variable(var, _), Expr::Variable(var2, _)) if var == var2 => {
|
(Expr::Variable(var, sp, _), Expr::Variable(var2, sp2, _)) if var == var2 && sp == sp2 => {
|
||||||
// Assignment to the same variable - fold
|
// Assignment to the same variable - fold
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
|
||||||
Expr::Assignment(
|
Expr::Assignment(
|
||||||
Box::new(Expr::Variable(var, pos)),
|
Box::new(Expr::Variable(var, sp, pos)),
|
||||||
Box::new(optimize_expr(*expr2, state)),
|
Box::new(optimize_expr(*expr2, state)),
|
||||||
pos,
|
pos,
|
||||||
)
|
)
|
||||||
@ -397,13 +397,11 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
Expr::Dot(lhs, rhs, pos) => match (*lhs, *rhs) {
|
Expr::Dot(lhs, rhs, pos) => match (*lhs, *rhs) {
|
||||||
// map.string
|
// map.string
|
||||||
(Expr::Map(items, pos), Expr::Property(s, _))
|
(Expr::Map(items, pos), Expr::Property(s, _)) if items.iter().all(|(_, x, _)| x.is_pure()) => {
|
||||||
if items.iter().all(|(_, x, _)| x.is_pure()) =>
|
|
||||||
{
|
|
||||||
// Map literal where everything is pure - promote the indexed item.
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
items.into_iter().find(|(name, _, _)| name == s.as_ref())
|
items.into_iter().find(|(name, _, _)| name == &s)
|
||||||
.map(|(_, expr, _)| expr.set_position(pos))
|
.map(|(_, expr, _)| expr.set_position(pos))
|
||||||
.unwrap_or_else(|| Expr::Unit(pos))
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
}
|
}
|
||||||
@ -428,13 +426,11 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
items.remove(i as usize).set_position(pos)
|
items.remove(i as usize).set_position(pos)
|
||||||
}
|
}
|
||||||
// map[string]
|
// map[string]
|
||||||
(Expr::Map(items, pos), Expr::StringConstant(s, _))
|
(Expr::Map(items, pos), Expr::StringConstant(s, _)) if items.iter().all(|(_, x, _)| x.is_pure()) => {
|
||||||
if items.iter().all(|(_, x, _)| x.is_pure()) =>
|
|
||||||
{
|
|
||||||
// Map literal where everything is pure - promote the indexed item.
|
// Map literal where everything is pure - promote the indexed item.
|
||||||
// All other items can be thrown away.
|
// All other items can be thrown away.
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
items.into_iter().find(|(name, _, _)| name == s.as_ref())
|
items.into_iter().find(|(name, _, _)| name == &s)
|
||||||
.map(|(_, expr, _)| expr.set_position(pos))
|
.map(|(_, expr, _)| expr.set_position(pos))
|
||||||
.unwrap_or_else(|| Expr::Unit(pos))
|
.unwrap_or_else(|| Expr::Unit(pos))
|
||||||
}
|
}
|
||||||
@ -470,7 +466,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
// "xxx" in "xxxxx"
|
// "xxx" in "xxxxx"
|
||||||
(Expr::StringConstant(lhs, pos), Expr::StringConstant(rhs, _)) => {
|
(Expr::StringConstant(lhs, pos), Expr::StringConstant(rhs, _)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
if rhs.contains(lhs.as_ref()) {
|
if rhs.contains(&lhs) {
|
||||||
Expr::True(pos)
|
Expr::True(pos)
|
||||||
} else {
|
} else {
|
||||||
Expr::False(pos)
|
Expr::False(pos)
|
||||||
@ -613,7 +609,7 @@ fn optimize_expr<'a>(expr: Expr, state: &mut State<'a>) -> Expr {
|
|||||||
Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos),
|
Expr::FunctionCall(id, args.into_iter().map(|a| optimize_expr(a, state)).collect(), def_value, pos),
|
||||||
|
|
||||||
// constant-name
|
// constant-name
|
||||||
Expr::Variable(name, pos) if state.contains_constant(&name) => {
|
Expr::Variable(name, _, pos) if state.contains_constant(&name) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
|
|
||||||
// Replace constant with value
|
// Replace constant with value
|
||||||
|
@ -12,7 +12,6 @@ use crate::stdlib::{
|
|||||||
boxed::Box,
|
boxed::Box,
|
||||||
char,
|
char,
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
fmt::Display,
|
|
||||||
format,
|
format,
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
ops::Add,
|
ops::Add,
|
||||||
@ -196,11 +195,11 @@ pub enum Stmt {
|
|||||||
/// loop { stmt }
|
/// loop { stmt }
|
||||||
Loop(Box<Stmt>),
|
Loop(Box<Stmt>),
|
||||||
/// for id in expr { stmt }
|
/// for id in expr { stmt }
|
||||||
For(Cow<'static, str>, Box<Expr>, Box<Stmt>),
|
For(String, Box<Expr>, Box<Stmt>),
|
||||||
/// let id = expr
|
/// let id = expr
|
||||||
Let(Cow<'static, str>, Option<Box<Expr>>, Position),
|
Let(String, Option<Box<Expr>>, Position),
|
||||||
/// const id = expr
|
/// const id = expr
|
||||||
Const(Cow<'static, str>, Box<Expr>, Position),
|
Const(String, Box<Expr>, Position),
|
||||||
/// { stmt; ... }
|
/// { stmt; ... }
|
||||||
Block(Vec<Stmt>, Position),
|
Block(Vec<Stmt>, Position),
|
||||||
/// { stmt }
|
/// { stmt }
|
||||||
@ -280,14 +279,16 @@ pub enum Expr {
|
|||||||
/// Character constant.
|
/// Character constant.
|
||||||
CharConstant(char, Position),
|
CharConstant(char, Position),
|
||||||
/// String constant.
|
/// String constant.
|
||||||
StringConstant(Cow<'static, str>, Position),
|
StringConstant(String, Position),
|
||||||
/// Variable access.
|
/// Variable access.
|
||||||
Variable(Cow<'static, str>, Position),
|
Variable(String, usize, Position),
|
||||||
/// Property access.
|
/// Property access.
|
||||||
Property(Cow<'static, str>, Position),
|
Property(String, Position),
|
||||||
/// { stmt }
|
/// { stmt }
|
||||||
Stmt(Box<Stmt>, Position),
|
Stmt(Box<Stmt>, Position),
|
||||||
/// func(expr, ... )
|
/// func(expr, ... )
|
||||||
|
/// Use `Cow<'static, str>` because a lot of operators (e.g. `==`, `>=`) are implemented as function calls
|
||||||
|
/// and the function names are predictable, so no need to allocate a new `String`.
|
||||||
FunctionCall(Cow<'static, str>, Vec<Expr>, Option<Dynamic>, Position),
|
FunctionCall(Cow<'static, str>, Vec<Expr>, Option<Dynamic>, Position),
|
||||||
/// expr = expr
|
/// expr = expr
|
||||||
Assignment(Box<Expr>, Box<Expr>, Position),
|
Assignment(Box<Expr>, Box<Expr>, Position),
|
||||||
@ -325,7 +326,7 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(f, _) => (*f).into(),
|
Self::FloatConstant(f, _) => (*f).into(),
|
||||||
Self::CharConstant(c, _) => (*c).into(),
|
Self::CharConstant(c, _) => (*c).into(),
|
||||||
Self::StringConstant(s, _) => s.to_string().into(),
|
Self::StringConstant(s, _) => s.clone().into(),
|
||||||
Self::True(_) => true.into(),
|
Self::True(_) => true.into(),
|
||||||
Self::False(_) => false.into(),
|
Self::False(_) => false.into(),
|
||||||
Self::Unit(_) => ().into(),
|
Self::Unit(_) => ().into(),
|
||||||
@ -382,7 +383,7 @@ impl Expr {
|
|||||||
| Self::StringConstant(_, pos)
|
| Self::StringConstant(_, pos)
|
||||||
| Self::Array(_, pos)
|
| Self::Array(_, pos)
|
||||||
| Self::Map(_, pos)
|
| Self::Map(_, pos)
|
||||||
| Self::Variable(_, pos)
|
| Self::Variable(_, _, pos)
|
||||||
| Self::Property(_, pos)
|
| Self::Property(_, pos)
|
||||||
| Self::Stmt(_, pos)
|
| Self::Stmt(_, pos)
|
||||||
| Self::FunctionCall(_, _, _, pos)
|
| Self::FunctionCall(_, _, _, pos)
|
||||||
@ -408,7 +409,7 @@ impl Expr {
|
|||||||
| Self::StringConstant(_, pos)
|
| Self::StringConstant(_, pos)
|
||||||
| Self::Array(_, pos)
|
| Self::Array(_, pos)
|
||||||
| Self::Map(_, pos)
|
| Self::Map(_, pos)
|
||||||
| Self::Variable(_, pos)
|
| Self::Variable(_, _, pos)
|
||||||
| Self::Property(_, pos)
|
| Self::Property(_, pos)
|
||||||
| Self::Stmt(_, pos)
|
| Self::Stmt(_, pos)
|
||||||
| Self::FunctionCall(_, _, _, pos)
|
| Self::FunctionCall(_, _, _, pos)
|
||||||
@ -439,7 +440,7 @@ impl Expr {
|
|||||||
|
|
||||||
Self::Stmt(stmt, _) => stmt.is_pure(),
|
Self::Stmt(stmt, _) => stmt.is_pure(),
|
||||||
|
|
||||||
Self::Variable(_, _) => true,
|
Self::Variable(_, _, _) => true,
|
||||||
|
|
||||||
expr => expr.is_constant(),
|
expr => expr.is_constant(),
|
||||||
}
|
}
|
||||||
@ -498,7 +499,7 @@ impl Expr {
|
|||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
Self::Variable(_, _) | Self::Property(_, _) => match token {
|
Self::Variable(_, _, _) | Self::Property(_, _) => match token {
|
||||||
Token::LeftBracket | Token::LeftParen => true,
|
Token::LeftBracket | Token::LeftParen => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
@ -508,7 +509,7 @@ impl Expr {
|
|||||||
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
||||||
pub(crate) fn into_property(self) -> Self {
|
pub(crate) fn into_property(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Variable(id, pos) => Self::Property(id, pos),
|
Self::Variable(id, _, pos) => Self::Property(id, pos),
|
||||||
_ => self,
|
_ => self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -567,8 +568,8 @@ fn parse_paren_expr<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a function call.
|
/// Parse a function call.
|
||||||
fn parse_call_expr<'a, S: Into<Cow<'static, str>> + Display>(
|
fn parse_call_expr<'a>(
|
||||||
id: S,
|
id: String,
|
||||||
input: &mut Peekable<TokenIterator<'a>>,
|
input: &mut Peekable<TokenIterator<'a>>,
|
||||||
begin: Position,
|
begin: Position,
|
||||||
allow_stmt_expr: bool,
|
allow_stmt_expr: bool,
|
||||||
@ -916,8 +917,8 @@ fn parse_primary<'a>(
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Token::FloatConstant(x) => Expr::FloatConstant(x, pos),
|
Token::FloatConstant(x) => Expr::FloatConstant(x, pos),
|
||||||
Token::CharConstant(c) => Expr::CharConstant(c, pos),
|
Token::CharConstant(c) => Expr::CharConstant(c, pos),
|
||||||
Token::StringConst(s) => Expr::StringConstant(s.into(), pos),
|
Token::StringConst(s) => Expr::StringConstant(s, pos),
|
||||||
Token::Identifier(s) => Expr::Variable(s.into(), pos),
|
Token::Identifier(s) => Expr::Variable(s, 0, pos),
|
||||||
Token::LeftParen => parse_paren_expr(input, pos, allow_stmt_expr)?,
|
Token::LeftParen => parse_paren_expr(input, pos, allow_stmt_expr)?,
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
Token::LeftBracket => parse_array_literal(input, pos, allow_stmt_expr)?,
|
Token::LeftBracket => parse_array_literal(input, pos, allow_stmt_expr)?,
|
||||||
@ -943,7 +944,7 @@ fn parse_primary<'a>(
|
|||||||
|
|
||||||
root_expr = match (root_expr, token) {
|
root_expr = match (root_expr, token) {
|
||||||
// Function call
|
// Function call
|
||||||
(Expr::Variable(id, pos), Token::LeftParen)
|
(Expr::Variable(id, _, pos), Token::LeftParen)
|
||||||
| (Expr::Property(id, pos), Token::LeftParen) => {
|
| (Expr::Property(id, pos), Token::LeftParen) => {
|
||||||
parse_call_expr(id, input, pos, allow_stmt_expr)?
|
parse_call_expr(id, input, pos, allow_stmt_expr)?
|
||||||
}
|
}
|
||||||
@ -1078,7 +1079,7 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position, is_index: bool) -> Expr
|
|||||||
idx_pos,
|
idx_pos,
|
||||||
),
|
),
|
||||||
// lhs.id
|
// lhs.id
|
||||||
(lhs, rhs @ Expr::Variable(_, _)) | (lhs, rhs @ Expr::Property(_, _)) => {
|
(lhs, rhs @ Expr::Variable(_, _, _)) | (lhs, rhs @ Expr::Property(_, _)) => {
|
||||||
let lhs = if is_index { lhs.into_property() } else { lhs };
|
let lhs = if is_index { lhs.into_property() } else { lhs };
|
||||||
Expr::Dot(Box::new(lhs), Box::new(rhs.into_property()), op_pos)
|
Expr::Dot(Box::new(lhs), Box::new(rhs.into_property()), op_pos)
|
||||||
}
|
}
|
||||||
@ -1479,7 +1480,7 @@ fn parse_for<'a>(
|
|||||||
let expr = parse_expr(input, allow_stmt_expr)?;
|
let expr = parse_expr(input, allow_stmt_expr)?;
|
||||||
let body = parse_block(input, true, allow_stmt_expr)?;
|
let body = parse_block(input, true, allow_stmt_expr)?;
|
||||||
|
|
||||||
Ok(Stmt::For(name.into(), Box::new(expr), Box::new(body)))
|
Ok(Stmt::For(name, Box::new(expr), Box::new(body)))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a variable definition statement.
|
/// Parse a variable definition statement.
|
||||||
@ -1505,10 +1506,10 @@ fn parse_let<'a>(
|
|||||||
|
|
||||||
match var_type {
|
match var_type {
|
||||||
// let name = expr
|
// let name = expr
|
||||||
ScopeEntryType::Normal => Ok(Stmt::Let(name.into(), Some(Box::new(init_value)), pos)),
|
ScopeEntryType::Normal => Ok(Stmt::Let(name, Some(Box::new(init_value)), pos)),
|
||||||
// const name = { expr:constant }
|
// const name = { expr:constant }
|
||||||
ScopeEntryType::Constant if init_value.is_constant() => {
|
ScopeEntryType::Constant if init_value.is_constant() => {
|
||||||
Ok(Stmt::Const(name.into(), Box::new(init_value), pos))
|
Ok(Stmt::Const(name, Box::new(init_value), pos))
|
||||||
}
|
}
|
||||||
// const name = expr - error
|
// const name = expr - error
|
||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
@ -1517,7 +1518,7 @@ fn parse_let<'a>(
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// let name
|
// let name
|
||||||
Ok(Stmt::Let(name.into(), None, pos))
|
Ok(Stmt::Let(name, None, pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1840,7 +1841,7 @@ pub fn map_dynamic_to_expr(value: Dynamic, pos: Position) -> Option<Expr> {
|
|||||||
Union::Unit(_) => Some(Expr::Unit(pos)),
|
Union::Unit(_) => Some(Expr::Unit(pos)),
|
||||||
Union::Int(value) => Some(Expr::IntegerConstant(value, pos)),
|
Union::Int(value) => Some(Expr::IntegerConstant(value, pos)),
|
||||||
Union::Char(value) => Some(Expr::CharConstant(value, pos)),
|
Union::Char(value) => Some(Expr::CharConstant(value, pos)),
|
||||||
Union::Str(value) => Some(Expr::StringConstant((*value).into(), pos)),
|
Union::Str(value) => Some(Expr::StringConstant((*value).clone(), pos)),
|
||||||
Union::Bool(true) => Some(Expr::True(pos)),
|
Union::Bool(true) => Some(Expr::True(pos)),
|
||||||
Union::Bool(false) => Some(Expr::False(pos)),
|
Union::Bool(false) => Some(Expr::False(pos)),
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
Loading…
Reference in New Issue
Block a user