0.1.1: structural reworks + dep version bump
This commit is contained in:
15
Cargo.lock
generated
15
Cargo.lock
generated
@@ -4,22 +4,13 @@ version = 3
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "plxml"
|
name = "plxml"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"roxmltree",
|
"roxmltree",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "roxmltree"
|
name = "roxmltree"
|
||||||
version = "0.14.1"
|
version = "0.19.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "921904a62e410e37e215c40381b7117f830d9d89ba60ab5236170541dd25646b"
|
checksum = "3cd14fd5e3b777a7422cca79358c57a8f6e3a703d9ac187448d0daf220c2407f"
|
||||||
dependencies = [
|
|
||||||
"xmlparser",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "xmlparser"
|
|
||||||
version = "0.13.3"
|
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
||||||
checksum = "114ba2b24d2167ef6d67d7d04c8cc86522b87f490025f39f0303b7db5bf5e3d8"
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "plxml"
|
name = "plxml"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
default-run = "interpreter"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
roxmltree = "0.14.1"
|
roxmltree = "0.19"
|
||||||
6
src/bin/compiler.rs
Normal file
6
src/bin/compiler.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if let Err(e) = plxml::compile_file(&args[1]) {
|
||||||
|
eprintln!("Error occurred: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
6
src/bin/interpreter.rs
Normal file
6
src/bin/interpreter.rs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if let Err(e) = plxml::run_file(&args[1]) {
|
||||||
|
eprintln!("Error occurred: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
42
src/compiler/compile.rs
Normal file
42
src/compiler/compile.rs
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
use std::error::Error;
|
||||||
|
use std::fs;
|
||||||
|
|
||||||
|
use roxmltree::Document;
|
||||||
|
|
||||||
|
use crate::error::{InvalidProgram, MissingChild};
|
||||||
|
use crate::instruction::Instruction;
|
||||||
|
use crate::util;
|
||||||
|
|
||||||
|
pub fn compile_file(filename: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let contents = fs::read_to_string(filename)?;
|
||||||
|
compile(contents)
|
||||||
|
}
|
||||||
|
|
||||||
|
trait Compile {
|
||||||
|
fn compile(&self);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Compile for Instruction {
|
||||||
|
fn compile(&self) {
|
||||||
|
unimplemented!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn compile(program: String) -> Result<(), Box<dyn Error>> {
|
||||||
|
let doc = Document::parse(&program)?;
|
||||||
|
let root = doc.root();
|
||||||
|
|
||||||
|
let main = root
|
||||||
|
.first_element_child()
|
||||||
|
.ok_or(InvalidProgram)?
|
||||||
|
.children()
|
||||||
|
.find(|node| util::tag_name(&node) == "main")
|
||||||
|
.ok_or(MissingChild("program", "main"))?;
|
||||||
|
let main_ast = Instruction::from_children(main)?;
|
||||||
|
|
||||||
|
for ins in main_ast {
|
||||||
|
ins.compile();
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
1
src/compiler/mod.rs
Normal file
1
src/compiler/mod.rs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
pub mod compile;
|
||||||
@@ -1,12 +1,7 @@
|
|||||||
use super::error::{
|
use super::error::{BadChildCount, MissingAttribute, MissingChild};
|
||||||
BadChildCount, IncompatibleValues, InvalidValue, MissingAttribute, MissingChild,
|
use crate::util;
|
||||||
UnknownVariable,
|
|
||||||
};
|
|
||||||
use super::{util, Context, Value};
|
|
||||||
use roxmltree::Node;
|
use roxmltree::Node;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
@@ -254,479 +249,4 @@ impl Instruction {
|
|||||||
.map(Instruction::new)
|
.map(Instruction::new)
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
|
||||||
if vals.iter().all(|v| matches!(v, Value::Integer(_))) {
|
|
||||||
Ok(Value::Integer(
|
|
||||||
vals.iter()
|
|
||||||
.map(|v| {
|
|
||||||
if let Value::Integer(i) = v {
|
|
||||||
Ok(i)
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("add"))?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sum::<Result<i64, Box<dyn Error>>>()?,
|
|
||||||
))
|
|
||||||
} else if vals
|
|
||||||
.iter()
|
|
||||||
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
|
||||||
{
|
|
||||||
Ok(Value::Real(
|
|
||||||
vals.iter()
|
|
||||||
.map(|v| {
|
|
||||||
if let Value::Integer(i) = v {
|
|
||||||
Ok(*i as f64)
|
|
||||||
} else if let Value::Real(f) = v {
|
|
||||||
Ok(*f)
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("add"))?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sum::<Result<f64, Box<dyn Error>>>()?,
|
|
||||||
))
|
|
||||||
} else if vals.iter().all(|v| {
|
|
||||||
matches!(v, Value::Integer(_))
|
|
||||||
|| matches!(v, Value::Real(_))
|
|
||||||
|| matches!(v, Value::String(_))
|
|
||||||
}) {
|
|
||||||
Ok(Value::String(
|
|
||||||
vals.iter()
|
|
||||||
.map(|v| {
|
|
||||||
Ok(if let Value::String(s) = v {
|
|
||||||
s.to_string()
|
|
||||||
} else if let Value::Integer(i) = v {
|
|
||||||
i.to_string()
|
|
||||||
} else if let Value::Real(f) = v {
|
|
||||||
f.to_string()
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("add"))?
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<String>, Box<dyn Error>>>()?
|
|
||||||
.join(""),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("add"))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn subtract(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
|
||||||
Ok(if vals.iter().all(|v| matches!(v, Value::Integer(_))) {
|
|
||||||
let first = match vals.first().ok_or(BadChildCount("subtract", 0usize))? {
|
|
||||||
Value::Integer(i) => i,
|
|
||||||
_ => Err(InvalidValue("subtract"))?,
|
|
||||||
};
|
|
||||||
Value::Integer(
|
|
||||||
*first
|
|
||||||
- vals
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.map(|v| {
|
|
||||||
if let Value::Integer(i) = v {
|
|
||||||
Ok(i)
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("subtract"))?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.sum::<Result<i64, Box<dyn Error>>>()?,
|
|
||||||
)
|
|
||||||
} else if vals
|
|
||||||
.iter()
|
|
||||||
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
|
||||||
{
|
|
||||||
let first = match vals.first().ok_or(BadChildCount("subtract", 0usize))? {
|
|
||||||
Value::Integer(v) => *v as f64,
|
|
||||||
Value::Real(v) => *v,
|
|
||||||
_ => Err(InvalidValue("subtract"))?,
|
|
||||||
};
|
|
||||||
Value::Real(
|
|
||||||
first
|
|
||||||
- vals
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.map(|val| {
|
|
||||||
Ok(match val {
|
|
||||||
Value::Integer(v) => *v as f64,
|
|
||||||
Value::Real(v) => *v,
|
|
||||||
_ => Err(InvalidValue("subtract"))?,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.sum::<Result<f64, Box<dyn Error>>>()?,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("subtract"))?
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn multiply(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
|
||||||
if vals.iter().all(|v| matches!(v, Value::Integer(_))) {
|
|
||||||
Ok(Value::Integer(
|
|
||||||
vals.iter()
|
|
||||||
.map(|v| {
|
|
||||||
if let Value::Integer(i) = v {
|
|
||||||
Ok(i)
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("multiply"))?
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.product::<Result<i64, Box<dyn Error>>>()?,
|
|
||||||
))
|
|
||||||
} else if vals
|
|
||||||
.iter()
|
|
||||||
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
|
||||||
{
|
|
||||||
Ok(Value::Real(
|
|
||||||
vals.iter()
|
|
||||||
.map(|val| {
|
|
||||||
Ok(match val {
|
|
||||||
Value::Integer(v) => *v as f64,
|
|
||||||
Value::Real(v) => *v,
|
|
||||||
_ => Err(InvalidValue("multiply"))?,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.product::<Result<f64, Box<dyn Error>>>()?,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("multiply"))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn divide(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
|
||||||
if vals
|
|
||||||
.iter()
|
|
||||||
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
|
||||||
{
|
|
||||||
let first = match vals.first().ok_or(BadChildCount("divide", 0))? {
|
|
||||||
Value::Integer(v) => *v as f64,
|
|
||||||
Value::Real(v) => *v,
|
|
||||||
_ => Err(InvalidValue("divide"))?,
|
|
||||||
};
|
|
||||||
Ok(Value::Real(
|
|
||||||
first
|
|
||||||
* vals
|
|
||||||
.iter()
|
|
||||||
.skip(1)
|
|
||||||
.map(|val| {
|
|
||||||
Ok(match val {
|
|
||||||
Value::Integer(v) => 1.0 / (*v as f64),
|
|
||||||
Value::Real(v) => 1.0 / *v,
|
|
||||||
_ => Err(InvalidValue("divide"))?,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.product::<Result<f64, Box<dyn Error>>>()?,
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("divide"))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn and(vals: Vec<Value>) -> Value {
|
|
||||||
Value::Integer(if vals.iter().all(Value::to_bool) {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn or(vals: Vec<Value>) -> Value {
|
|
||||||
Value::Integer(if vals.iter().any(Value::to_bool) {
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn compare(v1: Value, v2: Value) -> Result<i64, Box<dyn Error>> {
|
|
||||||
use std::cmp::Ordering;
|
|
||||||
match v1 {
|
|
||||||
Value::Integer(i1) => match v2 {
|
|
||||||
Value::Integer(i2) => Ok(i1 - i2),
|
|
||||||
Value::Real(f2) => Ok(
|
|
||||||
match (i1 as f64).partial_cmp(&f2).ok_or(IncompatibleValues)? {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
_ => Err(IncompatibleValues)?,
|
|
||||||
},
|
|
||||||
Value::Real(f1) => match v2 {
|
|
||||||
Value::Integer(i2) => Ok(
|
|
||||||
match f1.partial_cmp(&(i2 as f64)).ok_or(IncompatibleValues)? {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Value::Real(f2) => Ok(match f1.partial_cmp(&f2).ok_or(IncompatibleValues)? {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
}),
|
|
||||||
_ => Err(IncompatibleValues)?,
|
|
||||||
},
|
|
||||||
Value::String(s1) => {
|
|
||||||
if let Value::String(s2) = v2 {
|
|
||||||
Ok(match s1.cmp(&s2) {
|
|
||||||
Ordering::Less => -1,
|
|
||||||
Ordering::Equal => 0,
|
|
||||||
Ordering::Greater => 1,
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Err(IncompatibleValues)?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => Err(IncompatibleValues)?,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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, globals)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
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) => {
|
|
||||||
Some(match ctx.value(key).ok_or(UnknownVariable(key.clone()))? {
|
|
||||||
Value::Array(vecrc) => Value::Array(Rc::clone(vecrc)),
|
|
||||||
val => val.clone(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
Instruction::Assign(key, ins) => {
|
|
||||||
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, globals)?.ok_or(InvalidValue("integer"))? {
|
|
||||||
Value::Integer(i) => i,
|
|
||||||
Value::Real(f) => f as i64,
|
|
||||||
Value::String(s) => s.parse()?,
|
|
||||||
_ => Err(InvalidValue("integer"))?,
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::Real(val) => Some(Value::Real(val.parse()?)),
|
|
||||||
Instruction::RealCast(ins) => Some(Value::Real(
|
|
||||||
match ins.run(ctx, globals)?.ok_or(InvalidValue("real"))? {
|
|
||||||
Value::Integer(i) => i as f64,
|
|
||||||
Value::Real(f) => f,
|
|
||||||
Value::String(s) => s.parse()?,
|
|
||||||
_ => Err(InvalidValue("real"))?,
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::String(val) => Some(Value::String(val.clone())),
|
|
||||||
Instruction::StringCast(ins) => Some(Value::String(
|
|
||||||
match ins.run(ctx, globals)?.ok_or(InvalidValue("string"))? {
|
|
||||||
Value::Integer(i) => i.to_string(),
|
|
||||||
Value::Real(f) => f.to_string(),
|
|
||||||
Value::String(s) => s,
|
|
||||||
_ => Err(InvalidValue("string"))?,
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::Array(args) => Some(Value::Array(Rc::new(RefCell::new(
|
|
||||||
Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("array"))?,
|
|
||||||
)))),
|
|
||||||
Instruction::Add(args) => {
|
|
||||||
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, globals)?
|
|
||||||
.ok_or(InvalidValue("subtract"))?;
|
|
||||||
Some(Instruction::subtract(vals)?)
|
|
||||||
}
|
|
||||||
Instruction::Multiply(args) => {
|
|
||||||
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, globals)?.ok_or(InvalidValue("divide"))?;
|
|
||||||
Some(Instruction::divide(vals)?)
|
|
||||||
}
|
|
||||||
Instruction::And(args) => {
|
|
||||||
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, globals)?.ok_or(InvalidValue("or"))?;
|
|
||||||
Some(Instruction::or(vals))
|
|
||||||
}
|
|
||||||
Instruction::Not(arg) => Some(Value::Integer(
|
|
||||||
if arg.run(ctx, globals)?.ok_or(InvalidValue("not"))?.to_bool() {
|
|
||||||
0
|
|
||||||
} else {
|
|
||||||
1
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::Equal(v1, v2) => Some(Value::Integer(
|
|
||||||
if Instruction::compare(
|
|
||||||
v1.run(ctx, globals)?.ok_or(InvalidValue("equal"))?,
|
|
||||||
v2.run(ctx, globals)?.ok_or(InvalidValue("equal"))?,
|
|
||||||
)? == 0
|
|
||||||
{
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::Greater(v1, v2) => Some(Value::Integer(
|
|
||||||
if Instruction::compare(
|
|
||||||
v1.run(ctx, globals)?.ok_or(InvalidValue("greater"))?,
|
|
||||||
v2.run(ctx, globals)?.ok_or(InvalidValue("greater"))?,
|
|
||||||
)? > 0
|
|
||||||
{
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::Lower(v1, v2) => Some(Value::Integer(
|
|
||||||
if Instruction::compare(
|
|
||||||
v1.run(ctx, globals)?.ok_or(InvalidValue("lower"))?,
|
|
||||||
v2.run(ctx, globals)?.ok_or(InvalidValue("lower"))?,
|
|
||||||
)? < 0
|
|
||||||
{
|
|
||||||
1
|
|
||||||
} else {
|
|
||||||
0
|
|
||||||
},
|
|
||||||
)),
|
|
||||||
Instruction::Call(fct_ins, args) => {
|
|
||||||
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 {
|
|
||||||
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 {
|
|
||||||
Err(InvalidValue("call"))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Instruction::CallNamed(fct_name, args) => {
|
|
||||||
let vals: Vec<Value> =
|
|
||||||
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, globals)?
|
|
||||||
} else if let Value::StdFunction(f) = fct_val {
|
|
||||||
f(vals)?
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("call"))?
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Instruction::Return(ins) => {
|
|
||||||
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, globals)?.ok_or(InvalidValue("if"))?.to_bool() {
|
|
||||||
for i in then {
|
|
||||||
i.run(ctx, globals)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::IfElse(cond, then, els) => {
|
|
||||||
if cond.run(ctx, globals)?.ok_or(InvalidValue("if"))?.to_bool() {
|
|
||||||
for i in then {
|
|
||||||
i.run(ctx, globals)?;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for i in els {
|
|
||||||
i.run(ctx, globals)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::For {
|
|
||||||
variable,
|
|
||||||
from,
|
|
||||||
to,
|
|
||||||
step,
|
|
||||||
body,
|
|
||||||
} => {
|
|
||||||
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, globals)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::Each(variable, array_ins, body) => {
|
|
||||||
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, globals)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Err(InvalidValue("each"))?
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::While(cond, body) => {
|
|
||||||
while cond
|
|
||||||
.run(ctx, globals)?
|
|
||||||
.ok_or(InvalidValue("while"))?
|
|
||||||
.to_bool()
|
|
||||||
{
|
|
||||||
for ins in body {
|
|
||||||
ins.run(ctx, globals)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
Instruction::Handle(try_block, catch_block, variable) => {
|
|
||||||
for ins in try_block {
|
|
||||||
if let Err(e) = ins.run(ctx, globals) {
|
|
||||||
ctx.assign(variable.clone(), Value::String(e.to_string()));
|
|
||||||
for ins in catch_block {
|
|
||||||
ins.run(ctx, globals)?;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use super::value::Value;
|
use crate::interpreter::value::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
4
src/interpreter/mod.rs
Normal file
4
src/interpreter/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
mod context;
|
||||||
|
pub mod run;
|
||||||
|
mod stl;
|
||||||
|
mod value;
|
||||||
538
src/interpreter/run.rs
Normal file
538
src/interpreter/run.rs
Normal file
@@ -0,0 +1,538 @@
|
|||||||
|
use std::{cell::RefCell, error::Error, fs, rc::Rc};
|
||||||
|
|
||||||
|
use roxmltree::Document;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
error::{
|
||||||
|
BadChildCount, IncompatibleValues, InvalidProgram, InvalidValue, MissingChild,
|
||||||
|
UnknownVariable, Unnamed,
|
||||||
|
},
|
||||||
|
instruction::Instruction,
|
||||||
|
interpreter::context::Context,
|
||||||
|
interpreter::stl,
|
||||||
|
interpreter::value::{Function, Value},
|
||||||
|
util,
|
||||||
|
};
|
||||||
|
|
||||||
|
trait RunUtil {
|
||||||
|
fn add(vals: Vec<Value>) -> Result<Value, Box<dyn Error>>;
|
||||||
|
fn subtract(vals: Vec<Value>) -> Result<Value, Box<dyn Error>>;
|
||||||
|
fn multiply(vals: Vec<Value>) -> Result<Value, Box<dyn Error>>;
|
||||||
|
fn divide(vals: Vec<Value>) -> Result<Value, Box<dyn Error>>;
|
||||||
|
fn compare(v1: Value, v2: Value) -> Result<i64, Box<dyn Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RunUtil for Instruction {
|
||||||
|
fn add(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
||||||
|
if vals.iter().all(|v| matches!(v, Value::Integer(_))) {
|
||||||
|
Ok(Value::Integer(
|
||||||
|
vals.iter()
|
||||||
|
.map(|v| {
|
||||||
|
if let Value::Integer(i) = v {
|
||||||
|
Ok(i)
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("add"))?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum::<Result<i64, Box<dyn Error>>>()?,
|
||||||
|
))
|
||||||
|
} else if vals
|
||||||
|
.iter()
|
||||||
|
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
||||||
|
{
|
||||||
|
Ok(Value::Real(
|
||||||
|
vals.iter()
|
||||||
|
.map(|v| {
|
||||||
|
if let Value::Integer(i) = v {
|
||||||
|
Ok(*i as f64)
|
||||||
|
} else if let Value::Real(f) = v {
|
||||||
|
Ok(*f)
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("add"))?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum::<Result<f64, Box<dyn Error>>>()?,
|
||||||
|
))
|
||||||
|
} else if vals.iter().all(|v| {
|
||||||
|
matches!(v, Value::Integer(_))
|
||||||
|
|| matches!(v, Value::Real(_))
|
||||||
|
|| matches!(v, Value::String(_))
|
||||||
|
}) {
|
||||||
|
Ok(Value::String(
|
||||||
|
vals.iter()
|
||||||
|
.map(|v| {
|
||||||
|
Ok(if let Value::String(s) = v {
|
||||||
|
s.to_string()
|
||||||
|
} else if let Value::Integer(i) = v {
|
||||||
|
i.to_string()
|
||||||
|
} else if let Value::Real(f) = v {
|
||||||
|
f.to_string()
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("add"))?
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.collect::<Result<Vec<String>, Box<dyn Error>>>()?
|
||||||
|
.join(""),
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("add"))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn subtract(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
||||||
|
Ok(if vals.iter().all(|v| matches!(v, Value::Integer(_))) {
|
||||||
|
let first = match vals.first().ok_or(BadChildCount("subtract", 0usize))? {
|
||||||
|
Value::Integer(i) => i,
|
||||||
|
_ => Err(InvalidValue("subtract"))?,
|
||||||
|
};
|
||||||
|
Value::Integer(
|
||||||
|
*first
|
||||||
|
- vals
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|v| {
|
||||||
|
if let Value::Integer(i) = v {
|
||||||
|
Ok(i)
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("subtract"))?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.sum::<Result<i64, Box<dyn Error>>>()?,
|
||||||
|
)
|
||||||
|
} else if vals
|
||||||
|
.iter()
|
||||||
|
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
||||||
|
{
|
||||||
|
let first = match vals.first().ok_or(BadChildCount("subtract", 0usize))? {
|
||||||
|
Value::Integer(v) => *v as f64,
|
||||||
|
Value::Real(v) => *v,
|
||||||
|
_ => Err(InvalidValue("subtract"))?,
|
||||||
|
};
|
||||||
|
Value::Real(
|
||||||
|
first
|
||||||
|
- vals
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|val| {
|
||||||
|
Ok(match val {
|
||||||
|
Value::Integer(v) => *v as f64,
|
||||||
|
Value::Real(v) => *v,
|
||||||
|
_ => Err(InvalidValue("subtract"))?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.sum::<Result<f64, Box<dyn Error>>>()?,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("subtract"))?
|
||||||
|
})
|
||||||
|
}
|
||||||
|
fn multiply(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
||||||
|
if vals.iter().all(|v| matches!(v, Value::Integer(_))) {
|
||||||
|
Ok(Value::Integer(
|
||||||
|
vals.iter()
|
||||||
|
.map(|v| {
|
||||||
|
if let Value::Integer(i) = v {
|
||||||
|
Ok(i)
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("multiply"))?
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.product::<Result<i64, Box<dyn Error>>>()?,
|
||||||
|
))
|
||||||
|
} else if vals
|
||||||
|
.iter()
|
||||||
|
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
||||||
|
{
|
||||||
|
Ok(Value::Real(
|
||||||
|
vals.iter()
|
||||||
|
.map(|val| {
|
||||||
|
Ok(match val {
|
||||||
|
Value::Integer(v) => *v as f64,
|
||||||
|
Value::Real(v) => *v,
|
||||||
|
_ => Err(InvalidValue("multiply"))?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.product::<Result<f64, Box<dyn Error>>>()?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("multiply"))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn divide(vals: Vec<Value>) -> Result<Value, Box<dyn Error>> {
|
||||||
|
if vals
|
||||||
|
.iter()
|
||||||
|
.all(|v| matches!(v, Value::Integer(_)) || matches!(v, Value::Real(_)))
|
||||||
|
{
|
||||||
|
let first = match vals.first().ok_or(BadChildCount("divide", 0))? {
|
||||||
|
Value::Integer(v) => *v as f64,
|
||||||
|
Value::Real(v) => *v,
|
||||||
|
_ => Err(InvalidValue("divide"))?,
|
||||||
|
};
|
||||||
|
Ok(Value::Real(
|
||||||
|
first
|
||||||
|
* vals
|
||||||
|
.iter()
|
||||||
|
.skip(1)
|
||||||
|
.map(|val| {
|
||||||
|
Ok(match val {
|
||||||
|
Value::Integer(v) => 1.0 / (*v as f64),
|
||||||
|
Value::Real(v) => 1.0 / *v,
|
||||||
|
_ => Err(InvalidValue("divide"))?,
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.product::<Result<f64, Box<dyn Error>>>()?,
|
||||||
|
))
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("divide"))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn compare(v1: Value, v2: Value) -> Result<i64, Box<dyn Error>> {
|
||||||
|
use std::cmp::Ordering;
|
||||||
|
match v1 {
|
||||||
|
Value::Integer(i1) => match v2 {
|
||||||
|
Value::Integer(i2) => Ok(i1 - i2),
|
||||||
|
Value::Real(f2) => Ok(
|
||||||
|
match (i1 as f64).partial_cmp(&f2).ok_or(IncompatibleValues)? {
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
_ => Err(IncompatibleValues)?,
|
||||||
|
},
|
||||||
|
Value::Real(f1) => match v2 {
|
||||||
|
Value::Integer(i2) => Ok(
|
||||||
|
match f1.partial_cmp(&(i2 as f64)).ok_or(IncompatibleValues)? {
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Value::Real(f2) => Ok(match f1.partial_cmp(&f2).ok_or(IncompatibleValues)? {
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
}),
|
||||||
|
_ => Err(IncompatibleValues)?,
|
||||||
|
},
|
||||||
|
Value::String(s1) => {
|
||||||
|
if let Value::String(s2) = v2 {
|
||||||
|
Ok(match s1.cmp(&s2) {
|
||||||
|
Ordering::Less => -1,
|
||||||
|
Ordering::Equal => 0,
|
||||||
|
Ordering::Greater => 1,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Err(IncompatibleValues)?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => Err(IncompatibleValues)?,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Run {
|
||||||
|
fn run(&self, ctx: &mut Context, globals: &Context) -> Result<Option<Value>, Box<dyn Error>>;
|
||||||
|
fn run_all(
|
||||||
|
ins: &Vec<Instruction>,
|
||||||
|
ctx: &mut Context,
|
||||||
|
globals: &Context,
|
||||||
|
) -> Result<Option<Vec<Value>>, Box<dyn Error>>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Run for 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, globals)).collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
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) => {
|
||||||
|
Some(match ctx.value(key).ok_or(UnknownVariable(key.clone()))? {
|
||||||
|
Value::Array(vecrc) => Value::Array(Rc::clone(&vecrc)),
|
||||||
|
val => val.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Instruction::Assign(key, ins) => {
|
||||||
|
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, globals)?.ok_or(InvalidValue("integer"))? {
|
||||||
|
Value::Integer(i) => i,
|
||||||
|
Value::Real(f) => f as i64,
|
||||||
|
Value::String(s) => s.parse()?,
|
||||||
|
_ => Err(InvalidValue("integer"))?,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Real(val) => Some(Value::Real(val.parse()?)),
|
||||||
|
Instruction::RealCast(ins) => Some(Value::Real(
|
||||||
|
match ins.run(ctx, globals)?.ok_or(InvalidValue("real"))? {
|
||||||
|
Value::Integer(i) => i as f64,
|
||||||
|
Value::Real(f) => f,
|
||||||
|
Value::String(s) => s.parse()?,
|
||||||
|
_ => Err(InvalidValue("real"))?,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::String(val) => Some(Value::String(val.clone())),
|
||||||
|
Instruction::StringCast(ins) => Some(Value::String(
|
||||||
|
match ins.run(ctx, globals)?.ok_or(InvalidValue("string"))? {
|
||||||
|
Value::Integer(i) => i.to_string(),
|
||||||
|
Value::Real(f) => f.to_string(),
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => Err(InvalidValue("string"))?,
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Array(args) => Some(Value::Array(Rc::new(RefCell::new(
|
||||||
|
Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("array"))?,
|
||||||
|
)))),
|
||||||
|
Instruction::Add(args) => {
|
||||||
|
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, globals)?
|
||||||
|
.ok_or(InvalidValue("subtract"))?;
|
||||||
|
Some(Instruction::subtract(vals)?)
|
||||||
|
}
|
||||||
|
Instruction::Multiply(args) => {
|
||||||
|
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, globals)?.ok_or(InvalidValue("divide"))?;
|
||||||
|
Some(Instruction::divide(vals)?)
|
||||||
|
}
|
||||||
|
Instruction::And(args) => {
|
||||||
|
let vals =
|
||||||
|
Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("and"))?;
|
||||||
|
Some(Value::Integer(if vals.iter().all(Value::to_bool) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Instruction::Or(args) => {
|
||||||
|
let vals =
|
||||||
|
Instruction::run_all(args, ctx, globals)?.ok_or(InvalidValue("or"))?;
|
||||||
|
Some(Value::Integer(if vals.iter().any(Value::to_bool) {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
Instruction::Not(arg) => Some(Value::Integer(
|
||||||
|
if arg.run(ctx, globals)?.ok_or(InvalidValue("not"))?.to_bool() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
1
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Equal(v1, v2) => Some(Value::Integer(
|
||||||
|
if Instruction::compare(
|
||||||
|
v1.run(ctx, globals)?.ok_or(InvalidValue("equal"))?,
|
||||||
|
v2.run(ctx, globals)?.ok_or(InvalidValue("equal"))?,
|
||||||
|
)? == 0
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Greater(v1, v2) => Some(Value::Integer(
|
||||||
|
if Instruction::compare(
|
||||||
|
v1.run(ctx, globals)?.ok_or(InvalidValue("greater"))?,
|
||||||
|
v2.run(ctx, globals)?.ok_or(InvalidValue("greater"))?,
|
||||||
|
)? > 0
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Lower(v1, v2) => Some(Value::Integer(
|
||||||
|
if Instruction::compare(
|
||||||
|
v1.run(ctx, globals)?.ok_or(InvalidValue("lower"))?,
|
||||||
|
v2.run(ctx, globals)?.ok_or(InvalidValue("lower"))?,
|
||||||
|
)? < 0
|
||||||
|
{
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
},
|
||||||
|
)),
|
||||||
|
Instruction::Call(fct_ins, args) => {
|
||||||
|
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 {
|
||||||
|
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 {
|
||||||
|
Err(InvalidValue("call"))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::CallNamed(fct_name, args) => {
|
||||||
|
let vals: Vec<Value> =
|
||||||
|
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, globals)?
|
||||||
|
} else if let Value::StdFunction(f) = fct_val {
|
||||||
|
f(vals)?
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("call"))?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::Return(ins) => {
|
||||||
|
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, globals)?.ok_or(InvalidValue("if"))?.to_bool() {
|
||||||
|
for i in then {
|
||||||
|
i.run(ctx, globals)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Instruction::IfElse(cond, then, els) => {
|
||||||
|
if cond.run(ctx, globals)?.ok_or(InvalidValue("if"))?.to_bool() {
|
||||||
|
for i in then {
|
||||||
|
i.run(ctx, globals)?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for i in els {
|
||||||
|
i.run(ctx, globals)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Instruction::For {
|
||||||
|
variable,
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
step,
|
||||||
|
body,
|
||||||
|
} => {
|
||||||
|
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, globals)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Instruction::Each(variable, array_ins, body) => {
|
||||||
|
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, globals)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Err(InvalidValue("each"))?
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Instruction::While(cond, body) => {
|
||||||
|
while cond
|
||||||
|
.run(ctx, globals)?
|
||||||
|
.ok_or(InvalidValue("while"))?
|
||||||
|
.to_bool()
|
||||||
|
{
|
||||||
|
for ins in body {
|
||||||
|
ins.run(ctx, globals)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
Instruction::Handle(try_block, catch_block, variable) => {
|
||||||
|
for ins in try_block {
|
||||||
|
if let Err(e) = ins.run(ctx, globals) {
|
||||||
|
ctx.assign(variable.clone(), Value::String(e.to_string()));
|
||||||
|
for ins in catch_block {
|
||||||
|
ins.run(ctx, globals)?;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run_file(filename: &str) -> Result<(), Box<dyn Error>> {
|
||||||
|
let contents = fs::read_to_string(filename)?;
|
||||||
|
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);
|
||||||
|
stl::inject_all(&mut ctx);
|
||||||
|
|
||||||
|
let main = root
|
||||||
|
.first_element_child()
|
||||||
|
.ok_or(InvalidProgram)?
|
||||||
|
.children()
|
||||||
|
.find(|node| util::tag_name(&node) == "main")
|
||||||
|
.ok_or(MissingChild("program", "main"))?;
|
||||||
|
let main_ast = Instruction::from_children(main)?;
|
||||||
|
|
||||||
|
let functions = root
|
||||||
|
.first_element_child()
|
||||||
|
.ok_or(InvalidProgram)?
|
||||||
|
.children()
|
||||||
|
.filter(|node| node.tag_name().name() == String::from("function"));
|
||||||
|
|
||||||
|
for fun in functions {
|
||||||
|
ctx.assign(
|
||||||
|
String::from(fun.attribute("name").ok_or(Unnamed("function"))?),
|
||||||
|
Value::Function(Function::from(&fun)?),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut main_ctx = Context::new(Some(&ctx));
|
||||||
|
|
||||||
|
for ins in main_ast {
|
||||||
|
ins.run(&mut main_ctx, &ctx)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
use crate::error::InaccessibleFile;
|
use crate::error::{BadArgumentCount, InaccessibleFile, InvalidArgument};
|
||||||
|
use crate::interpreter::context::Context;
|
||||||
|
use crate::interpreter::value::Value;
|
||||||
|
|
||||||
use super::error::{BadArgumentCount, InvalidArgument};
|
|
||||||
use super::{Context, Value};
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::{self, OpenOptions};
|
use std::fs::{self, OpenOptions};
|
||||||
@@ -1,10 +1,14 @@
|
|||||||
use super::error::{BadArgumentCount, MissingChild, Unnamed};
|
|
||||||
use super::{util, Context, Instruction};
|
|
||||||
use roxmltree::Node;
|
use roxmltree::Node;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use crate::error::{BadArgumentCount, MissingChild, Unnamed};
|
||||||
|
use crate::instruction::Instruction;
|
||||||
|
use crate::interpreter::context::Context;
|
||||||
|
use crate::interpreter::run::Run;
|
||||||
|
use crate::util;
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
pub args: Vec<String>,
|
pub args: Vec<String>,
|
||||||
57
src/lib.rs
57
src/lib.rs
@@ -1,58 +1,9 @@
|
|||||||
use std::error::Error;
|
|
||||||
use std::fs;
|
|
||||||
|
|
||||||
use roxmltree::Document;
|
|
||||||
|
|
||||||
mod context;
|
|
||||||
mod error;
|
mod error;
|
||||||
mod instruction;
|
mod instruction;
|
||||||
mod stl;
|
|
||||||
mod util;
|
mod util;
|
||||||
mod value;
|
|
||||||
|
|
||||||
use context::Context;
|
mod compiler;
|
||||||
use error::{InvalidProgram, MissingChild, Unnamed};
|
mod interpreter;
|
||||||
use instruction::Instruction;
|
|
||||||
use value::{Function, Value};
|
|
||||||
|
|
||||||
pub fn run_file(filename: &str) -> Result<(), Box<dyn Error>> {
|
pub use compiler::compile::{compile, compile_file};
|
||||||
let contents = fs::read_to_string(filename)?;
|
pub use interpreter::run::{run, run_file};
|
||||||
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);
|
|
||||||
stl::inject_all(&mut ctx);
|
|
||||||
|
|
||||||
let main = root
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or(InvalidProgram)?
|
|
||||||
.children()
|
|
||||||
.find(|node| util::tag_name(&node) == "main")
|
|
||||||
.ok_or(MissingChild("program", "main"))?;
|
|
||||||
let main_ast = Instruction::from_children(main)?;
|
|
||||||
|
|
||||||
let functions = root
|
|
||||||
.first_element_child()
|
|
||||||
.ok_or(InvalidProgram)?
|
|
||||||
.children()
|
|
||||||
.filter(|node| node.tag_name().name() == String::from("function"));
|
|
||||||
|
|
||||||
for fun in functions {
|
|
||||||
ctx.assign(
|
|
||||||
String::from(fun.attribute("name").ok_or(Unnamed("function"))?),
|
|
||||||
Value::Function(Function::from(&fun)?),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut main_ctx = Context::new(Some(&ctx));
|
|
||||||
|
|
||||||
for ins in main_ast {
|
|
||||||
ins.run(&mut main_ctx, &ctx)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,9 +0,0 @@
|
|||||||
use plxml::run_file;
|
|
||||||
use std::env;
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
let args: Vec<String> = env::args().collect();
|
|
||||||
if let Err(e) = run_file(&args[1]) {
|
|
||||||
eprintln!("Error occurred: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user