Refine data structures

This commit is contained in:
Stephen Chung
2022-03-05 17:57:23 +08:00
parent e06c2b2abb
commit 8bda8c64df
15 changed files with 235 additions and 219 deletions

View File

@@ -135,7 +135,7 @@ impl<'e> ParseState<'e> {
#[cfg(not(feature = "no_closure"))]
if self.allow_capture {
if index == 0 && !self.external_vars.iter().any(|v| v.name == name) {
if index == 0 && !self.external_vars.iter().any(|v| v.as_str() == name) {
self.external_vars.push(crate::ast::Ident {
name: name.into(),
pos: _pos,
@@ -266,9 +266,9 @@ impl Expr {
fn into_property(self, state: &mut ParseState) -> Self {
match self {
#[cfg(not(feature = "no_module"))]
Self::Variable(.., x) if x.1.is_some() => unreachable!("qualified property"),
Self::Variable(.., pos, x) => {
let ident = x.2;
Self::Variable(x, ..) if !x.1.is_empty() => unreachable!("qualified property"),
Self::Variable(x, .., pos) => {
let ident = x.3;
let getter = state.get_identifier(crate::engine::FN_GET, &ident);
let hash_get = calc_fn_hash(&getter, 1);
let setter = state.get_identifier(crate::engine::FN_SET, &ident);
@@ -456,7 +456,7 @@ impl Engine {
lib: &mut FnLib,
id: Identifier,
capture_parent_scope: bool,
#[cfg(not(feature = "no_module"))] namespace: Option<crate::module::Namespace>,
#[cfg(not(feature = "no_module"))] namespace: crate::ast::Namespace,
settings: ParseSettings,
) -> ParseResult<Expr> {
#[cfg(not(feature = "unchecked"))]
@@ -484,7 +484,7 @@ impl Engine {
eat_token(input, Token::RightParen);
#[cfg(not(feature = "no_module"))]
let hash = if let Some(namespace) = namespace.as_mut() {
let hash = if !namespace.is_empty() {
let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_function"))]
@@ -499,7 +499,7 @@ impl Engine {
namespace.set_index(index);
crate::calc_qualified_fn_hash(namespace.iter().map(|m| m.name.as_str()), &id, 0)
crate::calc_qualified_fn_hash(namespace.iter().map(|m| m.as_str()), &id, 0)
} else {
calc_fn_hash(&id, 0)
};
@@ -544,7 +544,7 @@ impl Engine {
eat_token(input, Token::RightParen);
#[cfg(not(feature = "no_module"))]
let hash = if let Some(namespace) = namespace.as_mut() {
let hash = if !namespace.is_empty() {
let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_function"))]
@@ -560,7 +560,7 @@ impl Engine {
namespace.set_index(index);
crate::calc_qualified_fn_hash(
namespace.iter().map(|m| m.name.as_str()),
namespace.iter().map(|m| m.as_str()),
&id,
args.len(),
)
@@ -900,7 +900,7 @@ impl Engine {
let (name, pos) = match input.next().expect(NEVER_ENDS) {
(Token::Identifier(s), pos) | (Token::StringConstant(s), pos) => {
if map.iter().any(|(p, ..)| p.name == &*s) {
if map.iter().any(|(p, ..)| **p == s) {
return Err(PERR::DuplicatedProperty(s.to_string()).into_err(pos));
}
(s, pos)
@@ -1387,9 +1387,9 @@ impl Engine {
// Identifier
Token::Identifier(..) => {
#[cfg(not(feature = "no_module"))]
let none = None;
let ns = crate::ast::Namespace::NONE;
#[cfg(feature = "no_module")]
let none = ();
let ns = ();
let s = match input.next().expect(NEVER_ENDS) {
(Token::Identifier(s), ..) => s,
@@ -1405,9 +1405,9 @@ impl Engine {
state.allow_capture = true;
}
Expr::Variable(
(None, ns, 0, state.get_identifier("", s)).into(),
None,
settings.pos,
(None, none, state.get_identifier("", s)).into(),
)
}
// Namespace qualification
@@ -1419,9 +1419,9 @@ impl Engine {
state.allow_capture = true;
}
Expr::Variable(
(None, ns, 0, state.get_identifier("", s)).into(),
None,
settings.pos,
(None, none, state.get_identifier("", s)).into(),
)
}
// Normal variable access
@@ -1442,9 +1442,9 @@ impl Engine {
}
});
Expr::Variable(
(index, ns, 0, state.get_identifier("", s)).into(),
short_index,
settings.pos,
(index, none, state.get_identifier("", s)).into(),
)
}
}
@@ -1453,9 +1453,9 @@ impl Engine {
// Reserved keyword or symbol
Token::Reserved(..) => {
#[cfg(not(feature = "no_module"))]
let none = None;
let ns = crate::ast::Namespace::NONE;
#[cfg(feature = "no_module")]
let none = ();
let ns = ();
let s = match input.next().expect(NEVER_ENDS) {
(Token::Reserved(s), ..) => s,
@@ -1465,16 +1465,16 @@ impl Engine {
match input.peek().expect(NEVER_ENDS).0 {
// Function call is allowed to have reserved keyword
Token::LeftParen | Token::Bang if is_keyword_function(&s) => Expr::Variable(
(None, ns, 0, state.get_identifier("", s)).into(),
None,
settings.pos,
(None, none, state.get_identifier("", s)).into(),
),
// Access to `this` as a variable is OK within a function scope
#[cfg(not(feature = "no_function"))]
_ if &*s == KEYWORD_THIS && settings.is_function_scope => Expr::Variable(
(None, ns, 0, state.get_identifier("", s)).into(),
None,
settings.pos,
(None, none, state.get_identifier("", s)).into(),
),
// Cannot access to `this` as a variable not in a function scope
_ if &*s == KEYWORD_THIS => {
@@ -1527,7 +1527,7 @@ impl Engine {
lhs = match (lhs, tail_token) {
// Qualified function call with !
#[cfg(not(feature = "no_module"))]
(Expr::Variable(.., x), Token::Bang) if x.1.is_some() => {
(Expr::Variable(x, ..), Token::Bang) if !x.1.is_empty() => {
return if !match_token(input, Token::LeftParen).0 {
Err(LexError::UnexpectedInput(Token::Bang.syntax().to_string())
.into_err(tail_pos))
@@ -1540,7 +1540,7 @@ impl Engine {
};
}
// Function call with !
(Expr::Variable(.., pos, x), Token::Bang) => {
(Expr::Variable(x, .., pos), Token::Bang) => {
match match_token(input, Token::LeftParen) {
(false, pos) => {
return Err(PERR::MissingToken(
@@ -1552,10 +1552,8 @@ impl Engine {
_ => (),
}
let (.., _ns, name) = *x;
let (.., _ns, _, name) = *x;
settings.pos = pos;
#[cfg(not(feature = "no_module"))]
let _ns = _ns.map(|(ns, ..)| ns);
self.parse_fn_call(
input,
state,
@@ -1568,10 +1566,8 @@ impl Engine {
)?
}
// Function call
(Expr::Variable(.., pos, x), Token::LeftParen) => {
let (.., _ns, name) = *x;
#[cfg(not(feature = "no_module"))]
let _ns = _ns.map(|(ns, ..)| ns);
(Expr::Variable(x, .., pos), Token::LeftParen) => {
let (.., _ns, _, name) = *x;
settings.pos = pos;
self.parse_fn_call(
input,
@@ -1586,23 +1582,17 @@ impl Engine {
}
// module access
#[cfg(not(feature = "no_module"))]
(Expr::Variable(.., pos, x), Token::DoubleColon) => {
(Expr::Variable(x, .., pos), Token::DoubleColon) => {
let (id2, pos2) = parse_var_name(input)?;
let (.., mut namespace, name) = *x;
let (.., mut namespace, _, name) = *x;
let var_name_def = Ident { name, pos };
if let Some((ref mut namespace, ..)) = namespace {
namespace.push(var_name_def);
} else {
let mut ns = crate::module::Namespace::new();
ns.push(var_name_def);
namespace = Some((ns, 42));
}
namespace.push(var_name_def);
Expr::Variable(
(None, namespace, 0, state.get_identifier("", id2)).into(),
None,
pos2,
(None, namespace, state.get_identifier("", id2)).into(),
)
}
// Indexing
@@ -1641,33 +1631,35 @@ impl Engine {
// Cache the hash key for namespace-qualified variables
#[cfg(not(feature = "no_module"))]
let namespaced_variable = match lhs {
Expr::Variable(.., ref mut x) if x.1.is_some() => Some(x.as_mut()),
Expr::Variable(ref mut x, ..) if !x.1.is_empty() => Some(x.as_mut()),
Expr::Index(ref mut x, ..) | Expr::Dot(ref mut x, ..) => match x.lhs {
Expr::Variable(.., ref mut x) if x.1.is_some() => Some(x.as_mut()),
Expr::Variable(ref mut x, ..) if !x.1.is_empty() => Some(x.as_mut()),
_ => None,
},
_ => None,
};
#[cfg(not(feature = "no_module"))]
if let Some((.., Some((namespace, hash)), name)) = namespaced_variable {
*hash = crate::calc_qualified_var_hash(namespace.iter().map(|v| v.name.as_str()), name);
if let Some((.., namespace, hash, name)) = namespaced_variable {
if !namespace.is_empty() {
*hash = crate::calc_qualified_var_hash(namespace.iter().map(|v| v.as_str()), name);
#[cfg(not(feature = "no_module"))]
{
let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_module"))]
{
let index = state.find_module(namespace.root());
#[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope;
#[cfg(feature = "no_function")]
let relax = false;
#[cfg(not(feature = "no_function"))]
let relax = settings.is_function_scope;
#[cfg(feature = "no_function")]
let relax = false;
if !relax && settings.options.strict_var && index.is_none() {
return Err(PERR::ModuleUndefined(namespace.root().to_string())
.into_err(namespace.position()));
if !relax && settings.options.strict_var && index.is_none() {
return Err(PERR::ModuleUndefined(namespace.root().to_string())
.into_err(namespace.position()));
}
namespace.set_index(index);
}
namespace.set_index(index);
}
}
@@ -1826,13 +1818,13 @@ impl Engine {
Err(PERR::AssignmentToConstant("".into()).into_err(lhs.start_position()))
}
// var (non-indexed) = rhs
Expr::Variable(None, _, ref x) if x.0.is_none() => Ok(Stmt::Assignment(
Expr::Variable(ref x, None, _) if x.0.is_none() => Ok(Stmt::Assignment(
(op_info, (lhs, rhs).into()).into(),
op_pos,
)),
// var (indexed) = rhs
Expr::Variable(i, var_pos, ref x) => {
let (index, _, name) = x.as_ref();
Expr::Variable(ref x, i, var_pos) => {
let (index, .., name) = x.as_ref();
let index = i.map_or_else(
|| index.expect("either long or short index is `None`").get(),
|n| n.get() as usize,
@@ -1937,8 +1929,8 @@ impl Engine {
}
// lhs.module::id - syntax error
#[cfg(not(feature = "no_module"))]
(.., Expr::Variable(.., x)) if x.1.is_some() => {
Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0.position()))
(.., Expr::Variable(x, ..)) if !x.1.is_empty() => {
Err(PERR::PropertyExpected.into_err(x.1.position()))
}
// lhs.id
(lhs, var_expr @ Expr::Variable(..)) => {
@@ -1958,7 +1950,7 @@ impl Engine {
// lhs.nnn::func(...) - syntax error
#[cfg(not(feature = "no_module"))]
(.., Expr::FnCall(func, ..)) if func.is_qualified() => {
Err(PERR::PropertyExpected.into_err(func.namespace.expect("`Some`").position()))
Err(PERR::PropertyExpected.into_err(func.namespace.position()))
}
// lhs.Fn() or lhs.eval()
(.., Expr::FnCall(func, func_pos))
@@ -2006,14 +1998,13 @@ impl Engine {
match x.lhs {
// lhs.module::id.dot_rhs or lhs.module::id[idx_rhs] - syntax error
#[cfg(not(feature = "no_module"))]
Expr::Variable(.., x) if x.1.is_some() => {
Err(PERR::PropertyExpected.into_err(x.1.expect("`Some`").0.position()))
Expr::Variable(x, ..) if !x.1.is_empty() => {
Err(PERR::PropertyExpected.into_err(x.1.position()))
}
// lhs.module::func().dot_rhs or lhs.module::func()[idx_rhs] - syntax error
#[cfg(not(feature = "no_module"))]
Expr::FnCall(func, ..) if func.is_qualified() => {
Err(PERR::PropertyExpected
.into_err(func.namespace.expect("`Some`").position()))
Err(PERR::PropertyExpected.into_err(func.namespace.position()))
}
// lhs.id.dot_rhs or lhs.id[idx_rhs]
Expr::Variable(..) | Expr::Property(..) => {
@@ -2294,21 +2285,15 @@ impl Engine {
CUSTOM_SYNTAX_MARKER_IDENT => {
let (name, pos) = parse_var_name(input)?;
let name = state.get_identifier("", name);
#[cfg(not(feature = "no_module"))]
let ns = crate::ast::Namespace::NONE;
#[cfg(feature = "no_module")]
let ns = ();
segments.push(name.clone().into());
tokens.push(state.get_identifier("", CUSTOM_SYNTAX_MARKER_IDENT));
inputs.push(Expr::Variable(
None,
pos,
(
None,
#[cfg(not(feature = "no_module"))]
None,
#[cfg(feature = "no_module")]
(),
name,
)
.into(),
));
inputs.push(Expr::Variable((None, ns, 0, name).into(), None, pos));
}
CUSTOM_SYNTAX_MARKER_SYMBOL => {
let (symbol, pos) = parse_symbol(input)?;
@@ -2611,11 +2596,11 @@ impl Engine {
)
.into_err(pos));
}
(name, name_pos, Some(counter_name), Some(counter_pos))
(name, name_pos, counter_name, counter_pos)
} else {
// name
let (name, name_pos) = parse_var_name(input)?;
(name, name_pos, None, None)
(name, name_pos, Identifier::new_const(), Position::NONE)
};
// for name in ...
@@ -2639,12 +2624,13 @@ impl Engine {
let prev_stack_len = state.stack.len();
let counter_var = counter_name.map(|name| {
let name = state.get_identifier("", name);
let pos = counter_pos.expect("`Some`");
if !counter_name.is_empty() {
state.stack.push(name.clone(), ());
Ident { name, pos }
});
}
let counter_var = Ident {
name: state.get_identifier("", counter_name),
pos: counter_pos,
};
let loop_var = state.get_identifier("", name);
state.stack.push(loop_var.clone(), ());
@@ -2786,7 +2772,7 @@ impl Engine {
// import expr as ...
if !match_token(input, Token::As).0 {
return Ok(Stmt::Import((expr, None).into(), settings.pos));
return Ok(Stmt::Import((expr, Ident::EMPTY).into(), settings.pos));
}
// import expr as name ...
@@ -2795,7 +2781,7 @@ impl Engine {
state.imports.push(name.clone());
Ok(Stmt::Import(
(expr, Some(Ident { name, pos })).into(),
(expr, Ident { name, pos }).into(),
settings.pos,
))
}
@@ -3229,15 +3215,15 @@ impl Engine {
let name = state.get_identifier("", name);
state.stack.push(name.clone(), ());
Some(Ident { name, pos })
Ident { name, pos }
} else {
None
Ident::EMPTY
};
// try { try_block } catch ( var ) { catch_block }
let catch_block = self.parse_block(input, state, lib, settings.level_up())?;
if catch_var.is_some() {
if !catch_var.is_empty() {
// Remove the error variable from the stack
state.stack.rewind(state.stack.len() - 1);
}
@@ -3382,19 +3368,12 @@ impl Engine {
.iter()
.cloned()
.map(|crate::ast::Ident { name, pos }| {
Expr::Variable(
None,
pos,
(
None,
#[cfg(not(feature = "no_module"))]
None,
#[cfg(feature = "no_module")]
(),
name,
)
.into(),
)
#[cfg(not(feature = "no_module"))]
let ns = crate::ast::Namespace::NONE;
#[cfg(feature = "no_module")]
let ns = ();
Expr::Variable((None, ns, 0, name).into(), None, pos)
}),
);