From 0676d8691f7d16896a22b41add4a271f0705964a Mon Sep 17 00:00:00 2001 From: Artemy Date: Thu, 18 Aug 2022 17:45:27 +0300 Subject: [PATCH] feat: import --- src/interpreter.rs | 188 ++++++++++++++++++++++++++------------------- 1 file changed, 107 insertions(+), 81 deletions(-) diff --git a/src/interpreter.rs b/src/interpreter.rs index de7c63c..c0707c9 100644 --- a/src/interpreter.rs +++ b/src/interpreter.rs @@ -29,87 +29,13 @@ impl Interpreter { self.exit_from_scope(); } pub fn new(file_path: String) -> Self { - match Path::new(&file_path) - .extension() - .and_then(OsStr::to_str) - .expect("The file must have the extension (.yaml, .json, .json5, .onla or .conla)") - { - "yaml" => { - let file_input = fs::read_to_string(&file_path).expect("File reading error"); - let obj: serde_json::Value = - serde_yaml::from_str(&file_input).unwrap_or_else(|x| { - match x.location() { - Some(location) => { - eprintln!( - "{file_path}:{}:{} --> {x}", - location.column(), - location.line() - ); - } - None => { - eprintln!("{}", x); - } - } - - std::process::exit(1); - }); - let commands = obj.as_array().unwrap_or_else(|| { - obj.get("main") - .expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])") - .as_array() - .expect("The program must be an array of commands") - }); - Self { - commands: commands.clone(), - vars: HashMap::new(), - pos: 1, - scope: 0, - scopes: Vec::new(), - named_scopes: Vec::new(), - } - } - "conla" => { - let file_input = File::open(file_path).expect("File reading error"); - let obj: serde_json::Value = rmp_serde::from_read(file_input) - .expect(".conla file (MessagePack) is invalid! "); - let commands = obj.as_array().unwrap_or_else(|| { - obj.get("main") - .expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])") - .as_array() - .expect("The program must be an array of commands") - }); - Self { - commands: commands.clone(), - vars: HashMap::new(), - pos: 1, - scope: 0, - scopes: Vec::new(), - named_scopes: Vec::new(), - } - } - _ => { - let file_input = fs::read_to_string(&file_path).expect("File reading error"); - let obj: serde_json::Value = - json5::from_str::(&file_input).unwrap_or_else(|x| { - eprintln!("{file_path}{x}"); - std::process::exit(1); - }); - let commands = obj.as_array().unwrap_or_else(|| { - obj.get("main") - .expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])") - .as_array() - .expect("The program must be an array of commands") - }); - - Self { - commands: commands.clone(), - vars: HashMap::new(), - pos: 1, - scope: 0, - scopes: Vec::new(), - named_scopes: Vec::new(), - } - } + Self { + commands: Interpreter::get_commands(file_path), + vars: HashMap::new(), + pos: 1, + scope: 0, + scopes: Vec::new(), + named_scopes: Vec::new(), } } @@ -141,6 +67,70 @@ impl Interpreter { } } + fn get_commands(file_path: String) -> Vec { + match Path::new(&file_path) + .extension() + .and_then(OsStr::to_str) + .expect("The file must have the extension (.yaml, .json, .json5, .onla or .conla)") + { + "yaml" => { + let file_input = fs::read_to_string(&file_path).expect("File reading error"); + let obj: serde_json::Value = + serde_yaml::from_str(&file_input).unwrap_or_else(|x| { + match x.location() { + Some(location) => { + eprintln!( + "{file_path}:{}:{} --> {x}", + location.column(), + location.line() + ); + } + None => { + eprintln!("{}", x); + } + } + + std::process::exit(1); + }); + let commands = obj.as_array().unwrap_or_else(|| { + obj.get("main") + .expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])") + .as_array() + .expect("The program must be an array of commands") + }); + commands.clone() + } + "conla" => { + let file_input = File::open(file_path).expect("File reading error"); + let obj: serde_json::Value = rmp_serde::from_read(file_input) + .expect(".conla file (MessagePack) is invalid! "); + let commands = obj.as_array().unwrap_or_else(|| { + obj.get("main") + .expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])") + .as_array() + .expect("The program must be an array of commands") + }); + commands.clone() + } + _ => { + let file_input = fs::read_to_string(&file_path).expect("File reading error"); + let obj: serde_json::Value = + json5::from_str::(&file_input).unwrap_or_else(|x| { + eprintln!("{file_path}{x}"); + std::process::exit(1); + }); + let commands = obj.as_array().unwrap_or_else(|| { + obj.get("main") + .expect("Each program must contain a `{main: [..commands]}` object or be a command array ([..commands])") + .as_array() + .expect("The program must be an array of commands") + }); + + commands.clone() + } + } + } + fn convert_to_yaml(&self, output_path: String) { let mut output = File::create(output_path).expect("Failed to create output file"); write!( @@ -352,6 +342,14 @@ impl Interpreter { }, "return" => return json!({ "return": value }), + "import" => match value { + Value::Object(value) => { + self.import(value); + } + _ => { + self.error("Unsupported data type for the `obj` argument, must be an array"); + } + }, name => match value { Value::Array(value) => { return self.run_fn(name.to_string(), value); @@ -390,6 +388,34 @@ impl Interpreter { return Value::Null; } + fn import(&mut self, value: &Map) { + let path = value + .get("path") + .expect("The import must contain the `path` argument"); + let as_name = value + .get("as") + .expect("The import must contain the `as` argument"); + + if let Value::String(path) = path.clone() { + if let Value::String(as_name) = as_name.clone() { + let commands = Interpreter::get_commands(path); + let length = commands.len(); + + self.named_scopes.push(as_name); + for i in 0..length { + let command = &commands[i]; + self.eval_node(command); + self.pos = i; + } + self.named_scopes.pop(); + } else { + self.error("`as` argument must be a string"); + } + } else { + self.error("`path` argument must be a string"); + } + } + fn calc_arr(&mut self, value: &Vec) -> Value { Value::Array( value