Reshuffle code sections.

This commit is contained in:
Stephen Chung 2020-04-19 18:33:02 +08:00
parent dd09dbf79e
commit b23fd6e20a

View File

@ -344,6 +344,98 @@ pub(crate) fn calc_fn_def(fn_name: &str, params: usize) -> u64 {
s.finish() s.finish()
} }
/// Print/debug to stdout
fn default_print(s: &str) {
#[cfg(not(feature = "no_std"))]
println!("{}", s);
}
/// Search for a variable within the scope, returning its value and index inside the Scope
fn search_scope<'a>(
scope: &'a Scope,
id: &str,
begin: Position,
) -> Result<(ScopeSource<'a>, Dynamic), Box<EvalAltResult>> {
scope
.get(id)
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(id.into(), begin)))
}
/// Replace a character at an index position in a mutable string
fn str_replace_char(s: &mut String, idx: usize, new_ch: char) {
let mut chars: Vec<char> = s.chars().collect();
let ch = *chars.get(idx).expect("string index out of bounds");
// See if changed - if so, update the String
if ch != new_ch {
chars[idx] = new_ch;
s.clear();
chars.iter().for_each(|&ch| s.push(ch));
}
}
/// Update the value at an index position
fn update_indexed_val(
mut target: Dynamic,
idx: IndexValue,
new_val: Dynamic,
pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> {
match target.get_mut() {
Union::Array(arr) => {
arr[idx.as_num()] = new_val;
}
Union::Map(map) => {
map.insert(idx.as_str(), new_val);
}
Union::Str(s) => {
// Value must be a character
let ch = new_val
.as_char()
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
str_replace_char(s, idx.as_num(), ch);
}
// All other variable types should be an error
_ => panic!("invalid type for indexing: {}", target.type_name()),
}
Ok(target)
}
/// Update the value at an index position in a variable inside the scope
fn update_indexed_scope_var(
scope: &mut Scope,
src: ScopeSource,
idx: IndexValue,
new_val: Dynamic,
pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> {
let target = scope.get_mut(src);
match target.get_mut() {
// array_id[idx] = val
Union::Array(arr) => {
arr[idx.as_num()] = new_val;
}
// map_id[idx] = val
Union::Map(map) => {
map.insert(idx.as_str(), new_val);
}
// string_id[idx] = val
Union::Str(s) => {
// Value must be a character
let ch = new_val
.as_char()
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
str_replace_char(s, idx.as_num(), ch);
}
// All other variable types should be an error
_ => panic!("invalid type for indexing: {}", target.type_name()),
}
Ok(Dynamic::from_unit())
}
impl Engine { impl Engine {
/// Create a new `Engine` /// Create a new `Engine`
pub fn new() -> Self { pub fn new() -> Self {
@ -669,7 +761,7 @@ impl Engine {
match dot_lhs { match dot_lhs {
// id.??? // id.???
Expr::Variable(id, pos) => { Expr::Variable(id, pos) => {
let (entry, _) = Self::search_scope(scope, id, *pos)?; let (entry, _) = search_scope(scope, id, *pos)?;
// Avoid referencing scope which is used below as mut // Avoid referencing scope which is used below as mut
let entry = ScopeSource { name: id, ..entry }; let entry = ScopeSource { name: id, ..entry };
@ -696,8 +788,7 @@ impl Engine {
} }
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
let pos = dot_rhs.position(); update_indexed_scope_var(scope, src, index, val, dot_rhs.position())?;
Self::update_indexed_scope_var(scope, src, index, val, pos)?;
} }
} }
} }
@ -713,17 +804,6 @@ impl Engine {
} }
} }
/// Search for a variable within the scope, returning its value and index inside the Scope
fn search_scope<'a>(
scope: &'a Scope,
id: &str,
begin: Position,
) -> Result<(ScopeSource<'a>, Dynamic), Box<EvalAltResult>> {
scope
.get(id)
.ok_or_else(|| Box::new(EvalAltResult::ErrorVariableNotFound(id.into(), begin)))
}
/// Get the value at the indexed position of a base type /// Get the value at the indexed position of a base type
fn get_indexed_val( fn get_indexed_val(
&self, &self,
@ -746,6 +826,8 @@ impl Engine {
.as_int() .as_int()
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?; .map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_expr.position()))?;
let arr_len = arr.len();
if index >= 0 { if index >= 0 {
arr.get(index as usize) arr.get(index as usize)
.map(|v| { .map(|v| {
@ -759,13 +841,11 @@ impl Engine {
) )
}) })
.ok_or_else(|| { .ok_or_else(|| {
Box::new(EvalAltResult::ErrorArrayBounds(arr.len(), index, idx_pos)) Box::new(EvalAltResult::ErrorArrayBounds(arr_len, index, idx_pos))
}) })
} else { } else {
Err(Box::new(EvalAltResult::ErrorArrayBounds( Err(Box::new(EvalAltResult::ErrorArrayBounds(
arr.len(), arr_len, index, idx_pos,
index,
idx_pos,
))) )))
} }
} }
@ -834,21 +914,13 @@ impl Engine {
) -> Result<(Option<ScopeSource<'a>>, IndexValue, Dynamic), Box<EvalAltResult>> { ) -> Result<(Option<ScopeSource<'a>>, IndexValue, Dynamic), Box<EvalAltResult>> {
match lhs { match lhs {
// id[idx_expr] // id[idx_expr]
Expr::Variable(id, _) => { Expr::Variable(name, _) => {
let (ScopeSource { typ, index, .. }, val) = let (ScopeSource { typ, index, .. }, val) =
Self::search_scope(scope, &id, lhs.position())?; search_scope(scope, &name, lhs.position())?;
let (val, idx) = let (val, idx) =
self.get_indexed_val(scope, fn_lib, &val, idx_expr, op_pos, level, false)?; self.get_indexed_val(scope, fn_lib, &val, idx_expr, op_pos, level, false)?;
Ok(( Ok((Some(ScopeSource { name, typ, index }), idx, val))
Some(ScopeSource {
name: &id,
typ,
index,
}),
idx,
val,
))
} }
// (expr)[idx_expr] // (expr)[idx_expr]
@ -860,81 +932,6 @@ impl Engine {
} }
} }
/// Replace a character at an index position in a mutable string
fn str_replace_char(s: &mut String, idx: usize, new_ch: char) {
let mut chars: Vec<char> = s.chars().collect();
let ch = *chars.get(idx).expect("string index out of bounds");
// See if changed - if so, update the String
if ch != new_ch {
chars[idx] = new_ch;
s.clear();
chars.iter().for_each(|&ch| s.push(ch));
}
}
/// Update the value at an index position in a variable inside the scope
fn update_indexed_scope_var(
scope: &mut Scope,
src: ScopeSource,
idx: IndexValue,
new_val: Dynamic,
pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> {
let target = scope.get_mut(src);
match target.get_mut() {
// array_id[idx] = val
Union::Array(arr) => {
arr[idx.as_num()] = new_val;
}
// map_id[idx] = val
Union::Map(map) => {
map.insert(idx.as_str(), new_val);
}
// string_id[idx] = val
Union::Str(s) => {
// Value must be a character
let ch = new_val
.as_char()
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
Self::str_replace_char(s, idx.as_num(), ch);
}
// All other variable types should be an error
_ => panic!("invalid type for indexing: {}", target.type_name()),
}
Ok(Dynamic::from_unit())
}
/// Update the value at an index position
fn update_indexed_val(
mut target: Dynamic,
idx: IndexValue,
new_val: Dynamic,
pos: Position,
) -> Result<Dynamic, Box<EvalAltResult>> {
match target.get_mut() {
Union::Array(arr) => {
arr[idx.as_num()] = new_val;
}
Union::Map(map) => {
map.insert(idx.as_str(), new_val);
}
Union::Str(s) => {
// Value must be a character
let ch = new_val
.as_char()
.map_err(|_| EvalAltResult::ErrorCharMismatch(pos))?;
Self::str_replace_char(s, idx.as_num(), ch);
}
// All other variable types should be an error
_ => panic!("invalid type for indexing: {}", target.type_name()),
}
Ok(target)
}
/// Chain-evaluate a dot setter /// Chain-evaluate a dot setter
fn dot_set_helper( fn dot_set_helper(
&self, &self,
@ -965,7 +962,7 @@ impl Engine {
scope, fn_lib, &val, idx_expr, *op_pos, level, true, scope, fn_lib, &val, idx_expr, *op_pos, level, true,
)?; )?;
Self::update_indexed_val(val, index, new_val.clone(), val_pos) update_indexed_val(val, index, new_val.clone(), val_pos)
}) })
.and_then(|mut val| { .and_then(|mut val| {
let fn_name = make_setter(id); let fn_name = make_setter(id);
@ -990,8 +987,8 @@ impl Engine {
.and_then(|mut val| { .and_then(|mut val| {
self.dot_set_helper( self.dot_set_helper(
scope, fn_lib, &mut val, rhs, new_val, val_pos, level, scope, fn_lib, &mut val, rhs, new_val, val_pos, level,
) )?;
.map(|_| val) // Discard Ok return value Ok(val)
}) })
.and_then(|mut val| { .and_then(|mut val| {
let fn_name = make_setter(id); let fn_name = make_setter(id);
@ -1017,7 +1014,7 @@ impl Engine {
)?; )?;
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned. // In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
Self::update_indexed_val(v, index, value, val_pos) update_indexed_val(v, index, value, val_pos)
}) })
.and_then(|mut v| { .and_then(|mut v| {
let fn_name = make_setter(id); let fn_name = make_setter(id);
@ -1063,7 +1060,7 @@ impl Engine {
match dot_lhs { match dot_lhs {
// id.??? // id.???
Expr::Variable(id, pos) => { Expr::Variable(id, pos) => {
let (src, mut target) = Self::search_scope(scope, id, *pos)?; let (src, mut target) = search_scope(scope, id, *pos)?;
match src.typ { match src.typ {
ScopeEntryType::Constant => Err(Box::new( ScopeEntryType::Constant => Err(Box::new(
@ -1072,14 +1069,9 @@ impl Engine {
_ => { _ => {
// Avoid referencing scope which is used below as mut // Avoid referencing scope which is used below as mut
let entry = ScopeSource { name: id, ..src }; let entry = ScopeSource { name: id, ..src };
let this_ptr = &mut target;
let value = self.dot_set_helper( let value = self.dot_set_helper(
scope, scope, fn_lib, this_ptr, dot_rhs, new_val, val_pos, level,
fn_lib,
&mut target,
dot_rhs,
new_val,
val_pos,
level,
); );
// In case the expression mutated `target`, we need to update it back into the scope because it is cloned. // In case the expression mutated `target`, we need to update it back into the scope because it is cloned.
@ -1109,7 +1101,7 @@ impl Engine {
))); )));
} }
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
Self::update_indexed_scope_var(scope, src, index, target, val_pos)?; update_indexed_scope_var(scope, src, index, target, val_pos)?;
} }
} }
} }
@ -1198,7 +1190,7 @@ impl Engine {
Expr::FloatConstant(f, _) => Ok(Dynamic::from_float(*f)), Expr::FloatConstant(f, _) => Ok(Dynamic::from_float(*f)),
Expr::StringConstant(s, _) => Ok(Dynamic::from_string(s.to_string())), Expr::StringConstant(s, _) => Ok(Dynamic::from_string(s.to_string())),
Expr::CharConstant(c, _) => Ok(Dynamic::from_char(*c)), Expr::CharConstant(c, _) => Ok(Dynamic::from_char(*c)),
Expr::Variable(id, pos) => Self::search_scope(scope, id, *pos).map(|(_, val)| val), Expr::Variable(id, pos) => search_scope(scope, id, *pos).map(|(_, val)| val),
Expr::Property(_, _) => panic!("unexpected property."), Expr::Property(_, _) => panic!("unexpected property."),
// Statement block // Statement block
@ -1261,9 +1253,7 @@ impl Engine {
} }
ScopeEntryType::Normal => { ScopeEntryType::Normal => {
let pos = rhs.position(); let pos = rhs.position();
Ok(Self::update_indexed_scope_var( Ok(update_indexed_scope_var(scope, src, index, rhs_val, pos)?)
scope, src, index, rhs_val, pos,
)?)
} }
} }
} else { } else {
@ -1645,9 +1635,3 @@ impl Engine {
.unwrap_or(name) .unwrap_or(name)
} }
} }
/// Print/debug to stdout
fn default_print(s: &str) {
#[cfg(not(feature = "no_std"))]
println!("{}", s);
}