true local contexts
This commit is contained in:
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
12
src/lib.rs
12
src/lib.rs
@@ -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(())
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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")))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user