From d2456ef681dacdb8c7762c8471bfdaea596ced43 Mon Sep 17 00:00:00 2001 From: Altareos Date: Fri, 11 Mar 2022 11:11:03 +0100 Subject: [PATCH] true local contexts --- src/context.rs | 8 ++-- src/instruction.rs | 101 ++++++++++++++++++++++++++++----------------- src/lib.rs | 12 ++++-- src/main.rs | 4 +- src/value.rs | 3 +- 5 files changed, 79 insertions(+), 49 deletions(-) diff --git a/src/context.rs b/src/context.rs index cdbb51e..09ade12 100644 --- a/src/context.rs +++ b/src/context.rs @@ -2,13 +2,13 @@ use super::value::Value; use std::collections::HashMap; #[derive(Clone)] -pub struct Context { +pub struct Context<'par> { dict: HashMap, - parent: Option>, + parent: Option<&'par Context<'par>>, } -impl Context { - pub fn new(parent: Option>) -> Context { +impl<'par> Context<'par> { + pub fn new(parent: Option<&'par Context<'par>>) -> Context<'par> { Context { dict: HashMap::new(), parent, diff --git a/src/instruction.rs b/src/instruction.rs index 1900308..745841e 100644 --- a/src/instruction.rs +++ b/src/instruction.rs @@ -470,11 +470,16 @@ impl Instruction { fn run_all( ins: &Vec, ctx: &mut Context, + globals: &Context, ) -> Result>, Box> { - ins.iter().map(|i| i.run(ctx)).collect() + ins.iter().map(|i| i.run(ctx, globals)).collect() } - pub fn run(&self, ctx: &mut Context) -> Result, Box> { + pub fn run( + &self, + ctx: &mut Context, + globals: &Context, + ) -> Result, Box> { Ok(if let None = ctx.value(&String::from("__return")) { match self { Instruction::Value(key) => { @@ -484,13 +489,13 @@ impl Instruction { }) } Instruction::Assign(key, ins) => { - let v = ins.run(ctx)?.ok_or(InvalidValue("assign"))?; + let v = ins.run(ctx, globals)?.ok_or(InvalidValue("assign"))?; ctx.assign(key.clone(), v); None } Instruction::Integer(val) => Some(Value::Integer(val.parse()?)), Instruction::IntegerCast(ins) => Some(Value::Integer( - match ins.run(ctx)?.ok_or(InvalidValue("integer"))? { + match ins.run(ctx, globals)?.ok_or(InvalidValue("integer"))? { Value::Integer(i) => i, Value::Float(f) => f as i64, Value::String(s) => s.parse()?, @@ -499,7 +504,7 @@ impl Instruction { )), Instruction::Float(val) => Some(Value::Float(val.parse()?)), Instruction::FloatCast(ins) => Some(Value::Float( - match ins.run(ctx)?.ok_or(InvalidValue("float"))? { + match ins.run(ctx, globals)?.ok_or(InvalidValue("float"))? { Value::Integer(i) => i as f64, Value::Float(f) => f, Value::String(s) => s.parse()?, @@ -508,7 +513,7 @@ impl Instruction { )), Instruction::String(val) => Some(Value::String(val.clone())), Instruction::StringCast(ins) => Some(Value::String( - match ins.run(ctx)?.ok_or(InvalidValue("string"))? { + match ins.run(ctx, globals)?.ok_or(InvalidValue("string"))? { Value::Integer(i) => i.to_string(), Value::Float(f) => f.to_string(), Value::String(s) => s, @@ -516,34 +521,40 @@ impl Instruction { }, )), Instruction::Array(args) => Some(Value::Array(Rc::new(RefCell::new( - Instruction::run_all(args, ctx)?.ok_or(InvalidValue("array"))?, + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("array"))?, )))), Instruction::Add(args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("add"))?; + let vals = + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("add"))?; Some(Instruction::add(vals)?) } Instruction::Subtract(args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("subtract"))?; + let vals = Instruction::run_all(args, ctx, globals)? + .ok_or(InvalidValue("subtract"))?; Some(Instruction::subtract(vals)?) } Instruction::Multiply(args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("multiply"))?; + let vals = Instruction::run_all(args, ctx, globals)? + .ok_or(InvalidValue("multiply"))?; Some(Instruction::multiply(vals)?) } Instruction::Divide(args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("divide"))?; + let vals = + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("divide"))?; Some(Instruction::divide(vals)?) } Instruction::And(args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("and"))?; + let vals = + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("and"))?; Some(Instruction::and(vals)) } Instruction::Or(args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("or"))?; + let vals = + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("or"))?; Some(Instruction::or(vals)) } Instruction::Not(arg) => Some(Value::Integer( - if arg.run(ctx)?.ok_or(InvalidValue("not"))?.to_bool() { + if arg.run(ctx, globals)?.ok_or(InvalidValue("not"))?.to_bool() { 0 } else { 1 @@ -551,8 +562,8 @@ impl Instruction { )), Instruction::Equal(v1, v2) => Some(Value::Integer( if Instruction::compare( - v1.run(ctx)?.ok_or(InvalidValue("equal"))?, - v2.run(ctx)?.ok_or(InvalidValue("equal"))?, + v1.run(ctx, globals)?.ok_or(InvalidValue("equal"))?, + v2.run(ctx, globals)?.ok_or(InvalidValue("equal"))?, )? == 0 { 1 @@ -562,8 +573,8 @@ impl Instruction { )), Instruction::Greater(v1, v2) => Some(Value::Integer( if Instruction::compare( - v1.run(ctx)?.ok_or(InvalidValue("greater"))?, - v2.run(ctx)?.ok_or(InvalidValue("greater"))?, + v1.run(ctx, globals)?.ok_or(InvalidValue("greater"))?, + v2.run(ctx, globals)?.ok_or(InvalidValue("greater"))?, )? > 0 { 1 @@ -573,8 +584,8 @@ impl Instruction { )), Instruction::Lower(v1, v2) => Some(Value::Integer( if Instruction::compare( - v1.run(ctx)?.ok_or(InvalidValue("lower"))?, - v2.run(ctx)?.ok_or(InvalidValue("lower"))?, + v1.run(ctx, globals)?.ok_or(InvalidValue("lower"))?, + v2.run(ctx, globals)?.ok_or(InvalidValue("lower"))?, )? < 0 { 1 @@ -583,10 +594,12 @@ impl Instruction { }, )), Instruction::Call(fct_ins, args) => { - let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("call"))?; - let fct_val = fct_ins.run(ctx)?.ok_or(InvalidValue("call"))?; + let vals = + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("call"))?; + let fct_val = fct_ins.run(ctx, globals)?.ok_or(InvalidValue("call"))?; if let Value::Function(f) = fct_val { - f.run(vals, ctx)? + let mut fun_ctx = Context::new(Some(globals)); + f.run(vals, &mut fun_ctx, globals)? } else if let Value::StdFunction(f) = fct_val { f(vals)? } else { @@ -595,13 +608,13 @@ impl Instruction { } Instruction::CallNamed(fct_name, args) => { let vals: Vec = - Instruction::run_all(args, ctx)?.ok_or(InvalidValue("call"))?; + Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("call"))?; let fct_val = ctx .value(&fct_name) .ok_or(UnknownVariable(fct_name.clone()))?; if let Value::Function(f) = fct_val { let mut local = ctx.clone(); - f.run(vals, &mut local)? + f.run(vals, &mut local, globals)? } else if let Value::StdFunction(f) = fct_val { f(vals)? } else { @@ -609,26 +622,26 @@ impl Instruction { } } Instruction::Return(ins) => { - let v = ins.run(ctx)?.ok_or(InvalidValue("return"))?; + let v = ins.run(ctx, globals)?.ok_or(InvalidValue("return"))?; ctx.assign(String::from("__return"), v); None } Instruction::If(cond, then) => { - if cond.run(ctx)?.ok_or(InvalidValue("if"))?.to_bool() { + if cond.run(ctx, globals)?.ok_or(InvalidValue("if"))?.to_bool() { for i in then { - i.run(ctx)?; + i.run(ctx, globals)?; } } None } Instruction::IfElse(cond, then, els) => { - if cond.run(ctx)?.ok_or(InvalidValue("if"))?.to_bool() { + if cond.run(ctx, globals)?.ok_or(InvalidValue("if"))?.to_bool() { for i in then { - i.run(ctx)?; + i.run(ctx, globals)?; } } else { for i in els { - i.run(ctx)?; + i.run(ctx, globals)?; } } None @@ -640,13 +653,17 @@ impl Instruction { step, body, } => { - if let Value::Integer(f) = from.run(ctx)?.ok_or(InvalidValue("for"))? { - if let Value::Integer(t) = to.run(ctx)?.ok_or(InvalidValue("for"))? { - if let Value::Integer(s) = step.run(ctx)?.ok_or(InvalidValue("for"))? { + if let Value::Integer(f) = from.run(ctx, globals)?.ok_or(InvalidValue("for"))? { + if let Value::Integer(t) = + to.run(ctx, globals)?.ok_or(InvalidValue("for"))? + { + if let Value::Integer(s) = + step.run(ctx, globals)?.ok_or(InvalidValue("for"))? + { for i in (f..t).step_by(s.try_into()?) { ctx.assign(variable.clone(), Value::Integer(i)); for ins in body { - ins.run(ctx)?; + ins.run(ctx, globals)?; } } } @@ -655,11 +672,13 @@ impl Instruction { None } Instruction::Each(variable, array_ins, body) => { - if let Value::Array(v) = array_ins.run(ctx)?.ok_or(InvalidValue("each"))? { + if let Value::Array(v) = + array_ins.run(ctx, globals)?.ok_or(InvalidValue("each"))? + { for i in v.borrow().iter() { ctx.assign(variable.clone(), i.clone()); for ins in body { - ins.run(ctx)?; + ins.run(ctx, globals)?; } } } else { @@ -668,9 +687,13 @@ impl Instruction { None } Instruction::While(cond, body) => { - while cond.run(ctx)?.ok_or(InvalidValue("while"))?.to_bool() { + while cond + .run(ctx, globals)? + .ok_or(InvalidValue("while"))? + .to_bool() + { for ins in body { - ins.run(ctx)?; + ins.run(ctx, globals)?; } } None diff --git a/src/lib.rs b/src/lib.rs index 53c8ba5..bfd4522 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,9 +15,13 @@ use error::{InvalidProgram, MissingChild, Unnamed}; use instruction::Instruction; use value::{Function, Value}; -pub fn run(filename: &str) -> Result<(), Box> { +pub fn run_file(filename: &str) -> Result<(), Box> { let contents = fs::read_to_string(filename)?; - let doc = Document::parse(&contents)?; + run(contents) +} + +pub fn run(program: String) -> Result<(), Box> { + let doc = Document::parse(&program)?; let root = doc.root(); let mut ctx = Context::new(None); @@ -44,8 +48,10 @@ pub fn run(filename: &str) -> Result<(), Box> { ); } + let mut main_ctx = Context::new(Some(&ctx)); + for ins in main_ast { - ins.run(&mut ctx)?; + ins.run(&mut main_ctx, &ctx)?; } Ok(()) diff --git a/src/main.rs b/src/main.rs index 34480b3..e78f6c7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,9 +1,9 @@ -use plxml::run; +use plxml::run_file; use std::env; fn main() { let args: Vec = env::args().collect(); - if let Err(e) = run(&args[1]) { + if let Err(e) = run_file(&args[1]) { eprintln!("Error occurred: {}", e); } } diff --git a/src/value.rs b/src/value.rs index 51b46b6..580e9a4 100644 --- a/src/value.rs +++ b/src/value.rs @@ -16,6 +16,7 @@ impl Function { &self, args: Vec, ctx: &mut Context, + globals: &Context, ) -> Result, Box> { if args.len() != self.args.len() { Err(BadArgumentCount("function", args.len()))? @@ -25,7 +26,7 @@ impl Function { .zip(args.into_iter()) .for_each(|(p, a)| ctx.assign(p.clone(), a)); for i in self.ins.iter() { - i.run(ctx)?; + i.run(ctx, globals)?; } Ok(ctx.take(&String::from("__return"))) }