mirror of
https://github.com/zaphar/ucg.git
synced 2025-07-22 18:19:54 -04:00
DEV: Complex Format expressions are supported now.
This commit is contained in:
parent
e3f9b685c6
commit
cd23430f5f
@ -36,6 +36,13 @@ pub mod walk;
|
|||||||
|
|
||||||
pub use walk::Walker;
|
pub use walk::Walker;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
|
pub enum TemplatePart {
|
||||||
|
Str(Vec<char>),
|
||||||
|
PlaceHolder(usize),
|
||||||
|
Expression(Expression),
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! enum_type_equality {
|
macro_rules! enum_type_equality {
|
||||||
( $slf:ident, $r:expr, $( $l:pat ),* ) => {
|
( $slf:ident, $r:expr, $( $l:pat ),* ) => {
|
||||||
match $slf {
|
match $slf {
|
||||||
|
@ -18,24 +18,25 @@ use std::clone::Clone;
|
|||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::str::Chars;
|
use std::str::Chars;
|
||||||
|
|
||||||
|
use abortable_parser::iter::SliceIter;
|
||||||
|
use abortable_parser::Result as ParseResult;
|
||||||
|
|
||||||
use crate::ast::*;
|
use crate::ast::*;
|
||||||
use crate::build::assets;
|
use crate::build::assets;
|
||||||
use crate::build::{FileBuilder, Val};
|
use crate::build::{FileBuilder, Val};
|
||||||
use crate::error;
|
use crate::error;
|
||||||
|
use crate::iter;
|
||||||
|
use crate::parse;
|
||||||
|
use crate::tokenizer;
|
||||||
|
|
||||||
pub trait FormatRenderer {
|
pub trait FormatRenderer {
|
||||||
fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>>;
|
fn render(&self, pos: &Position) -> Result<String, Box<dyn Error>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
pub type TemplateResult = Result<Vec<TemplatePart>, Box<dyn Error>>;
|
||||||
pub enum TemplatePart<'a> {
|
|
||||||
Str(Vec<char>),
|
|
||||||
PlaceHolder(usize),
|
|
||||||
Expression(&'a str),
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait TemplateParser {
|
pub trait TemplateParser {
|
||||||
fn parse<'a>(&self, input: &'a str) -> Vec<TemplatePart<'a>>;
|
fn parse(&self, input: &str) -> TemplateResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct SimpleTemplate();
|
pub struct SimpleTemplate();
|
||||||
@ -63,7 +64,7 @@ impl<V: Into<String> + Clone> SimpleFormatter<V> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TemplateParser for SimpleTemplate {
|
impl TemplateParser for SimpleTemplate {
|
||||||
fn parse<'a>(&self, input: &'a str) -> Vec<TemplatePart<'a>> {
|
fn parse(&self, input: &str) -> TemplateResult {
|
||||||
let mut result = Vec::new();
|
let mut result = Vec::new();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let mut should_escape = false;
|
let mut should_escape = false;
|
||||||
@ -76,7 +77,6 @@ impl TemplateParser for SimpleTemplate {
|
|||||||
result.push(TemplatePart::PlaceHolder(count));
|
result.push(TemplatePart::PlaceHolder(count));
|
||||||
count += 1;
|
count += 1;
|
||||||
} else if c == '\\' && !should_escape {
|
} else if c == '\\' && !should_escape {
|
||||||
eprintln!("escaping next character");
|
|
||||||
should_escape = true;
|
should_escape = true;
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
@ -88,7 +88,7 @@ impl TemplateParser for SimpleTemplate {
|
|||||||
if buf.len() != 0 {
|
if buf.len() != 0 {
|
||||||
result.push(TemplatePart::Str(buf));
|
result.push(TemplatePart::Str(buf));
|
||||||
}
|
}
|
||||||
result
|
Ok(result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
|
|||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
let mut count = 0;
|
let mut count = 0;
|
||||||
let parser = SimpleTemplate::new();
|
let parser = SimpleTemplate::new();
|
||||||
let parts = parser.parse(&self.tmpl);
|
let parts = parser.parse(&self.tmpl)?;
|
||||||
for p in parts {
|
for p in parts {
|
||||||
match p {
|
match p {
|
||||||
TemplatePart::PlaceHolder(idx) => {
|
TemplatePart::PlaceHolder(idx) => {
|
||||||
@ -145,6 +145,88 @@ impl<V: Into<String> + Clone> FormatRenderer for SimpleFormatter<V> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct ExpressionTemplate();
|
||||||
|
|
||||||
|
impl ExpressionTemplate {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ExpressionTemplate()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn consume_expr(&self, iter: &mut Chars) -> Result<Expression, Box<dyn Error>> {
|
||||||
|
let mut result = String::new();
|
||||||
|
let mut brace_count = 0;
|
||||||
|
loop {
|
||||||
|
let c = match iter.next() {
|
||||||
|
Some(c) => c,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
if c == '{' {
|
||||||
|
brace_count += 1;
|
||||||
|
// We ignore the starting brace
|
||||||
|
if brace_count == 1 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if c == '}' {
|
||||||
|
brace_count -= 1;
|
||||||
|
// We ignore the closing brace
|
||||||
|
if brace_count == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if brace_count == 0 {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result.push(c);
|
||||||
|
}
|
||||||
|
let str_iter = iter::OffsetStrIter::new(&result);
|
||||||
|
let toks = match tokenizer::tokenize(str_iter, None) {
|
||||||
|
Ok(toks) => toks,
|
||||||
|
Err(_e) => panic!("TODO(jwall): make this not a thing"),
|
||||||
|
};
|
||||||
|
|
||||||
|
let i = SliceIter::new(&toks);
|
||||||
|
match parse::expression(i) {
|
||||||
|
ParseResult::Complete(_, expr) => Ok(expr),
|
||||||
|
ParseResult::Abort(e) | ParseResult::Fail(e) => {
|
||||||
|
panic!("TODO(jwall): make this not a thing")
|
||||||
|
}
|
||||||
|
ParseResult::Incomplete(_ei) => panic!("TODO(jwall): make this not a thing"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TemplateParser for ExpressionTemplate {
|
||||||
|
fn parse(&self, input: &str) -> TemplateResult {
|
||||||
|
let mut parts = Vec::new();
|
||||||
|
let mut should_escape = false;
|
||||||
|
let mut iter = input.chars();
|
||||||
|
let mut buf: Vec<char> = Vec::new();
|
||||||
|
loop {
|
||||||
|
let c = match iter.next() {
|
||||||
|
Some(c) => c,
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
if c == '@' && !should_escape {
|
||||||
|
parts.push(TemplatePart::Str(buf));
|
||||||
|
buf = Vec::new();
|
||||||
|
// consume our expression here
|
||||||
|
parts.push(TemplatePart::Expression(self.consume_expr(&mut iter)?));
|
||||||
|
} else if c == '\\' && !should_escape {
|
||||||
|
should_escape = true;
|
||||||
|
continue;
|
||||||
|
} else {
|
||||||
|
buf.push(c);
|
||||||
|
}
|
||||||
|
should_escape = false;
|
||||||
|
}
|
||||||
|
if buf.len() != 0 {
|
||||||
|
parts.push(TemplatePart::Str(buf));
|
||||||
|
}
|
||||||
|
Ok(parts)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ExpressionFormatter<'a, C>
|
pub struct ExpressionFormatter<'a, C>
|
||||||
where
|
where
|
||||||
C: assets::Cache,
|
C: assets::Cache,
|
||||||
|
@ -150,8 +150,10 @@ pub enum Hook {
|
|||||||
#[derive(Debug, PartialEq, Clone)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
// Stack and Name manipulation.
|
// Stack and Name manipulation.
|
||||||
Bind, // Bind a Val to a name in the heap
|
Bind, // Bind a Val to a name in the heap
|
||||||
Pop, // Pop a Value off the value stack and discard it.
|
BindOver, // Overwrite a value in the heap
|
||||||
|
Pop, // Pop a Value off the value stack and discard it.
|
||||||
|
NewScope(i32),
|
||||||
// Math ops
|
// Math ops
|
||||||
Add,
|
Add,
|
||||||
Sub,
|
Sub,
|
||||||
|
@ -16,9 +16,9 @@ use std::rc::Rc;
|
|||||||
use super::scope::Stack;
|
use super::scope::Stack;
|
||||||
use super::Composite::{List, Tuple};
|
use super::Composite::{List, Tuple};
|
||||||
use super::Op::{
|
use super::Op::{
|
||||||
Add, Bang, Bind, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, Index, InitList,
|
Add, Bang, Bind, BindOver, Cp, DeRef, Div, Element, Equal, FCall, Field, Func, Index, InitList,
|
||||||
InitThunk, InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, Noop, Pop, Render, Return,
|
InitThunk, InitTuple, Jump, JumpIfFalse, JumpIfTrue, Module, Mul, NewScope, Noop, Pop, Render,
|
||||||
SelectJump, Sub, Sym, Typ, Val,
|
Return, SelectJump, Sub, Sym, Typ, Val,
|
||||||
};
|
};
|
||||||
use super::Primitive::{Bool, Empty, Float, Int, Str};
|
use super::Primitive::{Bool, Empty, Float, Int, Str};
|
||||||
use super::Value::{C, P};
|
use super::Value::{C, P};
|
||||||
@ -78,6 +78,34 @@ fn math_ops() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn new_scopes() {
|
||||||
|
assert_cases![
|
||||||
|
vec![
|
||||||
|
Sym("foo".to_owned()),
|
||||||
|
Val(Int(1)),
|
||||||
|
Bind,
|
||||||
|
NewScope(5),
|
||||||
|
Sym("foo".to_owned()),
|
||||||
|
Val(Int(2)),
|
||||||
|
BindOver,
|
||||||
|
DeRef("foo".to_owned()),
|
||||||
|
Return,
|
||||||
|
] => P(Int(2)),
|
||||||
|
vec![
|
||||||
|
Sym("bar".to_owned()),
|
||||||
|
Val(Int(1)),
|
||||||
|
Bind,
|
||||||
|
NewScope(5),
|
||||||
|
Sym("foo".to_owned()),
|
||||||
|
Val(Int(2)),
|
||||||
|
Bind,
|
||||||
|
DeRef("bar".to_owned()),
|
||||||
|
Return,
|
||||||
|
] => P(Int(1)),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn bind_op() {
|
fn bind_op() {
|
||||||
let mut cases = vec![(
|
let mut cases = vec![(
|
||||||
@ -546,6 +574,7 @@ macro_rules! assert_parse_cases {
|
|||||||
(__impl__ $cases:expr) => {
|
(__impl__ $cases:expr) => {
|
||||||
for case in $cases.drain(0..) {
|
for case in $cases.drain(0..) {
|
||||||
let stmts = parse(OffsetStrIter::from(dbg!(case.0)), None).unwrap();
|
let stmts = parse(OffsetStrIter::from(dbg!(case.0)), None).unwrap();
|
||||||
|
// 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 mut vm = VM::new("foo.ucg", ops.clone());
|
||||||
@ -672,5 +701,6 @@ fn simple_format_expressions() {
|
|||||||
"\"@\" % (NULL);" => P(Str("NULL".to_owned())),
|
"\"@\" % (NULL);" => P(Str("NULL".to_owned())),
|
||||||
"\"@ @ @\" % (1, 2, 3);" => P(Str("1 2 3".to_owned())),
|
"\"@ @ @\" % (1, 2, 3);" => P(Str("1 2 3".to_owned())),
|
||||||
"\"@ \\\\@\" % (1);" => P(Str("1 @".to_owned())),
|
"\"@ \\\\@\" % (1);" => P(Str("1 @".to_owned())),
|
||||||
|
"\"@{item.num}\" % {num=1};" => P(Str("1".to_owned())),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
@ -11,11 +11,9 @@
|
|||||||
// 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 crate::ast::Position;
|
|
||||||
use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value};
|
use crate::ast::{BinaryExprType, Expression, FormatArgs, Statement, Value};
|
||||||
use crate::build::format::{
|
use crate::ast::{Position, TemplatePart};
|
||||||
ExpressionFormatter, FormatRenderer, SimpleTemplate, TemplateParser, TemplatePart,
|
use crate::build::format::{ExpressionTemplate, SimpleTemplate, TemplateParser};
|
||||||
};
|
|
||||||
use crate::build::opcode::Primitive;
|
use crate::build::opcode::Primitive;
|
||||||
use crate::build::opcode::Value::{C, F, M, P, T};
|
use crate::build::opcode::Value::{C, F, M, P, T};
|
||||||
use crate::build::opcode::{Hook, Op};
|
use crate::build::opcode::{Hook, Op};
|
||||||
@ -178,7 +176,9 @@ impl AST {
|
|||||||
match def.args {
|
match def.args {
|
||||||
FormatArgs::List(mut elems) => {
|
FormatArgs::List(mut elems) => {
|
||||||
let formatter = SimpleTemplate::new();
|
let formatter = SimpleTemplate::new();
|
||||||
let mut parts = dbg!(formatter.parse(&def.template));
|
// TODO(jwall): This really belongs in a preprocess step
|
||||||
|
// before here.
|
||||||
|
let mut parts = formatter.parse(&def.template).unwrap();
|
||||||
// We need to push process these in reverse order for the
|
// We need to push process these in reverse order for the
|
||||||
// vm to process things correctly;
|
// vm to process things correctly;
|
||||||
elems.reverse();
|
elems.reverse();
|
||||||
@ -196,8 +196,37 @@ impl AST {
|
|||||||
ops.push(Op::Add);
|
ops.push(Op::Add);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FormatArgs::Single(e) => {
|
FormatArgs::Single(expr) => {
|
||||||
// TODO(jwall): Use expression formatter here.
|
let formatter = ExpressionTemplate::new();
|
||||||
|
// TODO(jwall): This really belongs in a preprocess step
|
||||||
|
// before here.
|
||||||
|
let mut parts = formatter.parse(&def.template).unwrap();
|
||||||
|
parts.reverse();
|
||||||
|
let mut parts_iter = parts.drain(0..);
|
||||||
|
// TODO(jwall): We need to assume there is a new scope introduced now
|
||||||
|
ops.push(Op::Noop);
|
||||||
|
let scope_idx = ops.len() - 1;
|
||||||
|
|
||||||
|
// Add our item binding shadowing any binding that already
|
||||||
|
// existed.
|
||||||
|
ops.push(Op::Sym("item".to_owned()));
|
||||||
|
Self::translate_expr(*expr, &mut ops);
|
||||||
|
ops.push(Op::BindOver);
|
||||||
|
let mut elems = Vec::new();
|
||||||
|
let mut elems_iter = elems.drain(0..);
|
||||||
|
Self::translate_template_part(
|
||||||
|
parts_iter.next().unwrap(),
|
||||||
|
&mut elems_iter,
|
||||||
|
&mut ops,
|
||||||
|
false,
|
||||||
|
);
|
||||||
|
for p in parts_iter {
|
||||||
|
Self::translate_template_part(p, &mut elems_iter, &mut ops, false);
|
||||||
|
ops.push(Op::Add);
|
||||||
|
}
|
||||||
|
ops.push(Op::Return);
|
||||||
|
let jump_idx = (ops.len() - 1 - scope_idx) as i32;
|
||||||
|
ops[scope_idx] = Op::NewScope(jump_idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -233,16 +262,16 @@ impl AST {
|
|||||||
// In theory this should never be reachable
|
// In theory this should never be reachable
|
||||||
unreachable!();
|
unreachable!();
|
||||||
} else {
|
} else {
|
||||||
Self::translate_expr(dbg!(elems.next().unwrap()), &mut ops);
|
Self::translate_expr(elems.next().unwrap(), &mut ops);
|
||||||
ops.push(Op::Render);
|
ops.push(Op::Render);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TemplatePart::Expression(_expr) => {
|
TemplatePart::Expression(expr) => {
|
||||||
// TODO(jwall): We need to parse this.
|
|
||||||
if place_holder {
|
if place_holder {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
} else {
|
} else {
|
||||||
unimplemented!("Expression Formatters are unimmplemented");
|
Self::translate_expr(expr, &mut ops);
|
||||||
|
ops.push(Op::Render);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +86,8 @@ impl<'a> VM {
|
|||||||
Op::Sub => self.op_sub()?,
|
Op::Sub => self.op_sub()?,
|
||||||
Op::Mul => self.op_mul()?,
|
Op::Mul => self.op_mul()?,
|
||||||
Op::Div => self.op_div()?,
|
Op::Div => self.op_div()?,
|
||||||
Op::Bind => self.op_bind()?,
|
Op::Bind => self.op_bind(true)?,
|
||||||
|
Op::BindOver => self.op_bind(false)?,
|
||||||
Op::Equal => self.op_equal()?,
|
Op::Equal => self.op_equal()?,
|
||||||
Op::Not => self.op_not()?,
|
Op::Not => self.op_not()?,
|
||||||
Op::Gt => self.op_gt()?,
|
Op::Gt => self.op_gt()?,
|
||||||
@ -116,7 +117,11 @@ impl<'a> VM {
|
|||||||
Op::Module(mptr) => self.op_module(idx, mptr)?,
|
Op::Module(mptr) => self.op_module(idx, mptr)?,
|
||||||
Op::Func(jptr) => self.op_func(idx, jptr)?,
|
Op::Func(jptr) => self.op_func(idx, jptr)?,
|
||||||
Op::FCall => self.op_fcall()?,
|
Op::FCall => self.op_fcall()?,
|
||||||
Op::Return => return Ok(()),
|
Op::NewScope(jp) => self.op_new_scope(jp, self.ops.clone())?,
|
||||||
|
Op::Return => {
|
||||||
|
dbg!(&self.stack);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
Op::Pop => {
|
Op::Pop => {
|
||||||
self.pop()?;
|
self.pop()?;
|
||||||
}
|
}
|
||||||
@ -161,6 +166,7 @@ impl<'a> VM {
|
|||||||
.map(|v| (v as i32 + jp) as usize)
|
.map(|v| (v as i32 + jp) as usize)
|
||||||
.unwrap_or(jp as usize),
|
.unwrap_or(jp as usize),
|
||||||
)?;
|
)?;
|
||||||
|
dbg!(&self.stack);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -206,7 +212,7 @@ impl<'a> VM {
|
|||||||
let cond = self.pop()?;
|
let cond = self.pop()?;
|
||||||
if let &P(Bool(cond)) = cond.as_ref() {
|
if let &P(Bool(cond)) = cond.as_ref() {
|
||||||
if !cond {
|
if !cond {
|
||||||
self.op_jump(dbg!(jp))?;
|
self.op_jump(jp)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -214,15 +220,15 @@ impl<'a> VM {
|
|||||||
|
|
||||||
fn op_select_jump(&'a mut self, jp: i32) -> Result<(), Error> {
|
fn op_select_jump(&'a mut self, jp: i32) -> Result<(), Error> {
|
||||||
// pop field value off
|
// pop field value off
|
||||||
let field_name = dbg!(self.pop())?;
|
let field_name = self.pop()?;
|
||||||
// pop search value off
|
// pop search value off
|
||||||
let search = dbg!(self.pop())?;
|
let search = self.pop()?;
|
||||||
// compare them.
|
// compare them.
|
||||||
if dbg!(field_name != search) {
|
if field_name != search {
|
||||||
self.op_jump(dbg!(jp))?;
|
self.op_jump(jp)?;
|
||||||
self.push(dbg!(search))?;
|
self.push(search)?;
|
||||||
}
|
}
|
||||||
dbg!(self.ops.ptr.unwrap());
|
self.ops.ptr.unwrap();
|
||||||
// if they aren't equal then push search value back on and jump
|
// if they aren't equal then push search value back on and jump
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -246,11 +252,11 @@ impl<'a> VM {
|
|||||||
let mut ops = self.ops.clone();
|
let mut ops = self.ops.clone();
|
||||||
ops.jump(idx)?;
|
ops.jump(idx)?;
|
||||||
self.push(Rc::new(M(Module {
|
self.push(Rc::new(M(Module {
|
||||||
ptr: dbg!(ops),
|
ptr: ops,
|
||||||
result_ptr: result_ptr,
|
result_ptr: result_ptr,
|
||||||
flds: dbg!(flds),
|
flds: flds,
|
||||||
})))?;
|
})))?;
|
||||||
self.ops.jump(dbg!(jptr))
|
self.ops.jump(jptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_func(&mut self, idx: usize, jptr: usize) -> Result<(), Error> {
|
fn op_func(&mut self, idx: usize, jptr: usize) -> Result<(), Error> {
|
||||||
@ -276,11 +282,11 @@ impl<'a> VM {
|
|||||||
eprintln!("Pushing function definition on stack");
|
eprintln!("Pushing function definition on stack");
|
||||||
let mut ops = self.ops.clone();
|
let mut ops = self.ops.clone();
|
||||||
ops.jump(idx)?;
|
ops.jump(idx)?;
|
||||||
self.push(Rc::new(dbg!(F(Func {
|
self.push(Rc::new(F(Func {
|
||||||
ptr: ops, // where the function starts.
|
ptr: ops, // where the function starts.
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
snapshot: scope_snapshot,
|
snapshot: scope_snapshot,
|
||||||
}))))?;
|
})))?;
|
||||||
eprintln!("Jumping to {} past the function body", jptr);
|
eprintln!("Jumping to {} past the function body", jptr);
|
||||||
self.ops.jump(jptr)
|
self.ops.jump(jptr)
|
||||||
}
|
}
|
||||||
@ -302,13 +308,25 @@ impl<'a> VM {
|
|||||||
// TODO(jwall): This should do a better error if there is
|
// TODO(jwall): This should do a better error if there is
|
||||||
// nothing on the stack.
|
// nothing on the stack.
|
||||||
let val = stack.pop().unwrap();
|
let val = stack.pop().unwrap();
|
||||||
vm.binding_push(nm.clone(), val)?;
|
vm.binding_push(nm.clone(), val, false)?;
|
||||||
}
|
}
|
||||||
// proceed to the function body
|
// proceed to the function body
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
return vm.pop();
|
return vm.pop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn op_new_scope(&mut self, jp: i32, ptr: OpPointer) -> Result<(), Error> {
|
||||||
|
let scope_snapshot = self.symbols.snapshot();
|
||||||
|
dbg!(&ptr);
|
||||||
|
let mut vm = Self::with_pointer(&self.path, ptr).to_scoped(scope_snapshot);
|
||||||
|
dbg!(&vm.stack);
|
||||||
|
vm.run()?;
|
||||||
|
dbg!(&vm.stack);
|
||||||
|
self.push(vm.pop()?)?;
|
||||||
|
self.op_jump(jp)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn op_fcall(&mut self) -> Result<(), Error> {
|
fn op_fcall(&mut self) -> Result<(), Error> {
|
||||||
let f = self.pop()?;
|
let f = self.pop()?;
|
||||||
if let &F(ref f) = f.as_ref() {
|
if let &F(ref f) = f.as_ref() {
|
||||||
@ -319,7 +337,7 @@ impl<'a> VM {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn op_thunk(&mut self, idx: usize, jp: i32) -> Result<(), Error> {
|
fn op_thunk(&mut self, idx: usize, jp: i32) -> Result<(), Error> {
|
||||||
self.push(Rc::new(dbg!(T(idx))))?;
|
self.push(Rc::new(T(idx)))?;
|
||||||
self.op_jump(jp)
|
self.op_jump(jp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -444,13 +462,13 @@ impl<'a> VM {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn op_bind(&mut self) -> Result<(), Error> {
|
fn op_bind(&mut self, strict: bool) -> Result<(), Error> {
|
||||||
// pop val off stack.
|
// pop val off stack.
|
||||||
let val = dbg!(self.pop())?;
|
let val = self.pop()?;
|
||||||
// pop name off stack.
|
// pop name off stack.
|
||||||
let name = dbg!(self.pop())?;
|
let name = self.pop()?;
|
||||||
if let &S(ref name) = name.as_ref() {
|
if let &S(ref name) = name.as_ref() {
|
||||||
self.binding_push(name.clone(), val)?;
|
self.binding_push(name.clone(), val, strict)?;
|
||||||
} else {
|
} else {
|
||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
}
|
}
|
||||||
@ -542,8 +560,8 @@ impl<'a> VM {
|
|||||||
|
|
||||||
fn op_index(&mut self) -> Result<(), Error> {
|
fn op_index(&mut self) -> Result<(), Error> {
|
||||||
// left and then right
|
// left and then right
|
||||||
let right = dbg!(self.pop()?);
|
let right = self.pop()?;
|
||||||
let left = dbg!(self.pop()?);
|
let left = self.pop()?;
|
||||||
match right.as_ref() {
|
match right.as_ref() {
|
||||||
&P(Int(i)) => {
|
&P(Int(i)) => {
|
||||||
if let &C(List(ref elems)) = left.as_ref() {
|
if let &C(List(ref elems)) = left.as_ref() {
|
||||||
@ -573,7 +591,7 @@ impl<'a> VM {
|
|||||||
fn op_copy(&mut self) -> Result<(), Error> {
|
fn op_copy(&mut self) -> Result<(), Error> {
|
||||||
// TODO Use Cow pointers for this?
|
// TODO Use Cow pointers for this?
|
||||||
// get next value. It should be a Module or Tuple.
|
// get next value. It should be a Module or Tuple.
|
||||||
let tgt = dbg!(self.pop())?;
|
let tgt = self.pop()?;
|
||||||
// This value should always be a tuple
|
// This value should always be a tuple
|
||||||
let override_val = self.pop()?;
|
let override_val = self.pop()?;
|
||||||
let overrides = if let &C(Tuple(ref oflds)) = override_val.as_ref() {
|
let overrides = if let &C(Tuple(ref oflds)) = override_val.as_ref() {
|
||||||
@ -585,7 +603,7 @@ impl<'a> VM {
|
|||||||
&C(Tuple(ref flds)) => {
|
&C(Tuple(ref flds)) => {
|
||||||
let mut flds = flds.clone();
|
let mut flds = flds.clone();
|
||||||
for (name, val) in overrides {
|
for (name, val) in overrides {
|
||||||
dbg!(self.merge_field_into_tuple(&mut flds, name, val))?;
|
self.merge_field_into_tuple(&mut flds, name, val)?;
|
||||||
}
|
}
|
||||||
// Put the copy on the Stack
|
// Put the copy on the Stack
|
||||||
self.push(Rc::new(C(Tuple(flds))))?;
|
self.push(Rc::new(C(Tuple(flds))))?;
|
||||||
@ -608,14 +626,14 @@ impl<'a> VM {
|
|||||||
//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());
|
||||||
vm.push(Rc::new(S("mod".to_owned())))?;
|
vm.push(Rc::new(S("mod".to_owned())))?;
|
||||||
vm.push(Rc::new(C(Tuple(dbg!(flds)))))?;
|
vm.push(Rc::new(C(Tuple(flds))))?;
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
if let Some(ptr) = dbg!(result_ptr) {
|
if let Some(ptr) = result_ptr {
|
||||||
vm.ops.jump(ptr.clone())?;
|
vm.ops.jump(ptr.clone())?;
|
||||||
vm.run()?;
|
vm.run()?;
|
||||||
self.push(vm.pop()?)?;
|
self.push(vm.pop()?)?;
|
||||||
} else {
|
} else {
|
||||||
self.push(dbg!(Rc::new(vm.symbols_to_tuple(false))))?;
|
self.push(Rc::new(vm.symbols_to_tuple(false)))?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
@ -646,8 +664,13 @@ impl<'a> VM {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn binding_push(&mut self, name: String, val: Rc<Value>) -> Result<(), Error> {
|
pub fn binding_push(
|
||||||
if self.symbols.is_bound(&name) {
|
&mut self,
|
||||||
|
name: String,
|
||||||
|
val: Rc<Value>,
|
||||||
|
strict: bool,
|
||||||
|
) -> Result<(), Error> {
|
||||||
|
if self.symbols.is_bound(&name) && strict {
|
||||||
return Err(dbg!(Error {}));
|
return Err(dbg!(Error {}));
|
||||||
}
|
}
|
||||||
self.symbols.add(name, val);
|
self.symbols.add(name, val);
|
||||||
|
@ -771,7 +771,7 @@ make_fn!(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
fn expression(input: SliceIter<Token>) -> ParseResult<Expression> {
|
pub fn expression(input: SliceIter<Token>) -> ParseResult<Expression> {
|
||||||
let _input = input.clone();
|
let _input = input.clone();
|
||||||
match trace_parse!(_input, op_expression) {
|
match trace_parse!(_input, op_expression) {
|
||||||
Result::Incomplete(i) => Result::Incomplete(i),
|
Result::Incomplete(i) => Result::Incomplete(i),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user