Implement functions calls
This commit is contained in:
parent
65e513488f
commit
9d5c9d9fd0
@ -208,11 +208,12 @@ impl Instruction {
|
||||
instruction
|
||||
}
|
||||
|
||||
pub fn call(to_register: u8, function_index: u8) -> Instruction {
|
||||
pub fn call(to_register: u8, function_register: u8, argument_count: u8) -> Instruction {
|
||||
let mut instruction = Instruction(Operation::Call as u32);
|
||||
|
||||
instruction.set_a(to_register);
|
||||
instruction.set_b(function_index);
|
||||
instruction.set_b(function_register);
|
||||
instruction.set_c(argument_count);
|
||||
|
||||
instruction
|
||||
}
|
||||
@ -557,11 +558,19 @@ impl Instruction {
|
||||
}
|
||||
Operation::Call => {
|
||||
let to_register = self.a();
|
||||
let function_index = self.b();
|
||||
let function_register = self.b();
|
||||
let argument_count = self.c();
|
||||
|
||||
let mut output = format!("R{function_index}(");
|
||||
let mut output = format!("R{to_register} = R{function_register}(");
|
||||
let first_argument = function_register + 1;
|
||||
|
||||
for (index, register) in
|
||||
(first_argument..first_argument + argument_count).enumerate()
|
||||
{
|
||||
if index > 0 {
|
||||
output.push_str(", ");
|
||||
}
|
||||
|
||||
for register in function_index + 1..to_register {
|
||||
output.push_str(&format!("R{}", register));
|
||||
}
|
||||
|
||||
@ -778,11 +787,12 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn call() {
|
||||
let instruction = Instruction::call(4, 3);
|
||||
let instruction = Instruction::call(1, 3, 4);
|
||||
|
||||
assert_eq!(instruction.operation(), Operation::Call);
|
||||
assert_eq!(instruction.a(), 4);
|
||||
assert_eq!(instruction.a(), 1);
|
||||
assert_eq!(instruction.b(), 3);
|
||||
assert_eq!(instruction.c(), 4);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -7,7 +7,7 @@ const LOAD_BOOLEAN: u8 = 0b0000_0010;
|
||||
const LOAD_CONSTANT: u8 = 0b0000_0011;
|
||||
const LOAD_LIST: u8 = 0b0000_0100;
|
||||
|
||||
const DECLARE_LOCAL: u8 = 0b0000_0101;
|
||||
const DEFINE_LOCAL: u8 = 0b0000_0101;
|
||||
const GET_LOCAL: u8 = 0b0000_0110;
|
||||
const SET_LOCAL: u8 = 0b0000_0111;
|
||||
|
||||
@ -43,22 +43,22 @@ pub enum Operation {
|
||||
LoadList = LOAD_LIST as isize,
|
||||
|
||||
// Variables
|
||||
DefineLocal = DECLARE_LOCAL as isize,
|
||||
DefineLocal = DEFINE_LOCAL as isize,
|
||||
GetLocal = GET_LOCAL as isize,
|
||||
SetLocal = SET_LOCAL as isize,
|
||||
|
||||
// Binary operations
|
||||
// Binary math
|
||||
Add = ADD as isize,
|
||||
Subtract = SUBTRACT as isize,
|
||||
Multiply = MULTIPLY as isize,
|
||||
Divide = DIVIDE as isize,
|
||||
Modulo = MODULO as isize,
|
||||
|
||||
// Logical operations
|
||||
// Binary logic
|
||||
Test = TEST as isize,
|
||||
TestSet = TEST_SET as isize,
|
||||
|
||||
// Relational operations
|
||||
// Binary comparison
|
||||
Equal = EQUAL as isize,
|
||||
Less = LESS as isize,
|
||||
LessEqual = LESS_EQUAL as isize,
|
||||
@ -105,7 +105,7 @@ impl From<u8> for Operation {
|
||||
LOAD_BOOLEAN => Operation::LoadBoolean,
|
||||
LOAD_CONSTANT => Operation::LoadConstant,
|
||||
LOAD_LIST => Operation::LoadList,
|
||||
DECLARE_LOCAL => Operation::DefineLocal,
|
||||
DEFINE_LOCAL => Operation::DefineLocal,
|
||||
GET_LOCAL => Operation::GetLocal,
|
||||
SET_LOCAL => Operation::SetLocal,
|
||||
ADD => Operation::Add,
|
||||
@ -142,7 +142,7 @@ impl From<Operation> for u8 {
|
||||
Operation::LoadBoolean => LOAD_BOOLEAN,
|
||||
Operation::LoadConstant => LOAD_CONSTANT,
|
||||
Operation::LoadList => LOAD_LIST,
|
||||
Operation::DefineLocal => DECLARE_LOCAL,
|
||||
Operation::DefineLocal => DEFINE_LOCAL,
|
||||
Operation::GetLocal => GET_LOCAL,
|
||||
Operation::SetLocal => SET_LOCAL,
|
||||
Operation::Add => ADD,
|
||||
|
@ -183,21 +183,6 @@ impl<'src> Parser<'src> {
|
||||
let constant_index = self.chunk.push_constant(value, position)?;
|
||||
let register = self.next_register();
|
||||
|
||||
if let Some(instruction) = self
|
||||
.current_statement
|
||||
.last()
|
||||
.map(|(instruction, _)| instruction)
|
||||
{
|
||||
if let Operation::LoadConstant = instruction.operation() {
|
||||
self.push_instruction(
|
||||
Instruction::load_constant(instruction.a(), constant_index, false),
|
||||
position,
|
||||
);
|
||||
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
|
||||
self.push_instruction(
|
||||
Instruction::load_constant(register, constant_index, false),
|
||||
position,
|
||||
@ -1201,21 +1186,21 @@ impl<'src> Parser<'src> {
|
||||
}
|
||||
|
||||
let start = self.current_position.0;
|
||||
let function_register = last_instruction.a();
|
||||
|
||||
self.advance()?;
|
||||
|
||||
let function_register = self.next_register();
|
||||
|
||||
while !self.allow(Token::RightParenthesis)? {
|
||||
self.parse_expression()?;
|
||||
self.allow(Token::Comma)?;
|
||||
}
|
||||
|
||||
let end = self.current_position.1;
|
||||
let register = self.next_register();
|
||||
let argument_count = self.next_register() - function_register - 1;
|
||||
let to_register = self.next_register();
|
||||
|
||||
self.push_instruction(
|
||||
Instruction::call(register, function_register),
|
||||
Instruction::call(to_register, function_register, argument_count),
|
||||
Span(start, end),
|
||||
);
|
||||
|
||||
|
@ -347,8 +347,9 @@ impl Vm {
|
||||
}
|
||||
Operation::Call => {
|
||||
let to_register = instruction.a();
|
||||
let function_index = instruction.b();
|
||||
let value = self.get(function_index, position)?.clone();
|
||||
let function_register = instruction.b();
|
||||
let argument_count = instruction.c();
|
||||
let value = self.get(function_register, position)?.clone();
|
||||
let function = if let Value::Function(function) = value {
|
||||
function
|
||||
} else {
|
||||
@ -358,8 +359,11 @@ impl Vm {
|
||||
});
|
||||
};
|
||||
let mut function_vm = Vm::new(function.take_chunk());
|
||||
let first_argument_index = function_register + 1;
|
||||
|
||||
for argument_index in function_index + 1..to_register {
|
||||
for argument_index in
|
||||
first_argument_index..first_argument_index + argument_count
|
||||
{
|
||||
let argument = self.get(argument_index, position)?.clone();
|
||||
let top_of_stack = function_vm.stack.len() as u8;
|
||||
|
||||
@ -369,7 +373,7 @@ impl Vm {
|
||||
let return_value = function_vm.run()?;
|
||||
|
||||
if let Some(value) = return_value {
|
||||
self.set(function_index, value, position)?;
|
||||
self.set(to_register, value, position)?;
|
||||
}
|
||||
}
|
||||
Operation::Return => {
|
||||
|
@ -346,6 +346,52 @@ fn function() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn function_call() {
|
||||
let source = "fn(a: int, b: int) -> int { a + b }(1, 2)";
|
||||
|
||||
assert_eq!(
|
||||
parse(source),
|
||||
Ok(Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::load_constant(0, 0, false), Span(0, 36)),
|
||||
(Instruction::load_constant(1, 1, false), Span(36, 37)),
|
||||
(Instruction::load_constant(2, 2, false), Span(39, 40)),
|
||||
(Instruction::call(3, 0, 2), Span(35, 41)),
|
||||
(Instruction::r#return(true), Span(41, 41)),
|
||||
],
|
||||
vec![
|
||||
Value::function(
|
||||
Chunk::with_data(
|
||||
vec![
|
||||
(Instruction::add(2, 0, 1), Span(30, 31)),
|
||||
(Instruction::r#return(true), Span(34, 35)),
|
||||
],
|
||||
vec![],
|
||||
vec![
|
||||
Local::new(Identifier::new("a"), Some(Type::Integer), false, 0, 0),
|
||||
Local::new(Identifier::new("b"), Some(Type::Integer), false, 0, 1)
|
||||
]
|
||||
),
|
||||
FunctionType {
|
||||
type_parameters: None,
|
||||
value_parameters: Some(vec![
|
||||
(Identifier::new("a"), Type::Integer),
|
||||
(Identifier::new("b"), Type::Integer)
|
||||
]),
|
||||
return_type: Some(Box::new(Type::Integer)),
|
||||
}
|
||||
),
|
||||
Value::integer(1),
|
||||
Value::integer(2)
|
||||
],
|
||||
vec![]
|
||||
)),
|
||||
);
|
||||
|
||||
assert_eq!(run(source), Ok(Some(Value::integer(3))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn greater() {
|
||||
let source = "1 > 2";
|
||||
@ -416,7 +462,7 @@ fn if_else_expression() {
|
||||
),
|
||||
(Instruction::jump(1, true), Span(5, 7)),
|
||||
(Instruction::load_constant(0, 2, true), Span(12, 13)),
|
||||
(Instruction::load_constant(0, 3, false), Span(23, 24)),
|
||||
(Instruction::load_constant(1, 3, false), Span(23, 24)),
|
||||
(Instruction::r#return(true), Span(26, 26)),
|
||||
],
|
||||
vec![
|
||||
|
11
examples/fibonacci.ds
Normal file
11
examples/fibonacci.ds
Normal file
@ -0,0 +1,11 @@
|
||||
let fib = fn (n: int) -> int {
|
||||
if n == 0 {
|
||||
return 0;
|
||||
} else if n == 1 {
|
||||
return 1;
|
||||
} else {
|
||||
return fib(n - 1) + fib(n - 2);
|
||||
}
|
||||
};
|
||||
|
||||
fib(10)
|
Loading…
Reference in New Issue
Block a user