feat: named scopes, support of recursion

Initially named scopes were made for imports, but the side effect was to support recursion in functions
This commit is contained in:
Artemy 2022-08-18 14:12:36 +03:00
parent 16aad56fce
commit 6dbc9f7ba4
2 changed files with 82 additions and 26 deletions

View file

@ -14,6 +14,7 @@ pub struct Interpreter {
pos: usize, pos: usize,
scope: usize, scope: usize,
scopes: Vec<Vec<String>>, scopes: Vec<Vec<String>>,
named_scopes: Vec<String>,
} }
impl Interpreter { impl Interpreter {
@ -54,6 +55,7 @@ impl Interpreter {
pos: 1, pos: 1,
scope: 0, scope: 0,
scopes: Vec::new(), scopes: Vec::new(),
named_scopes: Vec::new(),
} }
} }
"conla" => { "conla" => {
@ -72,6 +74,7 @@ impl Interpreter {
pos: 1, pos: 1,
scope: 0, scope: 0,
scopes: Vec::new(), scopes: Vec::new(),
named_scopes: Vec::new(),
} }
} }
_ => { _ => {
@ -94,6 +97,7 @@ impl Interpreter {
pos: 1, pos: 1,
scope: 0, scope: 0,
scopes: Vec::new(), scopes: Vec::new(),
named_scopes: Vec::new(),
} }
} }
} }
@ -436,13 +440,23 @@ impl Interpreter {
VarTypes::Function => { VarTypes::Function => {
let function = function.body.clone(); let function = function.body.clone();
let real_len = args.len(); let real_len = args.len();
let func_args = function.get("args").unwrap().as_array().unwrap(); let func_args = function.get("args").unwrap().as_array().unwrap().clone();
if real_len == func_args.len() { if real_len == func_args.len() {
let args: Vec<Value> = args
.into_iter()
.map(|arg| match arg {
Value::Object(_) => self.eval_node(arg),
_ => arg.clone(),
})
.collect();
self.enter_the_named_scope(name.clone());
for i in 0..real_len { for i in 0..real_len {
let argname = &func_args[i]; let argname = &func_args[i];
match argname { match argname {
Value::String(argname) => { Value::String(argname) => {
self.create_var(&format!("{}.{}", name, argname), &args[i], false); self.create_var(argname, &args[i], true);
} }
_ => self.error("Argument name must be a string"), _ => self.error("Argument name must be a string"),
} }
@ -451,20 +465,23 @@ impl Interpreter {
let name = self.run_nodes(function.get("body").unwrap().as_array().unwrap()); let name = self.run_nodes(function.get("body").unwrap().as_array().unwrap());
match name { match name {
Value::Object(name) => { Value::Object(name) => {
self.exit_from_named_scope();
return name.get("return").unwrap().clone(); return name.get("return").unwrap().clone();
} }
_ => return Value::Null, _ => {
self.exit_from_named_scope();
return Value::Null;
}
} }
} else { } else {
self.error(&format!( self.error(&format!(
"`{}` must have {} arguments, but {} is specified", "`{name}` must have {} arguments, but {real_len} is specified",
name,
func_args.len(), func_args.len(),
real_len
)); ));
} }
} }
} }
self.exit_from_named_scope();
Value::Null Value::Null
} }
fn define_fn(&mut self, value: &Map<String, Value>) { fn define_fn(&mut self, value: &Map<String, Value>) {
@ -479,15 +496,19 @@ impl Interpreter {
Value::Array(body) => match args { Value::Array(body) => match args {
Some(args) => match args { Some(args) => match args {
Value::Array(args) => { Value::Array(args) => {
// let args: Vec<String> = args.iter().map(|val| format!("{}.{}", name, val)).collect(); let name = self.get_name_scoped_name(name, true);
self.vars.insert( if !self.var_exists(&name) {
name.clone(), self.vars.insert(
Var { name.clone(),
scope: self.scope, Var {
body: json!({"args":args, "body":body}), scope: self.scope,
var_type: VarTypes::Function, body: json!({"name":name,"args":args, "body":body}),
}, var_type: VarTypes::Function,
); },
);
} else {
self.error(&format!("The variable `{}` already exist, rename function", name));
}
} }
_ => self.error("Arguments must be an array of strings"), _ => self.error("Arguments must be an array of strings"),
}, },
@ -608,6 +629,16 @@ impl Interpreter {
self.scopes.push(Vec::new()); self.scopes.push(Vec::new());
} }
fn enter_the_named_scope(&mut self, name: String) {
self.enter_the_scope();
self.named_scopes.push(name);
}
fn exit_from_named_scope(&mut self) {
self.exit_from_scope();
self.named_scopes.pop();
}
fn exit_from_scope(&mut self) { fn exit_from_scope(&mut self) {
self.delete_last_scope(); self.delete_last_scope();
self.scope -= 1; self.scope -= 1;
@ -626,7 +657,27 @@ impl Interpreter {
self.create_var(name, value, true); self.create_var(name, value, true);
} }
} }
fn get_name_scoped_name(&mut self, name: &String, to_create: bool) -> String {
let n_len = self.named_scopes.len();
if n_len > 0 {
let new_name = format!("{}.{name}", self.named_scopes[n_len - 1]);
if to_create {
new_name
} else {
if let Some(_) = self.vars.get(&new_name) {
new_name
} else {
name.clone()
}
}
} else {
name.clone()
}
}
fn create_var(&mut self, name: &String, value: &Value, panic: bool) { fn create_var(&mut self, name: &String, value: &Value, panic: bool) {
let name = self.get_name_scoped_name(name, true);
if !self.var_exists(&name) { if !self.var_exists(&name) {
match value { match value {
Value::Object(_) => { Value::Object(_) => {
@ -639,7 +690,7 @@ impl Interpreter {
var_type: VarTypes::Variable, var_type: VarTypes::Variable,
}, },
); );
self.scopes[self.scope].push(name.clone()) self.scopes[self.scope].push(name)
} }
_ => { _ => {
self.vars.insert( self.vars.insert(
@ -657,13 +708,14 @@ impl Interpreter {
if panic { if panic {
self.error(&format!("The variable {} already exist, use assign", name)); self.error(&format!("The variable {} already exist, use assign", name));
} else { } else {
self.assign_var(name, value); self.assign_var(&name, value);
} }
} }
} }
fn delete(&mut self, var_name: &String, panic: bool) { fn delete(&mut self, var_name: &String, panic: bool) {
if self.var_exists(var_name) { let var_name = self.get_name_scoped_name(var_name, false);
self.vars.remove(var_name); if self.var_exists(&var_name) {
self.vars.remove(&var_name);
} else { } else {
if panic { if panic {
self.error(&format!( self.error(&format!(
@ -675,7 +727,8 @@ impl Interpreter {
} }
fn get_var(&mut self, var_name: &String) -> &Var { fn get_var(&mut self, var_name: &String) -> &Var {
let var = self.vars.get(var_name); let var_name = self.get_name_scoped_name(var_name, false);
let var = self.vars.get(&var_name);
match var { match var {
Some(var) => return var, Some(var) => return var,
None => { None => {
@ -698,11 +751,12 @@ impl Interpreter {
fn assign(&mut self, vars: &Map<String, Value>) { fn assign(&mut self, vars: &Map<String, Value>) {
for (name, value) in vars { for (name, value) in vars {
self.assign_var(name, value); self.assign_var(&name, value);
} }
} }
fn assign_var(&mut self, name: &String, value: &Value) { fn assign_var(&mut self, name: &String, value: &Value) {
let scope = self.get_var_scope(name); let name = self.get_name_scoped_name(name, false);
let scope = self.get_var_scope(&name);
match value { match value {
Value::Object(_) => { Value::Object(_) => {
let value = self.eval_node(value); let value = self.eval_node(value);
@ -727,15 +781,17 @@ impl Interpreter {
} }
} }
} }
fn var_exists(&self, name: &String) -> bool { fn var_exists(&mut self, name: &String) -> bool {
match self.vars.get(name) { let name = self.get_name_scoped_name(name, true);
match self.vars.get(&name) {
Some(_) => true, Some(_) => true,
None => false, None => false,
} }
} }
fn variable_reference(&mut self, name: &String) -> Value { fn variable_reference(&mut self, name: &String) -> Value {
if self.var_exists(name) { let name = self.get_name_scoped_name(name, false);
if self.var_exists(&name) {
return json!({ "var": name }); return json!({ "var": name });
} else { } else {
self.error(&format!( self.error(&format!(

View file

@ -23,7 +23,7 @@ mod interpreter;
use interpreter::Interpreter; use interpreter::Interpreter;
fn main() { fn main() {
// #[cfg(not(debug_assertions))] #[cfg(not(debug_assertions))]
std::panic::set_hook(Box::new(|info| { std::panic::set_hook(Box::new(|info| {
eprint!( eprint!(
"{}", "{}",