mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DEV: Extract the environmentally shared pieces out
This commit is contained in:
parent
946a112eb4
commit
3dd0cc6794
48
src/build/opcode/environment.rs
Normal file
48
src/build/opcode/environment.rs
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// Copyright 2019 Jeremy Wall
|
||||||
|
//
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
use std::collections::BTreeMap;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::cache;
|
||||||
|
use super::Value;
|
||||||
|
use crate::convert::{ConverterRegistry, ImporterRegistry};
|
||||||
|
|
||||||
|
// Shared Environmental between VM's for runtime usage.
|
||||||
|
pub struct Environment<Stdout, Stderr>
|
||||||
|
where
|
||||||
|
Stdout: Write,
|
||||||
|
Stderr: Write,
|
||||||
|
{
|
||||||
|
pub val_cache: BTreeMap<String, Rc<Value>>,
|
||||||
|
pub op_cache: cache::Ops, // Shared environment
|
||||||
|
pub converter_registry: ConverterRegistry, // Shared environment
|
||||||
|
pub importer_registry: ImporterRegistry, // Shared environment
|
||||||
|
pub stdout: Stdout, // Shared environment
|
||||||
|
pub stderr: Stderr, // Shared environment
|
||||||
|
// TODO(jwall): Environment Variables
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Stdout: Write, Stderr: Write> Environment<Stdout, Stderr> {
|
||||||
|
pub fn new(out: Stdout, err: Stderr) -> Self {
|
||||||
|
Self {
|
||||||
|
val_cache: BTreeMap::new(),
|
||||||
|
op_cache: cache::Ops::new(),
|
||||||
|
converter_registry: ConverterRegistry::make_registry(),
|
||||||
|
importer_registry: ImporterRegistry::make_registry(),
|
||||||
|
stdout: out,
|
||||||
|
stderr: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,6 +15,7 @@ use std::convert::{TryFrom, TryInto};
|
|||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
mod cache;
|
mod cache;
|
||||||
|
mod environment;
|
||||||
mod error;
|
mod error;
|
||||||
pub mod pointer;
|
pub mod pointer;
|
||||||
mod runtime;
|
mod runtime;
|
||||||
|
@ -11,87 +11,75 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::collections::BTreeMap;
|
use std::cell::RefCell;
|
||||||
use std::convert::TryFrom;
|
use std::convert::{TryFrom, TryInto};
|
||||||
use std::convert::TryInto;
|
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Write};
|
use std::io::Read;
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
|
|
||||||
use super::cache;
|
use super::environment::Environment;
|
||||||
use super::Value::{C, F, P};
|
use super::Value::{C, F, P};
|
||||||
use super::VM;
|
use super::VM;
|
||||||
use super::{Composite, Error, Hook, Primitive, Value};
|
use super::{Composite, Error, Hook, Primitive, Value};
|
||||||
use crate::ast::Position;
|
use crate::ast::Position;
|
||||||
use crate::build::ir::Val;
|
use crate::build::ir::Val;
|
||||||
use crate::build::AssertCollector;
|
use crate::build::AssertCollector;
|
||||||
use crate::convert::{ConverterRegistry, ImporterRegistry};
|
|
||||||
use Composite::{List, Tuple};
|
use Composite::{List, Tuple};
|
||||||
use Primitive::{Bool, Empty, Int, Str};
|
use Primitive::{Bool, Empty, Int, Str};
|
||||||
|
|
||||||
pub struct Builtins<Out: Write, Err: Write> {
|
pub struct Builtins {
|
||||||
op_cache: cache::Ops,
|
|
||||||
val_cache: BTreeMap<String, Rc<Value>>,
|
|
||||||
assert_results: AssertCollector,
|
assert_results: AssertCollector,
|
||||||
converter_registry: ConverterRegistry,
|
|
||||||
importer_registry: ImporterRegistry,
|
|
||||||
working_dir: PathBuf,
|
working_dir: PathBuf,
|
||||||
import_path: Vec<PathBuf>,
|
import_path: Vec<PathBuf>,
|
||||||
stdout: Out,
|
|
||||||
stderr: Err,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type ByteSink = Vec<u8>;
|
impl Builtins {
|
||||||
|
pub fn new() -> Self {
|
||||||
impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
Self::with_working_dir(std::env::current_dir().unwrap())
|
||||||
pub fn new(out: Out, err: Err) -> Self {
|
|
||||||
Self::with_working_dir(std::env::current_dir().unwrap(), out, err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_working_dir<P: Into<PathBuf>>(path: P, out: Out, err: Err) -> Self {
|
pub fn with_working_dir<P: Into<PathBuf>>(path: P) -> Self {
|
||||||
Self {
|
Self {
|
||||||
op_cache: cache::Ops::new(),
|
|
||||||
val_cache: BTreeMap::new(),
|
|
||||||
assert_results: AssertCollector::new(),
|
assert_results: AssertCollector::new(),
|
||||||
converter_registry: ConverterRegistry::make_registry(),
|
|
||||||
importer_registry: ImporterRegistry::make_registry(),
|
|
||||||
// FIXME(jwall): This should move into the VM and not in the Runtime.
|
|
||||||
working_dir: path.into(),
|
working_dir: path.into(),
|
||||||
import_path: Vec::new(),
|
import_path: Vec::new(),
|
||||||
stdout: out,
|
|
||||||
stderr: err,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_stdout(&self) -> &Out {
|
pub fn clone(&self) -> Self {
|
||||||
&self.stdout
|
Self {
|
||||||
|
assert_results: AssertCollector::new(),
|
||||||
|
working_dir: self.working_dir.clone(),
|
||||||
|
import_path: self.import_path.clone(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_stderr(&self) -> &Err {
|
pub fn handle<P: AsRef<Path>, O, E>(
|
||||||
&self.stderr
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handle<P: AsRef<Path>>(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
path: P,
|
path: P,
|
||||||
h: Hook,
|
h: Hook,
|
||||||
stack: &mut Vec<Rc<Value>>,
|
stack: &mut Vec<Rc<Value>>,
|
||||||
) -> Result<(), Error> {
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
match h {
|
match h {
|
||||||
Hook::Import => self.import(stack),
|
Hook::Import => self.import(stack, env),
|
||||||
Hook::Include => self.include(stack),
|
Hook::Include => self.include(stack, env),
|
||||||
Hook::Assert => self.assert(stack),
|
Hook::Assert => self.assert(stack),
|
||||||
Hook::Convert => self.convert(stack),
|
Hook::Convert => self.convert(stack, env),
|
||||||
Hook::Out => self.out(path, stack),
|
Hook::Out => self.out(path, stack, env),
|
||||||
Hook::Map => self.map(path, stack),
|
Hook::Map => self.map(path, stack, env),
|
||||||
Hook::Filter => self.filter(path, stack),
|
Hook::Filter => self.filter(path, stack, env),
|
||||||
Hook::Reduce => self.reduce(path, stack),
|
Hook::Reduce => self.reduce(path, stack, env),
|
||||||
Hook::Regex => self.regex(stack),
|
Hook::Regex => self.regex(stack),
|
||||||
Hook::Range => self.range(stack),
|
Hook::Range => self.range(stack),
|
||||||
Hook::Trace(pos) => self.trace(stack, pos),
|
Hook::Trace(pos) => self.trace(stack, pos, env),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -142,21 +130,35 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
Ok(contents)
|
Ok(contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import(&mut self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn import<O, E>(
|
||||||
|
&mut self,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
let path = stack.pop();
|
let path = stack.pop();
|
||||||
if let Some(val) = path {
|
if let Some(val) = path {
|
||||||
if let &Value::P(Str(ref path)) = val.as_ref() {
|
if let &Value::P(Str(ref path)) = val.as_ref() {
|
||||||
if self.val_cache.contains_key(path) {
|
let mut borrowed_env = env.borrow_mut();
|
||||||
stack.push(self.val_cache[path].clone());
|
let val_cache = &mut borrowed_env.val_cache;
|
||||||
|
if val_cache.contains_key(path) {
|
||||||
|
stack.push(val_cache[path].clone());
|
||||||
} else {
|
} else {
|
||||||
let op_pointer = self.op_cache.entry(path).get_pointer_or_else(|| {
|
let op_pointer =
|
||||||
// FIXME(jwall): import
|
env.borrow_mut()
|
||||||
unimplemented!("Compiling paths are not implemented yet");
|
.op_cache
|
||||||
});
|
.entry(path)
|
||||||
let mut vm = VM::with_pointer(path, op_pointer);
|
.get_pointer_or_else(|| {
|
||||||
|
// FIXME(jwall): import
|
||||||
|
unimplemented!("Compiling paths are not implemented yet");
|
||||||
|
});
|
||||||
|
let mut vm = VM::with_pointer(path, op_pointer, env.clone());
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
let result = Rc::new(vm.symbols_to_tuple(true));
|
let result = Rc::new(vm.symbols_to_tuple(true));
|
||||||
self.val_cache.insert(path.clone(), result.clone());
|
val_cache.insert(path.clone(), result.clone());
|
||||||
stack.push(result);
|
stack.push(result);
|
||||||
}
|
}
|
||||||
return Ok(());
|
return Ok(());
|
||||||
@ -165,7 +167,15 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn include(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn include<O, E>(
|
||||||
|
&self,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
// TODO(jwall): include
|
// TODO(jwall): include
|
||||||
let path = stack.pop();
|
let path = stack.pop();
|
||||||
let typ = stack.pop();
|
let typ = stack.pop();
|
||||||
@ -190,21 +200,23 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
if typ == "str" {
|
if typ == "str" {
|
||||||
stack.push(Rc::new(P(Str(self.get_file_as_string(&path)?))));
|
stack.push(Rc::new(P(Str(self.get_file_as_string(&path)?))));
|
||||||
} else {
|
} else {
|
||||||
stack.push(Rc::new(match self.importer_registry.get_importer(&typ) {
|
stack.push(Rc::new(
|
||||||
Some(importer) => {
|
match env.borrow().importer_registry.get_importer(&typ) {
|
||||||
let contents = self.get_file_as_string(&path)?;
|
Some(importer) => {
|
||||||
if contents.len() == 0 {
|
let contents = self.get_file_as_string(&path)?;
|
||||||
eprintln!("including an empty file. Use NULL as the result");
|
if contents.len() == 0 {
|
||||||
P(Empty)
|
eprintln!("including an empty file. Use NULL as the result");
|
||||||
} else {
|
P(Empty)
|
||||||
match importer.import(contents.as_bytes()) {
|
} else {
|
||||||
Ok(v) => v.try_into()?,
|
match importer.import(contents.as_bytes()) {
|
||||||
Err(_e) => return Err(dbg!(Error {})),
|
Ok(v) => v.try_into()?,
|
||||||
|
Err(_e) => return Err(dbg!(Error {})),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
None => return Err(dbg!(Error {})),
|
||||||
None => return Err(dbg!(Error {})),
|
},
|
||||||
}));
|
));
|
||||||
}
|
}
|
||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
}
|
}
|
||||||
@ -243,13 +255,22 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn out<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn out<P: AsRef<Path>, O, E>(
|
||||||
|
&self,
|
||||||
|
path: P,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
if let Some(val) = val {
|
if let Some(val) = val {
|
||||||
let val = val.try_into()?;
|
let val = val.try_into()?;
|
||||||
if let Some(c_type_val) = stack.pop() {
|
if let Some(c_type_val) = stack.pop() {
|
||||||
if let &Value::S(ref c_type) = c_type_val.as_ref() {
|
if let &Value::S(ref c_type) = c_type_val.as_ref() {
|
||||||
if let Some(c) = self.converter_registry.get_converter(c_type) {
|
if let Some(c) = env.borrow().converter_registry.get_converter(c_type) {
|
||||||
match c.convert(Rc::new(val), &mut File::create(path)?) {
|
match c.convert(Rc::new(val), &mut File::create(path)?) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// noop
|
// noop
|
||||||
@ -264,13 +285,21 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn convert(&self, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn convert<O, E>(
|
||||||
|
&self,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
let val = stack.pop();
|
let val = stack.pop();
|
||||||
if let Some(val) = val {
|
if let Some(val) = val {
|
||||||
let val = val.try_into()?;
|
let val = val.try_into()?;
|
||||||
if let Some(c_type_val) = stack.pop() {
|
if let Some(c_type_val) = stack.pop() {
|
||||||
if let &Value::S(ref c_type) = c_type_val.as_ref() {
|
if let &Value::S(ref c_type) = c_type_val.as_ref() {
|
||||||
if let Some(c) = self.converter_registry.get_converter(c_type) {
|
if let Some(c) = env.borrow().converter_registry.get_converter(c_type) {
|
||||||
let mut buf: Vec<u8> = Vec::new();
|
let mut buf: Vec<u8> = Vec::new();
|
||||||
match c.convert(Rc::new(val), &mut buf) {
|
match c.convert(Rc::new(val), &mut buf) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
@ -289,7 +318,16 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn map<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn map<P: AsRef<Path>, O, E>(
|
||||||
|
&self,
|
||||||
|
path: P,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
// get the list from the stack
|
// get the list from the stack
|
||||||
let list = if let Some(list) = stack.pop() {
|
let list = if let Some(list) = stack.pop() {
|
||||||
list
|
list
|
||||||
@ -326,13 +364,27 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
// push function argument on the stack.
|
// push function argument on the stack.
|
||||||
stack.push(e.clone());
|
stack.push(e.clone());
|
||||||
// call function and push it's result on the stack.
|
// call function and push it's result on the stack.
|
||||||
result_elems.push(VM::fcall_impl(path.as_ref().to_owned(), f, stack)?);
|
result_elems.push(VM::fcall_impl(
|
||||||
|
path.as_ref().to_owned(),
|
||||||
|
f,
|
||||||
|
stack,
|
||||||
|
env.clone(),
|
||||||
|
)?);
|
||||||
}
|
}
|
||||||
stack.push(Rc::new(C(List(result_elems))));
|
stack.push(Rc::new(C(List(result_elems))));
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn filter<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn filter<P: AsRef<Path>, O, E>(
|
||||||
|
&self,
|
||||||
|
path: P,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
// get the list from the stack
|
// get the list from the stack
|
||||||
let list = if let Some(list) = stack.pop() {
|
let list = if let Some(list) = stack.pop() {
|
||||||
list
|
list
|
||||||
@ -369,7 +421,7 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
// push function argument on the stack.
|
// push function argument on the stack.
|
||||||
stack.push(e.clone());
|
stack.push(e.clone());
|
||||||
// call function and push it's result on the stack.
|
// call function and push it's result on the stack.
|
||||||
let condition = VM::fcall_impl(path.as_ref().to_owned(), f, stack)?;
|
let condition = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?;
|
||||||
// Check for empty or boolean results and only push e back in
|
// Check for empty or boolean results and only push e back in
|
||||||
// if they are non empty and true
|
// if they are non empty and true
|
||||||
match condition.as_ref() {
|
match condition.as_ref() {
|
||||||
@ -412,7 +464,16 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reduce<P: AsRef<Path>>(&self, path: P, stack: &mut Vec<Rc<Value>>) -> Result<(), Error> {
|
fn reduce<P: AsRef<Path>, O, E>(
|
||||||
|
&self,
|
||||||
|
path: P,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
// get the list from the stack
|
// get the list from the stack
|
||||||
let list = if let Some(list) = stack.pop() {
|
let list = if let Some(list) = stack.pop() {
|
||||||
list
|
list
|
||||||
@ -455,7 +516,7 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
stack.push(e.clone());
|
stack.push(e.clone());
|
||||||
stack.push(acc.clone());
|
stack.push(acc.clone());
|
||||||
// call function and push it's result on the stack.
|
// call function and push it's result on the stack.
|
||||||
acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack)?;
|
acc = VM::fcall_impl(path.as_ref().to_owned(), f, stack, env.clone())?;
|
||||||
// Check for empty or boolean results and only push e back in
|
// Check for empty or boolean results and only push e back in
|
||||||
// if they are non empty and true
|
// if they are non empty and true
|
||||||
}
|
}
|
||||||
@ -505,7 +566,16 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn trace(&mut self, mut stack: &mut Vec<Rc<Value>>, pos: Position) -> Result<(), Error> {
|
fn trace<O, E>(
|
||||||
|
&mut self,
|
||||||
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
pos: Position,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Result<(), Error>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
let val = if let Some(val) = dbg!(stack.pop()) {
|
let val = if let Some(val) = dbg!(stack.pop()) {
|
||||||
val
|
val
|
||||||
} else {
|
} else {
|
||||||
@ -521,9 +591,11 @@ impl<Out: Write, Err: Write> Builtins<Out, Err> {
|
|||||||
};
|
};
|
||||||
let writable_val: Val = TryFrom::try_from(val.clone())?;
|
let writable_val: Val = TryFrom::try_from(val.clone())?;
|
||||||
if let Err(_) = writeln!(
|
if let Err(_) = writeln!(
|
||||||
&mut self.stderr,
|
&mut env.borrow_mut().stderr,
|
||||||
"TRACE: {} = {} at {}",
|
"TRACE: {} = {} at {}",
|
||||||
expr_pretty, writable_val, pos
|
expr_pretty,
|
||||||
|
writable_val,
|
||||||
|
pos
|
||||||
) {
|
) {
|
||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
};
|
};
|
||||||
|
@ -11,8 +11,10 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::environment::Environment;
|
||||||
use super::scope::Stack;
|
use super::scope::Stack;
|
||||||
use super::Composite::{List, Tuple};
|
use super::Composite::{List, Tuple};
|
||||||
use super::Op::{
|
use super::Op::{
|
||||||
@ -27,7 +29,8 @@ use super::VM;
|
|||||||
macro_rules! assert_cases {
|
macro_rules! assert_cases {
|
||||||
(__impl__ $cases:expr) => {
|
(__impl__ $cases:expr) => {
|
||||||
for case in $cases.drain(0..) {
|
for case in $cases.drain(0..) {
|
||||||
let mut vm = VM::new("foo.ucg", Rc::new(case.0));
|
let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
|
||||||
|
let mut vm = VM::new("foo.ucg", Rc::new(case.0), env);
|
||||||
vm.run().unwrap();
|
vm.run().unwrap();
|
||||||
assert_eq!(dbg!(vm.pop()).unwrap(), Rc::new(case.1));
|
assert_eq!(dbg!(vm.pop()).unwrap(), Rc::new(case.1));
|
||||||
}
|
}
|
||||||
@ -116,7 +119,8 @@ fn bind_op() {
|
|||||||
)];
|
)];
|
||||||
|
|
||||||
for case in cases.drain(0..) {
|
for case in cases.drain(0..) {
|
||||||
let mut vm = VM::new("bar.ucg", Rc::new(case.0));
|
let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
|
||||||
|
let mut vm = VM::new("bar.ucg", Rc::new(case.0), env);
|
||||||
vm.run().unwrap();
|
vm.run().unwrap();
|
||||||
let (name, result) = case.1;
|
let (name, result) = case.1;
|
||||||
let v = vm.get_binding(name).unwrap();
|
let v = vm.get_binding(name).unwrap();
|
||||||
@ -577,7 +581,8 @@ macro_rules! assert_parse_cases {
|
|||||||
// TODO(jwall): preprocessor
|
// TODO(jwall): preprocessor
|
||||||
let ops = Rc::new(translate::AST::translate(stmts));
|
let ops = Rc::new(translate::AST::translate(stmts));
|
||||||
assert!(ops.len() > 0);
|
assert!(ops.len() > 0);
|
||||||
let mut vm = VM::new("foo.ucg", ops.clone());
|
let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
|
||||||
|
let mut vm = VM::new("foo.ucg", ops.clone(), env);
|
||||||
vm.run().unwrap();
|
vm.run().unwrap();
|
||||||
assert_eq!(vm.pop().unwrap(), Rc::new(case.1));
|
assert_eq!(vm.pop().unwrap(), Rc::new(case.1));
|
||||||
}
|
}
|
||||||
@ -760,11 +765,11 @@ fn simple_trace() {
|
|||||||
let stmts = parse(OffsetStrIter::from(dbg!("TRACE 1+1;")), None).unwrap();
|
let stmts = parse(OffsetStrIter::from(dbg!("TRACE 1+1;")), None).unwrap();
|
||||||
let ops = Rc::new(translate::AST::translate(stmts));
|
let ops = Rc::new(translate::AST::translate(stmts));
|
||||||
assert!(ops.len() > 0);
|
assert!(ops.len() > 0);
|
||||||
let mut vm = VM::new("foo.ucg", ops.clone());
|
let env = Rc::new(RefCell::new(Environment::new(Vec::new(), Vec::new())));
|
||||||
|
let mut vm = VM::new("foo.ucg", ops.clone(), env);
|
||||||
vm.run().unwrap();
|
vm.run().unwrap();
|
||||||
assert_eq!(vm.pop().unwrap(), Rc::new(P(Int(2))));
|
assert_eq!(vm.pop().unwrap(), Rc::new(P(Int(2))));
|
||||||
let runtime = vm.get_runtime();
|
let err_out = &vm.env.borrow().stderr;
|
||||||
let err_out = runtime.get_stderr();
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
String::from_utf8_lossy(err_out).to_owned(),
|
String::from_utf8_lossy(err_out).to_owned(),
|
||||||
"TRACE: 1 + 1 = 2 at line: 1 column: 1\n"
|
"TRACE: 1 + 1 = 2 at line: 1 column: 1\n"
|
||||||
|
@ -12,10 +12,10 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value};
|
use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value};
|
||||||
use crate::ast::{FuncOpDef, Position, TemplatePart};
|
use crate::ast::{FuncOpDef, TemplatePart};
|
||||||
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
|
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
|
||||||
use crate::build::opcode::Primitive;
|
use crate::build::opcode::Primitive;
|
||||||
use crate::build::opcode::{Func, Hook, Op};
|
use crate::build::opcode::{Hook, Op};
|
||||||
|
|
||||||
pub struct AST();
|
pub struct AST();
|
||||||
|
|
||||||
|
@ -11,11 +11,11 @@
|
|||||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
use std::cell::Ref;
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use super::environment::Environment;
|
||||||
use super::pointer::OpPointer;
|
use super::pointer::OpPointer;
|
||||||
use super::runtime;
|
use super::runtime;
|
||||||
use super::scope::Stack;
|
use super::scope::Stack;
|
||||||
@ -26,35 +26,48 @@ use super::Value::{C, F, M, P, S, T};
|
|||||||
use super::{Error, Op, Primitive, Value};
|
use super::{Error, Op, Primitive, Value};
|
||||||
use super::{Func, Module};
|
use super::{Func, Module};
|
||||||
|
|
||||||
pub struct VM {
|
pub struct VM<O, E>
|
||||||
|
where
|
||||||
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
stack: Vec<Rc<Value>>,
|
stack: Vec<Rc<Value>>,
|
||||||
symbols: Stack,
|
symbols: Stack,
|
||||||
// FIXME(jwall): This should be parameterized.
|
runtime: runtime::Builtins,
|
||||||
runtime: Rc<RefCell<runtime::Builtins<Vec<u8>, Vec<u8>>>>,
|
|
||||||
ops: OpPointer,
|
ops: OpPointer,
|
||||||
// TODO(jwall): This should be optional
|
// TODO(jwall): This should be optional
|
||||||
path: PathBuf,
|
path: PathBuf,
|
||||||
|
pub env: Rc<RefCell<Environment<O, E>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> VM {
|
impl<'a, O, E> VM<O, E>
|
||||||
pub fn new<P: Into<PathBuf>>(path: P, ops: Rc<Vec<Op>>) -> Self {
|
where
|
||||||
Self::with_pointer(path, OpPointer::new(ops))
|
O: std::io::Write,
|
||||||
|
E: std::io::Write,
|
||||||
|
{
|
||||||
|
pub fn new<P: Into<PathBuf>>(
|
||||||
|
path: P,
|
||||||
|
ops: Rc<Vec<Op>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Self {
|
||||||
|
Self::with_pointer(path, OpPointer::new(ops), env)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn with_pointer<P: Into<PathBuf>>(path: P, ops: OpPointer) -> Self {
|
pub fn with_pointer<P: Into<PathBuf>>(
|
||||||
|
path: P,
|
||||||
|
ops: OpPointer,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
symbols: Stack::new(),
|
symbols: Stack::new(),
|
||||||
runtime: Rc::new(RefCell::new(runtime::Builtins::new(Vec::new(), Vec::new()))),
|
runtime: runtime::Builtins::new(),
|
||||||
ops: ops,
|
ops: ops,
|
||||||
path: path.into(),
|
path: path.into(),
|
||||||
|
env: env,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_runtime(&self) -> Ref<runtime::Builtins<Vec<u8>, Vec<u8>>> {
|
|
||||||
self.runtime.as_ref().borrow()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn to_scoped(self, symbols: Stack) -> Self {
|
pub fn to_scoped(self, symbols: Stack) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stack: Vec::new(),
|
stack: Vec::new(),
|
||||||
@ -62,6 +75,7 @@ impl<'a> VM {
|
|||||||
runtime: self.runtime.clone(),
|
runtime: self.runtime.clone(),
|
||||||
ops: self.ops.clone(),
|
ops: self.ops.clone(),
|
||||||
path: self.path.clone(),
|
path: self.path.clone(),
|
||||||
|
env: self.env.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,6 +318,7 @@ impl<'a> VM {
|
|||||||
path: P,
|
path: P,
|
||||||
f: &Func,
|
f: &Func,
|
||||||
stack: &mut Vec<Rc<Value>>,
|
stack: &mut Vec<Rc<Value>>,
|
||||||
|
env: Rc<RefCell<Environment<O, E>>>,
|
||||||
) -> Result<Rc<Value>, Error> {
|
) -> Result<Rc<Value>, Error> {
|
||||||
let Func {
|
let Func {
|
||||||
ref ptr,
|
ref ptr,
|
||||||
@ -311,7 +326,7 @@ impl<'a> VM {
|
|||||||
ref snapshot,
|
ref snapshot,
|
||||||
} = f;
|
} = f;
|
||||||
// use the captured scope snapshot for the function.
|
// use the captured scope snapshot for the function.
|
||||||
let mut vm = Self::with_pointer(path, ptr.clone()).to_scoped(snapshot.clone());
|
let mut vm = Self::with_pointer(path, ptr.clone(), env).to_scoped(snapshot.clone());
|
||||||
for nm in bindings.iter() {
|
for nm in bindings.iter() {
|
||||||
// now put each argument on our scope stack as a binding.
|
// now put each argument on our scope stack as a binding.
|
||||||
// TODO(jwall): This should do a better error if there is
|
// TODO(jwall): This should do a better error if there is
|
||||||
@ -327,7 +342,8 @@ impl<'a> VM {
|
|||||||
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
|
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
|
||||||
let scope_snapshot = self.symbols.snapshot();
|
let scope_snapshot = self.symbols.snapshot();
|
||||||
dbg!(&ptr);
|
dbg!(&ptr);
|
||||||
let mut vm = Self::with_pointer(&self.path, ptr).to_scoped(scope_snapshot);
|
let mut vm =
|
||||||
|
Self::with_pointer(&self.path, ptr, self.env.clone()).to_scoped(scope_snapshot);
|
||||||
dbg!(&vm.stack);
|
dbg!(&vm.stack);
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
dbg!(&vm.stack);
|
dbg!(&vm.stack);
|
||||||
@ -339,7 +355,7 @@ impl<'a> VM {
|
|||||||
fn op_fcall(&mut self) -> Result<(), Error> {
|
fn op_fcall(&mut self) -> Result<(), Error> {
|
||||||
let f = dbg!(self.pop())?;
|
let f = dbg!(self.pop())?;
|
||||||
if let &F(ref f) = f.as_ref() {
|
if let &F(ref f) = f.as_ref() {
|
||||||
let val = Self::fcall_impl(&self.path, f, &mut self.stack)?;
|
let val = Self::fcall_impl(&self.path, f, &mut self.stack, self.env.clone())?;
|
||||||
self.push(dbg!(val))?;
|
self.push(dbg!(val))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -641,7 +657,7 @@ impl<'a> VM {
|
|||||||
}
|
}
|
||||||
// FIXME(jwall): We need to populate the pkg key for modules.
|
// FIXME(jwall): We need to populate the pkg key for modules.
|
||||||
//self.merge_field_into_tuple(&mut flds, "this".to_owned(), this)?;
|
//self.merge_field_into_tuple(&mut flds, "this".to_owned(), this)?;
|
||||||
let mut vm = Self::with_pointer(self.path.clone(), ptr.clone());
|
let mut vm = Self::with_pointer(self.path.clone(), ptr.clone(), self.env.clone());
|
||||||
vm.push(Rc::new(S("mod".to_owned())))?;
|
vm.push(Rc::new(S("mod".to_owned())))?;
|
||||||
vm.push(Rc::new(C(Tuple(flds))))?;
|
vm.push(Rc::new(C(Tuple(flds))))?;
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
@ -757,8 +773,7 @@ impl<'a> VM {
|
|||||||
|
|
||||||
fn op_runtime(&mut self, h: Hook) -> Result<(), Error> {
|
fn op_runtime(&mut self, h: Hook) -> Result<(), Error> {
|
||||||
self.runtime
|
self.runtime
|
||||||
.borrow_mut()
|
.handle(&self.path, h, &mut self.stack, self.env.clone())
|
||||||
.handle(&self.path, h, &mut self.stack)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_render(&mut self) -> Result<(), Error> {
|
fn op_render(&mut self) -> Result<(), Error> {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user