Code cleanup.
This commit is contained in:
parent
6b8d78d64c
commit
5c813ca7c0
@ -4,13 +4,16 @@ Rhai Release Notes
|
|||||||
Version 0.19.9
|
Version 0.19.9
|
||||||
==============
|
==============
|
||||||
|
|
||||||
This version removes the confusing differences between _packages_ and _modules_
|
This version fixes a bug introduced in `0.19.8` which breaks property access
|
||||||
|
within closures.
|
||||||
|
|
||||||
|
It also removes the confusing differences between _packages_ and _modules_
|
||||||
by unifying the terminology and API under the global umbrella of _modules_.
|
by unifying the terminology and API under the global umbrella of _modules_.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
---------
|
---------
|
||||||
|
|
||||||
* Property access in
|
* Bug when accessing properties in closures is fixed.
|
||||||
|
|
||||||
Breaking changes
|
Breaking changes
|
||||||
----------------
|
----------------
|
||||||
|
@ -53,9 +53,10 @@ In this case, the first parameter should be `&mut T` of the custom type and the
|
|||||||
Script-defined [function] signatures contain parameter names. Since all parameters, as well as
|
Script-defined [function] signatures contain parameter names. Since all parameters, as well as
|
||||||
the return value, are [`Dynamic`] the types are simply not shown.
|
the return value, are [`Dynamic`] the types are simply not shown.
|
||||||
|
|
||||||
A script-defined function always takes dynamic arguments, and the return type is also dynamic:
|
A script-defined function always takes dynamic arguments, and the return type is also dynamic,
|
||||||
|
so no type information is needed:
|
||||||
|
|
||||||
> `foo(x, y, z) -> Dynamic`
|
> `foo(x, y, z)`
|
||||||
|
|
||||||
probably defined as:
|
probably defined as:
|
||||||
|
|
||||||
|
12
src/ast.rs
12
src/ast.rs
@ -91,7 +91,7 @@ impl fmt::Display for ScriptFnDef {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}({}) -> Dynamic",
|
"{}{}({})",
|
||||||
if self.access.is_private() {
|
if self.access.is_private() {
|
||||||
"private "
|
"private "
|
||||||
} else {
|
} else {
|
||||||
@ -133,7 +133,7 @@ impl fmt::Display for ScriptFnMetadata<'_> {
|
|||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
f,
|
f,
|
||||||
"{}{}({}) -> Dynamic",
|
"{}{}({})",
|
||||||
if self.access.is_private() {
|
if self.access.is_private() {
|
||||||
"private "
|
"private "
|
||||||
} else {
|
} else {
|
||||||
@ -646,7 +646,7 @@ impl AsRef<Module> for AST {
|
|||||||
/// ## WARNING
|
/// ## WARNING
|
||||||
///
|
///
|
||||||
/// This type is volatile and may change.
|
/// This type is volatile and may change.
|
||||||
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
#[derive(Clone, Eq, PartialEq, Hash)]
|
||||||
pub struct Ident {
|
pub struct Ident {
|
||||||
/// Identifier name.
|
/// Identifier name.
|
||||||
pub name: ImmutableString,
|
pub name: ImmutableString,
|
||||||
@ -654,6 +654,12 @@ pub struct Ident {
|
|||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl fmt::Debug for Ident {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
write!(f, "Ident({:?} @ {:?})", self.name, self.pos)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement.
|
/// _(INTERNALS)_ A type encapsulating the mode of a `return`/`throw` statement.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
///
|
///
|
||||||
|
@ -101,8 +101,6 @@ impl FuncInfo {
|
|||||||
if return_type != "()" {
|
if return_type != "()" {
|
||||||
sig.push_str(") -> ");
|
sig.push_str(") -> ");
|
||||||
sig.push_str(&return_type);
|
sig.push_str(&return_type);
|
||||||
} else if self.func.is_script() {
|
|
||||||
sig.push_str(") -> Dynamic");
|
|
||||||
} else {
|
} else {
|
||||||
sig.push_str(")");
|
sig.push_str(")");
|
||||||
}
|
}
|
||||||
@ -115,7 +113,7 @@ impl FuncInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if self.func.is_script() {
|
if self.func.is_script() {
|
||||||
sig.push_str(") -> Dynamic");
|
sig.push_str(")");
|
||||||
} else {
|
} else {
|
||||||
sig.push_str(") -> ?");
|
sig.push_str(") -> ?");
|
||||||
}
|
}
|
||||||
@ -471,6 +469,7 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// By taking a mutable reference, it is assumed that some sub-modules will be modified.
|
/// By taking a mutable reference, it is assumed that some sub-modules will be modified.
|
||||||
/// Thus the module is automatically set to be non-indexed.
|
/// Thus the module is automatically set to be non-indexed.
|
||||||
|
#[cfg(not(feature = "no_module"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
pub(crate) fn sub_modules_mut(&mut self) -> &mut HashMap<ImmutableString, Shared<Module>> {
|
||||||
// We must assume that the user has changed the sub-modules
|
// We must assume that the user has changed the sub-modules
|
||||||
|
@ -39,7 +39,7 @@ use crate::{Engine, EvalAltResult, Module, ModuleResolver, Position, Shared};
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct FileModuleResolver {
|
pub struct FileModuleResolver {
|
||||||
path: PathBuf,
|
base_path: PathBuf,
|
||||||
extension: String,
|
extension: String,
|
||||||
|
|
||||||
#[cfg(not(feature = "sync"))]
|
#[cfg(not(feature = "sync"))]
|
||||||
@ -99,7 +99,7 @@ impl FileModuleResolver {
|
|||||||
extension: impl Into<String>,
|
extension: impl Into<String>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
path: path.into(),
|
base_path: path.into(),
|
||||||
extension: extension.into(),
|
extension: extension.into(),
|
||||||
cache: Default::default(),
|
cache: Default::default(),
|
||||||
}
|
}
|
||||||
@ -127,13 +127,13 @@ impl FileModuleResolver {
|
|||||||
|
|
||||||
/// Get the base path for script files.
|
/// Get the base path for script files.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn path(&self) -> &Path {
|
pub fn base_path(&self) -> &Path {
|
||||||
self.path.as_ref()
|
self.base_path.as_ref()
|
||||||
}
|
}
|
||||||
/// Set the base path for script files.
|
/// Set the base path for script files.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_path(&mut self, path: impl Into<PathBuf>) -> &mut Self {
|
pub fn set_base_path(&mut self, path: impl Into<PathBuf>) -> &mut Self {
|
||||||
self.path = path.into();
|
self.base_path = path.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +186,7 @@ impl ModuleResolver for FileModuleResolver {
|
|||||||
pos: Position,
|
pos: Position,
|
||||||
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
) -> Result<Shared<Module>, Box<EvalAltResult>> {
|
||||||
// Construct the script file path
|
// Construct the script file path
|
||||||
let mut file_path = self.path.clone();
|
let mut file_path = self.base_path.clone();
|
||||||
file_path.push(path);
|
file_path.push(path);
|
||||||
file_path.set_extension(&self.extension); // Force extension
|
file_path.set_extension(&self.extension); // Force extension
|
||||||
|
|
||||||
|
145
src/parser.rs
145
src/parser.rs
@ -280,12 +280,12 @@ fn parse_paren_expr(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
// ( ...
|
|
||||||
settings.pos = eat_token(input, Token::LeftParen);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// ( ...
|
||||||
|
settings.pos = eat_token(input, Token::LeftParen);
|
||||||
|
|
||||||
if match_token(input, Token::RightParen).0 {
|
if match_token(input, Token::RightParen).0 {
|
||||||
return Ok(Expr::Unit(settings.pos));
|
return Ok(Expr::Unit(settings.pos));
|
||||||
}
|
}
|
||||||
@ -316,11 +316,11 @@ fn parse_fn_call(
|
|||||||
mut namespace: Option<NamespaceRef>,
|
mut namespace: Option<NamespaceRef>,
|
||||||
settings: ParseSettings,
|
settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
|
||||||
let mut args = StaticVec::new();
|
let mut args = StaticVec::new();
|
||||||
|
|
||||||
match token {
|
match token {
|
||||||
@ -642,12 +642,12 @@ fn parse_array_literal(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
// [ ...
|
|
||||||
settings.pos = eat_token(input, Token::LeftBracket);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// [ ...
|
||||||
|
settings.pos = eat_token(input, Token::LeftBracket);
|
||||||
|
|
||||||
let mut arr = StaticVec::new();
|
let mut arr = StaticVec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -712,12 +712,12 @@ fn parse_map_literal(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
// #{ ...
|
|
||||||
settings.pos = eat_token(input, Token::MapStart);
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// #{ ...
|
||||||
|
settings.pos = eat_token(input, Token::MapStart);
|
||||||
|
|
||||||
let mut map: StaticVec<(Ident, Expr)> = Default::default();
|
let mut map: StaticVec<(Ident, Expr)> = Default::default();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -823,13 +823,12 @@ fn parse_switch(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// switch ...
|
|
||||||
let token_pos = eat_token(input, Token::Switch);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// switch ...
|
||||||
|
settings.pos = eat_token(input, Token::Switch);
|
||||||
|
|
||||||
let item = parse_expr(input, state, lib, settings.level_up())?;
|
let item = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
match input.next().unwrap() {
|
match input.next().unwrap() {
|
||||||
@ -950,12 +949,12 @@ fn parse_primary(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
|
||||||
settings.pos = *token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
let mut root_expr = match token {
|
let mut root_expr = match token {
|
||||||
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
Token::EOF => return Err(PERR::UnexpectedEOF.into_err(settings.pos)),
|
||||||
|
|
||||||
@ -1241,7 +1240,7 @@ fn parse_primary(
|
|||||||
state.allow_capture = false;
|
state.allow_capture = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let rhs = parse_unary(input, state, lib, settings.level_up())?;
|
let rhs = parse_primary(input, state, lib, settings.level_up())?;
|
||||||
make_dot_expr(state, expr, rhs, tail_pos)?
|
make_dot_expr(state, expr, rhs, tail_pos)?
|
||||||
}
|
}
|
||||||
// Unknown postfix operator
|
// Unknown postfix operator
|
||||||
@ -1262,17 +1261,16 @@ fn parse_primary(
|
|||||||
},
|
},
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
.map(|x| {
|
.map(|x| match x.as_mut() {
|
||||||
if let (_, Some((ref mut hash, ref mut namespace)), Ident { name, .. }) = x.as_mut() {
|
(_, Some((ref mut hash, ref mut namespace)), Ident { name, .. }) => {
|
||||||
// Qualifiers + variable name
|
// Qualifiers + variable name
|
||||||
*hash =
|
*hash =
|
||||||
calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0).unwrap();
|
calc_script_fn_hash(namespace.iter().map(|v| v.name.as_str()), name, 0).unwrap();
|
||||||
|
|
||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
namespace.set_index(state.find_module(&namespace[0].name));
|
namespace.set_index(state.find_module(&namespace[0].name));
|
||||||
} else {
|
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make sure identifiers are valid
|
// Make sure identifiers are valid
|
||||||
@ -1458,12 +1456,12 @@ fn parse_op_assignment_stmt(
|
|||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
let (token, token_pos) = input.peek().unwrap();
|
|
||||||
settings.pos = *token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
let (token, token_pos) = input.peek().unwrap();
|
||||||
|
settings.pos = *token_pos;
|
||||||
|
|
||||||
let op = match token {
|
let op = match token {
|
||||||
Token::Equals => "".into(),
|
Token::Equals => "".into(),
|
||||||
|
|
||||||
@ -1714,11 +1712,11 @@ fn parse_binary_op(
|
|||||||
lhs: Expr,
|
lhs: Expr,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
settings.pos = lhs.position();
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = lhs.position();
|
||||||
|
|
||||||
let mut root = lhs;
|
let mut root = lhs;
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
@ -1868,12 +1866,6 @@ fn parse_binary_op(
|
|||||||
make_in_expr(current_lhs, rhs, pos)?
|
make_in_expr(current_lhs, rhs, pos)?
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(not(feature = "no_object"))]
|
|
||||||
// Token::Period => {
|
|
||||||
// let rhs = args.pop().unwrap();
|
|
||||||
// let current_lhs = args.pop().unwrap();
|
|
||||||
// make_dot_expr(state, current_lhs, rhs, pos)?
|
|
||||||
// }
|
|
||||||
Token::Custom(s)
|
Token::Custom(s)
|
||||||
if state
|
if state
|
||||||
.engine
|
.engine
|
||||||
@ -2017,11 +2009,11 @@ fn parse_expr(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Expr, ParseError> {
|
) -> Result<Expr, ParseError> {
|
||||||
settings.pos = input.peek().unwrap().1;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = input.peek().unwrap().1;
|
||||||
|
|
||||||
// Check if it is a custom syntax.
|
// Check if it is a custom syntax.
|
||||||
if !state.engine.custom_syntax.is_empty() {
|
if !state.engine.custom_syntax.is_empty() {
|
||||||
let (token, pos) = input.peek().unwrap();
|
let (token, pos) = input.peek().unwrap();
|
||||||
@ -2095,13 +2087,12 @@ fn parse_if(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// if ...
|
|
||||||
let token_pos = eat_token(input, Token::If);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// if ...
|
||||||
|
settings.pos = eat_token(input, Token::If);
|
||||||
|
|
||||||
// if guard { if_body }
|
// if guard { if_body }
|
||||||
ensure_not_statement_expr(input, "a boolean")?;
|
ensure_not_statement_expr(input, "a boolean")?;
|
||||||
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
@ -2121,7 +2112,11 @@ fn parse_if(
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Stmt::If(guard, Box::new((if_body, else_body)), token_pos))
|
Ok(Stmt::If(
|
||||||
|
guard,
|
||||||
|
Box::new((if_body, else_body)),
|
||||||
|
settings.pos,
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a while loop.
|
/// Parse a while loop.
|
||||||
@ -2149,7 +2144,7 @@ fn parse_while_loop(
|
|||||||
settings.is_breakable = true;
|
settings.is_breakable = true;
|
||||||
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
||||||
|
|
||||||
Ok(Stmt::While(guard, body, token_pos))
|
Ok(Stmt::While(guard, body, settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a do loop.
|
/// Parse a do loop.
|
||||||
@ -2159,13 +2154,12 @@ fn parse_do(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// do ...
|
|
||||||
let token_pos = eat_token(input, Token::Do);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// do ...
|
||||||
|
settings.pos = eat_token(input, Token::Do);
|
||||||
|
|
||||||
// do { body } [while|until] guard
|
// do { body } [while|until] guard
|
||||||
settings.is_breakable = true;
|
settings.is_breakable = true;
|
||||||
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
let body = Box::new(parse_block(input, state, lib, settings.level_up())?);
|
||||||
@ -2186,7 +2180,7 @@ fn parse_do(
|
|||||||
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
let guard = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
ensure_not_assignment(input)?;
|
ensure_not_assignment(input)?;
|
||||||
|
|
||||||
Ok(Stmt::Do(body, guard, is_while, token_pos))
|
Ok(Stmt::Do(body, guard, is_while, settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a for loop.
|
/// Parse a for loop.
|
||||||
@ -2196,13 +2190,12 @@ fn parse_for(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// for ...
|
|
||||||
let token_pos = eat_token(input, Token::For);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// for ...
|
||||||
|
settings.pos = eat_token(input, Token::For);
|
||||||
|
|
||||||
// for name ...
|
// for name ...
|
||||||
let name = match input.next().unwrap() {
|
let name = match input.next().unwrap() {
|
||||||
// Variable name
|
// Variable name
|
||||||
@ -2242,7 +2235,7 @@ fn parse_for(
|
|||||||
|
|
||||||
state.stack.truncate(prev_stack_len);
|
state.stack.truncate(prev_stack_len);
|
||||||
|
|
||||||
Ok(Stmt::For(expr, Box::new((name, body)), token_pos))
|
Ok(Stmt::For(expr, Box::new((name, body)), settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a variable definition statement.
|
/// Parse a variable definition statement.
|
||||||
@ -2254,13 +2247,12 @@ fn parse_let(
|
|||||||
export: bool,
|
export: bool,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// let/const... (specified in `var_type`)
|
|
||||||
let token_pos = input.next().unwrap().1;
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// let/const... (specified in `var_type`)
|
||||||
|
settings.pos = input.next().unwrap().1;
|
||||||
|
|
||||||
// let name ...
|
// let name ...
|
||||||
let (name, pos) = match input.next().unwrap() {
|
let (name, pos) = match input.next().unwrap() {
|
||||||
(Token::Identifier(s), pos) => (s, pos),
|
(Token::Identifier(s), pos) => (s, pos),
|
||||||
@ -2272,7 +2264,7 @@ fn parse_let(
|
|||||||
};
|
};
|
||||||
|
|
||||||
// let name = ...
|
// let name = ...
|
||||||
let init_expr = if match_token(input, Token::Equals).0 {
|
let expr = if match_token(input, Token::Equals).0 {
|
||||||
// let name = expr
|
// let name = expr
|
||||||
Some(parse_expr(input, state, lib, settings.level_up())?)
|
Some(parse_expr(input, state, lib, settings.level_up())?)
|
||||||
} else {
|
} else {
|
||||||
@ -2285,14 +2277,14 @@ fn parse_let(
|
|||||||
let name = state.get_interned_string(name);
|
let name = state.get_interned_string(name);
|
||||||
state.stack.push((name.clone(), AccessMode::ReadWrite));
|
state.stack.push((name.clone(), AccessMode::ReadWrite));
|
||||||
let var_def = Ident { name, pos };
|
let var_def = Ident { name, pos };
|
||||||
Ok(Stmt::Let(Box::new(var_def), init_expr, export, token_pos))
|
Ok(Stmt::Let(Box::new(var_def), expr, export, settings.pos))
|
||||||
}
|
}
|
||||||
// const name = { expr:constant }
|
// const name = { expr:constant }
|
||||||
AccessMode::ReadOnly => {
|
AccessMode::ReadOnly => {
|
||||||
let name = state.get_interned_string(name);
|
let name = state.get_interned_string(name);
|
||||||
state.stack.push((name.clone(), AccessMode::ReadOnly));
|
state.stack.push((name.clone(), AccessMode::ReadOnly));
|
||||||
let var_def = Ident { name, pos };
|
let var_def = Ident { name, pos };
|
||||||
Ok(Stmt::Const(Box::new(var_def), init_expr, export, token_pos))
|
Ok(Stmt::Const(Box::new(var_def), expr, export, settings.pos))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2305,23 +2297,22 @@ fn parse_import(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// import ...
|
|
||||||
let token_pos = eat_token(input, Token::Import);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// import ...
|
||||||
|
settings.pos = eat_token(input, Token::Import);
|
||||||
|
|
||||||
// import expr ...
|
// import expr ...
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
// import expr as ...
|
// import expr as ...
|
||||||
if !match_token(input, Token::As).0 {
|
if !match_token(input, Token::As).0 {
|
||||||
return Ok(Stmt::Import(expr, None, token_pos));
|
return Ok(Stmt::Import(expr, None, settings.pos));
|
||||||
}
|
}
|
||||||
|
|
||||||
// import expr as name ...
|
// import expr as name ...
|
||||||
let (name, _) = match input.next().unwrap() {
|
let (name, name_pos) = match input.next().unwrap() {
|
||||||
(Token::Identifier(s), pos) => (s, pos),
|
(Token::Identifier(s), pos) => (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));
|
||||||
@ -2337,9 +2328,9 @@ fn parse_import(
|
|||||||
expr,
|
expr,
|
||||||
Some(Box::new(Ident {
|
Some(Box::new(Ident {
|
||||||
name,
|
name,
|
||||||
pos: settings.pos,
|
pos: name_pos,
|
||||||
})),
|
})),
|
||||||
token_pos,
|
settings.pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2351,12 +2342,11 @@ fn parse_export(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
let token_pos = eat_token(input, Token::Export);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = eat_token(input, Token::Export);
|
||||||
|
|
||||||
match input.peek().unwrap() {
|
match input.peek().unwrap() {
|
||||||
(Token::Let, pos) => {
|
(Token::Let, pos) => {
|
||||||
let pos = *pos;
|
let pos = *pos;
|
||||||
@ -2424,7 +2414,7 @@ fn parse_export(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Stmt::Export(exports, token_pos))
|
Ok(Stmt::Export(exports, settings.pos))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Parse a statement block.
|
/// Parse a statement block.
|
||||||
@ -2513,11 +2503,11 @@ fn parse_expr_stmt(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
settings.pos = input.peek().unwrap().1;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
settings.pos = input.peek().unwrap().1;
|
||||||
|
|
||||||
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
let expr = parse_expr(input, state, lib, settings.level_up())?;
|
||||||
let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
|
let stmt = parse_op_assignment_stmt(input, state, lib, expr, settings.level_up())?;
|
||||||
Ok(stmt)
|
Ok(stmt)
|
||||||
@ -2715,13 +2705,12 @@ fn parse_try_catch(
|
|||||||
lib: &mut FunctionsLib,
|
lib: &mut FunctionsLib,
|
||||||
mut settings: ParseSettings,
|
mut settings: ParseSettings,
|
||||||
) -> Result<Stmt, ParseError> {
|
) -> Result<Stmt, ParseError> {
|
||||||
// try ...
|
|
||||||
let token_pos = eat_token(input, Token::Try);
|
|
||||||
settings.pos = token_pos;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "unchecked"))]
|
#[cfg(not(feature = "unchecked"))]
|
||||||
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
settings.ensure_level_within_max_limit(state.max_expr_depth)?;
|
||||||
|
|
||||||
|
// try ...
|
||||||
|
settings.pos = eat_token(input, Token::Try);
|
||||||
|
|
||||||
// try { body }
|
// try { body }
|
||||||
let body = parse_block(input, state, lib, settings.level_up())?;
|
let body = parse_block(input, state, lib, settings.level_up())?;
|
||||||
|
|
||||||
@ -2765,7 +2754,7 @@ fn parse_try_catch(
|
|||||||
|
|
||||||
Ok(Stmt::TryCatch(
|
Ok(Stmt::TryCatch(
|
||||||
Box::new((body, var_def, catch_body)),
|
Box::new((body, var_def, catch_body)),
|
||||||
token_pos,
|
settings.pos,
|
||||||
catch_pos,
|
catch_pos,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ fn test_optimizer_parse() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let ast = engine.compile("{ const DECISION = false; if DECISION { 42 } else { 123 } }")?;
|
let ast = engine.compile("{ const DECISION = false; if DECISION { 42 } else { 123 } }")?;
|
||||||
|
|
||||||
assert!(format!("{:?}", ast).starts_with(r#"AST { source: None, statements: [Block([Const(Ident { name: "DECISION", pos: 1:9 }, Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#));
|
assert!(format!("{:?}", ast).starts_with(r#"AST { source: None, statements: [Block([Const(Ident("DECISION" @ 1:9), Some(Unit(0:0)), false, 1:3), Expr(IntegerConstant(123, 1:53))], 1:1)]"#));
|
||||||
|
|
||||||
let ast = engine.compile("if 1 == 2 { 42 }")?;
|
let ast = engine.compile("if 1 == 2 { 42 }")?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user