true local contexts

This commit is contained in:
2022-03-11 11:11:03 +01:00
parent cb4fda6631
commit d2456ef681
5 changed files with 79 additions and 49 deletions

View File

@@ -2,13 +2,13 @@ use super::value::Value;
use std::collections::HashMap; use std::collections::HashMap;
#[derive(Clone)] #[derive(Clone)]
pub struct Context { pub struct Context<'par> {
dict: HashMap<String, Value>, dict: HashMap<String, Value>,
parent: Option<Box<Context>>, parent: Option<&'par Context<'par>>,
} }
impl Context { impl<'par> Context<'par> {
pub fn new(parent: Option<Box<Context>>) -> Context { pub fn new(parent: Option<&'par Context<'par>>) -> Context<'par> {
Context { Context {
dict: HashMap::new(), dict: HashMap::new(),
parent, parent,

View File

@@ -470,11 +470,16 @@ impl Instruction {
fn run_all( fn run_all(
ins: &Vec<Instruction>, ins: &Vec<Instruction>,
ctx: &mut Context, ctx: &mut Context,
globals: &Context,
) -> Result<Option<Vec<Value>>, Box<dyn Error>> { ) -> Result<Option<Vec<Value>>, Box<dyn Error>> {
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<Option<Value>, Box<dyn Error>> { pub fn run(
&self,
ctx: &mut Context,
globals: &Context,
) -> Result<Option<Value>, Box<dyn Error>> {
Ok(if let None = ctx.value(&String::from("__return")) { Ok(if let None = ctx.value(&String::from("__return")) {
match self { match self {
Instruction::Value(key) => { Instruction::Value(key) => {
@@ -484,13 +489,13 @@ impl Instruction {
}) })
} }
Instruction::Assign(key, ins) => { 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); ctx.assign(key.clone(), v);
None None
} }
Instruction::Integer(val) => Some(Value::Integer(val.parse()?)), Instruction::Integer(val) => Some(Value::Integer(val.parse()?)),
Instruction::IntegerCast(ins) => Some(Value::Integer( 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::Integer(i) => i,
Value::Float(f) => f as i64, Value::Float(f) => f as i64,
Value::String(s) => s.parse()?, Value::String(s) => s.parse()?,
@@ -499,7 +504,7 @@ impl Instruction {
)), )),
Instruction::Float(val) => Some(Value::Float(val.parse()?)), Instruction::Float(val) => Some(Value::Float(val.parse()?)),
Instruction::FloatCast(ins) => Some(Value::Float( 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::Integer(i) => i as f64,
Value::Float(f) => f, Value::Float(f) => f,
Value::String(s) => s.parse()?, Value::String(s) => s.parse()?,
@@ -508,7 +513,7 @@ impl Instruction {
)), )),
Instruction::String(val) => Some(Value::String(val.clone())), Instruction::String(val) => Some(Value::String(val.clone())),
Instruction::StringCast(ins) => Some(Value::String( 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::Integer(i) => i.to_string(),
Value::Float(f) => f.to_string(), Value::Float(f) => f.to_string(),
Value::String(s) => s, Value::String(s) => s,
@@ -516,34 +521,40 @@ impl Instruction {
}, },
)), )),
Instruction::Array(args) => Some(Value::Array(Rc::new(RefCell::new( 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) => { 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)?) Some(Instruction::add(vals)?)
} }
Instruction::Subtract(args) => { 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)?) Some(Instruction::subtract(vals)?)
} }
Instruction::Multiply(args) => { 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)?) Some(Instruction::multiply(vals)?)
} }
Instruction::Divide(args) => { 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)?) Some(Instruction::divide(vals)?)
} }
Instruction::And(args) => { 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)) Some(Instruction::and(vals))
} }
Instruction::Or(args) => { 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)) Some(Instruction::or(vals))
} }
Instruction::Not(arg) => Some(Value::Integer( 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 0
} else { } else {
1 1
@@ -551,8 +562,8 @@ impl Instruction {
)), )),
Instruction::Equal(v1, v2) => Some(Value::Integer( Instruction::Equal(v1, v2) => Some(Value::Integer(
if Instruction::compare( if Instruction::compare(
v1.run(ctx)?.ok_or(InvalidValue("equal"))?, v1.run(ctx, globals)?.ok_or(InvalidValue("equal"))?,
v2.run(ctx)?.ok_or(InvalidValue("equal"))?, v2.run(ctx, globals)?.ok_or(InvalidValue("equal"))?,
)? == 0 )? == 0
{ {
1 1
@@ -562,8 +573,8 @@ impl Instruction {
)), )),
Instruction::Greater(v1, v2) => Some(Value::Integer( Instruction::Greater(v1, v2) => Some(Value::Integer(
if Instruction::compare( if Instruction::compare(
v1.run(ctx)?.ok_or(InvalidValue("greater"))?, v1.run(ctx, globals)?.ok_or(InvalidValue("greater"))?,
v2.run(ctx)?.ok_or(InvalidValue("greater"))?, v2.run(ctx, globals)?.ok_or(InvalidValue("greater"))?,
)? > 0 )? > 0
{ {
1 1
@@ -573,8 +584,8 @@ impl Instruction {
)), )),
Instruction::Lower(v1, v2) => Some(Value::Integer( Instruction::Lower(v1, v2) => Some(Value::Integer(
if Instruction::compare( if Instruction::compare(
v1.run(ctx)?.ok_or(InvalidValue("lower"))?, v1.run(ctx, globals)?.ok_or(InvalidValue("lower"))?,
v2.run(ctx)?.ok_or(InvalidValue("lower"))?, v2.run(ctx, globals)?.ok_or(InvalidValue("lower"))?,
)? < 0 )? < 0
{ {
1 1
@@ -583,10 +594,12 @@ impl Instruction {
}, },
)), )),
Instruction::Call(fct_ins, args) => { Instruction::Call(fct_ins, args) => {
let vals = Instruction::run_all(args, ctx)?.ok_or(InvalidValue("call"))?; let vals =
let fct_val = fct_ins.run(ctx)?.ok_or(InvalidValue("call"))?; 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 { 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 { } else if let Value::StdFunction(f) = fct_val {
f(vals)? f(vals)?
} else { } else {
@@ -595,13 +608,13 @@ impl Instruction {
} }
Instruction::CallNamed(fct_name, args) => { Instruction::CallNamed(fct_name, args) => {
let vals: Vec<Value> = let vals: Vec<Value> =
Instruction::run_all(args, ctx)?.ok_or(InvalidValue("call"))?; Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("call"))?;
let fct_val = ctx let fct_val = ctx
.value(&fct_name) .value(&fct_name)
.ok_or(UnknownVariable(fct_name.clone()))?; .ok_or(UnknownVariable(fct_name.clone()))?;
if let Value::Function(f) = fct_val { if let Value::Function(f) = fct_val {
let mut local = ctx.clone(); let mut local = ctx.clone();
f.run(vals, &mut local)? f.run(vals, &mut local, globals)?
} else if let Value::StdFunction(f) = fct_val { } else if let Value::StdFunction(f) = fct_val {
f(vals)? f(vals)?
} else { } else {
@@ -609,26 +622,26 @@ impl Instruction {
} }
} }
Instruction::Return(ins) => { 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); ctx.assign(String::from("__return"), v);
None None
} }
Instruction::If(cond, then) => { 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 { for i in then {
i.run(ctx)?; i.run(ctx, globals)?;
} }
} }
None None
} }
Instruction::IfElse(cond, then, els) => { 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 { for i in then {
i.run(ctx)?; i.run(ctx, globals)?;
} }
} else { } else {
for i in els { for i in els {
i.run(ctx)?; i.run(ctx, globals)?;
} }
} }
None None
@@ -640,13 +653,17 @@ impl Instruction {
step, step,
body, body,
} => { } => {
if let Value::Integer(f) = from.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)?.ok_or(InvalidValue("for"))? { if let Value::Integer(t) =
if let Value::Integer(s) = step.run(ctx)?.ok_or(InvalidValue("for"))? { 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()?) { for i in (f..t).step_by(s.try_into()?) {
ctx.assign(variable.clone(), Value::Integer(i)); ctx.assign(variable.clone(), Value::Integer(i));
for ins in body { for ins in body {
ins.run(ctx)?; ins.run(ctx, globals)?;
} }
} }
} }
@@ -655,11 +672,13 @@ impl Instruction {
None None
} }
Instruction::Each(variable, array_ins, body) => { 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() { for i in v.borrow().iter() {
ctx.assign(variable.clone(), i.clone()); ctx.assign(variable.clone(), i.clone());
for ins in body { for ins in body {
ins.run(ctx)?; ins.run(ctx, globals)?;
} }
} }
} else { } else {
@@ -668,9 +687,13 @@ impl Instruction {
None None
} }
Instruction::While(cond, body) => { 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 { for ins in body {
ins.run(ctx)?; ins.run(ctx, globals)?;
} }
} }
None None

View File

@@ -15,9 +15,13 @@ use error::{InvalidProgram, MissingChild, Unnamed};
use instruction::Instruction; use instruction::Instruction;
use value::{Function, Value}; use value::{Function, Value};
pub fn run(filename: &str) -> Result<(), Box<dyn Error>> { pub fn run_file(filename: &str) -> Result<(), Box<dyn Error>> {
let contents = fs::read_to_string(filename)?; let contents = fs::read_to_string(filename)?;
let doc = Document::parse(&contents)?; run(contents)
}
pub fn run(program: String) -> Result<(), Box<dyn Error>> {
let doc = Document::parse(&program)?;
let root = doc.root(); let root = doc.root();
let mut ctx = Context::new(None); let mut ctx = Context::new(None);
@@ -44,8 +48,10 @@ pub fn run(filename: &str) -> Result<(), Box<dyn Error>> {
); );
} }
let mut main_ctx = Context::new(Some(&ctx));
for ins in main_ast { for ins in main_ast {
ins.run(&mut ctx)?; ins.run(&mut main_ctx, &ctx)?;
} }
Ok(()) Ok(())

