feat: beta functions

This commit is contained in:
Artemy 2022-08-15 16:12:58 +03:00
parent ef212320da
commit 1a693e38dd
4 changed files with 238 additions and 93 deletions

View file

@ -275,6 +275,25 @@
"After scope", "After scope",
['isExist("scoped"): ', { isExist: "scoped" }], ['isExist("scoped"): ', { isExist: "scoped" }],
"Creating function `sum`",
{
fn: {
name: "sum",
args: ["first", "second"],
body: [
{
return: {
calc: [{ var: "sum.first" }, "+", { var: "sum.second" }],
},
},
],
},
},
"Run function `sum`",
["fn sum(first, second){ return first+second}; sum(2,2) = ", { sum: [2, 2] }],
"\nInput a var", "\nInput a var",
{ {
let: { let: {

View file

@ -113,7 +113,7 @@ impl Interpreter {
"var" => match value { "var" => match value {
Value::String(value) => { Value::String(value) => {
return self.get_var(value); return self.get_var(value).body.clone();
} }
_ => { _ => {
self.error("Unsupported data type for the `var` argument, must be a string"); self.error("Unsupported data type for the `var` argument, must be a string");
@ -167,6 +167,14 @@ impl Interpreter {
self.error("Unsupported data type for the `if` argument, must be an object"); self.error("Unsupported data type for the `if` argument, must be an object");
} }
}, },
"fn" => match value {
Value::Object(value) => {
self.define_fn(value);
}
_ => {
self.error("Unsupported data type for the `fn` argument, must be an object");
}
},
"loop" => match value { "loop" => match value {
Value::Array(value) => { Value::Array(value) => {
return self.loop_cycle(value); return self.loop_cycle(value);
@ -206,9 +214,16 @@ impl Interpreter {
self.error("Unsupported data type for the `obj` argument, must be an array"); self.error("Unsupported data type for the `obj` argument, must be an array");
} }
}, },
name => {
self.unk_token(&name); "return" => return json!({ "return": value }),
} name => match value {
Value::Array(value) => {
return self.run_fn(name.to_string(), value);
}
_ => {
self.unk_token(&name);
}
},
} }
} }
} }
@ -231,7 +246,8 @@ impl Interpreter {
Value::Array(command) => { Value::Array(command) => {
self.print(command, true); self.print(command, true);
} }
_ => { val => {
println!("{}", serde_json::to_string_pretty(val).unwrap());
self.error("Unsupported data type for the command"); self.error("Unsupported data type for the command");
} }
} }
@ -280,6 +296,86 @@ impl Interpreter {
Value::String(input.trim_end().to_string()) Value::String(input.trim_end().to_string())
} }
fn run_fn(&mut self, name: String, args: &Vec<Value>) -> Value {
let function = self.get_var(&name);
match function.var_type {
VarTypes::Variable => {
self.error(&format!("`{}` not a function", name));
}
VarTypes::Function => {
let function = function.body.clone();
let real_len = args.len();
let func_args = function.get("args").unwrap().as_array().unwrap();
if real_len == func_args.len() {
self.enter_the_scope();
for i in 0..real_len {
let argname = &func_args[i];
match argname {
Value::String(argname) => {
self.create_var(&format!("{}.{}", name, argname), &args[i], false);
}
_ => self.error("Argument name must be a string"),
}
}
let name = self.run_nodes(function.get("body").unwrap().as_array().unwrap());
match name {
Value::Object(name) => {
let result = self.eval_node(&name.get("return").unwrap());
self.exit_from_scope();
return result;
}
_ => return Value::Null,
}
} else {
self.error(&format!(
"`{}` must have {} arguments, but {} is specified",
name,
func_args.len(),
real_len
));
}
}
}
self.exit_from_scope();
Value::Null
}
fn define_fn(&mut self, value: &Map<String, Value>) {
let name = &value.get("name");
let body = &value.get("body");
let args = &value.get("args");
match name {
Some(name) => match name {
Value::String(name) => match body {
Some(body) => match body {
Value::Array(body) => match args {
Some(args) => match args {
Value::Array(args) => {
// let args: Vec<String> = args.iter().map(|val| format!("{}.{}", name, val)).collect();
self.vars.insert(
name.clone(),
Var {
scope: self.scope,
body: json!({"args":args, "body":body}),
var_type: VarTypes::Function,
},
);
}
_ => self.error("Arguments must be an array of strings"),
},
None => self
.error("Each function must have an array of arguments or an empty array instead of them"),
},
_ => self.error("Body must be an array of commands"),
},
None => self.error("Each function must have a body"),
},
_ => self.error("Name must be a string"),
},
None => self.error("Function must have a name"),
}
}
fn if_node(&mut self, value: &Map<String, Value>) -> Value { fn if_node(&mut self, value: &Map<String, Value>) -> Value {
let condition = self.eval_node(&value["condition"]); let condition = self.eval_node(&value["condition"]);
let nodes = &value.get("body"); let nodes = &value.get("body");
@ -292,43 +388,23 @@ impl Interpreter {
Value::Array(else_nodes) => { Value::Array(else_nodes) => {
if condition == true { if condition == true {
let name = self.run_nodes(nodes); let name = self.run_nodes(nodes);
if name == "break" { return name;
return Value::String("break".to_string());
}
if name == "continue" {
return Value::String("continue".to_string());
}
} else { } else {
let name = self.run_nodes(else_nodes); let name = self.run_nodes(else_nodes);
if name == "break" { return name;
return Value::String("break".to_string());
}
if name == "continue" {
return Value::String("continue".to_string());
}
}; };
} }
_ => { _ => {
if condition == true { if condition == true {
let name = self.run_nodes(nodes); let name = self.run_nodes(nodes);
if name == "break" { return name;
return Value::String("break".to_string());
}
if name == "continue" {
return Value::String("continue".to_string());
}
} }
} }
}, },
None => { None => {
if condition == true { if condition == true {
let name = self.run_nodes(nodes); let name = self.run_nodes(nodes);
if name == "break" { return name;
return Value::String("break".to_string());
}
if name == "continue" {
return Value::String("continue".to_string());
}
} }
} }
}, },
@ -344,28 +420,54 @@ impl Interpreter {
fn loop_cycle(&mut self, value: &Vec<Value>) -> Value { fn loop_cycle(&mut self, value: &Vec<Value>) -> Value {
loop { loop {
let name = self.run_nodes(value); let name = self.run_nodes(value);
if name == "break" { match name {
break Value::Null; Value::String(name) => {
} if name == "break" {
if name == "continue" { break Value::Null;
continue; } else if name == "continue" {
continue;
}
}
Value::Object(_) => {
return name;
}
_ => {}
} }
} }
} }
fn run_nodes(&mut self, arr: &Vec<Value>) -> String { fn run_nodes(&mut self, arr: &Vec<Value>) -> Value {
self.scope += 1; self.enter_the_scope();
self.scopes.push(Vec::new());
for command in arr { for command in arr {
let to_do = self.eval_node(command); let to_do = self.eval_node(command);
match to_do { match to_do {
Value::String(name) => return name, Value::String(name) => {
if name == "break" || name == "continue" {
return Value::String(name);
}
}
Value::Object(name) => {
let check = name.get("return");
match check {
Some(_) => return Value::Object(name),
None => {}
}
}
_ => {} _ => {}
} }
} }
self.exit_from_scope();
Value::String("end".to_string())
}
fn enter_the_scope(&mut self) {
self.scope += 1;
self.scopes.push(Vec::new());
}
fn exit_from_scope(&mut self) {
self.delete_last_scope(); self.delete_last_scope();
self.scope -= 1; self.scope -= 1;
"end".to_string()
} }
fn delete_last_scope(&mut self) { fn delete_last_scope(&mut self) {
@ -378,36 +480,44 @@ impl Interpreter {
fn define(&mut self, vars: &Map<String, Value>) { fn define(&mut self, vars: &Map<String, Value>) {
for (name, value) in vars { for (name, value) in vars {
if !self.var_exists(&name) { self.create_var(name, value, true);
match value { }
Value::Object(_) => { }
let value = self.eval_node(value); fn create_var(&mut self, name: &String, value: &Value, panic: bool) {
self.vars.insert( if !self.var_exists(&name) {
name.clone(), match value {
Var { Value::Object(_) => {
scope: self.scope, let value = self.eval_node(value);
body: value, self.vars.insert(
}, name.clone(),
); Var {
self.scopes[self.scope].push(name.clone()) scope: self.scope,
} body: value,
_ => { var_type: VarTypes::Variable,
self.vars.insert( },
name.clone(), );
Var { self.scopes[self.scope].push(name.clone())
scope: self.scope,
body: value.clone(),
},
);
self.scopes[self.scope].push(name.clone())
}
} }
} else { _ => {
self.vars.insert(
name.clone(),
Var {
scope: self.scope,
body: value.clone(),
var_type: VarTypes::Variable,
},
);
self.scopes[self.scope].push(name.clone())
}
}
} else {
if panic {
self.error(&format!("The variable {} already exist, use assign", name)); self.error(&format!("The variable {} already exist, use assign", name));
} else {
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) { if self.var_exists(var_name) {
self.vars.remove(var_name); self.vars.remove(var_name);
@ -421,15 +531,15 @@ impl Interpreter {
} }
} }
fn get_var(&mut self, var_name: &String) -> Value { fn get_var(&mut self, var_name: &String) -> &Var {
let var = self.vars.get(var_name); let var = self.vars.get(var_name);
match var { match var {
Some(var) => return var.body.clone(), Some(var) => return var,
None => { None => {
self.error(&format!("The variable {} does not exist", var_name)); self.error(&format!("The variable {} does not exist", var_name));
panic!();
} }
} }
Value::Null
} }
fn get_var_scope(&mut self, var_name: &String) -> usize { fn get_var_scope(&mut self, var_name: &String) -> usize {
@ -445,26 +555,35 @@ 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 {
let scope = self.get_var_scope(name); self.assign_var(name, value);
match value { }
Value::Object(_) => { }
let value = self.eval_node(value); fn assign_var(&mut self, name: &String, value: &Value) {
self.vars let scope = self.get_var_scope(name);
.insert(name.to_string(), Var { scope, body: value }); match value {
} Value::Object(_) => {
_ => { let value = self.eval_node(value);
self.vars.insert( self.vars.insert(
name.to_string(), name.to_string(),
Var { Var {
scope, scope,
body: value.clone(), body: value,
}, var_type: VarTypes::Variable,
); },
} );
}
_ => {
self.vars.insert(
name.to_string(),
Var {
scope,
body: value.clone(),
var_type: VarTypes::Variable,
},
);
} }
} }
} }
fn var_exists(&self, name: &String) -> bool { fn var_exists(&self, name: &String) -> bool {
match self.vars.get(name) { match self.vars.get(name) {
Some(_) => true, Some(_) => true,

View file

@ -15,15 +15,15 @@ mod interpreter;
use interpreter::Interpreter; use interpreter::Interpreter;
fn main() { fn main() {
std::panic::set_hook(Box::new(|info| { // std::panic::set_hook(Box::new(|info| {
eprint!( // eprint!(
"{msg}", // "{msg}",
msg = match info.payload().downcast_ref::<String>() { // msg = match info.payload().downcast_ref::<String>() {
None => "Program panicked without a message!", // None => "Program panicked without a message!",
Some(x) => x, // Some(x) => x,
} // }
); // );
})); // }));
let start = Instant::now(); let start = Instant::now();
let args = Args::parse(); let args = Args::parse();

View file

@ -3,5 +3,12 @@ use serde::{Deserialize, Serialize};
#[derive(Serialize, Deserialize, Debug, Clone)] #[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Var { pub struct Var {
pub scope: usize, pub scope: usize,
pub var_type: VarTypes,
pub body: serde_json::Value, pub body: serde_json::Value,
} }
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum VarTypes {
Variable,
Function,
}