Streamline.
This commit is contained in:
parent
304c658f89
commit
21c3edb31e
@ -189,7 +189,7 @@ impl StaticVec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A type that holds all the current states of the Engine.
|
/// A type that holds all the current states of the Engine.
|
||||||
#[derive(Debug, Clone, Hash, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub struct State {
|
pub struct State {
|
||||||
/// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup.
|
/// Normally, access to variables are parsed with a relative offset into the scope to avoid a lookup.
|
||||||
/// In some situation, e.g. after running an `eval` statement, subsequent offsets may become mis-aligned.
|
/// In some situation, e.g. after running an `eval` statement, subsequent offsets may become mis-aligned.
|
||||||
@ -198,6 +198,7 @@ pub struct State {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
/// Create a new `State`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
always_search: false,
|
always_search: false,
|
||||||
@ -914,10 +915,9 @@ impl Engine {
|
|||||||
match dot_lhs {
|
match dot_lhs {
|
||||||
// id.??? or id[???]
|
// id.??? or id[???]
|
||||||
Expr::Variable(id, index, pos) => {
|
Expr::Variable(id, index, pos) => {
|
||||||
let (target, typ) = if !state.always_search && *index > 0 {
|
let (target, typ) = match index {
|
||||||
scope.get_mut(scope.len() - *index)
|
Some(i) if !state.always_search => scope.get_mut(scope.len() - i.get()),
|
||||||
} else {
|
_ => search_scope(scope, id, *pos)?,
|
||||||
search_scope(scope, id, *pos)?
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Constants cannot be modified
|
// Constants cannot be modified
|
||||||
@ -1156,8 +1156,8 @@ impl Engine {
|
|||||||
Expr::FloatConstant(f, _) => Ok((*f).into()),
|
Expr::FloatConstant(f, _) => Ok((*f).into()),
|
||||||
Expr::StringConstant(s, _) => Ok(s.to_string().into()),
|
Expr::StringConstant(s, _) => Ok(s.to_string().into()),
|
||||||
Expr::CharConstant(c, _) => Ok((*c).into()),
|
Expr::CharConstant(c, _) => Ok((*c).into()),
|
||||||
Expr::Variable(_, index, _) if !state.always_search && *index > 0 => {
|
Expr::Variable(_, Some(index), _) if !state.always_search => {
|
||||||
Ok(scope.get_mut(scope.len() - *index).0.clone())
|
Ok(scope.get_mut(scope.len() - index.get()).0.clone())
|
||||||
}
|
}
|
||||||
Expr::Variable(id, _, pos) => search_scope(scope, id, *pos).map(|(v, _)| v.clone()),
|
Expr::Variable(id, _, pos) => search_scope(scope, id, *pos).map(|(v, _)| v.clone()),
|
||||||
Expr::Property(_, _) => panic!("unexpected property."),
|
Expr::Property(_, _) => panic!("unexpected property."),
|
||||||
@ -1272,13 +1272,17 @@ impl Engine {
|
|||||||
&& args.len() == 1
|
&& args.len() == 1
|
||||||
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
&& !self.has_override(fn_lib, KEYWORD_EVAL)
|
||||||
{
|
{
|
||||||
|
let prev_len = scope.len();
|
||||||
|
|
||||||
// Evaluate the text string as a script
|
// Evaluate the text string as a script
|
||||||
let result =
|
let result =
|
||||||
self.eval_script_expr(scope, fn_lib, args[0], arg_exprs[0].position());
|
self.eval_script_expr(scope, fn_lib, args[0], arg_exprs[0].position());
|
||||||
|
|
||||||
// IMPORTANT! The eval may define new variables in the current scope!
|
if scope.len() != prev_len {
|
||||||
// We can no longer trust the variable offsets.
|
// IMPORTANT! If the eval defines new variables in the current scope,
|
||||||
state.always_search = true;
|
// all variable offsets from this point on will be mis-aligned.
|
||||||
|
state.always_search = true;
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -729,10 +729,10 @@ pub fn optimize_into_ast(
|
|||||||
|
|
||||||
// Optimize the function body
|
// Optimize the function body
|
||||||
let mut body =
|
let mut body =
|
||||||
optimize(vec![fn_def.body], engine, &Scope::new(), &fn_lib, level);
|
optimize(vec![*fn_def.body], engine, &Scope::new(), &fn_lib, level);
|
||||||
|
|
||||||
// {} -> Noop
|
// {} -> Noop
|
||||||
fn_def.body = match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
fn_def.body = Box::new(match body.pop().unwrap_or_else(|| Stmt::Noop(pos)) {
|
||||||
// { return val; } -> val
|
// { return val; } -> val
|
||||||
Stmt::ReturnWithVal(Some(val), ReturnType::Return, _) => Stmt::Expr(val),
|
Stmt::ReturnWithVal(Some(val), ReturnType::Return, _) => Stmt::Expr(val),
|
||||||
// { return; } -> ()
|
// { return; } -> ()
|
||||||
@ -741,7 +741,7 @@ pub fn optimize_into_ast(
|
|||||||
}
|
}
|
||||||
// All others
|
// All others
|
||||||
stmt => stmt,
|
stmt => stmt,
|
||||||
};
|
});
|
||||||
}
|
}
|
||||||
fn_def
|
fn_def
|
||||||
})
|
})
|
||||||
|
@ -14,6 +14,7 @@ use crate::stdlib::{
|
|||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
format,
|
format,
|
||||||
iter::Peekable,
|
iter::Peekable,
|
||||||
|
num::NonZeroUsize,
|
||||||
ops::Add,
|
ops::Add,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
string::{String, ToString},
|
string::{String, ToString},
|
||||||
@ -169,7 +170,7 @@ pub struct FnDef {
|
|||||||
/// Names of function parameters.
|
/// Names of function parameters.
|
||||||
pub params: Vec<String>,
|
pub params: Vec<String>,
|
||||||
/// Function body.
|
/// Function body.
|
||||||
pub body: Stmt,
|
pub body: Box<Stmt>,
|
||||||
/// Position of the function definition.
|
/// Position of the function definition.
|
||||||
pub pos: Position,
|
pub pos: Position,
|
||||||
}
|
}
|
||||||
@ -184,29 +185,37 @@ pub enum ReturnType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A type that encapsulates a local stack with variable names to simulate an actual runtime scope.
|
/// A type that encapsulates a local stack with variable names to simulate an actual runtime scope.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
struct Stack(Vec<String>);
|
struct Stack(Vec<String>);
|
||||||
|
|
||||||
impl Stack {
|
impl Stack {
|
||||||
|
/// Create a new `Stack`.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self(Vec::new())
|
Self(Vec::new())
|
||||||
}
|
}
|
||||||
|
/// Get the number of variables in the `Stack`.
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.0.len()
|
self.0.len()
|
||||||
}
|
}
|
||||||
|
/// Push (add) a new variable onto the `Stack`.
|
||||||
pub fn push(&mut self, name: String) {
|
pub fn push(&mut self, name: String) {
|
||||||
self.0.push(name);
|
self.0.push(name);
|
||||||
}
|
}
|
||||||
|
/// Rewind the stack to a previous size.
|
||||||
pub fn rewind(&mut self, len: usize) {
|
pub fn rewind(&mut self, len: usize) {
|
||||||
self.0.truncate(len);
|
self.0.truncate(len);
|
||||||
}
|
}
|
||||||
pub fn find(&self, name: &str) -> usize {
|
/// Find a variable by name in the `Stack`, searching in reverse.
|
||||||
|
/// The return value is the offset to be deducted from `Stack::len`,
|
||||||
|
/// i.e. the top element of the `Stack` is offset 1.
|
||||||
|
/// Return zero when the variable name is not found in the `Stack`.
|
||||||
|
pub fn find(&self, name: &str) -> Option<NonZeroUsize> {
|
||||||
self.0
|
self.0
|
||||||
.iter()
|
.iter()
|
||||||
.rev()
|
.rev()
|
||||||
.enumerate()
|
.enumerate()
|
||||||
.find(|(_, n)| *n == name)
|
.find(|(_, n)| *n == name)
|
||||||
.map(|(i, _)| i + 1)
|
.and_then(|(i, _)| NonZeroUsize::new(i + 1))
|
||||||
.unwrap_or(0)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -308,7 +317,7 @@ pub enum Expr {
|
|||||||
/// String constant.
|
/// String constant.
|
||||||
StringConstant(String, Position),
|
StringConstant(String, Position),
|
||||||
/// Variable access.
|
/// Variable access.
|
||||||
Variable(String, usize, Position),
|
Variable(String, Option<NonZeroUsize>, Position),
|
||||||
/// Property access.
|
/// Property access.
|
||||||
Property(String, Position),
|
Property(String, Position),
|
||||||
/// { stmt }
|
/// { stmt }
|
||||||
@ -1836,10 +1845,10 @@ fn parse_fn<'a>(
|
|||||||
})?;
|
})?;
|
||||||
|
|
||||||
// Parse function body
|
// Parse function body
|
||||||
let body = match input.peek().unwrap() {
|
let body = Box::new(match input.peek().unwrap() {
|
||||||
(Token::LeftBrace, _) => parse_block(input, stack, false, allow_stmt_expr)?,
|
(Token::LeftBrace, _) => parse_block(input, stack, false, allow_stmt_expr)?,
|
||||||
(_, pos) => return Err(PERR::FnMissingBody(name).into_err(*pos)),
|
(_, pos) => return Err(PERR::FnMissingBody(name).into_err(*pos)),
|
||||||
};
|
});
|
||||||
|
|
||||||
let params = params.into_iter().map(|(p, _)| p).collect();
|
let params = params.into_iter().map(|(p, _)| p).collect();
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user