Simplify code.

This commit is contained in:
Stephen Chung 2020-04-11 18:09:03 +08:00
parent 5848339d5a
commit bc0d43d68f
3 changed files with 102 additions and 116 deletions

View File

@ -172,11 +172,10 @@ impl FunctionsLib {
} }
/// Get a function definition from the `FunctionsLib`. /// Get a function definition from the `FunctionsLib`.
pub fn get_function(&self, name: &str, params: usize) -> Option<&FnDef> { pub fn get_function(&self, name: &str, params: usize) -> Option<&FnDef> {
if let Ok(n) = self.0.binary_search_by(|f| f.compare(name, params)) { self.0
Some(&self.0[n]) .binary_search_by(|f| f.compare(name, params))
} else { .ok()
None .map(|n| self.0[n].as_ref())
}
} }
/// Merge another `FunctionsLib` into this `FunctionsLib`. /// Merge another `FunctionsLib` into this `FunctionsLib`.
pub fn merge(&self, other: &Self) -> Self { pub fn merge(&self, other: &Self) -> Self {
@ -441,58 +440,56 @@ impl Engine<'_> {
const fn_lib: Option<&FunctionsLib> = None; const fn_lib: Option<&FunctionsLib> = None;
// First search in script-defined functions (can override built-in) // First search in script-defined functions (can override built-in)
if let Some(lib) = fn_lib { if let Some(fn_def) = fn_lib.and_then(|lib| lib.get_function(fn_name, args.len())) {
if let Some(fn_def) = lib.get_function(fn_name, args.len()) { match scope {
match scope { // Extern scope passed in which is not empty
// Extern scope passed in which is not empty Some(scope) if scope.len() > 0 => {
Some(scope) if scope.len() > 0 => { let scope_len = scope.len();
let scope_len = scope.len();
scope.extend( scope.extend(
// Put arguments into scope as variables - variable name is copied // Put arguments into scope as variables - variable name is copied
// TODO - avoid copying variable name // TODO - avoid copying variable name
fn_def fn_def
.params .params
.iter() .iter()
.zip(args.into_iter().map(|x| (*x).into_dynamic())) .zip(args.into_iter().map(|x| (*x).into_dynamic()))
.map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)), .map(|(name, value)| (name.clone(), ScopeEntryType::Normal, value)),
); );
// Evaluate the function at one higher level of call depth // Evaluate the function at one higher level of call depth
let result = self let result = self
.eval_stmt(scope, fn_lib, &fn_def.body, level + 1) .eval_stmt(scope, fn_lib, &fn_def.body, level + 1)
.or_else(|err| match err { .or_else(|err| match err {
// Convert return statement to return value // Convert return statement to return value
EvalAltResult::Return(x, _) => Ok(x), EvalAltResult::Return(x, _) => Ok(x),
err => Err(err.set_position(pos)), err => Err(err.set_position(pos)),
}); });
scope.rewind(scope_len); scope.rewind(scope_len);
return result; return result;
} }
// No new scope - create internal scope // No new scope - create internal scope
_ => { _ => {
let mut scope = Scope::new(); let mut scope = Scope::new();
scope.extend( scope.extend(
// Put arguments into scope as variables // Put arguments into scope as variables
fn_def fn_def
.params .params
.iter() .iter()
.zip(args.into_iter().map(|x| (*x).into_dynamic())) .zip(args.into_iter().map(|x| (*x).into_dynamic()))
.map(|(name, value)| (name, ScopeEntryType::Normal, value)), .map(|(name, value)| (name, ScopeEntryType::Normal, value)),
); );
// Evaluate the function at one higher level of call depth // Evaluate the function at one higher level of call depth
return self return self
.eval_stmt(&mut scope, fn_lib, &fn_def.body, level + 1) .eval_stmt(&mut scope, fn_lib, &fn_def.body, level + 1)
.or_else(|err| match err { .or_else(|err| match err {
// Convert return statement to return value // Convert return statement to return value
EvalAltResult::Return(x, _) => Ok(x), EvalAltResult::Return(x, _) => Ok(x),
err => Err(err.set_position(pos)), err => Err(err.set_position(pos)),
}); });
}
} }
} }
} }
@ -510,25 +507,23 @@ impl Engine<'_> {
} }
// Search built-in's and external functions // Search built-in's and external functions
if let Some(functions) = &self.functions { if let Some(func) = self.functions.as_ref().and_then(|f| f.get(&spec)) {
if let Some(func) = functions.get(&spec) { // Run external function
// Run external function let result = func(args, pos)?;
let result = func(args, pos)?;
// See if the function match print/debug (which requires special processing) // See if the function match print/debug (which requires special processing)
return Ok(match fn_name { return match fn_name {
KEYWORD_PRINT if self.on_print.is_some() => { KEYWORD_PRINT if self.on_print.is_some() => Ok(self.on_print.as_ref().unwrap()(
self.on_print.as_ref().unwrap()(cast_to_string(result.as_ref(), pos)?) cast_to_string(result.as_ref(), pos)?,
.into_dynamic() )
} .into_dynamic()),
KEYWORD_DEBUG if self.on_debug.is_some() => { KEYWORD_DEBUG if self.on_debug.is_some() => Ok(self.on_debug.as_ref().unwrap()(
self.on_debug.as_ref().unwrap()(cast_to_string(result.as_ref(), pos)?) cast_to_string(result.as_ref(), pos)?,
.into_dynamic() )
} .into_dynamic()),
KEYWORD_PRINT | KEYWORD_DEBUG => ().into_dynamic(), KEYWORD_PRINT | KEYWORD_DEBUG => Ok(().into_dynamic()),
_ => result, _ => Ok(result),
}); };
}
} }
if let Some(prop) = extract_prop_from_getter(fn_name) { if let Some(prop) = extract_prop_from_getter(fn_name) {
@ -1603,33 +1598,29 @@ impl Engine<'_> {
let arr = self.eval_expr(scope, fn_lib, expr, level)?; let arr = self.eval_expr(scope, fn_lib, expr, level)?;
let tid = Any::type_id(arr.as_ref()); let tid = Any::type_id(arr.as_ref());
if let Some(type_iterators) = &self.type_iterators { if let Some(iter_fn) = self.type_iterators.as_ref().and_then(|t| t.get(&tid)) {
if let Some(iter_fn) = type_iterators.get(&tid) { // Add the loop variable - variable name is copied
// Add the loop variable - variable name is copied // TODO - avoid copying variable name
// TODO - avoid copying variable name scope.push(name.clone(), ());
scope.push(name.clone(), ());
let entry = ScopeSource { let entry = ScopeSource {
name, name,
index: scope.len() - 1, index: scope.len() - 1,
typ: ScopeEntryType::Normal, typ: ScopeEntryType::Normal,
}; };
for a in iter_fn(&arr) { for a in iter_fn(&arr) {
*scope.get_mut(entry) = a; *scope.get_mut(entry) = a;
match self.eval_stmt(scope, fn_lib, body, level) { match self.eval_stmt(scope, fn_lib, body, level) {
Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (), Ok(_) | Err(EvalAltResult::ErrorLoopBreak(false, _)) => (),
Err(EvalAltResult::ErrorLoopBreak(true, _)) => break, Err(EvalAltResult::ErrorLoopBreak(true, _)) => break,
Err(x) => return Err(x), Err(x) => return Err(x),
}
} }
scope.rewind(scope.len() - 1);
Ok(().into_dynamic())
} else {
Err(EvalAltResult::ErrorFor(expr.position()))
} }
scope.rewind(scope.len() - 1);
Ok(().into_dynamic())
} else { } else {
Err(EvalAltResult::ErrorFor(expr.position())) Err(EvalAltResult::ErrorFor(expr.position()))
} }
@ -1694,16 +1685,10 @@ impl Engine<'_> {
/// Map a type_name into a pretty-print name /// Map a type_name into a pretty-print name
pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str { pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
if self.type_names.is_none() { self.type_names
name .as_ref()
} else { .and_then(|list| list.get(name).map(String::as_str))
self.type_names .unwrap_or(name)
.as_ref()
.unwrap()
.get(name)
.map(String::as_str)
.unwrap_or(name)
}
} }
} }

