start work on partial application, fix/abstract binding resolution
This commit is contained in:
parent
f3bf55fe72
commit
dee9bcfc33
|
@ -377,6 +377,7 @@ pub fn r#type(x: &Value) -> Value {
|
||||||
Value::Fn(_) => Value::Keyword("fn"),
|
Value::Fn(_) => Value::Keyword("fn"),
|
||||||
Value::Box(_) => Value::Keyword("box"),
|
Value::Box(_) => Value::Keyword("box"),
|
||||||
Value::BaseFn(_) => Value::Keyword("fn"),
|
Value::BaseFn(_) => Value::Keyword("fn"),
|
||||||
|
Value::Partial(_) => Value::Keyword("fn"),
|
||||||
Value::Nothing => unreachable!(),
|
Value::Nothing => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
128
src/compiler.rs
128
src/compiler.rs
|
@ -13,6 +13,7 @@ use std::rc::Rc;
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, FromPrimitive, ToPrimitive)]
|
||||||
pub enum Op {
|
pub enum Op {
|
||||||
Noop,
|
Noop,
|
||||||
|
Nothing,
|
||||||
Nil,
|
Nil,
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
|
@ -68,6 +69,7 @@ pub enum Op {
|
||||||
|
|
||||||
Call,
|
Call,
|
||||||
Return,
|
Return,
|
||||||
|
Partial,
|
||||||
|
|
||||||
Eq,
|
Eq,
|
||||||
Add,
|
Add,
|
||||||
|
@ -129,6 +131,7 @@ impl std::fmt::Display for Op {
|
||||||
use Op::*;
|
use Op::*;
|
||||||
let rep = match self {
|
let rep = match self {
|
||||||
Noop => "noop",
|
Noop => "noop",
|
||||||
|
Nothing => "nothing",
|
||||||
Nil => "nil",
|
Nil => "nil",
|
||||||
True => "true",
|
True => "true",
|
||||||
False => "false",
|
False => "false",
|
||||||
|
@ -198,6 +201,7 @@ impl std::fmt::Display for Op {
|
||||||
|
|
||||||
Call => "call",
|
Call => "call",
|
||||||
Return => "return",
|
Return => "return",
|
||||||
|
Partial => "partial",
|
||||||
|
|
||||||
SetUpvalue => "set_upvalue",
|
SetUpvalue => "set_upvalue",
|
||||||
GetUpvalue => "get_upvalue",
|
GetUpvalue => "get_upvalue",
|
||||||
|
@ -237,21 +241,21 @@ impl Chunk {
|
||||||
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
||||||
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
||||||
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
||||||
| ConcatList | PushList | PushDict | AppendDict | ConcatDict => {
|
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing => {
|
||||||
println!("{i:04}: {op}")
|
println!("{i:04}: {op}")
|
||||||
}
|
}
|
||||||
Constant | MatchConstant => {
|
Constant | MatchConstant => {
|
||||||
let next = self.bytecode[*i + 1];
|
let next = self.bytecode[*i + 1];
|
||||||
let value = &self.constants[next as usize].show();
|
let value = &self.constants[next as usize].show();
|
||||||
println!("{i:04}: {:16} {next:04}: {value}", op.to_string());
|
println!("{i:04}: {:16} {next:03}: {value}", op.to_string());
|
||||||
*i += 1;
|
*i += 1;
|
||||||
}
|
}
|
||||||
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||||
| PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch | JumpIfMatch
|
| PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch | JumpIfMatch
|
||||||
| JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt | Call | SetUpvalue
|
| JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt | Call | SetUpvalue
|
||||||
| GetUpvalue => {
|
| GetUpvalue | Partial => {
|
||||||
let next = self.bytecode[*i + 1];
|
let next = self.bytecode[*i + 1];
|
||||||
println!("{i:04}: {:16} {next:04}", op.to_string());
|
println!("{i:04}: {:16} {next:03}", op.to_string());
|
||||||
*i += 1;
|
*i += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -335,6 +339,10 @@ fn is_binding(expr: &Spanned<Ast>) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn has_placeholder(args: &[Spanned<Ast>]) -> bool {
|
||||||
|
args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _)))
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a> Compiler<'a> {
|
impl<'a> Compiler<'a> {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
ast: &'static Spanned<Ast>,
|
ast: &'static Spanned<Ast>,
|
||||||
|
@ -465,16 +473,43 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn resolve_binding(&self, name: &'static str) -> usize {
|
fn resolve_binding(&mut self, name: &'static str) {
|
||||||
if let Some(pos) = self.resolve_local(name) {
|
match self.resolve_local(name) {
|
||||||
return pos;
|
Some(position) => {
|
||||||
|
self.emit_op(Op::PushBinding);
|
||||||
|
self.emit_byte(position);
|
||||||
|
self.stack_depth += 1;
|
||||||
}
|
}
|
||||||
match self.enclosing {
|
None => match self.resolve_upvalue(name) {
|
||||||
Some(compiler) => compiler.resolve_binding(name),
|
Some(position) => {
|
||||||
None => unreachable!(),
|
println!("resolved upvalue: {name}");
|
||||||
|
self.emit_op(Op::GetUpvalue);
|
||||||
|
self.emit_byte(position);
|
||||||
|
self.stack_depth += 1;
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
println!("setting upvalue: {name}");
|
||||||
|
let upvalue = self.get_upvalue(name);
|
||||||
|
self.emit_op(Op::GetUpvalue);
|
||||||
|
self.emit_byte(upvalue.stack_pos);
|
||||||
|
self.upvalues.push(upvalue);
|
||||||
|
dbg!(&self.upvalues);
|
||||||
|
self.stack_depth += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// fn resolve_binding(&self, name: &'static str) -> usize {
|
||||||
|
// if let Some(pos) = self.resolve_local(name) {
|
||||||
|
// return pos;
|
||||||
|
// }
|
||||||
|
// match self.enclosing {
|
||||||
|
// Some(compiler) => compiler.resolve_binding(name),
|
||||||
|
// None => unreachable!(),
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
|
||||||
fn pop(&mut self) {
|
fn pop(&mut self) {
|
||||||
println!("Popping from: {}", self.ast);
|
println!("Popping from: {}", self.ast);
|
||||||
self.emit_op(Op::Pop);
|
self.emit_op(Op::Pop);
|
||||||
|
@ -599,30 +634,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.emit_op(Op::Match);
|
self.emit_op(Op::Match);
|
||||||
self.bind(name);
|
self.bind(name);
|
||||||
}
|
}
|
||||||
Word(name) | Splat(name) => match self.resolve_local(name) {
|
Word(name) | Splat(name) => self.resolve_binding(name),
|
||||||
Some(position) => {
|
|
||||||
self.emit_op(Op::PushBinding);
|
|
||||||
self.emit_byte(position);
|
|
||||||
self.stack_depth += 1;
|
|
||||||
}
|
|
||||||
None => match self.resolve_upvalue(name) {
|
|
||||||
Some(position) => {
|
|
||||||
println!("resolved upvalue: {name}");
|
|
||||||
self.emit_op(Op::GetUpvalue);
|
|
||||||
self.emit_byte(position);
|
|
||||||
self.stack_depth += 1;
|
|
||||||
}
|
|
||||||
None => {
|
|
||||||
println!("setting upvalue: {name}");
|
|
||||||
let upvalue = self.get_upvalue(name);
|
|
||||||
self.emit_op(Op::GetUpvalue);
|
|
||||||
self.emit_byte(upvalue.stack_pos);
|
|
||||||
self.upvalues.push(upvalue);
|
|
||||||
dbg!(&self.upvalues);
|
|
||||||
self.stack_depth += 1;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
PlaceholderPattern => {
|
PlaceholderPattern => {
|
||||||
self.emit_op(Op::Match);
|
self.emit_op(Op::Match);
|
||||||
}
|
}
|
||||||
|
@ -797,14 +809,6 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Dict(pairs) => {
|
|
||||||
// for pair in pairs {
|
|
||||||
// self.visit(pair);
|
|
||||||
// }
|
|
||||||
// self.emit_op(Op::PushDict);
|
|
||||||
// self.emit_byte(pairs.len());
|
|
||||||
// self.stack_depth = self.stack_depth + 1 - (pairs.len() * 2);
|
|
||||||
// }
|
|
||||||
Pair(key, value) => {
|
Pair(key, value) => {
|
||||||
self.emit_constant(Value::Keyword(key));
|
self.emit_constant(Value::Keyword(key));
|
||||||
self.visit(value);
|
self.visit(value);
|
||||||
|
@ -863,7 +867,18 @@ impl<'a> Compiler<'a> {
|
||||||
}
|
}
|
||||||
self.stack_depth = stack_depth + 1;
|
self.stack_depth = stack_depth + 1;
|
||||||
}
|
}
|
||||||
(Word(fn_name), Arguments(args)) => match get_builtin(fn_name, args.len()) {
|
(Word(fn_name), Arguments(args)) => {
|
||||||
|
if has_placeholder(args) {
|
||||||
|
let arity = args.len();
|
||||||
|
for arg in args {
|
||||||
|
self.visit(arg);
|
||||||
|
}
|
||||||
|
self.resolve_binding(fn_name);
|
||||||
|
self.emit_op(Op::Partial);
|
||||||
|
self.emit_byte(arity);
|
||||||
|
self.stack_depth -= 1;
|
||||||
|
} else {
|
||||||
|
match get_builtin(fn_name, args.len()) {
|
||||||
Some(code) => {
|
Some(code) => {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.visit(arg);
|
self.visit(arg);
|
||||||
|
@ -876,21 +891,14 @@ impl<'a> Compiler<'a> {
|
||||||
for arg in args {
|
for arg in args {
|
||||||
self.visit(arg);
|
self.visit(arg);
|
||||||
}
|
}
|
||||||
|
self.resolve_binding(fn_name);
|
||||||
self.emit_op(Op::PushBinding);
|
|
||||||
self.stack_depth += 1;
|
|
||||||
// let biter = self.bindings.iter().rev();
|
|
||||||
for binding in self.bindings.iter() {
|
|
||||||
if binding.name == *fn_name {
|
|
||||||
self.emit_byte(binding.stack_pos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.emit_op(Op::Call);
|
self.emit_op(Op::Call);
|
||||||
self.emit_byte(arity);
|
self.emit_byte(arity);
|
||||||
self.stack_depth -= arity;
|
self.stack_depth -= arity;
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
for (term, _) in rest {
|
for (term, _) in rest {
|
||||||
|
@ -1275,14 +1283,7 @@ impl<'a> Compiler<'a> {
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
}
|
}
|
||||||
StringPart::Word(word) => {
|
StringPart::Word(word) => {
|
||||||
self.emit_op(Op::PushBinding);
|
self.resolve_binding(word);
|
||||||
let biter = self.bindings.iter().rev();
|
|
||||||
for binding in biter {
|
|
||||||
if binding.name == word.as_str() {
|
|
||||||
self.emit_byte(binding.stack_pos);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
self.emit_op(Op::Stringify);
|
self.emit_op(Op::Stringify);
|
||||||
self.emit_op(Op::ConcatStrings);
|
self.emit_op(Op::ConcatStrings);
|
||||||
}
|
}
|
||||||
|
@ -1301,6 +1302,9 @@ impl<'a> Compiler<'a> {
|
||||||
self.stack_depth -= 1;
|
self.stack_depth -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Placeholder => {
|
||||||
|
self.emit_op(Op::Nothing);
|
||||||
|
}
|
||||||
Arguments(..) | Placeholder | InterpolatedPattern(..) | Splattern(..) => {
|
Arguments(..) | Placeholder | InterpolatedPattern(..) | Splattern(..) => {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,10 +76,7 @@ pub fn run(src: &'static str) {
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
env::set_var("RUST_BACKTRACE", "1");
|
env::set_var("RUST_BACKTRACE", "1");
|
||||||
let src = "
|
let src = "
|
||||||
let x = #{:a 1, :b 2}
|
|
||||||
let y = #{x}
|
|
||||||
let z = #{...x, y}
|
|
||||||
z :y :x :a
|
|
||||||
|
|
||||||
";
|
";
|
||||||
run(src);
|
run(src);
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
// TODO:
|
||||||
|
// * [ ] ensure `or` and `and` never get passed by reference
|
||||||
|
// * [ ] ensure no placeholder in `or` and `and`
|
||||||
|
|
||||||
use crate::parser::*;
|
use crate::parser::*;
|
||||||
use crate::spans::{Span, Spanned};
|
use crate::spans::{Span, Spanned};
|
||||||
use crate::value::Value;
|
use crate::value::Value;
|
||||||
|
|
12
src/value.rs
12
src/value.rs
|
@ -66,6 +66,13 @@ impl LFn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
|
pub struct Partial {
|
||||||
|
args: Vec<Value>,
|
||||||
|
name: &'static str,
|
||||||
|
function: Value,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum Value {
|
pub enum Value {
|
||||||
Nothing,
|
Nothing,
|
||||||
|
@ -82,6 +89,7 @@ pub enum Value {
|
||||||
Box(Rc<RefCell<Value>>),
|
Box(Rc<RefCell<Value>>),
|
||||||
Fn(Rc<LFn>),
|
Fn(Rc<LFn>),
|
||||||
BaseFn(BaseFn),
|
BaseFn(BaseFn),
|
||||||
|
Partial(Rc<Partial>),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PartialEq for Value {
|
impl PartialEq for Value {
|
||||||
|
@ -100,6 +108,7 @@ impl PartialEq for Value {
|
||||||
(Box(x), Box(y)) => std::ptr::eq(x.as_ref().as_ptr(), y.as_ref().as_ptr()),
|
(Box(x), Box(y)) => std::ptr::eq(x.as_ref().as_ptr(), y.as_ref().as_ptr()),
|
||||||
(Fn(x), Fn(y)) => x == y,
|
(Fn(x), Fn(y)) => x == y,
|
||||||
(BaseFn(x), BaseFn(y)) => std::ptr::eq(x, y),
|
(BaseFn(x), BaseFn(y)) => std::ptr::eq(x, y),
|
||||||
|
(Partial(x), Partial(y)) => x == y,
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +156,7 @@ impl std::fmt::Display for Value {
|
||||||
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
|
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
|
||||||
Fn(lfn) => write!(f, "fn {}", lfn.name()),
|
Fn(lfn) => write!(f, "fn {}", lfn.name()),
|
||||||
BaseFn(_) => write!(f, "base fn"),
|
BaseFn(_) => write!(f, "base fn"),
|
||||||
|
Partial(partial) => write!(f, "fn {}/partial", partial.name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -187,6 +197,7 @@ impl Value {
|
||||||
}
|
}
|
||||||
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
Box(x) => format!("box {{ {} }}", x.as_ref().borrow().show()),
|
||||||
Fn(lfn) => format!("fn {}", lfn.name()),
|
Fn(lfn) => format!("fn {}", lfn.name()),
|
||||||
|
Partial(partial) => format!("fn {}/partial", partial.name),
|
||||||
BaseFn(_) => "base fn".to_string(),
|
BaseFn(_) => "base fn".to_string(),
|
||||||
Nothing => unreachable!(),
|
Nothing => unreachable!(),
|
||||||
}
|
}
|
||||||
|
@ -253,6 +264,7 @@ impl Value {
|
||||||
Box(..) => "box",
|
Box(..) => "box",
|
||||||
Fn(..) => "fn",
|
Fn(..) => "fn",
|
||||||
BaseFn(..) => "fn",
|
BaseFn(..) => "fn",
|
||||||
|
Partial(..) => "fn",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -186,6 +186,10 @@ impl Vm {
|
||||||
self.push(Value::Nil);
|
self.push(Value::Nil);
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
|
Nothing => {
|
||||||
|
self.push(Value::Nothing);
|
||||||
|
self.ip += 1;
|
||||||
|
}
|
||||||
True => {
|
True => {
|
||||||
self.push(Value::True);
|
self.push(Value::True);
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
|
@ -700,6 +704,9 @@ impl Vm {
|
||||||
self.push(stringified);
|
self.push(stringified);
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
|
Partial => {
|
||||||
|
todo!();
|
||||||
|
}
|
||||||
Call => {
|
Call => {
|
||||||
let arity = self.chunk().bytecode[self.ip + 1];
|
let arity = self.chunk().bytecode[self.ip + 1];
|
||||||
self.ip += 2;
|
self.ip += 2;
|
||||||
|
|
Loading…
Reference in New Issue
Block a user