Add support for &optional arguments
This commit is contained in:
@@ -28,6 +28,9 @@
|
||||
;; vectors
|
||||
#[1 2 3]
|
||||
|
||||
; alternate syntax for lists
|
||||
[] () nil NIL
|
||||
|
||||
;; progn
|
||||
(progn
|
||||
1
|
||||
|
||||
+13
-4
@@ -27,13 +27,13 @@ pub struct FunctionBlock {
|
||||
parent: Option<usize>,
|
||||
identifier: Option<IdentifierValue>,
|
||||
docstring: Option<StringValue>,
|
||||
signature: FunctionSignature,
|
||||
|
||||
// Data
|
||||
pub(crate) constants: Vec<Value>,
|
||||
locals: Vec<Local>,
|
||||
upvalues: Vec<UpvalueDef>,
|
||||
scope_depth: usize,
|
||||
arity: usize,
|
||||
|
||||
// Code
|
||||
pub(crate) instructions: Vec<Emitted>,
|
||||
@@ -363,20 +363,25 @@ impl FunctionBlock {
|
||||
parent,
|
||||
identifier,
|
||||
docstring,
|
||||
signature: signature.clone(),
|
||||
constants: vec![],
|
||||
locals: vec![],
|
||||
upvalues: vec![],
|
||||
scope_depth: 0,
|
||||
instructions: vec![],
|
||||
labels: vec![],
|
||||
arity: signature.required_arguments.len(),
|
||||
loop_stack: vec![],
|
||||
};
|
||||
for required in signature.required_arguments.iter().rev() {
|
||||
for required in signature.required_arguments.iter() {
|
||||
block
|
||||
.add_local(required.clone(), Some(-100))
|
||||
.expect("couldn't add an argument");
|
||||
}
|
||||
for optional in signature.optional_arguments.iter() {
|
||||
block
|
||||
.add_local(optional.clone(), Some(-100))
|
||||
.expect("couldn't add an argument");
|
||||
}
|
||||
block
|
||||
}
|
||||
|
||||
@@ -484,13 +489,17 @@ impl FunctionBlock {
|
||||
instructions[position] = branch_offset as u8;
|
||||
}
|
||||
|
||||
let min_arity = self.signature.min_arity();
|
||||
let max_arity = self.signature.max_arity();
|
||||
|
||||
Ok(Rc::new(BytecodeFunction {
|
||||
identifier: self.identifier.clone(),
|
||||
instructions: instructions.into(),
|
||||
docstring: self.docstring.clone(),
|
||||
constants: self.constants.iter().cloned().collect(),
|
||||
upvalues: self.upvalues.iter().copied().collect(),
|
||||
arity: self.arity,
|
||||
min_arity,
|
||||
max_arity,
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ impl Compile for CallExpression {
|
||||
let callee = self.callee.compile(cx)?;
|
||||
cx.push(callee)?;
|
||||
}
|
||||
for expression in self.arguments.iter().rev() {
|
||||
for expression in self.arguments.iter() {
|
||||
let value = expression.compile(cx)?;
|
||||
cx.push(value)?;
|
||||
}
|
||||
|
||||
@@ -38,7 +38,15 @@ impl FunctionSignature {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn arity(&self) -> usize {
|
||||
pub fn min_arity(&self) -> usize {
|
||||
self.required_arguments.len()
|
||||
}
|
||||
|
||||
pub fn max_arity(&self) -> usize {
|
||||
if self.rest_argument.is_none() {
|
||||
self.required_arguments.len() + self.optional_arguments.len()
|
||||
} else {
|
||||
usize::MAX
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ pub enum Trace {
|
||||
Execute,
|
||||
Call,
|
||||
Return,
|
||||
Stack,
|
||||
}
|
||||
|
||||
impl FromStr for Trace {
|
||||
@@ -46,6 +47,7 @@ impl FromStr for Trace {
|
||||
"execute" => Ok(Self::Execute),
|
||||
"call" => Ok(Self::Call),
|
||||
"return" => Ok(Self::Return),
|
||||
"stack" => Ok(Self::Stack),
|
||||
_ => Err(format!("Unknown trace flag: {s:?}")),
|
||||
}
|
||||
}
|
||||
@@ -199,6 +201,7 @@ fn main() -> ExitCode {
|
||||
vm.trace_instructions = args.trace.contains(&Trace::Execute);
|
||||
vm.trace_calls = args.trace.contains(&Trace::Call);
|
||||
vm.trace_returns = args.trace.contains(&Trace::Return);
|
||||
vm.trace_stack = args.trace.contains(&Trace::Stack);
|
||||
let mut env = Environment::default();
|
||||
prelude::load(&mut env);
|
||||
let mut arguments = vec![];
|
||||
|
||||
+32
-5
@@ -203,9 +203,10 @@ impl Machine {
|
||||
Value::NativeFunction(function) => {
|
||||
let function = function.clone();
|
||||
// TODO remove argument cloning
|
||||
let arguments = (0..argument_count)
|
||||
let mut arguments = (0..argument_count)
|
||||
.map(|_| self.pop())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
arguments.reverse();
|
||||
|
||||
if self.trace_calls {
|
||||
eprintln!("TRACE: Call native");
|
||||
@@ -240,9 +241,21 @@ impl Machine {
|
||||
}
|
||||
};
|
||||
|
||||
if argument_count != closure.function.arity {
|
||||
todo!("TODO error here")
|
||||
if argument_count < closure.function.min_arity {
|
||||
todo!("TODO function called with less arguments than expected")
|
||||
}
|
||||
if argument_count > closure.function.max_arity {
|
||||
todo!("TODO function called with more arguments than expected")
|
||||
}
|
||||
if closure.function.max_arity == usize::MAX {
|
||||
todo!("VM support for &rest argument")
|
||||
}
|
||||
for _ in argument_count..closure.function.max_arity {
|
||||
self.push(Value::Nil)?;
|
||||
}
|
||||
// if argument_count != closure.function.arity {
|
||||
// todo!("TODO error here")
|
||||
// }
|
||||
|
||||
if self.trace_calls {
|
||||
eprintln!("TRACE: Call closure");
|
||||
@@ -500,9 +513,10 @@ impl Machine {
|
||||
| Instruction::Not
|
||||
| Instruction::Negate => {
|
||||
let argument_count = usize::from(ArgumentCount::read_encoded(self)?);
|
||||
let arguments = (0..argument_count)
|
||||
let mut arguments = (0..argument_count)
|
||||
.map(|_| self.pop())
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
arguments.reverse();
|
||||
let function = prelude::dispatch_arithmetic(opcode);
|
||||
let value = (function)(self, env, &arguments[..])?;
|
||||
self.push(value)?;
|
||||
@@ -579,11 +593,24 @@ impl Machine {
|
||||
closure: ClosureValue,
|
||||
args: &[Value],
|
||||
) -> Result<Value, MachineErrorAt> {
|
||||
let max_arity = closure.function.max_arity;
|
||||
if args.len() < closure.function.min_arity {
|
||||
todo!()
|
||||
}
|
||||
if args.len() > closure.function.max_arity {
|
||||
todo!()
|
||||
}
|
||||
self.push(Value::Closure(closure))
|
||||
.map_err(MachineErrorAt::at_unknown)?;
|
||||
for arg in args.iter().rev() {
|
||||
if max_arity == usize::MAX {
|
||||
todo!("VM support for &rest argument")
|
||||
}
|
||||
for arg in args.iter() {
|
||||
self.push(arg.clone()).map_err(MachineErrorAt::at_unknown)?;
|
||||
}
|
||||
for _ in args.len()..max_arity {
|
||||
self.push(Value::Nil).map_err(MachineErrorAt::at_unknown)?;
|
||||
}
|
||||
let unwind_target = self.call_stack.pointer();
|
||||
self.execute_call(env, args.len())
|
||||
.map_err(MachineErrorAt::at_unknown)?;
|
||||
|
||||
@@ -16,7 +16,8 @@ pub struct BytecodeFunction {
|
||||
pub instructions: Box<[u8]>,
|
||||
pub constants: Box<[Value]>,
|
||||
pub upvalues: Box<[UpvalueDef]>,
|
||||
pub arity: usize,
|
||||
pub min_arity: usize,
|
||||
pub max_arity: usize,
|
||||
}
|
||||
|
||||
enum TraceArgument {
|
||||
|
||||
Reference in New Issue
Block a user