diff --git a/src/base.rs b/src/base.rs index 0c8a988..b3f2f88 100644 --- a/src/base.rs +++ b/src/base.rs @@ -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!(), } } diff --git a/src/compiler.rs b/src/compiler.rs index 59d03dc..5e73c2e 100644 --- a/src/compiler.rs +++ b/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) -> bool { } } +fn has_placeholder(args: &[Spanned]) -> bool { + args.iter().any(|arg| matches!(arg, (Ast::Placeholder, _))) +} + impl<'a> Compiler<'a> { pub fn new( ast: &'static Spanned, @@ -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; - } - match self.enclosing { - Some(compiler) => compiler.resolve_binding(name), - None => unreachable!(), + 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; + } + 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,34 +867,38 @@ impl<'a> Compiler<'a> { } self.stack_depth = stack_depth + 1; } - (Word(fn_name), Arguments(args)) => match get_builtin(fn_name, args.len()) { - Some(code) => { - for arg in args { - self.visit(arg); - } - self.emit_op(code); - self.stack_depth -= args.len() - 1; - } - None => { + (Word(fn_name), Arguments(args)) => { + if has_placeholder(args) { let arity = args.len(); 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::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); + } + self.emit_op(code); + self.stack_depth -= args.len() - 1; + } + None => { + let arity = args.len(); + for arg in args { + self.visit(arg); + } + self.resolve_binding(fn_name); + self.emit_op(Op::Call); + self.emit_byte(arity); + self.stack_depth -= arity; } } - 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!() } diff --git a/src/main.rs b/src/main.rs index 4b19dfd..c3c6528 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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); diff --git a/src/validator.rs b/src/validator.rs index 24d672c..d8a1af9 100644 --- a/src/validator.rs +++ b/src/validator.rs @@ -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; diff --git a/src/value.rs b/src/value.rs index cb8fee9..bae3389 100644 --- a/src/value.rs +++ b/src/value.rs @@ -66,6 +66,13 @@ impl LFn { } } +#[derive(Clone, Debug, PartialEq)] +pub struct Partial { + args: Vec, + name: &'static str, + function: Value, +} + #[derive(Clone, Debug)] pub enum Value { Nothing, @@ -82,6 +89,7 @@ pub enum Value { Box(Rc>), Fn(Rc), BaseFn(BaseFn), + Partial(Rc), } 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", } } } diff --git a/src/vm.rs b/src/vm.rs index b123c35..8ff12a2 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -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;