true local contexts
This commit is contained in:
@@ -2,13 +2,13 @@ use super::value::Value;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Context {
|
||||
pub struct Context<'par> {
|
||||
dict: HashMap<String, Value>,
|
||||
parent: Option<Box<Context>>,
|
||||
parent: Option<&'par Context<'par>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(parent: Option<Box<Context>>) -> Context {
|
||||
impl<'par> Context<'par> {
|
||||
pub fn new(parent: Option<&'par Context<'par>>) -> Context<'par> {
|
||||
Context {
|
||||
dict: HashMap::new(),
|
||||
parent,
|
||||
|
||||
@@ -470,11 +470,16 @@ impl Instruction {
|
||||
fn run_all(
|
||||
ins: &Vec<Instruction>,
|
||||
ctx: &mut Context,
|
||||
globals: &Context,
|
||||
) -> 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")) {
|
||||
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<Value> =
|
||||
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
|
||||
|
||||
12
src/lib.rs
12
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<dyn Error>> {
|
||||
pub fn run_file(filename: &str) -> Result<(), Box<dyn Error>> {
|
||||
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 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 {
|
||||
ins.run(&mut ctx)?;
|
||||
ins.run(&mut main_ctx, &ctx)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use plxml::run;
|
||||
use plxml::run_file;
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ impl Function {
|
||||
&self,
|
||||
args: Vec<Value>,
|
||||
ctx: &mut Context,
|
||||
globals: &Context,
|
||||
) -> Result<Option<Value>, Box<dyn Error>> {
|
||||
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")))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user