0.1.1: structural reworks + dep version bump

This commit is contained in:
Altareos
2023-11-28 18:01:09 +01:00
parent 2e2712704e
commit 0e5a9acccf
14 changed files with 619 additions and 564 deletions

15
Cargo.lock generated
View File

@@ -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"

View File

@@ -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
View 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
View 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
View 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
View File

@@ -0,0 +1 @@
pub mod compile;

View File

@@ -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
})
}
} }

View File

@@ -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
View File

@@ -0,0 +1,4 @@
mod context;
pub mod run;
mod stl;
mod value;

538
src/interpreter/run.rs Normal file
View 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(())
}

View File

@@ -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};

View File

@@ -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>,

View File

@@ -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(())
}

View File

@@ -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);
}
}