2019-07-13 10:59:10 -05:00
|
|
|
// Copyright 2019 Jeremy Wall
|
2019-07-17 18:54:19 -05:00
|
|
|
//
|
2019-07-13 10:59:10 -05:00
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
2019-07-17 18:54:19 -05:00
|
|
|
//
|
2019-07-13 10:59:10 -05:00
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
2019-07-17 18:54:19 -05:00
|
|
|
//
|
2019-07-13 10:59:10 -05:00
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
2019-07-17 18:54:19 -05:00
|
|
|
use std::cell::RefCell;
|
2019-08-20 21:30:17 -05:00
|
|
|
use std::collections::BTreeSet;
|
2019-11-11 20:06:17 -06:00
|
|
|
use std::convert::TryInto;
|
2019-09-02 10:10:24 -05:00
|
|
|
use std::path::PathBuf;
|
2019-07-13 10:59:10 -05:00
|
|
|
use std::rc::Rc;
|
|
|
|
|
2019-11-11 20:06:17 -06:00
|
|
|
use crate::ast::{CastType, Position};
|
2019-08-18 08:40:30 -05:00
|
|
|
|
2019-08-17 12:57:40 -05:00
|
|
|
use super::environment::Environment;
|
2019-07-13 10:59:10 -05:00
|
|
|
use super::pointer::OpPointer;
|
2019-07-17 18:54:19 -05:00
|
|
|
use super::runtime;
|
|
|
|
use super::scope::Stack;
|
2019-08-18 08:40:30 -05:00
|
|
|
use super::translate::PositionMap;
|
2019-07-13 10:59:10 -05:00
|
|
|
use super::Composite::{List, Tuple};
|
2019-07-17 18:54:19 -05:00
|
|
|
use super::Hook;
|
2019-07-31 20:08:05 -05:00
|
|
|
use super::Primitive::{Bool, Empty, Float, Int, Str};
|
2019-07-17 18:54:19 -05:00
|
|
|
use super::Value::{C, F, M, P, S, T};
|
2019-08-03 16:53:43 -05:00
|
|
|
use super::{Error, Op, Primitive, Value};
|
2019-07-13 10:59:10 -05:00
|
|
|
use super::{Func, Module};
|
|
|
|
|
2019-08-20 21:30:17 -05:00
|
|
|
fn construct_reserved_word_set() -> BTreeSet<&'static str> {
|
|
|
|
let mut words = BTreeSet::new();
|
|
|
|
for word in vec![
|
|
|
|
"let", "module", "func", "out", "assert", "self", "import", "include", "as", "map",
|
|
|
|
"filter", "convert", "fail", "NULL", "in", "is", "TRACE",
|
|
|
|
] {
|
|
|
|
words.insert(word);
|
|
|
|
}
|
|
|
|
words
|
|
|
|
}
|
|
|
|
|
2019-08-17 12:57:40 -05:00
|
|
|
pub struct VM<O, E>
|
|
|
|
where
|
2019-09-02 17:22:58 -05:00
|
|
|
O: std::io::Write + Clone,
|
|
|
|
E: std::io::Write + Clone,
|
2019-08-17 12:57:40 -05:00
|
|
|
{
|
2019-09-02 10:10:24 -05:00
|
|
|
working_dir: PathBuf,
|
2019-08-18 15:40:23 -05:00
|
|
|
stack: Vec<(Rc<Value>, Position)>,
|
2019-07-13 10:59:10 -05:00
|
|
|
symbols: Stack,
|
2019-09-01 19:21:02 -05:00
|
|
|
import_stack: Vec<String>,
|
2019-08-17 12:57:40 -05:00
|
|
|
runtime: runtime::Builtins,
|
2019-07-13 10:59:10 -05:00
|
|
|
ops: OpPointer,
|
2019-08-17 12:57:40 -05:00
|
|
|
pub env: Rc<RefCell<Environment<O, E>>>,
|
2019-08-20 12:41:37 -05:00
|
|
|
pub last: Option<(Rc<Value>, Position)>,
|
2019-08-20 19:36:07 -05:00
|
|
|
self_stack: Vec<(Rc<Value>, Position)>,
|
2019-08-20 21:30:17 -05:00
|
|
|
reserved_words: BTreeSet<&'static str>,
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
|
2019-08-17 12:57:40 -05:00
|
|
|
impl<'a, O, E> VM<O, E>
|
|
|
|
where
|
2019-09-02 17:22:58 -05:00
|
|
|
O: std::io::Write + Clone,
|
|
|
|
E: std::io::Write + Clone,
|
2019-08-17 12:57:40 -05:00
|
|
|
{
|
2019-09-02 10:10:24 -05:00
|
|
|
pub fn new<P: Into<PathBuf>>(
|
2019-11-09 15:07:46 -06:00
|
|
|
strict: bool,
|
2019-09-02 10:10:24 -05:00
|
|
|
ops: Rc<PositionMap>,
|
|
|
|
env: Rc<RefCell<Environment<O, E>>>,
|
|
|
|
working_dir: P,
|
|
|
|
) -> Self {
|
2019-11-09 15:07:46 -06:00
|
|
|
Self::with_pointer(strict, OpPointer::new(ops), env, working_dir)
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
|
2019-09-02 10:10:24 -05:00
|
|
|
pub fn with_pointer<P: Into<PathBuf>>(
|
2019-11-09 15:07:46 -06:00
|
|
|
strict: bool,
|
2019-09-02 10:10:24 -05:00
|
|
|
ops: OpPointer,
|
|
|
|
env: Rc<RefCell<Environment<O, E>>>,
|
|
|
|
working_dir: P,
|
|
|
|
) -> Self {
|
2019-07-13 10:59:10 -05:00
|
|
|
Self {
|
2019-09-02 10:10:24 -05:00
|
|
|
working_dir: working_dir.into(),
|
2019-07-13 10:59:10 -05:00
|
|
|
stack: Vec::new(),
|
|
|
|
symbols: Stack::new(),
|
2019-09-01 19:21:02 -05:00
|
|
|
import_stack: Vec::new(),
|
2019-11-09 15:07:46 -06:00
|
|
|
runtime: runtime::Builtins::new(strict),
|
2019-07-13 10:59:10 -05:00
|
|
|
ops: ops,
|
2019-08-17 12:57:40 -05:00
|
|
|
env: env,
|
2019-08-20 12:41:37 -05:00
|
|
|
last: None,
|
2019-08-20 19:36:07 -05:00
|
|
|
self_stack: Vec::new(),
|
2019-08-20 21:30:17 -05:00
|
|
|
reserved_words: construct_reserved_word_set(),
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
2019-09-02 10:10:24 -05:00
|
|
|
|
2019-09-02 17:22:58 -05:00
|
|
|
pub fn set_path(&mut self, path: PathBuf) {
|
|
|
|
self.ops.set_path(path);
|
|
|
|
}
|
|
|
|
|
2019-09-02 10:10:24 -05:00
|
|
|
pub fn to_new_pointer(mut self, ops: OpPointer) -> Self {
|
|
|
|
self.ops = ops;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-09-01 19:21:02 -05:00
|
|
|
pub fn with_import_stack(mut self, imports: Vec<String>) -> Self {
|
|
|
|
self.import_stack = imports;
|
|
|
|
self
|
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
|
2019-08-26 21:24:17 -05:00
|
|
|
pub fn enable_validate_mode(&mut self) {
|
|
|
|
self.runtime.enable_validate_mode();
|
|
|
|
}
|
|
|
|
|
2019-09-02 10:10:24 -05:00
|
|
|
pub fn clean_copy(&self) -> Self {
|
2019-07-13 10:59:10 -05:00
|
|
|
Self {
|
2019-09-02 10:10:24 -05:00
|
|
|
working_dir: self.working_dir.clone(),
|
2019-07-13 10:59:10 -05:00
|
|
|
stack: Vec::new(),
|
2019-09-02 10:10:24 -05:00
|
|
|
symbols: Stack::new(),
|
|
|
|
import_stack: Vec::new(),
|
2019-07-17 18:54:19 -05:00
|
|
|
runtime: self.runtime.clone(),
|
2019-07-13 10:59:10 -05:00
|
|
|
ops: self.ops.clone(),
|
2019-08-17 12:57:40 -05:00
|
|
|
env: self.env.clone(),
|
2019-09-02 10:10:24 -05:00
|
|
|
last: None,
|
|
|
|
self_stack: self.self_stack.clone(),
|
|
|
|
reserved_words: self.reserved_words.clone(),
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-02 10:10:24 -05:00
|
|
|
pub fn to_scoped(mut self, symbols: Stack) -> Self {
|
|
|
|
self.symbols = symbols;
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2019-07-17 18:54:19 -05:00
|
|
|
pub fn symbols_to_tuple(&self, include_mod: bool) -> Value {
|
|
|
|
let mut flds = Vec::new();
|
2019-09-01 19:21:02 -05:00
|
|
|
let mut pos_list = Vec::new();
|
2019-07-17 18:54:19 -05:00
|
|
|
for sym in self.symbols.symbol_list() {
|
|
|
|
if include_mod || sym != "mod" {
|
2019-09-01 19:21:02 -05:00
|
|
|
let (val, pos) = self.symbols.get(sym).unwrap().clone();
|
|
|
|
pos_list.push((pos.clone(), pos.clone()));
|
2019-08-20 19:03:49 -05:00
|
|
|
flds.push((sym.clone(), val));
|
2019-07-17 18:54:19 -05:00
|
|
|
}
|
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
return C(Tuple(flds, pos_list));
|
2019-07-17 18:54:19 -05:00
|
|
|
}
|
2019-11-03 14:20:25 -06:00
|
|
|
|
2019-09-03 18:38:06 -05:00
|
|
|
pub fn remove_symbol(&mut self, sym: &str) -> Option<(Rc<Value>, Position)> {
|
|
|
|
self.symbols.remove_symbol(sym)
|
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
|
2019-07-13 10:59:10 -05:00
|
|
|
pub fn run(&mut self) -> Result<(), Error> {
|
|
|
|
loop {
|
2019-08-20 20:51:46 -05:00
|
|
|
let op = if let Some(op) = self.ops.next() {
|
2019-07-13 10:59:10 -05:00
|
|
|
op.clone()
|
|
|
|
} else {
|
|
|
|
break;
|
|
|
|
};
|
2019-08-18 08:40:30 -05:00
|
|
|
let pos = self.ops.pos().unwrap().clone();
|
2019-07-13 10:59:10 -05:00
|
|
|
let idx = self.ops.idx()?;
|
|
|
|
match op {
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::Val(p) => self.push(Rc::new(P(p.clone())), pos)?,
|
2019-11-11 20:06:17 -06:00
|
|
|
Op::Cast(t) => self.op_cast(t)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::Sym(s) => self.push(Rc::new(S(s.clone())), pos)?,
|
2019-08-18 08:40:30 -05:00
|
|
|
Op::DeRef(s) => self.op_deref(s.clone(), &pos)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::Add => self.op_add(pos)?,
|
|
|
|
Op::Mod => self.op_mod(pos)?,
|
|
|
|
Op::Sub => self.op_sub(pos)?,
|
|
|
|
Op::Mul => self.op_mul(pos)?,
|
|
|
|
Op::Div => self.op_div(pos)?,
|
|
|
|
Op::Bind => self.op_bind(true)?,
|
|
|
|
Op::BindOver => self.op_bind(false)?,
|
|
|
|
Op::Equal => self.op_equal(pos)?,
|
2019-08-18 08:40:30 -05:00
|
|
|
Op::Not => self.op_not(&pos)?,
|
|
|
|
Op::Gt => self.op_gt(&pos)?,
|
|
|
|
Op::Lt => self.op_lt(&pos)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::GtEq => self.op_gteq(pos)?,
|
|
|
|
Op::LtEq => self.op_lteq(pos)?,
|
2019-07-13 10:59:10 -05:00
|
|
|
// Add a Composite list value to the stack
|
2019-09-01 19:21:02 -05:00
|
|
|
Op::InitList => self.push(Rc::new(C(List(Vec::new(), Vec::new()))), pos)?,
|
2019-07-13 10:59:10 -05:00
|
|
|
// Add a composite tuple value to the stack
|
2019-09-01 19:21:02 -05:00
|
|
|
Op::InitTuple => self.push(Rc::new(C(Tuple(Vec::new(), Vec::new()))), pos)?,
|
2019-07-13 10:59:10 -05:00
|
|
|
Op::Field => self.op_field()?,
|
|
|
|
Op::Element => self.op_element()?,
|
2019-11-09 15:07:46 -06:00
|
|
|
Op::Index => self.op_index(!self.runtime.strict, pos)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::SafeIndex => self.op_index(true, pos)?,
|
2019-09-01 10:21:05 -05:00
|
|
|
Op::Exist => self.op_exist(pos)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::Cp => self.op_copy(pos)?,
|
2019-08-17 17:45:37 -05:00
|
|
|
//FIXME(jwall): Should this take a user provided message?
|
2019-08-14 19:52:41 -05:00
|
|
|
Op::Bang => self.op_bang()?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::InitThunk(jp) => self.op_thunk(idx, jp, pos)?,
|
2019-07-13 10:59:10 -05:00
|
|
|
Op::Noop => {
|
|
|
|
// Do nothing
|
|
|
|
}
|
|
|
|
Op::Jump(jp) => self.op_jump(jp)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::JumpIfTrue(jp) => self.op_jump_if_true(jp)?,
|
|
|
|
Op::JumpIfFalse(jp) => self.op_jump_if_false(jp)?,
|
2019-07-13 10:59:10 -05:00
|
|
|
Op::SelectJump(jp) => self.op_select_jump(jp)?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::And(jp) => self.op_and(jp, pos)?,
|
|
|
|
Op::Or(jp) => self.op_or(jp, pos)?,
|
|
|
|
Op::Module(mptr) => self.op_module(idx, mptr, pos)?,
|
|
|
|
Op::Func(jptr) => self.op_func(idx, jptr, pos)?,
|
|
|
|
Op::FCall => self.op_fcall(pos)?,
|
2019-08-12 22:07:26 -05:00
|
|
|
Op::NewScope(jp) => self.op_new_scope(jp, self.ops.clone())?,
|
|
|
|
Op::Return => {
|
2019-08-26 21:24:17 -05:00
|
|
|
&self.stack;
|
2019-08-12 22:07:26 -05:00
|
|
|
return Ok(());
|
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
Op::Pop => {
|
2019-08-20 20:51:46 -05:00
|
|
|
self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-07-31 20:08:05 -05:00
|
|
|
Op::Typ => self.op_typ()?,
|
2019-08-18 15:40:23 -05:00
|
|
|
Op::Runtime(h) => self.op_runtime(h, pos)?,
|
2019-08-05 19:04:38 -05:00
|
|
|
Op::Render => self.op_render()?,
|
2019-08-20 19:36:07 -05:00
|
|
|
Op::PushSelf => self.op_push_self()?,
|
|
|
|
Op::PopSelf => self.op_pop_self()?,
|
2019-07-13 10:59:10 -05:00
|
|
|
};
|
|
|
|
}
|
2019-09-02 10:10:24 -05:00
|
|
|
if let Some(p) = self.ops.path.as_ref() {
|
|
|
|
self.import_stack.push(p.to_string_lossy().to_string());
|
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-11-11 20:06:17 -06:00
|
|
|
fn op_cast(&mut self, t: CastType) -> Result<(), Error> {
|
|
|
|
let (val, pos) = self.pop()?;
|
|
|
|
if let Value::P(ref p) = val.as_ref() {
|
|
|
|
self.push(
|
|
|
|
Rc::new(match t {
|
|
|
|
CastType::Str => Value::P(Primitive::Str(format!("{}", p))),
|
|
|
|
CastType::Int => Value::P(Primitive::Int(p.try_into()?)),
|
|
|
|
CastType::Float => Value::P(Primitive::Float(p.try_into()?)),
|
|
|
|
CastType::Bool => Value::P(Primitive::Bool(p.try_into()?)),
|
|
|
|
}),
|
|
|
|
pos,
|
|
|
|
)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-07-31 20:08:05 -05:00
|
|
|
fn op_typ(&mut self) -> Result<(), Error> {
|
2019-08-18 15:40:23 -05:00
|
|
|
let (val, pos) = self.pop()?;
|
2019-07-31 20:08:05 -05:00
|
|
|
let typ_name = match val.as_ref() {
|
|
|
|
P(Int(_)) => "int",
|
|
|
|
P(Float(_)) => "float",
|
|
|
|
P(Bool(_)) => "bool",
|
|
|
|
P(Str(_)) => "str",
|
|
|
|
P(Empty) => "null",
|
2019-09-01 19:21:02 -05:00
|
|
|
C(Tuple(_, _)) => "tuple",
|
|
|
|
C(List(_, _)) => "list",
|
2019-07-31 20:08:05 -05:00
|
|
|
F(_) => "func",
|
|
|
|
M(_) => "module",
|
2019-08-18 08:40:30 -05:00
|
|
|
S(_) => "sym",
|
|
|
|
T(_) => "thunk",
|
2019-07-31 20:08:05 -05:00
|
|
|
}
|
|
|
|
.to_owned();
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Str(typ_name))), pos)?;
|
2019-07-31 20:08:05 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn op_deref(&mut self, name: String, pos: &Position) -> Result<(), Error> {
|
2019-08-20 19:03:49 -05:00
|
|
|
let (val, _) = self.get_binding(&name, pos)?.clone();
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(val, pos.clone())
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
fn op_jump(&mut self, jp: i32) -> Result<(), Error> {
|
|
|
|
self.ops.jump(
|
|
|
|
self.ops
|
|
|
|
.ptr
|
|
|
|
.map(|v| (v as i32 + jp) as usize)
|
|
|
|
.unwrap_or(jp as usize),
|
|
|
|
)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_and(&mut self, jp: i32, pos: Position) -> Result<(), Error> {
|
|
|
|
let (cond, cond_pos) = self.pop()?;
|
2019-08-01 19:04:58 -05:00
|
|
|
let cc = cond.clone();
|
|
|
|
if let &P(Bool(cond)) = cond.as_ref() {
|
|
|
|
if !cond {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(cc, cond_pos)?;
|
2019-08-01 19:04:58 -05:00
|
|
|
self.op_jump(jp)?;
|
|
|
|
}
|
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 15:40:23 -05:00
|
|
|
format!(
|
|
|
|
"Not a boolean condition {:?} in && expression at {}",
|
|
|
|
cond, pos
|
|
|
|
),
|
|
|
|
cond_pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-01 19:04:58 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_or(&mut self, jp: i32, pos: Position) -> Result<(), Error> {
|
|
|
|
let (cond, cond_pos) = self.pop()?;
|
2019-08-26 21:24:17 -05:00
|
|
|
let cc = cond.clone();
|
2019-08-01 19:04:58 -05:00
|
|
|
if let &P(Bool(cond)) = cond.as_ref() {
|
2019-08-26 21:24:17 -05:00
|
|
|
if cond {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(cc, cond_pos)?;
|
2019-08-01 19:04:58 -05:00
|
|
|
self.op_jump(jp)?;
|
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 15:40:23 -05:00
|
|
|
format!(
|
|
|
|
"Not a boolean condition {:?} in || expression at {}!",
|
|
|
|
cond, pos
|
|
|
|
),
|
|
|
|
cond_pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-01 19:04:58 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_jump_if_true(&mut self, jp: i32) -> Result<(), Error> {
|
|
|
|
let (cond, cond_pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
if let &P(Bool(cond)) = cond.as_ref() {
|
2019-07-13 10:59:10 -05:00
|
|
|
if cond {
|
|
|
|
self.op_jump(jp)?;
|
|
|
|
}
|
2019-08-01 19:04:58 -05:00
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:40:30 -05:00
|
|
|
format!("Expected boolean but got {:?}!", cond),
|
2019-08-18 15:40:23 -05:00
|
|
|
cond_pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_jump_if_false(&mut self, jp: i32) -> Result<(), Error> {
|
|
|
|
let (cond, pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
if let &P(Bool(cond)) = cond.as_ref() {
|
2019-07-13 10:59:10 -05:00
|
|
|
if !cond {
|
2019-08-12 22:07:26 -05:00
|
|
|
self.op_jump(jp)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:40:30 -05:00
|
|
|
format!("Expected boolean but got {:?}!", cond),
|
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_select_jump(&'a mut self, jp: i32) -> Result<(), Error> {
|
|
|
|
// pop field value off
|
2019-08-26 21:24:17 -05:00
|
|
|
let (field_name, _) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// pop search value off
|
2019-08-26 21:24:17 -05:00
|
|
|
let (search, srch_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// compare them.
|
2019-08-16 20:34:04 -05:00
|
|
|
let matched = match (field_name.as_ref(), search.as_ref()) {
|
|
|
|
(&S(ref fname), &P(Str(ref sname))) | (&S(ref fname), &S(ref sname)) => fname == sname,
|
2019-09-01 10:21:05 -05:00
|
|
|
(&S(ref fname), &P(Bool(b))) => {
|
|
|
|
if fname == "true" && b {
|
|
|
|
true
|
|
|
|
} else if fname == "false" && !b {
|
|
|
|
true
|
|
|
|
} else {
|
|
|
|
false
|
|
|
|
}
|
|
|
|
}
|
2019-08-16 20:34:04 -05:00
|
|
|
_ => false,
|
|
|
|
};
|
|
|
|
if !matched {
|
|
|
|
// if they aren't equal then push search value back on and jump
|
2019-08-26 21:24:17 -05:00
|
|
|
self.push(search, srch_pos)?;
|
|
|
|
self.op_jump(jp)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_module(&'a mut self, idx: usize, jptr: i32, pos: Position) -> Result<(), Error> {
|
2019-08-26 21:24:17 -05:00
|
|
|
let (mod_val, mod_val_pos) = self.pop()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
let (result_ptr, flds, pos_list) = match mod_val.as_ref() {
|
|
|
|
&C(Tuple(ref flds, ref pos_list)) => (None, flds.clone(), pos_list.clone()),
|
2019-07-17 18:54:19 -05:00
|
|
|
&T(ptr) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
let (tpl_val, tpl_val_pos) = self.pop()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &C(Tuple(ref flds, ref pos_list)) = tpl_val.as_ref() {
|
|
|
|
(Some(ptr), flds.clone(), pos_list.clone())
|
2019-07-13 10:59:10 -05:00
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:40:30 -05:00
|
|
|
format!("Expected tuple but got {:?}", tpl_val),
|
2019-08-18 15:40:23 -05:00
|
|
|
tpl_val_pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:44:01 -05:00
|
|
|
format!("Expected tuple but got {:?}", mod_val),
|
2019-08-18 15:40:23 -05:00
|
|
|
mod_val_pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
let mut ops = self.ops.clone();
|
2019-08-18 08:40:30 -05:00
|
|
|
let pkg_pos = self.ops.pos().unwrap().clone();
|
2019-07-13 10:59:10 -05:00
|
|
|
ops.jump(idx)?;
|
2019-08-17 16:57:45 -05:00
|
|
|
let pkg_ptr = if let Some(ref path) = self.ops.path {
|
|
|
|
let pkg_ops = vec![
|
|
|
|
Op::InitList,
|
|
|
|
Op::Func(3),
|
|
|
|
Op::Val(Str(path.to_string_lossy().to_string())),
|
|
|
|
Op::Runtime(Hook::Import),
|
|
|
|
Op::Return,
|
|
|
|
];
|
2019-08-18 08:40:30 -05:00
|
|
|
let pos_list = vec![
|
|
|
|
pkg_pos.clone(),
|
|
|
|
pkg_pos.clone(),
|
|
|
|
pkg_pos.clone(),
|
|
|
|
pkg_pos.clone(),
|
2019-08-18 15:40:23 -05:00
|
|
|
pkg_pos,
|
2019-08-18 08:40:30 -05:00
|
|
|
];
|
|
|
|
Some(OpPointer::new(Rc::new(PositionMap {
|
|
|
|
ops: pkg_ops,
|
|
|
|
pos: pos_list,
|
|
|
|
})))
|
2019-08-17 16:57:45 -05:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(
|
|
|
|
Rc::new(M(Module {
|
|
|
|
ptr: ops,
|
|
|
|
result_ptr: result_ptr,
|
2019-09-01 19:21:02 -05:00
|
|
|
flds_pos_list: pos_list,
|
2019-08-18 15:40:23 -05:00
|
|
|
flds: flds,
|
|
|
|
pkg_ptr: pkg_ptr,
|
|
|
|
})),
|
|
|
|
pos,
|
|
|
|
)?;
|
2019-08-14 19:52:41 -05:00
|
|
|
self.op_jump(jptr)
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_func(&mut self, idx: usize, jptr: i32, pos: Position) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// get arity from stack
|
2019-08-18 15:40:23 -05:00
|
|
|
let scope_snapshot = self.symbols.snapshot();
|
2019-07-13 10:59:10 -05:00
|
|
|
let mut bindings = Vec::new();
|
|
|
|
// get imported symbols from stack
|
2019-08-18 15:40:23 -05:00
|
|
|
let (list_val, args_pos) = self.pop()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &C(List(ref elems, _)) = list_val.as_ref() {
|
2019-07-13 10:59:10 -05:00
|
|
|
for e in elems {
|
2019-07-17 18:54:19 -05:00
|
|
|
if let &S(ref sym) = e.as_ref() {
|
|
|
|
bindings.push(sym.clone());
|
2019-07-13 10:59:10 -05:00
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:40:30 -05:00
|
|
|
format!("Not an argument name {:?}", e),
|
2019-08-18 15:40:23 -05:00
|
|
|
args_pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(format!("Fault!!! Bad Argument List"), args_pos));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
let mut ops = self.ops.clone();
|
|
|
|
ops.jump(idx)?;
|
2019-09-01 10:21:05 -05:00
|
|
|
// Our arguments will be pulled off the stack in reverse order;
|
|
|
|
bindings.reverse();
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(
|
|
|
|
Rc::new(F(Func {
|
|
|
|
ptr: ops, // where the function starts.
|
|
|
|
bindings: bindings,
|
|
|
|
snapshot: scope_snapshot,
|
|
|
|
})),
|
|
|
|
pos,
|
|
|
|
)?;
|
2019-08-14 19:52:41 -05:00
|
|
|
self.op_jump(jptr)
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
|
2019-08-17 17:41:49 -05:00
|
|
|
pub fn fcall_impl(
|
2019-07-28 18:07:57 -05:00
|
|
|
f: &Func,
|
2019-11-09 15:07:46 -06:00
|
|
|
strict: bool,
|
2019-08-18 15:40:23 -05:00
|
|
|
stack: &mut Vec<(Rc<Value>, Position)>,
|
2019-08-17 12:57:40 -05:00
|
|
|
env: Rc<RefCell<Environment<O, E>>>,
|
2019-09-01 19:21:02 -05:00
|
|
|
import_stack: &Vec<String>,
|
2019-08-18 15:40:23 -05:00
|
|
|
) -> Result<(Rc<Value>, Position), Error> {
|
2019-07-28 18:07:57 -05:00
|
|
|
let Func {
|
2019-07-17 18:54:19 -05:00
|
|
|
ref ptr,
|
|
|
|
ref bindings,
|
|
|
|
ref snapshot,
|
2019-07-28 18:07:57 -05:00
|
|
|
} = f;
|
|
|
|
// use the captured scope snapshot for the function.
|
2019-11-09 15:07:46 -06:00
|
|
|
let mut vm = Self::with_pointer(strict, ptr.clone(), env, std::env::current_dir()?)
|
2019-09-01 19:21:02 -05:00
|
|
|
.to_scoped(snapshot.clone())
|
|
|
|
.with_import_stack(import_stack.clone());
|
2019-07-28 18:07:57 -05:00
|
|
|
for nm in bindings.iter() {
|
|
|
|
// now put each argument on our scope stack as a binding.
|
|
|
|
// TODO(jwall): This should do a better error if there is
|
|
|
|
// nothing on the stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (val, pos) = stack.pop().unwrap();
|
2019-08-20 21:30:17 -05:00
|
|
|
vm.binding_push(nm.clone(), val, false, &pos, &pos)?;
|
2019-07-28 18:07:57 -05:00
|
|
|
}
|
|
|
|
// proceed to the function body
|
|
|
|
vm.run()?;
|
|
|
|
return vm.pop();
|
|
|
|
}
|
|
|
|
|
2019-08-12 22:07:26 -05:00
|
|
|
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
|
|
|
|
let scope_snapshot = self.symbols.snapshot();
|
2019-09-02 10:10:24 -05:00
|
|
|
let mut vm = self
|
|
|
|
.clean_copy()
|
|
|
|
.to_new_pointer(ptr)
|
2019-09-01 19:21:02 -05:00
|
|
|
.to_scoped(scope_snapshot)
|
|
|
|
.with_import_stack(self.import_stack.clone());
|
2019-08-12 22:07:26 -05:00
|
|
|
vm.run()?;
|
2019-08-18 15:40:23 -05:00
|
|
|
let result = vm.pop()?;
|
|
|
|
self.push(result.0, result.1)?;
|
2019-08-12 22:07:26 -05:00
|
|
|
self.op_jump(jp)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_fcall(&mut self, pos: Position) -> Result<(), Error> {
|
2019-09-01 19:21:02 -05:00
|
|
|
let (f, f_pos) = self.pop()?;
|
|
|
|
let (arg_length, _) = self.pop()?;
|
2019-07-28 18:07:57 -05:00
|
|
|
if let &F(ref f) = f.as_ref() {
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &P(Int(arg_length)) = arg_length.as_ref() {
|
|
|
|
let arity = f.bindings.len() as i64;
|
|
|
|
if arg_length > arity {
|
|
|
|
return Err(Error::new(
|
|
|
|
format!(
|
|
|
|
"Func called with too many args expected {} args but got {}",
|
|
|
|
arity, arg_length
|
|
|
|
),
|
|
|
|
pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
if arg_length < arity {
|
|
|
|
return Err(Error::new(
|
|
|
|
format!(
|
|
|
|
"Func called with too few args expected {} args but got {}",
|
|
|
|
arity, arg_length
|
|
|
|
),
|
|
|
|
pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
let (val, _) = decorate_call!(f_pos =>
|
2019-11-09 15:07:46 -06:00
|
|
|
Self::fcall_impl(f, self.runtime.strict, &mut self.stack, self.env.clone(), &self.import_stack))?;
|
2019-08-26 21:24:17 -05:00
|
|
|
self.push(val, pos.clone())?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_thunk(&mut self, idx: usize, jp: i32, pos: Position) -> Result<(), Error> {
|
|
|
|
self.push(Rc::new(T(idx)), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
self.op_jump(jp)
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn op_not(&mut self, pos: &Position) -> Result<(), Error> {
|
2019-08-18 15:40:23 -05:00
|
|
|
let (operand, operand_pos) = self.pop()?;
|
2019-07-29 17:53:02 -05:00
|
|
|
if let P(Bool(val)) = operand.as_ref() {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(!val))), operand_pos)?;
|
2019-07-29 17:53:02 -05:00
|
|
|
return Ok(());
|
|
|
|
}
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 15:40:23 -05:00
|
|
|
format!(
|
|
|
|
"Expected Boolean but got {:?} in expression at {}",
|
|
|
|
operand, pos
|
|
|
|
),
|
|
|
|
operand_pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-29 17:53:02 -05:00
|
|
|
}
|
2019-07-31 18:12:35 -05:00
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_equal(&mut self, pos: Position) -> Result<(), Error> {
|
2019-09-01 19:21:02 -05:00
|
|
|
let (left, left_pos) = self.pop()?;
|
|
|
|
let (right, right_pos) = self.pop()?;
|
|
|
|
if left.type_name() != right.type_name()
|
|
|
|
&& !(left.type_name() == "NULL" || right.type_name() == "NULL")
|
|
|
|
{
|
|
|
|
return Err(Error::new(
|
|
|
|
format!(
|
|
|
|
"Expected values of the same type but got {:?} at {} and {:?} at {} for expression",
|
|
|
|
left, left_pos, right, right_pos,
|
|
|
|
),
|
|
|
|
pos,
|
|
|
|
));
|
|
|
|
}
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(left == right))), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn op_gt(&mut self, pos: &Position) -> Result<(), Error> {
|
2019-08-28 19:11:09 -05:00
|
|
|
let (left, left_pos) = self.pop()?;
|
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
match (left.as_ref(), right.as_ref()) {
|
|
|
|
(&P(Int(i)), &P(Int(ii))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(i > ii))), pos.clone())?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
(&P(Float(f)), &P(Float(ff))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(f > ff))), pos.clone())?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:44:01 -05:00
|
|
|
format!(
|
2019-08-28 19:11:09 -05:00
|
|
|
"Expected numeric values of the same type but got {:?} at {} and {:?} at {} for expression",
|
|
|
|
left, left_pos, right, right_pos,
|
2019-08-18 08:44:01 -05:00
|
|
|
),
|
2019-08-18 08:40:30 -05:00
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn op_lt(&mut self, pos: &Position) -> Result<(), Error> {
|
2019-08-28 19:11:09 -05:00
|
|
|
let (left, left_pos) = self.pop()?;
|
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
match (left.as_ref(), right.as_ref()) {
|
|
|
|
(&P(Int(i)), &P(Int(ii))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(i < ii))), pos.clone())?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
(&P(Float(f)), &P(Float(ff))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(f < ff))), pos.clone())?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:44:01 -05:00
|
|
|
format!(
|
2019-08-28 19:11:09 -05:00
|
|
|
"Expected numeric values of the same type but got {:?} at {} and {:?} at {} for expression",
|
|
|
|
left, left_pos, right, right_pos,
|
2019-08-18 08:44:01 -05:00
|
|
|
),
|
2019-08-18 08:40:30 -05:00
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_lteq(&mut self, pos: Position) -> Result<(), Error> {
|
2019-08-28 19:11:09 -05:00
|
|
|
let (left, left_pos) = self.pop()?;
|
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
match (left.as_ref(), right.as_ref()) {
|
|
|
|
(&P(Int(i)), &P(Int(ii))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(i <= ii))), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
(&P(Float(f)), &P(Float(ff))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(f <= ff))), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:44:01 -05:00
|
|
|
format!(
|
2019-08-28 19:11:09 -05:00
|
|
|
"Expected numeric values of the same type but got {:?} at {} and {:?} at {} for expression",
|
|
|
|
left, left_pos, right, right_pos,
|
2019-08-18 08:44:01 -05:00
|
|
|
),
|
2019-08-18 15:40:23 -05:00
|
|
|
pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_gteq(&mut self, pos: Position) -> Result<(), Error> {
|
2019-08-28 19:11:09 -05:00
|
|
|
let (left, left_pos) = self.pop()?;
|
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
match (left.as_ref(), right.as_ref()) {
|
|
|
|
(&P(Int(i)), &P(Int(ii))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(i >= ii))), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
(&P(Float(f)), &P(Float(ff))) => {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Bool(f >= ff))), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:44:01 -05:00
|
|
|
format!(
|
2019-08-28 19:11:09 -05:00
|
|
|
"Expected numeric values of the same type but got {:?} at {} and {:?} at {} for expression",
|
|
|
|
left, left_pos, right, right_pos,
|
2019-08-18 08:44:01 -05:00
|
|
|
),
|
2019-08-18 15:40:23 -05:00
|
|
|
pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_mod(&mut self, pos: Position) -> Result<(), Error> {
|
2019-08-02 18:02:45 -05:00
|
|
|
// Adds the previous two items in the stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (left, _) = self.pop()?;
|
2019-08-28 19:11:09 -05:00
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-08-02 18:02:45 -05:00
|
|
|
// Then pushes the result onto the stack.
|
2019-08-28 19:11:09 -05:00
|
|
|
self.push(Rc::new(P(self.modulus(&left, &right, &right_pos)?)), pos)?;
|
2019-08-02 18:02:45 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_add(&mut self, pos: Position) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// Adds the previous two items in the stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (left, _) = self.pop()?;
|
2019-08-28 19:11:09 -05:00
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// Then pushes the result onto the stack.
|
2019-08-28 19:11:09 -05:00
|
|
|
self.push(Rc::new(self.add(&left, &right, &right_pos)?), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_sub(&mut self, pos: Position) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// Subtracts the previous two items in the stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (left, _) = self.pop()?;
|
2019-08-28 19:11:09 -05:00
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// Then pushes the result onto the stack.
|
2019-08-28 19:11:09 -05:00
|
|
|
self.push(Rc::new(P(self.sub(&left, &right, &right_pos)?)), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_mul(&mut self, pos: Position) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// Multiplies the previous two items in the stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (left, _) = self.pop()?;
|
2019-08-28 19:11:09 -05:00
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// Then pushes the result onto the stack.
|
2019-08-28 19:11:09 -05:00
|
|
|
self.push(Rc::new(P(self.mul(&left, &right, &right_pos)?)), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_div(&mut self, pos: Position) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// Divides the previous two items in the stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (left, _) = self.pop()?;
|
2019-08-28 19:11:09 -05:00
|
|
|
let (right, right_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// Then pushes the result onto the stack.
|
2019-08-28 19:11:09 -05:00
|
|
|
self.push(Rc::new(P(self.div(&left, &right, &right_pos)?)), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-20 19:36:07 -05:00
|
|
|
fn op_push_self(&mut self) -> Result<(), Error> {
|
|
|
|
// We'll need a self stack.
|
|
|
|
let (val, pos) = self.pop()?;
|
2019-08-26 21:24:17 -05:00
|
|
|
self.self_stack.push((val.clone(), pos.clone()));
|
2019-08-20 19:36:07 -05:00
|
|
|
self.push(val.clone(), pos)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_pop_self(&mut self) -> Result<(), Error> {
|
|
|
|
// We'll need a self stack.
|
|
|
|
self.self_stack.pop();
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_bind(&mut self, strict: bool) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// pop val off stack.
|
2019-08-18 15:40:23 -05:00
|
|
|
let (val, val_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// pop name off stack.
|
2019-08-20 21:30:17 -05:00
|
|
|
let (name, name_pos) = self.pop()?;
|
|
|
|
// TODO(jwall): We need to restrict against our reserved word list.
|
2019-07-17 18:54:19 -05:00
|
|
|
if let &S(ref name) = name.as_ref() {
|
2019-08-20 21:30:17 -05:00
|
|
|
self.binding_push(name.clone(), val, strict, &val_pos, &name_pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
} else {
|
2019-08-18 08:40:30 -05:00
|
|
|
unreachable!();
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_field(&mut self) -> Result<(), Error> {
|
|
|
|
// Add a Composite field value to a tuple on the stack
|
|
|
|
// get value from stack
|
2019-09-01 19:21:02 -05:00
|
|
|
let (val, val_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// get name from stack.
|
2019-09-01 19:21:02 -05:00
|
|
|
let (name_val, name_pos) = self.pop()?;
|
2019-07-17 18:54:19 -05:00
|
|
|
let name = if let &S(ref s) | &P(Str(ref s)) = name_val.as_ref() {
|
2019-07-13 10:59:10 -05:00
|
|
|
s
|
|
|
|
} else {
|
2019-08-18 08:40:30 -05:00
|
|
|
unreachable!();
|
2019-07-13 10:59:10 -05:00
|
|
|
};
|
|
|
|
// get composite tuple from stack
|
2019-08-18 15:40:23 -05:00
|
|
|
let (tpl, tpl_pos) = self.pop()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &C(Tuple(ref flds, ref pos_list)) = tpl.as_ref() {
|
2019-07-13 10:59:10 -05:00
|
|
|
// add name and value to tuple
|
2019-07-17 18:54:19 -05:00
|
|
|
let mut flds = flds.clone();
|
2019-09-01 19:21:02 -05:00
|
|
|
let mut pos_list = pos_list.clone();
|
|
|
|
self.merge_field_into_tuple(
|
|
|
|
&mut flds,
|
|
|
|
&mut pos_list,
|
|
|
|
name.clone(),
|
|
|
|
&name_pos,
|
|
|
|
val,
|
|
|
|
&val_pos,
|
|
|
|
)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// place composite tuple back on stack
|
2019-09-01 19:21:02 -05:00
|
|
|
self.push(Rc::new(C(Tuple(flds, pos_list))), tpl_pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
} else {
|
2019-08-18 08:40:30 -05:00
|
|
|
unreachable!();
|
2019-07-13 10:59:10 -05:00
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn op_element(&mut self) -> Result<(), Error> {
|
|
|
|
// get element from stack.
|
2019-09-01 19:21:02 -05:00
|
|
|
let (val, val_pos) = self.pop()?;
|
2019-07-13 10:59:10 -05:00
|
|
|
// get next value. It should be a Composite list.
|
2019-08-26 21:24:17 -05:00
|
|
|
let (list, pos) = self.pop()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &C(List(ref elems, ref pos_list)) = list.as_ref() {
|
2019-07-13 10:59:10 -05:00
|
|
|
// add value to list
|
2019-07-17 18:54:19 -05:00
|
|
|
let mut elems = elems.clone();
|
2019-07-13 10:59:10 -05:00
|
|
|
elems.push(val);
|
2019-09-01 19:21:02 -05:00
|
|
|
let mut pos_list = pos_list.clone();
|
|
|
|
pos_list.push(val_pos);
|
2019-07-13 10:59:10 -05:00
|
|
|
// Add that value to the list and put list back on stack.
|
2019-09-01 19:21:02 -05:00
|
|
|
self.push(Rc::new(C(List(elems, pos_list))), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
} else {
|
2019-08-18 08:40:30 -05:00
|
|
|
unreachable!();
|
2019-07-13 10:59:10 -05:00
|
|
|
};
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-14 19:52:41 -05:00
|
|
|
fn op_bang(&mut self) -> Result<(), Error> {
|
2019-08-28 19:11:09 -05:00
|
|
|
let (msg_val, err_pos) = self.pop()?;
|
|
|
|
if let &P(Str(ref msg)) = msg_val.as_ref() {
|
|
|
|
return Err(Error::new(msg.clone(), err_pos));
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
}
|
2019-08-14 19:52:41 -05:00
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_index(&mut self, safe: bool, pos: Position) -> Result<(), Error> {
|
2019-08-02 18:55:18 -05:00
|
|
|
// left and then right
|
2019-08-26 21:24:17 -05:00
|
|
|
let (right, right_pos) = self.pop()?;
|
|
|
|
let (left, _) = self.pop()?;
|
2019-08-02 18:55:18 -05:00
|
|
|
match right.as_ref() {
|
|
|
|
&P(Int(i)) => {
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &C(List(ref elems, _)) = left.as_ref() {
|
2019-08-02 18:55:18 -05:00
|
|
|
if i < (elems.len() as i64) && i >= 0 {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(elems[i as usize].clone(), right_pos)?;
|
2019-08-02 18:55:18 -05:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&P(Str(ref s)) => {
|
2019-09-01 19:21:02 -05:00
|
|
|
if let &C(Tuple(ref flds, _)) = left.as_ref() {
|
2019-08-02 18:55:18 -05:00
|
|
|
for &(ref key, ref val) in flds.iter() {
|
|
|
|
if key == s {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(val.clone(), right_pos)?;
|
2019-08-02 18:55:18 -05:00
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-02 18:55:18 -05:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// noop
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
};
|
2019-08-13 18:16:00 -05:00
|
|
|
if safe {
|
2019-08-18 15:40:23 -05:00
|
|
|
self.push(Rc::new(P(Empty)), pos)?;
|
2019-08-13 18:16:00 -05:00
|
|
|
return Ok(());
|
|
|
|
}
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:40:30 -05:00
|
|
|
format!("Invalid selector index: {:?} target: {:?}", right, left),
|
2019-08-18 15:40:23 -05:00
|
|
|
pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
|
2019-09-01 10:21:05 -05:00
|
|
|
fn op_exist(&mut self, pos: Position) -> Result<(), Error> {
|
|
|
|
let (right, right_pos) = self.pop()?;
|
|
|
|
let (left, left_pos) = self.pop()?;
|
|
|
|
match left.as_ref() {
|
2019-09-01 19:21:02 -05:00
|
|
|
&C(Tuple(ref flds, _)) => {
|
2019-09-01 10:21:05 -05:00
|
|
|
if let &P(Str(ref name)) = right.as_ref() {
|
|
|
|
for (ref nm, _) in flds {
|
|
|
|
if nm == name {
|
|
|
|
self.push(Rc::new(P(Bool(true))), pos)?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected String or Symbol got: {}", right.type_name()),
|
|
|
|
right_pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
&C(List(ref elems, _)) => {
|
2019-09-01 10:21:05 -05:00
|
|
|
for e in elems {
|
2019-11-09 18:48:39 -06:00
|
|
|
if e == &right {
|
2019-09-01 10:21:05 -05:00
|
|
|
self.push(Rc::new(P(Bool(true))), pos)?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
&P(Str(ref s)) => {
|
|
|
|
if let &P(Str(ref part)) = right.as_ref() {
|
|
|
|
self.push(Rc::new(P(Bool(s.contains(part)))), pos)?;
|
|
|
|
return Ok(());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected String, Tuple, or List got: {}", left.type_name()),
|
|
|
|
left_pos,
|
|
|
|
));
|
|
|
|
}
|
|
|
|
};
|
|
|
|
self.push(Rc::new(P(Bool(false))), pos)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_copy(&mut self, pos: Position) -> Result<(), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
// This value should always be a tuple
|
2019-09-01 19:21:02 -05:00
|
|
|
let (override_val, val_pos) = self.pop()?;
|
|
|
|
// get target value. It should be a Module or Tuple.
|
2019-08-26 21:24:17 -05:00
|
|
|
let (tgt, tgt_pos) = self.pop()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
let (overrides, override_pos_list) =
|
|
|
|
if let &C(Tuple(ref oflds, ref pos_list)) = override_val.as_ref() {
|
|
|
|
(oflds.clone(), pos_list.clone())
|
|
|
|
} else {
|
|
|
|
unreachable!();
|
|
|
|
};
|
2019-07-17 18:54:19 -05:00
|
|
|
match tgt.as_ref() {
|
2019-09-01 19:21:02 -05:00
|
|
|
&C(Tuple(ref flds, ref pos_list)) => {
|
2019-07-17 18:54:19 -05:00
|
|
|
let mut flds = flds.clone();
|
2019-09-01 19:21:02 -05:00
|
|
|
let mut pos_list = pos_list.clone();
|
|
|
|
let mut counter = 0;
|
2019-07-13 10:59:10 -05:00
|
|
|
for (name, val) in overrides {
|
2019-09-01 19:21:02 -05:00
|
|
|
let name_pos = override_pos_list[counter].0.clone();
|
|
|
|
let val_pos = override_pos_list[counter].1.clone();
|
|
|
|
self.merge_field_into_tuple(
|
|
|
|
&mut flds,
|
|
|
|
&mut pos_list,
|
|
|
|
name,
|
|
|
|
&name_pos,
|
|
|
|
val,
|
|
|
|
&val_pos,
|
|
|
|
)?;
|
|
|
|
counter += 1;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
// Put the copy on the Stack
|
2019-09-01 19:21:02 -05:00
|
|
|
self.push(Rc::new(C(Tuple(flds, pos_list))), tgt_pos.clone())?;
|
2019-08-20 19:03:49 -05:00
|
|
|
self.last = Some((tgt.clone(), tgt_pos));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
&M(Module {
|
|
|
|
ref ptr,
|
|
|
|
ref result_ptr,
|
|
|
|
ref flds,
|
2019-09-01 19:21:02 -05:00
|
|
|
ref flds_pos_list,
|
2019-08-17 16:57:45 -05:00
|
|
|
ref pkg_ptr,
|
2019-07-13 10:59:10 -05:00
|
|
|
}) => {
|
2019-08-17 16:57:45 -05:00
|
|
|
let this = M(Module {
|
|
|
|
ptr: ptr.clone(),
|
|
|
|
result_ptr: result_ptr.clone(),
|
|
|
|
flds: flds.clone(),
|
2019-09-01 19:21:02 -05:00
|
|
|
flds_pos_list: flds_pos_list.clone(),
|
2019-08-17 16:57:45 -05:00
|
|
|
pkg_ptr: pkg_ptr.clone(),
|
|
|
|
});
|
|
|
|
|
2019-07-17 18:54:19 -05:00
|
|
|
let mut flds = flds.clone();
|
2019-09-01 19:21:02 -05:00
|
|
|
let mut flds_pos_list = flds_pos_list.clone();
|
|
|
|
let mut counter = 0;
|
2019-07-13 10:59:10 -05:00
|
|
|
for (name, val) in overrides {
|
2019-09-01 19:21:02 -05:00
|
|
|
let name_pos = override_pos_list[counter].0.clone();
|
|
|
|
let val_pos = override_pos_list[counter].1.clone();
|
|
|
|
self.merge_field_into_tuple(
|
|
|
|
&mut flds,
|
|
|
|
&mut flds_pos_list,
|
|
|
|
name,
|
|
|
|
&name_pos,
|
|
|
|
val,
|
|
|
|
&val_pos,
|
|
|
|
)?;
|
|
|
|
counter += 1;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
self.merge_field_into_tuple(
|
|
|
|
&mut flds,
|
|
|
|
&mut flds_pos_list,
|
|
|
|
"this".to_owned(),
|
|
|
|
&pos,
|
|
|
|
Rc::new(this),
|
|
|
|
&val_pos,
|
|
|
|
)?;
|
2019-08-17 16:57:45 -05:00
|
|
|
if let Some(ptr) = pkg_ptr {
|
2019-09-02 10:10:24 -05:00
|
|
|
let mut pkg_vm = self
|
|
|
|
.clean_copy()
|
|
|
|
.to_new_pointer(ptr.clone())
|
2019-09-01 19:21:02 -05:00
|
|
|
.with_import_stack(self.import_stack.clone());
|
2019-08-17 16:57:45 -05:00
|
|
|
pkg_vm.run()?;
|
2019-09-01 19:21:02 -05:00
|
|
|
let (pkg_func, val_pos) = pkg_vm.pop()?;
|
|
|
|
self.merge_field_into_tuple(
|
|
|
|
&mut flds,
|
|
|
|
&mut flds_pos_list,
|
|
|
|
"pkg".to_owned(),
|
|
|
|
&pos,
|
|
|
|
pkg_func,
|
|
|
|
&val_pos,
|
|
|
|
)?;
|
2019-08-17 16:57:45 -05:00
|
|
|
}
|
|
|
|
|
2019-09-02 10:10:24 -05:00
|
|
|
let mut vm = self
|
|
|
|
.clean_copy()
|
|
|
|
.to_new_pointer(ptr.clone())
|
2019-09-01 19:21:02 -05:00
|
|
|
.with_import_stack(self.import_stack.clone());
|
2019-08-18 15:40:23 -05:00
|
|
|
vm.push(Rc::new(S("mod".to_owned())), pos.clone())?;
|
2019-09-01 19:21:02 -05:00
|
|
|
vm.push(Rc::new(C(Tuple(flds, flds_pos_list))), pos.clone())?;
|
|
|
|
decorate_call!(pos => vm.run())?;
|
2019-08-12 22:07:26 -05:00
|
|
|
if let Some(ptr) = result_ptr {
|
2019-07-17 18:54:19 -05:00
|
|
|
vm.ops.jump(ptr.clone())?;
|
2019-07-13 10:59:10 -05:00
|
|
|
vm.run()?;
|
2019-08-18 15:40:23 -05:00
|
|
|
let (result_val, result_pos) = vm.pop()?;
|
2019-08-26 21:24:17 -05:00
|
|
|
self.push(result_val, result_pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
} else {
|
2019-08-26 21:24:17 -05:00
|
|
|
self.push(Rc::new(vm.symbols_to_tuple(false)), pos)?;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-09-01 19:21:02 -05:00
|
|
|
format!("Expected a Tuple or Module but got {:?}", tgt),
|
2019-08-18 15:40:23 -05:00
|
|
|
pos,
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn merge_field_into_tuple(
|
|
|
|
&self,
|
2019-07-17 18:54:19 -05:00
|
|
|
src_fields: &'a mut Vec<(String, Rc<Value>)>,
|
2019-09-01 19:21:02 -05:00
|
|
|
pos_fields: &'a mut Vec<(Position, Position)>,
|
2019-07-13 10:59:10 -05:00
|
|
|
name: String,
|
2019-09-01 19:21:02 -05:00
|
|
|
name_pos: &Position,
|
2019-07-17 18:54:19 -05:00
|
|
|
value: Rc<Value>,
|
2019-09-01 19:21:02 -05:00
|
|
|
val_pos: &Position,
|
2019-07-13 10:59:10 -05:00
|
|
|
) -> Result<(), Error> {
|
2019-09-01 19:21:02 -05:00
|
|
|
let mut counter = 0;
|
2019-07-13 10:59:10 -05:00
|
|
|
for fld in src_fields.iter_mut() {
|
|
|
|
if fld.0 == name {
|
2019-09-01 19:21:02 -05:00
|
|
|
if fld.1.type_name() != value.type_name()
|
|
|
|
&& !(fld.1.type_name() == "NULL" || value.type_name() == "NULL")
|
|
|
|
{
|
|
|
|
return Err(Error::new(
|
|
|
|
format!(
|
|
|
|
"Expected type {} for field {} but got ({})",
|
|
|
|
fld.1.type_name(),
|
|
|
|
name,
|
|
|
|
value.type_name(),
|
|
|
|
),
|
|
|
|
val_pos.clone(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
pos_fields[counter].1 = val_pos.clone();
|
2019-07-13 10:59:10 -05:00
|
|
|
fld.1 = value;
|
|
|
|
return Ok(());
|
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
counter += 1;
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
src_fields.push((name, value));
|
2019-09-01 19:21:02 -05:00
|
|
|
pos_fields.push((name_pos.clone(), val_pos.clone()));
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn push(&mut self, val: Rc<Value>, pos: Position) -> Result<(), Error> {
|
|
|
|
self.stack.push((val, pos));
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-12 22:07:26 -05:00
|
|
|
pub fn binding_push(
|
|
|
|
&mut self,
|
|
|
|
name: String,
|
|
|
|
val: Rc<Value>,
|
|
|
|
strict: bool,
|
2019-08-18 08:40:30 -05:00
|
|
|
pos: &Position,
|
2019-08-20 21:30:17 -05:00
|
|
|
name_pos: &Position,
|
2019-08-12 22:07:26 -05:00
|
|
|
) -> Result<(), Error> {
|
2019-08-20 21:30:17 -05:00
|
|
|
if self.reserved_words.contains(name.as_str()) {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-20 21:30:17 -05:00
|
|
|
format!("{} is a reserved word.", name),
|
|
|
|
name_pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-08-20 21:30:17 -05:00
|
|
|
}
|
2019-08-12 22:07:26 -05:00
|
|
|
if self.symbols.is_bound(&name) && strict {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
2019-08-18 08:40:30 -05:00
|
|
|
format!("Binding {} already exists", name),
|
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
));
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-20 19:03:49 -05:00
|
|
|
self.symbols.add(name, val, pos.clone());
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-08-20 19:03:49 -05:00
|
|
|
pub fn get_binding(
|
|
|
|
&'a self,
|
|
|
|
name: &str,
|
|
|
|
pos: &Position,
|
|
|
|
) -> Result<(Rc<Value>, Position), Error> {
|
2019-08-20 19:36:07 -05:00
|
|
|
if name == "self" {
|
|
|
|
if let Some((val, pos)) = self.self_stack.last() {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Ok((val.clone(), pos.clone()));
|
2019-08-20 19:36:07 -05:00
|
|
|
}
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(format!("No such binding {}", name), pos.clone()));
|
2019-08-20 19:36:07 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
match self.symbols.get(name) {
|
2019-08-20 19:03:49 -05:00
|
|
|
Some((ref v, ref pos)) => Ok((v.clone(), pos.clone())),
|
2019-08-20 20:51:46 -05:00
|
|
|
None => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(format!("No such binding {}", name), pos.clone()));
|
2019-08-20 20:51:46 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
pub fn pop(&mut self) -> Result<(Rc<Value>, Position), Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
match self.stack.pop() {
|
2019-08-20 20:51:46 -05:00
|
|
|
Some(v) => {
|
|
|
|
self.last = Some(v.clone());
|
|
|
|
Ok(v)
|
|
|
|
}
|
2019-08-18 08:40:30 -05:00
|
|
|
None => unreachable!(),
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn mul(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(match (left, right) {
|
|
|
|
(P(Int(i)), P(Int(ii))) => Int(i * ii),
|
|
|
|
(P(Float(f)), P(Float(ff))) => Float(f * ff),
|
2019-08-18 08:44:01 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected {} but got {:?}", left.type_name(), right),
|
2019-08-18 08:44:01 -05:00
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
))
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn div(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(match (left, right) {
|
|
|
|
(P(Int(i)), P(Int(ii))) => Int(i / ii),
|
|
|
|
(P(Float(f)), P(Float(ff))) => Float(f / ff),
|
2019-08-18 08:44:01 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected {} but got {:?}", left.type_name(), right),
|
2019-08-18 08:44:01 -05:00
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
))
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn sub(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(match (left, right) {
|
|
|
|
(P(Int(i)), Value::P(Int(ii))) => Int(i - ii),
|
|
|
|
(P(Float(f)), Value::P(Float(ff))) => Float(f - ff),
|
2019-08-18 08:44:01 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected {} but got {:?}", left.type_name(), right),
|
2019-08-18 08:44:01 -05:00
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
))
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn modulus(&self, left: &Value, right: &Value, pos: &Position) -> Result<Primitive, Error> {
|
2019-08-02 18:02:45 -05:00
|
|
|
Ok(match (left, right) {
|
|
|
|
(P(Int(i)), Value::P(Int(ii))) => Int(i % ii),
|
|
|
|
(P(Float(f)), Value::P(Float(ff))) => Float(f % ff),
|
2019-08-18 08:44:01 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected {} but got {:?}", left.type_name(), right),
|
2019-08-18 08:44:01 -05:00
|
|
|
pos.clone(),
|
2019-08-26 21:24:17 -05:00
|
|
|
))
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-08-02 18:02:45 -05:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-08-18 08:40:30 -05:00
|
|
|
fn add(&self, left: &Value, right: &Value, pos: &Position) -> Result<Value, Error> {
|
2019-07-13 10:59:10 -05:00
|
|
|
Ok(match (left, right) {
|
2019-08-17 14:42:56 -05:00
|
|
|
(P(Int(i)), Value::P(Int(ii))) => P(Int(i + ii)),
|
|
|
|
(P(Float(f)), Value::P(Float(ff))) => P(Float(f + ff)),
|
2019-07-13 10:59:10 -05:00
|
|
|
(P(Str(s)), Value::P(Str(ss))) => {
|
|
|
|
let mut ns = String::new();
|
|
|
|
ns.push_str(&s);
|
|
|
|
ns.push_str(&ss);
|
2019-08-17 14:42:56 -05:00
|
|
|
P(Str(ns))
|
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
(
|
|
|
|
C(List(ref left_list, ref left_pos_list)),
|
|
|
|
C(List(ref right_list, ref right_pos_list)),
|
|
|
|
) => {
|
|
|
|
let cap = left_list.len() + right_list.len();
|
|
|
|
let mut new_list = Vec::with_capacity(cap);
|
|
|
|
let mut new_pos_list = Vec::with_capacity(cap);
|
|
|
|
let mut counter = 0;
|
2019-08-17 14:42:56 -05:00
|
|
|
for v in left_list.iter() {
|
|
|
|
new_list.push(v.clone());
|
2019-09-01 19:21:02 -05:00
|
|
|
new_pos_list.push(left_pos_list[counter].clone());
|
|
|
|
counter += 1;
|
2019-08-17 14:42:56 -05:00
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
counter = 0;
|
2019-08-17 14:42:56 -05:00
|
|
|
for v in right_list.iter() {
|
|
|
|
new_list.push(v.clone());
|
2019-09-01 19:21:02 -05:00
|
|
|
new_pos_list.push(right_pos_list[counter].clone());
|
|
|
|
counter += 1;
|
2019-08-17 14:42:56 -05:00
|
|
|
}
|
2019-09-01 19:21:02 -05:00
|
|
|
C(List(new_list, new_pos_list))
|
2019-07-13 10:59:10 -05:00
|
|
|
}
|
2019-08-18 08:44:01 -05:00
|
|
|
_ => {
|
2019-08-26 21:24:17 -05:00
|
|
|
return Err(Error::new(
|
|
|
|
format!("Expected {} but got {:?}", left.type_name(), right),
|
|
|
|
pos.clone(),
|
|
|
|
))
|
2019-08-18 08:44:01 -05:00
|
|
|
}
|
2019-07-13 10:59:10 -05:00
|
|
|
})
|
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
|
2019-08-18 15:40:23 -05:00
|
|
|
fn op_runtime(&mut self, h: Hook, pos: Position) -> Result<(), Error> {
|
2019-08-18 08:44:01 -05:00
|
|
|
self.runtime.handle(
|
|
|
|
self.ops.path.as_ref(),
|
|
|
|
h,
|
|
|
|
&mut self.stack,
|
|
|
|
self.env.clone(),
|
2019-09-01 19:21:02 -05:00
|
|
|
&mut self.import_stack,
|
2019-09-02 10:10:24 -05:00
|
|
|
&self.working_dir,
|
2019-08-18 08:44:01 -05:00
|
|
|
pos,
|
|
|
|
)
|
2019-07-17 18:54:19 -05:00
|
|
|
}
|
2019-08-03 16:53:43 -05:00
|
|
|
|
2019-08-05 19:04:38 -05:00
|
|
|
fn op_render(&mut self) -> Result<(), Error> {
|
2019-08-18 15:40:23 -05:00
|
|
|
let (val, pos) = self.pop()?;
|
|
|
|
self.push(Rc::new(P(Str(val.as_ref().into()))), pos)?;
|
2019-08-03 16:53:43 -05:00
|
|
|
Ok(())
|
|
|
|
}
|
2019-07-17 18:54:19 -05:00
|
|
|
}
|