View File

@@ -1,9 +1,9 @@
use plxml::run; use plxml::run_file;
use std::env; use std::env;
fn main() { fn main() {
let args: Vec<String> = env::args().collect(); let args: Vec<String> = env::args().collect();
if let Err(e) = run(&args[1]) { if let Err(e) = run_file(&args[1]) {
eprintln!("Error occurred: {}", e); eprintln!("Error occurred: {}", e);
} }
} }

View File

@@ -16,6 +16,7 @@ impl Function {
&self, &self,
args: Vec<Value>, args: Vec<Value>,
ctx: &mut Context, ctx: &mut Context,
globals: &Context,
) -> Result<Option<Value>, Box<dyn Error>> { ) -> Result<Option<Value>, Box<dyn Error>> {
if args.len() != self.args.len() { if args.len() != self.args.len() {
Err(BadArgumentCount("function", args.len()))? Err(BadArgumentCount("function", args.len()))?
@@ -25,7 +26,7 @@ impl Function {
.zip(args.into_iter()) .zip(args.into_iter())
.for_each(|(p, a)| ctx.assign(p.clone(), a)); .for_each(|(p, a)| ctx.assign(p.clone(), a));
for i in self.ins.iter() { for i in self.ins.iter() {
i.run(ctx)?; i.run(ctx, globals)?;
} }
Ok(ctx.take(&String::from("__return"))) Ok(ctx.take(&String::from("__return")))
} }