View File

@ -663,16 +663,18 @@ fn optimize<'a>(
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(i, stmt)| { .map(|(i, stmt)| {
if let Stmt::Const(name, value, _) = &stmt { match stmt {
// Load constants Stmt::Const(ref name, ref value, _) => {
state.push_constant(name, value.as_ref().clone()); // Load constants
stmt // Keep it in the global scope state.push_constant(name.as_ref(), value.as_ref().clone());
} else { stmt // Keep it in the global scope
// Keep all variable declarations at this level }
// and always keep the last return value _ => {
let keep = matches!(stmt, Stmt::Let(_, _, _)) || i == num_statements - 1; // Keep all variable declarations at this level
// and always keep the last return value
optimize_stmt(stmt, &mut state, keep) let keep = matches!(stmt, Stmt::Let(_, _, _)) || i == num_statements - 1;
optimize_stmt(stmt, &mut state, keep)
}
} }
}) })
.collect(); .collect();

View File

@ -2192,11 +2192,10 @@ fn parse_binary_op<'a>(
let mut current_lhs = lhs; let mut current_lhs = lhs;
loop { loop {
let (current_precedence, bind_right) = if let Some((current_op, _)) = input.peek() { let (current_precedence, bind_right) = input.peek().map_or_else(
(current_op.precedence(), current_op.is_bind_right()) || (0, false),
} else { |(current_op, _)| (current_op.precedence(), current_op.is_bind_right()),
(0, false) );
};
// Bind left to the parent lhs expression if precedence is higher // Bind left to the parent lhs expression if precedence is higher
// If same precedence, then check if the operator binds right // If same precedence, then check if the operator binds right