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::Box(_) => Value::Keyword("box"),
|
||||
Value::BaseFn(_) => Value::Keyword("fn"),
|
||||
Value::Partial(_) => Value::Keyword("fn"),
|
||||
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)]
|
||||
pub enum Op {
|
||||
Noop,
|
||||
Nothing,
|
||||
Nil,
|
||||
True,
|
||||
False,
|
||||
|
@ -68,6 +69,7 @@ pub enum Op {
|
|||
|
||||
Call,
|
||||
Return,
|
||||
Partial,
|
||||
|
||||
Eq,
|
||||
Add,
|
||||
|
@ -129,6 +131,7 @@ impl std::fmt::Display for Op {
|
|||
use Op::*;
|
||||
let rep = match self {
|
||||
Noop => "noop",
|
||||
Nothing => "nothing",
|
||||
Nil => "nil",
|
||||
True => "true",
|
||||
False => "false",
|
||||
|
@ -198,6 +201,7 @@ impl std::fmt::Display for Op {
|
|||
|
||||
Call => "call",
|
||||
Return => "return",
|
||||
Partial => "partial",
|
||||
|
||||
SetUpvalue => "set_upvalue",
|
||||
GetUpvalue => "get_upvalue",
|
||||
|
@ -237,21 +241,21 @@ impl Chunk {
|
|||
| Duplicate | Decrement | Truncate | Noop | LoadTuple | LoadList | Eq | Add | Sub
|
||||
| Mult | Div | Unbox | BoxStore | Assert | Get | At | Not | Panic | EmptyString
|
||||
| ConcatStrings | Stringify | MatchType | Return | Match | Print | AppendList
|
||||
| ConcatList | PushList | PushDict | AppendDict | ConcatDict => {
|
||||
| ConcatList | PushList | PushDict | AppendDict | ConcatDict | Nothing => {
|
||||
println!("{i:04}: {op}")
|
||||
}
|
||||
Constant | MatchConstant => {
|
||||
let next = self.bytecode[*i + 1];
|
||||
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;
|
||||
}
|
||||
PushBinding | MatchTuple | MatchList | MatchDict | LoadDictValue | PushTuple
|
||||
| PushBox | Jump | JumpIfFalse | JumpIfTrue | JumpIfNoMatch | JumpIfMatch
|
||||
| JumpBack | JumpIfZero | MatchDepth | PopN | StoreAt | Call | SetUpvalue
|
||||
| GetUpvalue => {
|
||||
| GetUpvalue | Partial => {
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
@ -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> {
|
||||
pub fn new(
|
||||
ast: &'static Spanned<Ast>,
|
||||
|
@ -465,16 +473,43 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_binding(&self, name: &'static str) -> usize {
|
||||
if let Some(pos) = self.resolve_local(name) {
|
||||
return pos;
|
||||
fn resolve_binding(&mut self, name: &'static str) {
|
||||
match self.resolve_local(name) {
|
||||
Some(position) => {
|
||||
self.emit_op(Op::PushBinding);
|
||||
self.emit_byte(position);
|
||||
self.stack_depth += 1;
|
||||
}
|
||||
match self.enclosing {
|
||||
Some(compiler) => compiler.resolve_binding(name),
|
||||
None => unreachable!(),
|
||||
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;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// 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) {
|
||||
println!("Popping from: {}", self.ast);
|
||||
self.emit_op(Op::Pop);
|
||||
|
@ -599,30 +634,7 @@ impl<'a> Compiler<'a> {
|
|||
self.emit_op(Op::Match);
|
||||
self.bind(name);
|
||||
}
|
||||
Word(name) | Splat(name) => match self.resolve_local(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;
|
||||
}
|
||||
},
|
||||
},
|
||||
Word(name) | Splat(name) => self.resolve_binding(name),
|
||||
PlaceholderPattern => {
|
||||
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) => {
|
||||
self.emit_constant(Value::Keyword(key));
|
||||
self.visit(value);
|
||||
|
@ -863,7 +867,18 @@ impl<'a> Compiler<'a> {
|
|||
}
|
||||
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) => {
|
||||
for arg in args {
|
||||
self.visit(arg);
|
||||
|
@ -876,21 +891,14 @@ impl<'a> Compiler<'a> {
|
|||
for arg in args {
|
||||
self.visit(arg);
|
||||
}
|
||||
|
||||
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.resolve_binding(fn_name);
|
||||
self.emit_op(Op::Call);
|
||||
self.emit_byte(arity);
|
||||
self.stack_depth -= arity;
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
for (term, _) in rest {
|
||||
|
@ -1275,14 +1283,7 @@ impl<'a> Compiler<'a> {
|
|||
self.stack_depth -= 1;
|
||||
}
|
||||
StringPart::Word(word) => {
|
||||
self.emit_op(Op::PushBinding);
|
||||
let biter = self.bindings.iter().rev();
|
||||
for binding in biter {
|
||||
if binding.name == word.as_str() {
|
||||
self.emit_byte(binding.stack_pos);
|
||||
break;
|
||||
}
|
||||
}
|
||||
self.resolve_binding(word);
|
||||
self.emit_op(Op::Stringify);
|
||||
self.emit_op(Op::ConcatStrings);
|
||||
}
|
||||
|
@ -1301,6 +1302,9 @@ impl<'a> Compiler<'a> {
|
|||
self.stack_depth -= 1;
|
||||
}
|
||||
}
|
||||
Placeholder => {
|
||||
self.emit_op(Op::Nothing);
|
||||
}
|
||||
Arguments(..) | Placeholder | InterpolatedPattern(..) | Splattern(..) => {
|
||||
todo!()
|
||||
}
|
||||
|
|
|
@ -76,10 +76,7 @@ pub fn run(src: &'static str) {
|
|||
pub fn main() {
|
||||
env::set_var("RUST_BACKTRACE", "1");
|
||||
let src = "
|
||||
let x = #{:a 1, :b 2}
|
||||
let y = #{x}
|
||||
let z = #{...x, y}
|
||||
z :y :x :a
|
||||
|
||||
|
||||
";
|
||||
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::spans::{Span, Spanned};
|
||||
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)]
|
||||
pub enum Value {
|
||||
Nothing,
|
||||
|
@ -82,6 +89,7 @@ pub enum Value {
|
|||
Box(Rc<RefCell<Value>>),
|
||||
Fn(Rc<LFn>),
|
||||
BaseFn(BaseFn),
|
||||
Partial(Rc<Partial>),
|
||||
}
|
||||
|
||||
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()),
|
||||
(Fn(x), Fn(y)) => x == y,
|
||||
(BaseFn(x), BaseFn(y)) => std::ptr::eq(x, y),
|
||||
(Partial(x), Partial(y)) => x == y,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
@ -147,6 +156,7 @@ impl std::fmt::Display for Value {
|
|||
Box(value) => write!(f, "box {{ {} }}", value.as_ref().borrow()),
|
||||
Fn(lfn) => write!(f, "fn {}", lfn.name()),
|
||||
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()),
|
||||
Fn(lfn) => format!("fn {}", lfn.name()),
|
||||
Partial(partial) => format!("fn {}/partial", partial.name),
|
||||
BaseFn(_) => "base fn".to_string(),
|
||||
Nothing => unreachable!(),
|
||||
}
|
||||
|
@ -253,6 +264,7 @@ impl Value {
|
|||
Box(..) => "box",
|
||||
Fn(..) => "fn",
|
||||
BaseFn(..) => "fn",
|
||||
Partial(..) => "fn",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -186,6 +186,10 @@ impl Vm {
|
|||
self.push(Value::Nil);
|
||||
self.ip += 1;
|
||||
}
|
||||
Nothing => {
|
||||
self.push(Value::Nothing);
|
||||
self.ip += 1;
|
||||
}
|
||||
True => {
|
||||
self.push(Value::True);
|
||||
self.ip += 1;
|
||||
|
@ -700,6 +704,9 @@ impl Vm {
|
|||
self.push(stringified);
|
||||
self.ip += 1;
|
||||
}
|
||||
Partial => {
|
||||
todo!();
|
||||
}
|
||||
Call => {
|
||||
let arity = self.chunk().bytecode[self.ip + 1];
|
||||
self.ip += 2;
|
||||
|
|
Loading…
Reference in New Issue
Block a user