diff --git a/src/ast.rs b/src/ast.rs index bd81b4c3..16288c17 100644 --- a/src/ast.rs +++ b/src/ast.rs @@ -950,6 +950,18 @@ impl From for Stmt { } } +/// _(internals)_ Type of variable declaration. +/// Exported under the `internals` feature only. +/// +/// # Volatile Data Structure +/// +/// This type is volatile and may change. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Hash)] +pub enum VarDeclaration { + Let, + Const, +} + /// _(internals)_ A statement. /// Exported under the `internals` feature only. /// @@ -974,10 +986,8 @@ pub enum Stmt { Do(Box, Expr, bool, Position), /// `for` `(` id `,` counter `)` `in` expr `{` stmt `}` For(Expr, Box<(Ident, Option, StmtBlock)>, Position), - /// \[`export`\] `let` id `=` expr - Let(Expr, Box, bool, Position), - /// \[`export`\] `const` id `=` expr - Const(Expr, Box, bool, Position), + /// \[`export`\] `let`/`const` id `=` expr + Var(Expr, Box, VarDeclaration, bool, Position), /// expr op`=` expr Assignment(Box<(Expr, Option>, Expr)>, Position), /// func `(` expr `,` ... `)` @@ -1058,8 +1068,7 @@ impl Stmt { | Self::Do(_, _, _, pos) | Self::For(_, _, pos) | Self::Return(_, _, pos) - | Self::Let(_, _, _, pos) - | Self::Const(_, _, _, pos) + | Self::Var(_, _, _, _, pos) | Self::TryCatch(_, pos) => *pos, Self::Expr(x) => x.position(), @@ -1088,8 +1097,7 @@ impl Stmt { | Self::Do(_, _, _, pos) | Self::For(_, _, pos) | Self::Return(_, _, pos) - | Self::Let(_, _, _, pos) - | Self::Const(_, _, _, pos) + | Self::Var(_, _, _, _, pos) | Self::TryCatch(_, pos) => *pos = new_pos, Self::Expr(x) => { @@ -1123,8 +1131,7 @@ impl Stmt { | Self::For(_, _, _) | Self::TryCatch(_, _) => false, - Self::Let(_, _, _, _) - | Self::Const(_, _, _, _) + Self::Var(_, _, _, _, _) | Self::Assignment(_, _) | Self::Continue(_) | Self::Break(_) @@ -1151,8 +1158,7 @@ impl Stmt { // A No-op requires a semicolon in order to know it is an empty statement! Self::Noop(_) => false, - Self::Let(_, _, _, _) - | Self::Const(_, _, _, _) + Self::Var(_, _, _, _, _) | Self::Assignment(_, _) | Self::FnCall(_, _) | Self::Expr(_) @@ -1193,10 +1199,7 @@ impl Stmt { condition.is_pure() && block.0.iter().all(Stmt::is_pure) } Self::For(iterable, x, _) => iterable.is_pure() && (x.2).0.iter().all(Stmt::is_pure), - Self::Let(_, _, _, _) - | Self::Const(_, _, _, _) - | Self::Assignment(_, _) - | Self::FnCall(_, _) => false, + Self::Var(_, _, _, _, _) | Self::Assignment(_, _) | Self::FnCall(_, _) => false, Self::Block(block, _) => block.iter().all(|stmt| stmt.is_pure()), Self::Continue(_) | Self::Break(_) | Self::Return(_, _, _) => false, Self::TryCatch(x, _) => { @@ -1222,7 +1225,7 @@ impl Stmt { #[must_use] pub fn is_internally_pure(&self) -> bool { match self { - Self::Let(expr, _, _, _) | Self::Const(expr, _, _, _) => expr.is_pure(), + Self::Var(expr, _, _, _, _) => expr.is_pure(), #[cfg(not(feature = "no_module"))] Self::Import(expr, _, _) => expr.is_pure(), @@ -1260,7 +1263,7 @@ impl Stmt { } match self { - Self::Let(e, _, _, _) | Self::Const(e, _, _, _) => { + Self::Var(e, _, _, _, _) => { if !e.walk(path, on_node) { return false; } diff --git a/src/engine.rs b/src/engine.rs index 90cf5393..8bd29996 100644 --- a/src/engine.rs +++ b/src/engine.rs @@ -1,6 +1,6 @@ //! Main module defining the script evaluation [`Engine`]. -use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt}; +use crate::ast::{Expr, FnCallExpr, Ident, OpAssignment, ReturnType, Stmt, VarDeclaration}; use crate::custom_syntax::CustomSyntax; use crate::dynamic::{map_std_type_name, AccessMode, Union, Variant}; use crate::fn_hash::get_hasher; @@ -2851,12 +2851,11 @@ impl Engine { } // Let/const statement - Stmt::Let(expr, x, export, _) | Stmt::Const(expr, x, export, _) => { + Stmt::Var(expr, x, var_type, export, _) => { let name = &x.name; - let entry_type = match stmt { - Stmt::Let(_, _, _, _) => AccessMode::ReadWrite, - Stmt::Const(_, _, _, _) => AccessMode::ReadOnly, - _ => unreachable!("should be Stmt::Let or Stmt::Const, but gets {:?}", stmt), + let entry_type = match var_type { + VarDeclaration::Let => AccessMode::ReadWrite, + VarDeclaration::Const => AccessMode::ReadOnly, }; let value = self diff --git a/src/lib.rs b/src/lib.rs index 9be39b92..1d72720f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -228,7 +228,7 @@ pub use token::{InputStream, Token, TokenizeState, TokenizerControl, TokenizerCo #[deprecated = "this type is volatile and may change"] pub use ast::{ ASTNode, BinaryExpr, CustomExpr, Expr, FloatWrapper, FnCallExpr, FnCallHashes, Ident, - OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock, + OpAssignment, ReturnType, ScriptFnDef, Stmt, StmtBlock, VarDeclaration, }; #[cfg(feature = "internals")] diff --git a/src/optimize.rs b/src/optimize.rs index b5d25a9b..75fe9a83 100644 --- a/src/optimize.rs +++ b/src/optimize.rs @@ -1,6 +1,6 @@ //! Module implementing the [`AST`] optimizer. -use crate::ast::{Expr, OpAssignment, Stmt}; +use crate::ast::{Expr, OpAssignment, Stmt, VarDeclaration}; use crate::dynamic::AccessMode; use crate::engine::{KEYWORD_DEBUG, KEYWORD_EVAL, KEYWORD_FN_PTR, KEYWORD_PRINT, KEYWORD_TYPE_OF}; use crate::fn_builtin::get_builtin_binary_op_fn; @@ -202,7 +202,7 @@ fn optimize_stmt_block( statements.iter_mut().for_each(|stmt| { match stmt { // Add constant literals into the state - Stmt::Const(value_expr, x, _, _) => { + Stmt::Var(value_expr, x, VarDeclaration::Const, _, _) => { optimize_expr(value_expr, state, false); if value_expr.is_constant() { @@ -214,7 +214,7 @@ fn optimize_stmt_block( } } // Add variables into the state - Stmt::Let(value_expr, x, _, _) => { + Stmt::Var(value_expr, x, VarDeclaration::Let, _, _) => { optimize_expr(value_expr, state, false); state.push_var(&x.name, AccessMode::ReadWrite, None); } @@ -232,11 +232,7 @@ fn optimize_stmt_block( .find_map(|(i, stmt)| match stmt { stmt if !is_pure(stmt) => Some(i), - Stmt::Let(e, _, _, _) | Stmt::Const(e, _, _, _) | Stmt::Expr(e) - if !e.is_constant() => - { - Some(i) - } + Stmt::Var(e, _, _, _, _) | Stmt::Expr(e) if !e.is_constant() => Some(i), #[cfg(not(feature = "no_module"))] Stmt::Import(e, _, _) if !e.is_constant() => Some(i), @@ -609,7 +605,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b *x.2.statements_mut() = optimize_stmt_block(body, state, false, true, false).into(); } // let id = expr; - Stmt::Let(expr, _, _, _) => optimize_expr(expr, state, false), + Stmt::Var(expr, _, VarDeclaration::Let, _, _) => optimize_expr(expr, state, false), // import expr as var; #[cfg(not(feature = "no_module"))] Stmt::Import(expr, _, _) => optimize_expr(expr, state, false), diff --git a/src/parse.rs b/src/parse.rs index d6aa9072..a87ed5c8 100644 --- a/src/parse.rs +++ b/src/parse.rs @@ -2,7 +2,7 @@ use crate::ast::{ BinaryExpr, CustomExpr, Expr, FnCallExpr, FnCallHashes, Ident, OpAssignment, ReturnType, - ScriptFnDef, Stmt, StmtBlock, + ScriptFnDef, Stmt, StmtBlock, VarDeclaration, }; use crate::custom_syntax::{ CustomSyntax, CUSTOM_SYNTAX_MARKER_BLOCK, CUSTOM_SYNTAX_MARKER_BOOL, CUSTOM_SYNTAX_MARKER_EXPR, @@ -2383,9 +2383,21 @@ fn parse_let( match var_type { // let name = expr - AccessMode::ReadWrite => Ok(Stmt::Let(expr, var_def.into(), export, settings.pos)), + AccessMode::ReadWrite => Ok(Stmt::Var( + expr, + var_def.into(), + VarDeclaration::Let, + export, + settings.pos, + )), // const name = { expr:constant } - AccessMode::ReadOnly => Ok(Stmt::Const(expr, var_def.into(), export, settings.pos)), + AccessMode::ReadOnly => Ok(Stmt::Var( + expr, + var_def.into(), + VarDeclaration::Const, + export, + settings.pos, + )), } } diff --git a/tests/optimizer.rs b/tests/optimizer.rs index ac2d5f7f..8f64d7a2 100644 --- a/tests/optimizer.rs +++ b/tests/optimizer.rs @@ -86,7 +86,7 @@ fn test_optimizer_parse() -> Result<(), Box> { assert_eq!( format!("{:?}", ast), - r#"AST { source: None, body: Block[Const(false @ 1:18, "DECISION" @ 1:7, false, 1:1), Expr(123 @ 1:51)], functions: Module, resolver: None }"# + r#"AST { source: None, body: Block[Var(false @ 1:18, "DECISION" @ 1:7, Const, false, 1:1), Expr(123 @ 1:51)], functions: Module, resolver: None }"# ); let ast = engine.compile("if 1 == 2 { 42 }")?;