More interned strings.
This commit is contained in:
parent
27619b86db
commit
7d1b971b39
50
src/ast.rs
50
src/ast.rs
@ -98,10 +98,10 @@ pub struct ScriptFnDef {
|
|||||||
/// Function access mode.
|
/// Function access mode.
|
||||||
pub access: FnAccess,
|
pub access: FnAccess,
|
||||||
/// Names of function parameters.
|
/// Names of function parameters.
|
||||||
pub params: StaticVec<String>,
|
pub params: StaticVec<ImmutableString>,
|
||||||
/// Access to external variables.
|
/// Access to external variables.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
pub externals: HashSet<String>,
|
pub externals: HashSet<ImmutableString>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for ScriptFnDef {
|
impl fmt::Display for ScriptFnDef {
|
||||||
@ -637,10 +637,10 @@ pub enum Stmt {
|
|||||||
Import(Expr, Option<Box<IdentX>>, Position),
|
Import(Expr, Option<Box<IdentX>>, Position),
|
||||||
/// export var as var, ...
|
/// export var as var, ...
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Export(Vec<(Ident, Option<Ident>)>, Position),
|
Export(Vec<(IdentX, Option<IdentX>)>, Position),
|
||||||
/// Convert a variable to shared.
|
/// Convert a variable to shared.
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
Share(Box<Ident>),
|
Share(IdentX),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Stmt {
|
impl Default for Stmt {
|
||||||
@ -915,9 +915,9 @@ pub enum Expr {
|
|||||||
/// Character constant.
|
/// Character constant.
|
||||||
CharConstant(char, Position),
|
CharConstant(char, Position),
|
||||||
/// String constant.
|
/// String constant.
|
||||||
StringConstant(Box<IdentX>),
|
StringConstant(ImmutableString, Position),
|
||||||
/// FnPtr constant.
|
/// FnPtr constant.
|
||||||
FnPointer(Box<IdentX>),
|
FnPointer(ImmutableString, Position),
|
||||||
/// Variable access - (optional index, optional modules, hash, variable name)
|
/// Variable access - (optional index, optional modules, hash, variable name)
|
||||||
Variable(Box<(Option<NonZeroUsize>, Option<Box<NamespaceRef>>, u64, IdentX)>),
|
Variable(Box<(Option<NonZeroUsize>, Option<Box<NamespaceRef>>, u64, IdentX)>),
|
||||||
/// Property access - (getter, setter), prop
|
/// Property access - (getter, setter), prop
|
||||||
@ -971,8 +971,8 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(_, _) => TypeId::of::<FLOAT>(),
|
Self::FloatConstant(_, _) => TypeId::of::<FLOAT>(),
|
||||||
Self::CharConstant(_, _) => TypeId::of::<char>(),
|
Self::CharConstant(_, _) => TypeId::of::<char>(),
|
||||||
Self::StringConstant(_) => TypeId::of::<ImmutableString>(),
|
Self::StringConstant(_, _) => TypeId::of::<ImmutableString>(),
|
||||||
Self::FnPointer(_) => TypeId::of::<FnPtr>(),
|
Self::FnPointer(_, _) => TypeId::of::<FnPtr>(),
|
||||||
Self::True(_) | Self::False(_) | Self::In(_, _) | Self::And(_, _) | Self::Or(_, _) => {
|
Self::True(_) | Self::False(_) | Self::In(_, _) | Self::And(_, _) | Self::Or(_, _) => {
|
||||||
TypeId::of::<bool>()
|
TypeId::of::<bool>()
|
||||||
}
|
}
|
||||||
@ -999,9 +999,9 @@ impl Expr {
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Self::FloatConstant(x, _) => x.0.into(),
|
Self::FloatConstant(x, _) => x.0.into(),
|
||||||
Self::CharConstant(x, _) => (*x).into(),
|
Self::CharConstant(x, _) => (*x).into(),
|
||||||
Self::StringConstant(x) => x.name.clone().into(),
|
Self::StringConstant(x, _) => x.clone().into(),
|
||||||
Self::FnPointer(x) => Dynamic(Union::FnPtr(Box::new(FnPtr::new_unchecked(
|
Self::FnPointer(x, _) => Dynamic(Union::FnPtr(Box::new(FnPtr::new_unchecked(
|
||||||
x.name.clone(),
|
x.clone(),
|
||||||
Default::default(),
|
Default::default(),
|
||||||
)))),
|
)))),
|
||||||
Self::True(_) => true.into(),
|
Self::True(_) => true.into(),
|
||||||
@ -1044,8 +1044,8 @@ impl Expr {
|
|||||||
|
|
||||||
Self::IntegerConstant(_, pos) => *pos,
|
Self::IntegerConstant(_, pos) => *pos,
|
||||||
Self::CharConstant(_, pos) => *pos,
|
Self::CharConstant(_, pos) => *pos,
|
||||||
Self::StringConstant(x) => x.pos,
|
Self::StringConstant(_, pos) => *pos,
|
||||||
Self::FnPointer(x) => x.pos,
|
Self::FnPointer(_, pos) => *pos,
|
||||||
Self::Array(_, pos) => *pos,
|
Self::Array(_, pos) => *pos,
|
||||||
Self::Map(_, pos) => *pos,
|
Self::Map(_, pos) => *pos,
|
||||||
Self::Property(x) => (x.1).pos,
|
Self::Property(x) => (x.1).pos,
|
||||||
@ -1075,8 +1075,8 @@ impl Expr {
|
|||||||
|
|
||||||
Self::IntegerConstant(_, pos) => *pos = new_pos,
|
Self::IntegerConstant(_, pos) => *pos = new_pos,
|
||||||
Self::CharConstant(_, pos) => *pos = new_pos,
|
Self::CharConstant(_, pos) => *pos = new_pos,
|
||||||
Self::StringConstant(x) => x.pos = new_pos,
|
Self::StringConstant(_, pos) => *pos = new_pos,
|
||||||
Self::FnPointer(x) => x.pos = new_pos,
|
Self::FnPointer(_, pos) => *pos = new_pos,
|
||||||
Self::Array(_, pos) => *pos = new_pos,
|
Self::Array(_, pos) => *pos = new_pos,
|
||||||
Self::Map(_, pos) => *pos = new_pos,
|
Self::Map(_, pos) => *pos = new_pos,
|
||||||
Self::Variable(x) => (x.3).pos = new_pos,
|
Self::Variable(x) => (x.3).pos = new_pos,
|
||||||
@ -1134,8 +1134,8 @@ impl Expr {
|
|||||||
|
|
||||||
Self::IntegerConstant(_, _)
|
Self::IntegerConstant(_, _)
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(_, _)
|
||||||
| Self::StringConstant(_)
|
| Self::StringConstant(_, _)
|
||||||
| Self::FnPointer(_)
|
| Self::FnPointer(_, _)
|
||||||
| Self::True(_)
|
| Self::True(_)
|
||||||
| Self::False(_)
|
| Self::False(_)
|
||||||
| Self::Unit(_) => true,
|
| Self::Unit(_) => true,
|
||||||
@ -1148,8 +1148,8 @@ impl Expr {
|
|||||||
|
|
||||||
// Check in expression
|
// Check in expression
|
||||||
Self::In(x, _) => match (&x.lhs, &x.rhs) {
|
Self::In(x, _) => match (&x.lhs, &x.rhs) {
|
||||||
(Self::StringConstant(_), Self::StringConstant(_))
|
(Self::StringConstant(_, _), Self::StringConstant(_, _))
|
||||||
| (Self::CharConstant(_, _), Self::StringConstant(_)) => true,
|
| (Self::CharConstant(_, _), Self::StringConstant(_, _)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1167,8 +1167,8 @@ impl Expr {
|
|||||||
|
|
||||||
Self::IntegerConstant(_, _)
|
Self::IntegerConstant(_, _)
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(_, _)
|
||||||
| Self::StringConstant(_)
|
| Self::StringConstant(_, _)
|
||||||
| Self::FnPointer(_)
|
| Self::FnPointer(_, _)
|
||||||
| Self::True(_)
|
| Self::True(_)
|
||||||
| Self::False(_)
|
| Self::False(_)
|
||||||
| Self::Unit(_) => true,
|
| Self::Unit(_) => true,
|
||||||
@ -1181,8 +1181,8 @@ impl Expr {
|
|||||||
|
|
||||||
// Check in expression
|
// Check in expression
|
||||||
Self::In(x, _) => match (&x.lhs, &x.rhs) {
|
Self::In(x, _) => match (&x.lhs, &x.rhs) {
|
||||||
(Self::StringConstant(_), Self::StringConstant(_))
|
(Self::StringConstant(_, _), Self::StringConstant(_, _))
|
||||||
| (Self::CharConstant(_, _), Self::StringConstant(_)) => true,
|
| (Self::CharConstant(_, _), Self::StringConstant(_, _)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -1200,7 +1200,7 @@ impl Expr {
|
|||||||
|
|
||||||
Self::IntegerConstant(_, _)
|
Self::IntegerConstant(_, _)
|
||||||
| Self::CharConstant(_, _)
|
| Self::CharConstant(_, _)
|
||||||
| Self::FnPointer(_)
|
| Self::FnPointer(_, _)
|
||||||
| Self::In(_, _)
|
| Self::In(_, _)
|
||||||
| Self::And(_, _)
|
| Self::And(_, _)
|
||||||
| Self::Or(_, _)
|
| Self::Or(_, _)
|
||||||
@ -1208,7 +1208,7 @@ impl Expr {
|
|||||||
| Self::False(_)
|
| Self::False(_)
|
||||||
| Self::Unit(_) => false,
|
| Self::Unit(_) => false,
|
||||||
|
|
||||||
Self::StringConstant(_)
|
Self::StringConstant(_, _)
|
||||||
| Self::Stmt(_, _)
|
| Self::Stmt(_, _)
|
||||||
| Self::FnCall(_, _)
|
| Self::FnCall(_, _)
|
||||||
| Self::Dot(_, _)
|
| Self::Dot(_, _)
|
||||||
|
@ -1544,11 +1544,9 @@ impl Engine {
|
|||||||
Expr::IntegerConstant(x, _) => Ok((*x).into()),
|
Expr::IntegerConstant(x, _) => Ok((*x).into()),
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(x, _) => Ok(x.0.into()),
|
Expr::FloatConstant(x, _) => Ok(x.0.into()),
|
||||||
Expr::StringConstant(x) => Ok(x.name.clone().into()),
|
Expr::StringConstant(x, _) => Ok(x.clone().into()),
|
||||||
Expr::CharConstant(x, _) => Ok((*x).into()),
|
Expr::CharConstant(x, _) => Ok((*x).into()),
|
||||||
Expr::FnPointer(x) => {
|
Expr::FnPointer(x, _) => Ok(FnPtr::new_unchecked(x.clone(), Default::default()).into()),
|
||||||
Ok(FnPtr::new_unchecked(x.name.clone(), Default::default()).into())
|
|
||||||
}
|
|
||||||
Expr::Variable(x) if (x.3).name == KEYWORD_THIS => {
|
Expr::Variable(x) if (x.3).name == KEYWORD_THIS => {
|
||||||
if let Some(val) = this_ptr {
|
if let Some(val) = this_ptr {
|
||||||
Ok(val.clone())
|
Ok(val.clone())
|
||||||
@ -2178,13 +2176,14 @@ impl Engine {
|
|||||||
// Export statement
|
// Export statement
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
Stmt::Export(list, _) => {
|
Stmt::Export(list, _) => {
|
||||||
for (Ident { name, pos: id_pos }, rename) in list.iter() {
|
for (IdentX { name, pos: id_pos }, rename) in list.iter() {
|
||||||
// Mark scope variables as public
|
// Mark scope variables as public
|
||||||
if let Some(index) = scope.get_index(name).map(|(i, _)| i) {
|
if let Some(index) = scope.get_index(name).map(|(i, _)| i) {
|
||||||
let alias = rename.as_ref().map(|x| &x.name).unwrap_or_else(|| name);
|
let alias = rename.as_ref().map(|x| &x.name).unwrap_or_else(|| name);
|
||||||
scope.add_entry_alias(index, alias.clone());
|
scope.add_entry_alias(index, alias.to_string());
|
||||||
} else {
|
} else {
|
||||||
return EvalAltResult::ErrorVariableNotFound(name.into(), *id_pos).into();
|
return EvalAltResult::ErrorVariableNotFound(name.to_string(), *id_pos)
|
||||||
|
.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Default::default())
|
Ok(Default::default())
|
||||||
|
@ -502,19 +502,19 @@ 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.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.name)
|
*expr = mem::take(m).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));
|
||||||
}
|
}
|
||||||
// string[int]
|
// string[int]
|
||||||
(Expr::StringConstant(s), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.name.chars().count() => {
|
(Expr::StringConstant(s, pos), Expr::IntegerConstant(i, _)) if *i >= 0 && (*i as usize) < s.chars().count() => {
|
||||||
// String literal indexing - get the character
|
// String literal indexing - get the character
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = Expr::CharConstant(s.name.chars().nth(*i as usize).unwrap(), s.pos);
|
*expr = Expr::CharConstant(s.chars().nth(*i as usize).unwrap(), *pos);
|
||||||
}
|
}
|
||||||
// var[rhs]
|
// var[rhs]
|
||||||
(Expr::Variable(_), rhs) => optimize_expr(rhs, state),
|
(Expr::Variable(_), rhs) => optimize_expr(rhs, state),
|
||||||
@ -530,22 +530,22 @@ fn optimize_expr(expr: &mut Expr, state: &mut State) {
|
|||||||
// lhs in rhs
|
// lhs in rhs
|
||||||
Expr::In(x, _) => match (&mut x.lhs, &mut x.rhs) {
|
Expr::In(x, _) => match (&mut x.lhs, &mut x.rhs) {
|
||||||
// "xxx" in "xxxxx"
|
// "xxx" in "xxxxx"
|
||||||
(Expr::StringConstant(a), Expr::StringConstant(b)) => {
|
(Expr::StringConstant(a, pos), Expr::StringConstant(b, _)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = if b.name.contains(a.name.as_str()) { Expr::True(a.pos) } else { Expr::False(a.pos) };
|
*expr = if b.contains(a.as_str()) { Expr::True(*pos) } else { Expr::False(*pos) };
|
||||||
}
|
}
|
||||||
// 'x' in "xxxxx"
|
// 'x' in "xxxxx"
|
||||||
(Expr::CharConstant(a, pos), Expr::StringConstant(b)) => {
|
(Expr::CharConstant(a, pos), Expr::StringConstant(b, _)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = if b.name.contains(*a) { Expr::True(*pos) } else { Expr::False(*pos) };
|
*expr = if b.contains(*a) { Expr::True(*pos) } else { Expr::False(*pos) };
|
||||||
}
|
}
|
||||||
// "xxx" in #{...}
|
// "xxx" in #{...}
|
||||||
(Expr::StringConstant(a), Expr::Map(b, _)) => {
|
(Expr::StringConstant(a, pos), Expr::Map(b, _)) => {
|
||||||
state.set_dirty();
|
state.set_dirty();
|
||||||
*expr = if b.iter().find(|(x, _)| x.name == a.name).is_some() {
|
*expr = if b.iter().find(|(x, _)| x.name == *a).is_some() {
|
||||||
Expr::True(a.pos)
|
Expr::True(*pos)
|
||||||
} else {
|
} else {
|
||||||
Expr::False(a.pos)
|
Expr::False(*pos)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// 'x' in #{...}
|
// 'x' in #{...}
|
||||||
|
@ -66,10 +66,10 @@ struct ParseState<'e> {
|
|||||||
/// Interned strings.
|
/// Interned strings.
|
||||||
strings: HashMap<String, ImmutableString>,
|
strings: HashMap<String, ImmutableString>,
|
||||||
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
/// Encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||||
stack: Vec<(String, ScopeEntryType)>,
|
stack: Vec<(ImmutableString, ScopeEntryType)>,
|
||||||
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
/// Tracks a list of external variables (variables that are not explicitly declared in the scope).
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals: HashMap<String, Position>,
|
externals: HashMap<ImmutableString, Position>,
|
||||||
/// An indicator that disables variable capturing into externals one single time
|
/// An indicator that disables variable capturing into externals one single time
|
||||||
/// up until the nearest consumed Identifier token.
|
/// up until the nearest consumed Identifier token.
|
||||||
/// If set to false the next call to `access_var` will not capture the variable.
|
/// If set to false the next call to `access_var` will not capture the variable.
|
||||||
@ -78,7 +78,7 @@ struct ParseState<'e> {
|
|||||||
allow_capture: bool,
|
allow_capture: bool,
|
||||||
/// Encapsulates a local stack with imported module names.
|
/// Encapsulates a local stack with imported module names.
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Vec<String>,
|
modules: Vec<ImmutableString>,
|
||||||
/// Maximum levels of expression nesting.
|
/// Maximum levels of expression nesting.
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
max_expr_depth: usize,
|
max_expr_depth: usize,
|
||||||
@ -136,7 +136,7 @@ impl<'e> ParseState<'e> {
|
|||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
if self.allow_capture {
|
if self.allow_capture {
|
||||||
if index.is_none() && !self.externals.contains_key(name) {
|
if index.is_none() && !self.externals.contains_key(name) {
|
||||||
self.externals.insert(name.to_string(), _pos);
|
self.externals.insert(name.into(), _pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
self.allow_capture = true
|
self.allow_capture = true
|
||||||
@ -162,20 +162,24 @@ impl<'e> ParseState<'e> {
|
|||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, n)| *n == name)
|
.find(|(_, n)| **n == name)
|
||||||
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get an interned string, creating one if it is not yet interned.
|
/// Get an interned string, creating one if it is not yet interned.
|
||||||
pub fn get_interned_string(&mut self, text: String) -> ImmutableString {
|
pub fn get_interned_string<S>(&mut self, text: S) -> ImmutableString
|
||||||
|
where
|
||||||
|
S: AsRef<str> + Into<ImmutableString>,
|
||||||
|
{
|
||||||
#[allow(clippy::map_entry)]
|
#[allow(clippy::map_entry)]
|
||||||
if !self.strings.contains_key(&text) {
|
if !self.strings.contains_key(text.as_ref()) {
|
||||||
let value: ImmutableString = text.clone().into();
|
let value: ImmutableString = text.into();
|
||||||
let result = value.clone();
|
let result = value.clone();
|
||||||
self.strings.insert(text, value);
|
let key = value.to_string();
|
||||||
|
self.strings.insert(key, value);
|
||||||
result
|
result
|
||||||
} else {
|
} else {
|
||||||
self.strings.get(&text).unwrap().clone()
|
self.strings.get(text.as_ref()).unwrap().clone()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -456,7 +460,7 @@ fn parse_index_chain(
|
|||||||
.into_err(*pos))
|
.into_err(*pos))
|
||||||
}
|
}
|
||||||
Expr::IntegerConstant(_, pos) => match lhs {
|
Expr::IntegerConstant(_, pos) => match lhs {
|
||||||
Expr::Array(_, _) | Expr::StringConstant(_) => (),
|
Expr::Array(_, _) | Expr::StringConstant(_, _) => (),
|
||||||
|
|
||||||
Expr::Map(_, _) => {
|
Expr::Map(_, _) => {
|
||||||
return Err(PERR::MalformedIndexExpr(
|
return Err(PERR::MalformedIndexExpr(
|
||||||
@ -490,14 +494,14 @@ fn parse_index_chain(
|
|||||||
},
|
},
|
||||||
|
|
||||||
// lhs[string]
|
// lhs[string]
|
||||||
Expr::StringConstant(x) => match lhs {
|
Expr::StringConstant(_, pos) => match lhs {
|
||||||
Expr::Map(_, _) => (),
|
Expr::Map(_, _) => (),
|
||||||
|
|
||||||
Expr::Array(_, _) | Expr::StringConstant(_) => {
|
Expr::Array(_, _) | Expr::StringConstant(_, _) => {
|
||||||
return Err(PERR::MalformedIndexExpr(
|
return Err(PERR::MalformedIndexExpr(
|
||||||
"Array or string expects numeric index, not a string".into(),
|
"Array or string expects numeric index, not a string".into(),
|
||||||
)
|
)
|
||||||
.into_err(x.pos))
|
.into_err(*pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
@ -817,10 +821,9 @@ fn parse_primary(
|
|||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Token::FloatConstant(x) => Expr::FloatConstant(FloatWrapper(x), settings.pos),
|
Token::FloatConstant(x) => Expr::FloatConstant(FloatWrapper(x), settings.pos),
|
||||||
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
|
Token::CharConstant(c) => Expr::CharConstant(c, settings.pos),
|
||||||
Token::StringConstant(s) => Expr::StringConstant(Box::new(IdentX::new(
|
Token::StringConstant(s) => {
|
||||||
state.get_interned_string(s),
|
Expr::StringConstant(state.get_interned_string(s), settings.pos)
|
||||||
settings.pos,
|
}
|
||||||
))),
|
|
||||||
|
|
||||||
// Function call
|
// Function call
|
||||||
Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
Token::Identifier(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
||||||
@ -1345,19 +1348,19 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "xxx" in "xxxx", 'x' in "xxxx" - OK!
|
// "xxx" in "xxxx", 'x' in "xxxx" - OK!
|
||||||
(Expr::StringConstant(_), Expr::StringConstant(_))
|
(Expr::StringConstant(_, _), Expr::StringConstant(_, _))
|
||||||
| (Expr::CharConstant(_, _), Expr::StringConstant(_)) => (),
|
| (Expr::CharConstant(_, _), Expr::StringConstant(_, _)) => (),
|
||||||
|
|
||||||
// 123.456 in "xxxx"
|
// 123.456 in "xxxx"
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
(x @ Expr::FloatConstant(_, _), Expr::StringConstant(_)) => {
|
(x @ Expr::FloatConstant(_, _), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not a float".into(),
|
"'in' expression for a string expects a string, not a float".into(),
|
||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// 123 in "xxxx"
|
// 123 in "xxxx"
|
||||||
(x @ Expr::IntegerConstant(_, _), Expr::StringConstant(_)) => {
|
(x @ Expr::IntegerConstant(_, _), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not a number".into(),
|
"'in' expression for a string expects a string, not a number".into(),
|
||||||
)
|
)
|
||||||
@ -1365,32 +1368,32 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
}
|
}
|
||||||
// (??? && ???) in "xxxx", (??? || ???) in "xxxx", (??? in ???) in "xxxx",
|
// (??? && ???) in "xxxx", (??? || ???) in "xxxx", (??? in ???) in "xxxx",
|
||||||
// true in "xxxx", false in "xxxx"
|
// true in "xxxx", false in "xxxx"
|
||||||
(x @ Expr::And(_, _), Expr::StringConstant(_))
|
(x @ Expr::And(_, _), Expr::StringConstant(_, _))
|
||||||
| (x @ Expr::Or(_, _), Expr::StringConstant(_))
|
| (x @ Expr::Or(_, _), Expr::StringConstant(_, _))
|
||||||
| (x @ Expr::In(_, _), Expr::StringConstant(_))
|
| (x @ Expr::In(_, _), Expr::StringConstant(_, _))
|
||||||
| (x @ Expr::True(_), Expr::StringConstant(_))
|
| (x @ Expr::True(_), Expr::StringConstant(_, _))
|
||||||
| (x @ Expr::False(_), Expr::StringConstant(_)) => {
|
| (x @ Expr::False(_), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not a boolean".into(),
|
"'in' expression for a string expects a string, not a boolean".into(),
|
||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// [???, ???, ???] in "xxxx"
|
// [???, ???, ???] in "xxxx"
|
||||||
(x @ Expr::Array(_, _), Expr::StringConstant(_)) => {
|
(x @ Expr::Array(_, _), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not an array".into(),
|
"'in' expression for a string expects a string, not an array".into(),
|
||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// #{...} in "xxxx"
|
// #{...} in "xxxx"
|
||||||
(x @ Expr::Map(_, _), Expr::StringConstant(_)) => {
|
(x @ Expr::Map(_, _), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not an object map".into(),
|
"'in' expression for a string expects a string, not an object map".into(),
|
||||||
)
|
)
|
||||||
.into_err(x.position()))
|
.into_err(x.position()))
|
||||||
}
|
}
|
||||||
// () in "xxxx"
|
// () in "xxxx"
|
||||||
(x @ Expr::Unit(_), Expr::StringConstant(_)) => {
|
(x @ Expr::Unit(_), Expr::StringConstant(_, _)) => {
|
||||||
return Err(PERR::MalformedInExpr(
|
return Err(PERR::MalformedInExpr(
|
||||||
"'in' expression for a string expects a string, not ()".into(),
|
"'in' expression for a string expects a string, not ()".into(),
|
||||||
)
|
)
|
||||||
@ -1398,7 +1401,7 @@ fn make_in_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseErr
|
|||||||
}
|
}
|
||||||
|
|
||||||
// "xxx" in #{...}, 'x' in #{...} - OK!
|
// "xxx" in #{...}, 'x' in #{...} - OK!
|
||||||
(Expr::StringConstant(_), Expr::Map(_, _))
|
(Expr::StringConstant(_, _), Expr::Map(_, _))
|
||||||
| (Expr::CharConstant(_, _), Expr::Map(_, _)) => (),
|
| (Expr::CharConstant(_, _), Expr::Map(_, _)) => (),
|
||||||
|
|
||||||
// 123.456 in #{...}
|
// 123.456 in #{...}
|
||||||
@ -1664,7 +1667,7 @@ fn parse_custom_syntax(
|
|||||||
delta if delta > 0 => {
|
delta if delta > 0 => {
|
||||||
state.stack.resize(
|
state.stack.resize(
|
||||||
state.stack.len() + delta as usize,
|
state.stack.len() + delta as usize,
|
||||||
("".to_string(), ScopeEntryType::Normal),
|
("".into(), ScopeEntryType::Normal),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
delta if delta < 0 && state.stack.len() <= delta.abs() as usize => state.stack.clear(),
|
delta if delta < 0 && state.stack.len() <= delta.abs() as usize => state.stack.clear(),
|
||||||
@ -1944,8 +1947,9 @@ fn parse_for(
|
|||||||
ensure_not_statement_expr(input, "a boolean")?;
|
ensure_not_statement_expr(input, "a boolean")?;
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
|
let loop_var = state.get_interned_string(name.clone());
|
||||||
let prev_stack_len = state.stack.len();
|
let prev_stack_len = state.stack.len();
|
||||||
state.stack.push((name.clone(), ScopeEntryType::Normal));
|
state.stack.push((loop_var, ScopeEntryType::Normal));
|
||||||
|
|
||||||
settings.is_breakable = true;
|
settings.is_breakable = true;
|
||||||
let body = parse_block(input, state, lib, settings.level_up())?;
|
let body = parse_block(input, state, lib, settings.level_up())?;
|
||||||
@ -1992,13 +1996,15 @@ fn parse_let(
|
|||||||
match var_type {
|
match var_type {
|
||||||
// let name = expr
|
// let name = expr
|
||||||
ScopeEntryType::Normal => {
|
ScopeEntryType::Normal => {
|
||||||
state.stack.push((name.clone(), ScopeEntryType::Normal));
|
let var_name = state.get_interned_string(name.clone());
|
||||||
|
state.stack.push((var_name, ScopeEntryType::Normal));
|
||||||
let var_def = Ident::new(name, pos);
|
let var_def = Ident::new(name, pos);
|
||||||
Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos))
|
Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos))
|
||||||
}
|
}
|
||||||
// const name = { expr:constant }
|
// const name = { expr:constant }
|
||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
state.stack.push((name.clone(), ScopeEntryType::Constant));
|
let var_name = state.get_interned_string(name.clone());
|
||||||
|
state.stack.push((var_name, ScopeEntryType::Constant));
|
||||||
let var_def = Ident::new(name, pos);
|
let var_def = Ident::new(name, pos);
|
||||||
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
|
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
|
||||||
}
|
}
|
||||||
@ -2038,6 +2044,7 @@ fn parse_import(
|
|||||||
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
|
(_, pos) => return Err(PERR::VariableExpected.into_err(pos)),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let name = state.get_interned_string(name);
|
||||||
state.modules.push(name.clone());
|
state.modules.push(name.clone());
|
||||||
|
|
||||||
Ok(Stmt::Import(
|
Ok(Stmt::Import(
|
||||||
@ -2091,7 +2098,7 @@ fn parse_export(
|
|||||||
|
|
||||||
let rename = if match_token(input, Token::As).0 {
|
let rename = if match_token(input, Token::As).0 {
|
||||||
match input.next().unwrap() {
|
match input.next().unwrap() {
|
||||||
(Token::Identifier(s), pos) => Some(Ident::new(s.clone(), pos)),
|
(Token::Identifier(s), pos) => Some(IdentX::new(state.get_interned_string(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));
|
||||||
}
|
}
|
||||||
@ -2102,7 +2109,7 @@ fn parse_export(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.push((Ident::new(id, id_pos), rename));
|
exports.push((IdentX::new(state.get_interned_string(id), id_pos), rename));
|
||||||
|
|
||||||
match input.peek().unwrap() {
|
match input.peek().unwrap() {
|
||||||
(Token::Comma, _) => {
|
(Token::Comma, _) => {
|
||||||
@ -2464,6 +2471,7 @@ fn parse_fn(
|
|||||||
match input.next().unwrap() {
|
match input.next().unwrap() {
|
||||||
(Token::RightParen, _) => break,
|
(Token::RightParen, _) => break,
|
||||||
(Token::Identifier(s), pos) => {
|
(Token::Identifier(s), pos) => {
|
||||||
|
let s = state.get_interned_string(s);
|
||||||
state.stack.push((s.clone(), ScopeEntryType::Normal));
|
state.stack.push((s.clone(), ScopeEntryType::Normal));
|
||||||
params.push((s, pos))
|
params.push((s, pos))
|
||||||
}
|
}
|
||||||
@ -2538,7 +2546,7 @@ fn parse_fn(
|
|||||||
|
|
||||||
/// Creates a curried expression from a list of external variables
|
/// Creates a curried expression from a list of external variables
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Position) -> Expr {
|
fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<IdentX>, pos: Position) -> Expr {
|
||||||
if externals.is_empty() {
|
if externals.is_empty() {
|
||||||
return fn_expr;
|
return fn_expr;
|
||||||
}
|
}
|
||||||
@ -2577,7 +2585,7 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
|
|||||||
// Statement block
|
// Statement block
|
||||||
let mut statements: StaticVec<_> = Default::default();
|
let mut statements: StaticVec<_> = Default::default();
|
||||||
// Insert `Share` statements
|
// Insert `Share` statements
|
||||||
statements.extend(externals.into_iter().map(|x| Stmt::Share(Box::new(x))));
|
statements.extend(externals.into_iter().map(|x| Stmt::Share(x)));
|
||||||
// Final expression
|
// Final expression
|
||||||
statements.push(Stmt::Expr(expr));
|
statements.push(Stmt::Expr(expr));
|
||||||
Expr::Stmt(Box::new(statements), pos)
|
Expr::Stmt(Box::new(statements), pos)
|
||||||
@ -2606,6 +2614,7 @@ fn parse_anon_fn(
|
|||||||
match input.next().unwrap() {
|
match input.next().unwrap() {
|
||||||
(Token::Pipe, _) => break,
|
(Token::Pipe, _) => break,
|
||||||
(Token::Identifier(s), pos) => {
|
(Token::Identifier(s), pos) => {
|
||||||
|
let s = state.get_interned_string(s);
|
||||||
state.stack.push((s.clone(), ScopeEntryType::Normal));
|
state.stack.push((s.clone(), ScopeEntryType::Normal));
|
||||||
params.push((s, pos))
|
params.push((s, pos))
|
||||||
}
|
}
|
||||||
@ -2656,13 +2665,13 @@ fn parse_anon_fn(
|
|||||||
|
|
||||||
// External variables may need to be processed in a consistent order,
|
// External variables may need to be processed in a consistent order,
|
||||||
// so extract them into a list.
|
// so extract them into a list.
|
||||||
let externals: StaticVec<Ident> = {
|
let externals: StaticVec<IdentX> = {
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
{
|
{
|
||||||
state
|
state
|
||||||
.externals
|
.externals
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, &v)| Ident::new(k.clone(), v))
|
.map(|(k, &v)| IdentX::new(k.clone(), v))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
#[cfg(feature = "no_closure")]
|
#[cfg(feature = "no_closure")]
|
||||||
@ -2706,7 +2715,7 @@ fn parse_anon_fn(
|
|||||||
mods: Default::default(),
|
mods: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let expr = Expr::FnPointer(Box::new(IdentX::new(fn_name, settings.pos)));
|
let expr = Expr::FnPointer(fn_name, settings.pos);
|
||||||
|
|
||||||
let expr = if cfg!(not(feature = "no_closure")) {
|
let expr = if cfg!(not(feature = "no_closure")) {
|
||||||
make_curry_from_externals(expr, externals, settings.pos)
|
make_curry_from_externals(expr, externals, settings.pos)
|
||||||
@ -2860,7 +2869,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(Box::new(IdentX::new(value, pos)))),
|
Union::Str(value) => Some(Expr::StringConstant(value, 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