Use template for object map literal.

This commit is contained in:
Stephen Chung 2021-03-23 18:25:40 +08:00
parent f70225ca1d
commit f9429c06f9
4 changed files with 24 additions and 25 deletions

View File

@ -26,9 +26,6 @@ use crate::{stdlib::str::FromStr, FLOAT};
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
use crate::Array; use crate::Array;
#[cfg(not(feature = "no_object"))]
use crate::Map;
/// A type representing the access mode of a function. /// A type representing the access mode of a function.
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
pub enum FnAccess { pub enum FnAccess {
@ -1535,7 +1532,10 @@ pub enum Expr {
/// [ expr, ... ] /// [ expr, ... ]
Array(Box<StaticVec<Expr>>, Position), Array(Box<StaticVec<Expr>>, Position),
/// #{ name:expr, ... } /// #{ name:expr, ... }
Map(Box<StaticVec<(Ident, Expr)>>, Position), Map(
Box<(StaticVec<(Ident, Expr)>, BTreeMap<ImmutableString, Dynamic>)>,
Position,
),
/// () /// ()
Unit(Position), Unit(Position),
/// Variable access - (optional index, optional (hash, modules), variable name) /// Variable access - (optional index, optional (hash, modules), variable name)
@ -1594,11 +1594,10 @@ impl Expr {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Self::Map(x, _) if self.is_constant() => { Self::Map(x, _) if self.is_constant() => {
let mut map = Map::new(); let mut map = x.1.clone();
map.extend( x.0.iter().for_each(|(k, v)| {
x.iter() *map.get_mut(&k.name).unwrap() = v.get_constant_value().unwrap()
.map(|(k, v)| (k.name.clone(), v.get_constant_value().unwrap())), });
);
Dynamic(Union::Map(Box::new(map), AccessMode::ReadOnly)) Dynamic(Union::Map(Box::new(map), AccessMode::ReadOnly))
} }
@ -1677,7 +1676,7 @@ impl Expr {
match self { match self {
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.0.iter().map(|(_, v)| v).all(Self::is_pure),
Self::Index(x, _) | Self::And(x, _) | Self::Or(x, _) => { Self::Index(x, _) | Self::And(x, _) | Self::Or(x, _) => {
x.lhs.is_pure() && x.rhs.is_pure() x.lhs.is_pure() && x.rhs.is_pure()
@ -1717,7 +1716,7 @@ impl Expr {
Self::Array(x, _) => x.iter().all(Self::is_constant), Self::Array(x, _) => x.iter().all(Self::is_constant),
// An map literal is constant if all items are constant // An map literal is constant if all items are constant
Self::Map(x, _) => x.iter().map(|(_, expr)| expr).all(Self::is_constant), Self::Map(x, _) => x.0.iter().map(|(_, expr)| expr).all(Self::is_constant),
_ => false, _ => false,
} }
@ -1804,7 +1803,7 @@ impl Expr {
} }
} }
Self::Map(x, _) => { Self::Map(x, _) => {
for (_, e) in x.as_ref() { for (_, e) in &x.0 {
if !e.walk(path, on_node) { if !e.walk(path, on_node) {
return false; return false;
} }

View File

@ -1686,13 +1686,11 @@ impl Engine {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Map(x, _) => { Expr::Map(x, _) => {
let mut map = Map::new(); let mut map = x.1.clone();
for (Ident { name: key, .. }, expr) in x.as_ref() { for (Ident { name: key, .. }, expr) in &x.0 {
map.insert( *map.get_mut(key).unwrap() = self
key.clone(), .eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
self.eval_expr(scope, mods, state, lib, this_ptr, expr, level)? .flatten();
.flatten(),
);
} }
Ok(Dynamic(Union::Map(Box::new(map), AccessMode::ReadWrite))) Ok(Dynamic(Union::Map(Box::new(map), AccessMode::ReadWrite)))
} }

View File

@ -615,12 +615,12 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Dot(x, _) => match (&mut x.lhs, &mut x.rhs) { Expr::Dot(x, _) => match (&mut x.lhs, &mut x.rhs) {
// map.string // map.string
(Expr::Map(m, pos), Expr::Property(p)) if m.iter().all(|(_, x)| x.is_pure()) => { (Expr::Map(m, pos), Expr::Property(p)) if m.0.iter().all(|(_, x)| x.is_pure()) => {
let prop = &p.2.name; let prop = &p.2.name;
// 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();
*expr = mem::take(m).into_iter().find(|(x, _)| &x.name == prop) *expr = mem::take(&mut m.0).into_iter().find(|(x, _)| &x.name == prop)
.map(|(_, mut expr)| { expr.set_position(*pos); expr }) .map(|(_, mut expr)| { expr.set_position(*pos); expr })
.unwrap_or_else(|| Expr::Unit(*pos)); .unwrap_or_else(|| Expr::Unit(*pos));
} }
@ -645,11 +645,11 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
*expr = result; *expr = result;
} }
// map[string] // map[string]
(Expr::Map(m, pos), Expr::StringConstant(s, _)) if m.iter().all(|(_, x)| x.is_pure()) => { (Expr::Map(m, pos), Expr::StringConstant(s, _)) if m.0.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();
*expr = mem::take(m).into_iter().find(|(x, _)| x.name == *s) *expr = mem::take(&mut m.0).into_iter().find(|(x, _)| x.name == *s)
.map(|(_, mut expr)| { expr.set_position(*pos); expr }) .map(|(_, mut expr)| { expr.set_position(*pos); expr })
.unwrap_or_else(|| Expr::Unit(*pos)); .unwrap_or_else(|| Expr::Unit(*pos));
} }
@ -681,7 +681,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
} }
// #{ key:value, .. } // #{ key:value, .. }
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Map(x, _) => x.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state)), Expr::Map(x, _) => x.0.iter_mut().for_each(|(_, expr)| optimize_expr(expr, state)),
// lhs && rhs // lhs && rhs
Expr::And(x, _) => match (&mut x.lhs, &mut x.rhs) { Expr::And(x, _) => match (&mut x.lhs, &mut x.rhs) {
// true && rhs -> rhs // true && rhs -> rhs

View File

@ -690,6 +690,7 @@ fn parse_map_literal(
settings.pos = eat_token(input, Token::MapStart); settings.pos = eat_token(input, Token::MapStart);
let mut map: StaticVec<(Ident, Expr)> = Default::default(); let mut map: StaticVec<(Ident, Expr)> = Default::default();
let mut template: BTreeMap<ImmutableString, Dynamic> = Default::default();
loop { loop {
const MISSING_RBRACE: &str = "to end this object map literal"; const MISSING_RBRACE: &str = "to end this object map literal";
@ -760,6 +761,7 @@ fn parse_map_literal(
let expr = parse_expr(input, state, lib, settings.level_up())?; let expr = parse_expr(input, state, lib, settings.level_up())?;
let name = state.get_interned_string(name); let name = state.get_interned_string(name);
template.insert(name.clone(), Default::default());
map.push((Ident { name, pos }, expr)); map.push((Ident { name, pos }, expr));
match input.peek().unwrap() { match input.peek().unwrap() {
@ -784,7 +786,7 @@ fn parse_map_literal(
} }
} }
Ok(Expr::Map(Box::new(map), settings.pos)) Ok(Expr::Map(Box::new((map, template)), settings.pos))
} }
/// Parse a switch expression. /// Parse a switch expression.