Use interned strings to prepare for match statement.
This commit is contained in:
parent
8e5a53bc0d
commit
69a0f044f4
21
src/ast.rs
21
src/ast.rs
@ -16,7 +16,7 @@ use crate::FLOAT;
|
|||||||
use crate::engine::Array;
|
use crate::engine::Array;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
use crate::engine::{make_getter, make_setter, Map};
|
use crate::engine::Map;
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
use crate::engine::Imports;
|
use crate::engine::Imports;
|
||||||
@ -919,9 +919,9 @@ pub enum Expr {
|
|||||||
/// FnPtr constant.
|
/// FnPtr constant.
|
||||||
FnPointer(Box<IdentX>),
|
FnPointer(Box<IdentX>),
|
||||||
/// 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, Ident)>),
|
Variable(Box<(Option<NonZeroUsize>, Option<Box<NamespaceRef>>, u64, IdentX)>),
|
||||||
/// Property access - (getter, setter), prop
|
/// Property access - (getter, setter), prop
|
||||||
Property(Box<((String, String), IdentX)>),
|
Property(Box<((ImmutableString, ImmutableString), IdentX)>),
|
||||||
/// { stmt }
|
/// { stmt }
|
||||||
Stmt(Box<StaticVec<Stmt>>, Position),
|
Stmt(Box<StaticVec<Stmt>>, Position),
|
||||||
/// Wrapped expression - should not be optimized away.
|
/// Wrapped expression - should not be optimized away.
|
||||||
@ -1239,21 +1239,6 @@ impl Expr {
|
|||||||
Self::Custom(_, _) => false,
|
Self::Custom(_, _) => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
|
||||||
#[cfg(not(feature = "no_object"))]
|
|
||||||
#[inline]
|
|
||||||
pub(crate) fn into_property(self) -> Self {
|
|
||||||
match self {
|
|
||||||
Self::Variable(x) if x.1.is_none() => {
|
|
||||||
let ident = x.3;
|
|
||||||
let getter = make_getter(&ident.name);
|
|
||||||
let setter = make_setter(&ident.name);
|
|
||||||
Self::Property(Box::new(((getter, setter), ident.into())))
|
|
||||||
}
|
|
||||||
_ => self,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
@ -650,7 +650,7 @@ pub fn search_imports(
|
|||||||
state: &mut State,
|
state: &mut State,
|
||||||
namespace: &NamespaceRef,
|
namespace: &NamespaceRef,
|
||||||
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
||||||
let Ident { name: root, pos } = &namespace[0];
|
let IdentX { name: root, pos } = &namespace[0];
|
||||||
|
|
||||||
// Qualified - check if the root module is directly indexed
|
// Qualified - check if the root module is directly indexed
|
||||||
let index = if state.always_search {
|
let index = if state.always_search {
|
||||||
@ -794,7 +794,7 @@ impl Engine {
|
|||||||
match expr {
|
match expr {
|
||||||
Expr::Variable(v) => match v.as_ref() {
|
Expr::Variable(v) => match v.as_ref() {
|
||||||
// Qualified variable
|
// Qualified variable
|
||||||
(_, Some(modules), hash_var, Ident { name, pos }) => {
|
(_, Some(modules), hash_var, IdentX { name, pos }) => {
|
||||||
let module = search_imports(mods, state, modules)?;
|
let module = search_imports(mods, state, modules)?;
|
||||||
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
|
let target = module.get_qualified_var(*hash_var).map_err(|mut err| {
|
||||||
match *err {
|
match *err {
|
||||||
@ -826,13 +826,13 @@ impl Engine {
|
|||||||
this_ptr: &'s mut Option<&mut Dynamic>,
|
this_ptr: &'s mut Option<&mut Dynamic>,
|
||||||
expr: &'a Expr,
|
expr: &'a Expr,
|
||||||
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
|
) -> Result<(Target<'s>, &'a str, ScopeEntryType, Position), Box<EvalAltResult>> {
|
||||||
let (index, _, _, Ident { name, pos }) = match expr {
|
let (index, _, _, IdentX { name, pos }) = match expr {
|
||||||
Expr::Variable(v) => v.as_ref(),
|
Expr::Variable(v) => v.as_ref(),
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if the variable is `this`
|
// Check if the variable is `this`
|
||||||
if name == KEYWORD_THIS {
|
if name.as_str() == KEYWORD_THIS {
|
||||||
if let Some(val) = this_ptr {
|
if let Some(val) = this_ptr {
|
||||||
return Ok(((*val).into(), KEYWORD_THIS, ScopeEntryType::Normal, *pos));
|
return Ok(((*val).into(), KEYWORD_THIS, ScopeEntryType::Normal, *pos));
|
||||||
} else {
|
} else {
|
||||||
@ -871,7 +871,7 @@ impl Engine {
|
|||||||
// Find the variable in the scope
|
// Find the variable in the scope
|
||||||
scope
|
scope
|
||||||
.get_index(name)
|
.get_index(name)
|
||||||
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(name.into(), *pos))?
|
.ok_or_else(|| EvalAltResult::ErrorVariableNotFound(name.to_string(), *pos))?
|
||||||
.0
|
.0
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1234,7 +1234,7 @@ impl Engine {
|
|||||||
match lhs {
|
match lhs {
|
||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(x) => {
|
Expr::Variable(x) => {
|
||||||
let Ident {
|
let IdentX {
|
||||||
name: var_name,
|
name: var_name,
|
||||||
pos: var_pos,
|
pos: var_pos,
|
||||||
} = &x.3;
|
} = &x.3;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
//! Module defining external-loaded modules for Rhai.
|
//! Module defining external-loaded modules for Rhai.
|
||||||
|
|
||||||
use crate::ast::{FnAccess, Ident};
|
use crate::ast::{FnAccess, IdentX};
|
||||||
use crate::dynamic::{Dynamic, Variant};
|
use crate::dynamic::{Dynamic, Variant};
|
||||||
use crate::fn_native::{
|
use crate::fn_native::{
|
||||||
shared_make_mut, shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn,
|
shared_make_mut, shared_take_or_clone, CallableFunction, FnCallArgs, IteratorFn,
|
||||||
@ -1528,7 +1528,7 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Clone, Eq, PartialEq, Default, Hash)]
|
#[derive(Clone, Eq, PartialEq, Default, Hash)]
|
||||||
pub struct NamespaceRef(StaticVec<Ident>, Option<NonZeroUsize>);
|
pub struct NamespaceRef(StaticVec<IdentX>, Option<NonZeroUsize>);
|
||||||
|
|
||||||
impl fmt::Debug for NamespaceRef {
|
impl fmt::Debug for NamespaceRef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
@ -1543,7 +1543,7 @@ impl fmt::Debug for NamespaceRef {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Deref for NamespaceRef {
|
impl Deref for NamespaceRef {
|
||||||
type Target = StaticVec<Ident>;
|
type Target = StaticVec<IdentX>;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
&self.0
|
&self.0
|
||||||
@ -1558,15 +1558,15 @@ impl DerefMut for NamespaceRef {
|
|||||||
|
|
||||||
impl fmt::Display for NamespaceRef {
|
impl fmt::Display for NamespaceRef {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
for Ident { name, .. } in self.0.iter() {
|
for IdentX { name, .. } in self.0.iter() {
|
||||||
write!(f, "{}{}", name, Token::DoubleColon.syntax())?;
|
write!(f, "{}{}", name, Token::DoubleColon.syntax())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<StaticVec<Ident>> for NamespaceRef {
|
impl From<StaticVec<IdentX>> for NamespaceRef {
|
||||||
fn from(modules: StaticVec<Ident>) -> Self {
|
fn from(modules: StaticVec<IdentX>) -> Self {
|
||||||
Self(modules, None)
|
Self(modules, None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
115
src/parser.rs
115
src/parser.rs
@ -64,6 +64,8 @@ type FunctionsLib = HashMap<u64, ScriptFnDef, StraightHasherBuilder>;
|
|||||||
struct ParseState<'e> {
|
struct ParseState<'e> {
|
||||||
/// Reference to the scripting `Engine`.
|
/// Reference to the scripting `Engine`.
|
||||||
engine: &'e Engine,
|
engine: &'e Engine,
|
||||||
|
/// Interned strings.
|
||||||
|
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<(String, 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).
|
||||||
@ -108,6 +110,7 @@ impl<'e> ParseState<'e> {
|
|||||||
externals: Default::default(),
|
externals: Default::default(),
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
allow_capture: true,
|
allow_capture: true,
|
||||||
|
strings: Default::default(),
|
||||||
stack: Default::default(),
|
stack: Default::default(),
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
modules: Default::default(),
|
modules: Default::default(),
|
||||||
@ -163,6 +166,18 @@ impl<'e> ParseState<'e> {
|
|||||||
.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.
|
||||||
|
pub fn get_interned_string(&mut self, text: String) -> ImmutableString {
|
||||||
|
if !self.strings.contains_key(&text) {
|
||||||
|
let value: ImmutableString = text.clone().into();
|
||||||
|
let result = value.clone();
|
||||||
|
self.strings.insert(text, value);
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
self.strings.get(&text).unwrap().clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
|
||||||
@ -208,6 +223,24 @@ impl ParseSettings {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Expr {
|
||||||
|
/// Convert a `Variable` into a `Property`. All other variants are untouched.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[inline]
|
||||||
|
fn into_property(self, state: &mut ParseState) -> Self {
|
||||||
|
match self {
|
||||||
|
Self::Variable(x) if x.1.is_none() => {
|
||||||
|
let ident = x.3;
|
||||||
|
let getter = state.get_interned_string(make_getter(&ident.name));
|
||||||
|
let setter = state.get_interned_string(make_setter(&ident.name));
|
||||||
|
Self::Property(Box::new(((getter, setter), ident.into())))
|
||||||
|
}
|
||||||
|
_ => self,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Consume a particular token, checking that it is the expected one.
|
/// Consume a particular token, checking that it is the expected one.
|
||||||
fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
fn eat_token(input: &mut TokenStream, token: Token) -> Position {
|
||||||
let (t, pos) = input.next().unwrap();
|
let (t, pos) = input.next().unwrap();
|
||||||
@ -268,7 +301,7 @@ fn parse_fn_call(
|
|||||||
input: &mut TokenStream,
|
input: &mut TokenStream,
|
||||||
state: &mut ParseState,
|
state: &mut ParseState,
|
||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
id: String,
|
id: ImmutableString,
|
||||||
capture: bool,
|
capture: bool,
|
||||||
mut namespace: Option<Box<NamespaceRef>>,
|
mut namespace: Option<Box<NamespaceRef>>,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
@ -314,7 +347,7 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
return Ok(Expr::FnCall(
|
return Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: id.into(),
|
name: id.to_string().into(),
|
||||||
capture,
|
capture,
|
||||||
namespace,
|
namespace,
|
||||||
hash: hash_script,
|
hash: hash_script,
|
||||||
@ -361,7 +394,7 @@ fn parse_fn_call(
|
|||||||
|
|
||||||
return Ok(Expr::FnCall(
|
return Ok(Expr::FnCall(
|
||||||
Box::new(FnCallExpr {
|
Box::new(FnCallExpr {
|
||||||
name: id.into(),
|
name: id.to_string().into(),
|
||||||
capture,
|
capture,
|
||||||
namespace,
|
namespace,
|
||||||
hash: hash_script,
|
hash: hash_script,
|
||||||
@ -784,7 +817,10 @@ 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(s, settings.pos))),
|
Token::StringConstant(s) => Expr::StringConstant(Box::new(IdentX::new(
|
||||||
|
state.get_interned_string(s),
|
||||||
|
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 => {
|
||||||
@ -793,7 +829,8 @@ fn parse_primary(
|
|||||||
{
|
{
|
||||||
state.allow_capture = true;
|
state.allow_capture = true;
|
||||||
}
|
}
|
||||||
Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
|
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||||
|
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
||||||
}
|
}
|
||||||
// Module qualification
|
// Module qualification
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
@ -803,18 +840,21 @@ fn parse_primary(
|
|||||||
{
|
{
|
||||||
state.allow_capture = true;
|
state.allow_capture = true;
|
||||||
}
|
}
|
||||||
Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
|
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||||
|
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
||||||
}
|
}
|
||||||
// Normal variable access
|
// Normal variable access
|
||||||
Token::Identifier(s) => {
|
Token::Identifier(s) => {
|
||||||
let index = state.access_var(&s, settings.pos);
|
let index = state.access_var(&s, settings.pos);
|
||||||
Expr::Variable(Box::new((index, None, 0, Ident::new(s, settings.pos))))
|
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||||
|
Expr::Variable(Box::new((index, None, 0, var_name_def)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function call is allowed to have reserved keyword
|
// Function call is allowed to have reserved keyword
|
||||||
Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
Token::Reserved(s) if *next_token == Token::LeftParen || *next_token == Token::Bang => {
|
||||||
if is_keyword_function(&s) {
|
if is_keyword_function(&s) {
|
||||||
Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
|
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||||
|
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
||||||
} else {
|
} else {
|
||||||
return Err(PERR::Reserved(s).into_err(settings.pos));
|
return Err(PERR::Reserved(s).into_err(settings.pos));
|
||||||
}
|
}
|
||||||
@ -829,7 +869,8 @@ fn parse_primary(
|
|||||||
)))
|
)))
|
||||||
.into_err(settings.pos));
|
.into_err(settings.pos));
|
||||||
} else {
|
} else {
|
||||||
Expr::Variable(Box::new((None, None, 0, Ident::new(s, settings.pos))))
|
let var_name_def = IdentX::new(state.get_interned_string(s), settings.pos);
|
||||||
|
Expr::Variable(Box::new((None, None, 0, var_name_def)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -888,13 +929,13 @@ fn parse_primary(
|
|||||||
.into_err(pos));
|
.into_err(pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
let (_, modules, _, Ident { name, pos }) = *x;
|
let (_, modules, _, IdentX { name, pos }) = *x;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
parse_fn_call(input, state, lib, name, true, modules, settings.level_up())?
|
parse_fn_call(input, state, lib, name, true, modules, settings.level_up())?
|
||||||
}
|
}
|
||||||
// Function call
|
// Function call
|
||||||
(Expr::Variable(x), Token::LeftParen) => {
|
(Expr::Variable(x), Token::LeftParen) => {
|
||||||
let (_, modules, _, Ident { name, pos }) = *x;
|
let (_, modules, _, IdentX { name, pos }) = *x;
|
||||||
settings.pos = pos;
|
settings.pos = pos;
|
||||||
parse_fn_call(input, state, lib, name, false, modules, settings.level_up())?
|
parse_fn_call(input, state, lib, name, false, modules, settings.level_up())?
|
||||||
}
|
}
|
||||||
@ -912,7 +953,8 @@ fn parse_primary(
|
|||||||
modules = Some(Box::new(m));
|
modules = Some(Box::new(m));
|
||||||
}
|
}
|
||||||
|
|
||||||
Expr::Variable(Box::new((index, modules, 0, Ident::new(id2, pos2))))
|
let var_name_def = IdentX::new(state.get_interned_string(id2), pos2);
|
||||||
|
Expr::Variable(Box::new((index, modules, 0, var_name_def)))
|
||||||
}
|
}
|
||||||
(Token::Reserved(id2), pos2) if is_valid_identifier(id2.chars()) => {
|
(Token::Reserved(id2), pos2) if is_valid_identifier(id2.chars()) => {
|
||||||
return Err(PERR::Reserved(id2).into_err(pos2));
|
return Err(PERR::Reserved(id2).into_err(pos2));
|
||||||
@ -936,7 +978,7 @@ fn parse_primary(
|
|||||||
match &mut root_expr {
|
match &mut root_expr {
|
||||||
// Cache the hash key for namespace-qualified variables
|
// Cache the hash key for namespace-qualified variables
|
||||||
Expr::Variable(x) if x.1.is_some() => {
|
Expr::Variable(x) if x.1.is_some() => {
|
||||||
let (_, modules, hash, Ident { name, .. }) = x.as_mut();
|
let (_, modules, hash, IdentX { name, .. }) = x.as_mut();
|
||||||
let namespace = modules.as_mut().unwrap();
|
let namespace = modules.as_mut().unwrap();
|
||||||
|
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
@ -1102,7 +1144,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
index,
|
index,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Ident {
|
IdentX {
|
||||||
name,
|
name,
|
||||||
pos: name_pos,
|
pos: name_pos,
|
||||||
},
|
},
|
||||||
@ -1113,7 +1155,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
}
|
}
|
||||||
// Constant values cannot be assigned to
|
// Constant values cannot be assigned to
|
||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
Err(PERR::AssignmentToConstant(name.clone()).into_err(*name_pos))
|
Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1129,7 +1171,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
index,
|
index,
|
||||||
_,
|
_,
|
||||||
_,
|
_,
|
||||||
Ident {
|
IdentX {
|
||||||
name,
|
name,
|
||||||
pos: name_pos,
|
pos: name_pos,
|
||||||
},
|
},
|
||||||
@ -1140,7 +1182,7 @@ fn make_assignment_stmt<'a>(
|
|||||||
}
|
}
|
||||||
// Constant values cannot be assigned to
|
// Constant values cannot be assigned to
|
||||||
ScopeEntryType::Constant => {
|
ScopeEntryType::Constant => {
|
||||||
Err(PERR::AssignmentToConstant(name.clone()).into_err(*name_pos))
|
Err(PERR::AssignmentToConstant(name.to_string()).into_err(*name_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1200,20 +1242,25 @@ fn parse_op_assignment_stmt(
|
|||||||
|
|
||||||
/// Make a dot expression.
|
/// Make a dot expression.
|
||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseError> {
|
fn make_dot_expr(
|
||||||
|
state: &mut ParseState,
|
||||||
|
lhs: Expr,
|
||||||
|
rhs: Expr,
|
||||||
|
op_pos: Position,
|
||||||
|
) -> Result<Expr, ParseError> {
|
||||||
Ok(match (lhs, rhs) {
|
Ok(match (lhs, rhs) {
|
||||||
// idx_lhs[idx_expr].rhs
|
// idx_lhs[idx_expr].rhs
|
||||||
// Attach dot chain to the bottom level of indexing chain
|
// Attach dot chain to the bottom level of indexing chain
|
||||||
(Expr::Index(mut x, pos), rhs) => {
|
(Expr::Index(mut x, pos), rhs) => {
|
||||||
x.rhs = make_dot_expr(x.rhs, rhs, op_pos)?;
|
x.rhs = make_dot_expr(state, x.rhs, rhs, op_pos)?;
|
||||||
Expr::Index(x, pos)
|
Expr::Index(x, pos)
|
||||||
}
|
}
|
||||||
// lhs.id
|
// lhs.id
|
||||||
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
(lhs, Expr::Variable(x)) if x.1.is_none() => {
|
||||||
let ident = x.3;
|
let ident = x.3;
|
||||||
let getter = make_getter(&ident.name);
|
let getter = state.get_interned_string(make_getter(&ident.name));
|
||||||
let setter = make_setter(&ident.name);
|
let setter = state.get_interned_string(make_setter(&ident.name));
|
||||||
let rhs = Expr::Property(Box::new(((getter, setter), ident.into())));
|
let rhs = Expr::Property(Box::new(((getter, setter), ident)));
|
||||||
|
|
||||||
Expr::Dot(Box::new(BinaryExpr { lhs, rhs }), op_pos)
|
Expr::Dot(Box::new(BinaryExpr { lhs, rhs }), op_pos)
|
||||||
}
|
}
|
||||||
@ -1229,7 +1276,7 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
|
|||||||
(lhs, Expr::Dot(x, pos)) => {
|
(lhs, Expr::Dot(x, pos)) => {
|
||||||
let rhs = Expr::Dot(
|
let rhs = Expr::Dot(
|
||||||
Box::new(BinaryExpr {
|
Box::new(BinaryExpr {
|
||||||
lhs: x.lhs.into_property(),
|
lhs: x.lhs.into_property(state),
|
||||||
rhs: x.rhs,
|
rhs: x.rhs,
|
||||||
}),
|
}),
|
||||||
pos,
|
pos,
|
||||||
@ -1240,7 +1287,7 @@ fn make_dot_expr(lhs: Expr, rhs: Expr, op_pos: Position) -> Result<Expr, ParseEr
|
|||||||
(lhs, Expr::Index(x, pos)) => {
|
(lhs, Expr::Index(x, pos)) => {
|
||||||
let rhs = Expr::Index(
|
let rhs = Expr::Index(
|
||||||
Box::new(BinaryExpr {
|
Box::new(BinaryExpr {
|
||||||
lhs: x.lhs.into_property(),
|
lhs: x.lhs.into_property(state),
|
||||||
rhs: x.rhs,
|
rhs: x.rhs,
|
||||||
}),
|
}),
|
||||||
pos,
|
pos,
|
||||||
@ -1579,7 +1626,7 @@ fn parse_binary_op(
|
|||||||
Token::Period => {
|
Token::Period => {
|
||||||
let rhs = args.pop().unwrap();
|
let rhs = args.pop().unwrap();
|
||||||
let current_lhs = args.pop().unwrap();
|
let current_lhs = args.pop().unwrap();
|
||||||
make_dot_expr(current_lhs, rhs, pos)?
|
make_dot_expr(state, current_lhs, rhs, pos)?
|
||||||
}
|
}
|
||||||
|
|
||||||
Token::Custom(s) if state.engine.custom_keywords.contains_key(&s) => {
|
Token::Custom(s) if state.engine.custom_keywords.contains_key(&s) => {
|
||||||
@ -1647,12 +1694,8 @@ fn parse_custom_syntax(
|
|||||||
MARKER_IDENT => match input.next().unwrap() {
|
MARKER_IDENT => match input.next().unwrap() {
|
||||||
(Token::Identifier(s), pos) => {
|
(Token::Identifier(s), pos) => {
|
||||||
segments.push(s.clone());
|
segments.push(s.clone());
|
||||||
exprs.push(Expr::Variable(Box::new((
|
let var_name_def = IdentX::new(state.get_interned_string(s), pos);
|
||||||
None,
|
exprs.push(Expr::Variable(Box::new((None, None, 0, var_name_def))));
|
||||||
None,
|
|
||||||
0,
|
|
||||||
Ident::new(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));
|
||||||
@ -1950,14 +1993,14 @@ fn parse_let(
|
|||||||
// let name = expr
|
// let name = expr
|
||||||
ScopeEntryType::Normal => {
|
ScopeEntryType::Normal => {
|
||||||
state.stack.push((name.clone(), ScopeEntryType::Normal));
|
state.stack.push((name.clone(), ScopeEntryType::Normal));
|
||||||
let ident = Ident::new(name, pos);
|
let var_def = Ident::new(name, pos);
|
||||||
Ok(Stmt::Let(Box::new(ident), 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));
|
state.stack.push((name.clone(), ScopeEntryType::Constant));
|
||||||
let ident = Ident::new(name, pos);
|
let var_def = Ident::new(name, pos);
|
||||||
Ok(Stmt::Const(Box::new(ident), init_expr, export, token_pos))
|
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2507,7 +2550,7 @@ fn make_curry_from_externals(fn_expr: Expr, externals: StaticVec<Ident>, pos: Po
|
|||||||
|
|
||||||
#[cfg(not(feature = "no_closure"))]
|
#[cfg(not(feature = "no_closure"))]
|
||||||
externals.iter().for_each(|x| {
|
externals.iter().for_each(|x| {
|
||||||
args.push(Expr::Variable(Box::new((None, None, 0, x.clone()))));
|
args.push(Expr::Variable(Box::new((None, None, 0, x.clone().into()))));
|
||||||
});
|
});
|
||||||
|
|
||||||
#[cfg(feature = "no_closure")]
|
#[cfg(feature = "no_closure")]
|
||||||
|
Loading…
Reference in New Issue
Block a user