More work on calling and returning.
This commit is contained in:
parent
3cacde6a4c
commit
d39e9afee2
@ -10,6 +10,8 @@ pub enum AsmInstruction {
|
|||||||
InvokePlatformStatic(InvokePlatformStatic),
|
InvokePlatformStatic(InvokePlatformStatic),
|
||||||
LoadConstant(LoadConstant),
|
LoadConstant(LoadConstant),
|
||||||
Add(Add),
|
Add(Add),
|
||||||
|
SetReturnValue(SetReturnValue),
|
||||||
|
Return(Return),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsmInstruction {
|
impl AsmInstruction {
|
||||||
@ -24,6 +26,8 @@ impl AsmInstruction {
|
|||||||
}
|
}
|
||||||
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
||||||
AsmInstruction::Add(add) => add.dvm(),
|
AsmInstruction::Add(add) => add.dvm(),
|
||||||
|
AsmInstruction::SetReturnValue(set_return_value) => set_return_value.dvm(),
|
||||||
|
AsmInstruction::Return(asm_return) => asm_return.dvm(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -181,3 +185,33 @@ impl Add {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct SetReturnValue {
|
||||||
|
source_register: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SetReturnValue {
|
||||||
|
pub fn new(source_register: usize) -> Self {
|
||||||
|
Self { source_register }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
Instruction::SetReturnValue(self.source_register)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Return {
|
||||||
|
caller_pop_count: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Return {
|
||||||
|
pub fn new(caller_pop_count: usize) -> Self {
|
||||||
|
Self { caller_pop_count }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
Instruction::Return(self.caller_pop_count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -1,8 +1,10 @@
|
|||||||
|
use crate::asm::asm_instruction::{AsmInstruction, Pop, SetReturnValue};
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
use crate::ast::assemble_context::AssembleContext;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::constants_table::ConstantsTable;
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
pub struct ExpressionStatement {
|
pub struct ExpressionStatement {
|
||||||
expression: Box<Expression>,
|
expression: Box<Expression>,
|
||||||
@ -36,10 +38,23 @@ impl ExpressionStatement {
|
|||||||
context: &mut AssembleContext,
|
context: &mut AssembleContext,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
|
is_last: bool,
|
||||||
) {
|
) {
|
||||||
match self.expression.as_ref() {
|
match self.expression.as_ref() {
|
||||||
Expression::Call(call) => {
|
Expression::Call(call) => {
|
||||||
call.assemble(context, symbol_table, constants_table);
|
call.assemble(context, symbol_table, constants_table);
|
||||||
|
// if last expression and the return value of the callee isn't void, return that
|
||||||
|
// return value
|
||||||
|
if is_last && !matches!(call.type_info(), TypeInfo::Void) {
|
||||||
|
// move to register
|
||||||
|
let return_value_register = context.new_local_register();
|
||||||
|
context.instruction(AsmInstruction::Pop(Pop::new(return_value_register)));
|
||||||
|
|
||||||
|
// set return value
|
||||||
|
context.instruction(AsmInstruction::SetReturnValue(SetReturnValue::new(
|
||||||
|
return_value_register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expression::Additive(additive) => {
|
Expression::Additive(additive) => {
|
||||||
additive.assemble(context, symbol_table, constants_table);
|
additive.assemble(context, symbol_table, constants_table);
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::asm::asm_instruction::{AsmInstruction, Return};
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
use crate::ast::assemble_context::AssembleContext;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
@ -158,10 +159,13 @@ impl Function {
|
|||||||
) {
|
) {
|
||||||
context.new_function(&self.declared_name, &self.declared_name_source_range);
|
context.new_function(&self.declared_name, &self.declared_name_source_range);
|
||||||
context.new_block(&format!("{}_enter", self.declared_name));
|
context.new_block(&format!("{}_enter", self.declared_name));
|
||||||
for statement in &self.statements {
|
for (i, statement) in self.statements.iter().enumerate() {
|
||||||
statement.assemble(context, symbol_table, constants_table);
|
let is_last = i == self.statements.len() - 1;
|
||||||
|
statement.assemble(context, symbol_table, constants_table, is_last);
|
||||||
}
|
}
|
||||||
// todo: function exit, including popping passed args and pushing return value
|
// return
|
||||||
|
context.instruction(AsmInstruction::Return(Return::new(self.parameters.len())));
|
||||||
|
|
||||||
context.complete_function();
|
context.complete_function();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -43,13 +43,14 @@ impl Statement {
|
|||||||
context: &mut AssembleContext,
|
context: &mut AssembleContext,
|
||||||
symbol_table: &SymbolTable,
|
symbol_table: &SymbolTable,
|
||||||
constants_table: &mut ConstantsTable,
|
constants_table: &mut ConstantsTable,
|
||||||
|
is_last: bool,
|
||||||
) {
|
) {
|
||||||
match self {
|
match self {
|
||||||
Statement::Let(let_statement) => {
|
Statement::Let(let_statement) => {
|
||||||
let_statement.assemble(context, symbol_table, constants_table);
|
let_statement.assemble(context, symbol_table, constants_table);
|
||||||
}
|
}
|
||||||
Statement::Expression(expression_statement) => {
|
Statement::Expression(expression_statement) => {
|
||||||
expression_statement.assemble(context, symbol_table, constants_table);
|
expression_statement.assemble(context, symbol_table, constants_table, is_last);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub type Register = usize;
|
pub type Register = usize;
|
||||||
pub type ConstantName = Rc<str>;
|
pub type ConstantName = Rc<str>;
|
||||||
pub type FunctionName = Rc<str>;
|
pub type FunctionName = Rc<str>;
|
||||||
pub type ArgCount = usize;
|
pub type ArgCount = usize;
|
||||||
|
pub type CallerPopCount = usize;
|
||||||
|
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
MoveRegister(Register, Register),
|
MoveRegister(Register, Register),
|
||||||
@ -24,4 +26,67 @@ pub enum Instruction {
|
|||||||
AddIntInt(Register, Register, Register),
|
AddIntInt(Register, Register, Register),
|
||||||
AddStringInt(Register, Register, Register),
|
AddStringInt(Register, Register, Register),
|
||||||
AddStringString(Register, Register, Register),
|
AddStringString(Register, Register, Register),
|
||||||
|
|
||||||
|
SetReturnValue(Register),
|
||||||
|
Return(CallerPopCount),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Instruction {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Instruction::MoveRegister(source, destination) => {
|
||||||
|
write!(f, "movr r{}, r{}", source, destination)
|
||||||
|
}
|
||||||
|
Instruction::MoveInt(i, destination) => {
|
||||||
|
write!(f, "movi {}, r{}", i, destination)
|
||||||
|
}
|
||||||
|
Instruction::MoveStackFrameOffset(offset, destination) => {
|
||||||
|
write!(f, "movsf {}, r{}", offset, destination)
|
||||||
|
}
|
||||||
|
Instruction::PushRegister(source) => {
|
||||||
|
write!(f, "pushr r{}", source)
|
||||||
|
}
|
||||||
|
Instruction::PushInt(i) => {
|
||||||
|
write!(f, "pushi {}", i)
|
||||||
|
}
|
||||||
|
Instruction::PushStackFrameOffset(offset) => {
|
||||||
|
write!(f, "pushsf {}", offset)
|
||||||
|
}
|
||||||
|
Instruction::InvokeStatic(name, arg_count) => {
|
||||||
|
write!(f, "invoke_static {} (arg_count: {})", name, arg_count)
|
||||||
|
}
|
||||||
|
Instruction::InvokePlatformStatic(name, arg_count) => {
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"invoke_platform_static {} (arg_count: {})",
|
||||||
|
name, arg_count
|
||||||
|
)
|
||||||
|
}
|
||||||
|
Instruction::LoadStringConstant(name, destination) => {
|
||||||
|
write!(f, "loadsc {}, r{}", name, destination)
|
||||||
|
}
|
||||||
|
Instruction::Pop(maybe_destination) => {
|
||||||
|
if let Some(destination) = maybe_destination {
|
||||||
|
write!(f, "pop r{}", destination)
|
||||||
|
} else {
|
||||||
|
write!(f, "pop")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Instruction::AddIntInt(left, right, destination) => {
|
||||||
|
write!(f, "addii r{}, r{}, r{}", left, right, destination)
|
||||||
|
}
|
||||||
|
Instruction::AddStringInt(left, right, destination) => {
|
||||||
|
write!(f, "addsi r{}, r{}, r{}", left, right, destination)
|
||||||
|
}
|
||||||
|
Instruction::AddStringString(left, right, destination) => {
|
||||||
|
write!(f, "addss r{}, r{}, r{}", left, right, destination)
|
||||||
|
}
|
||||||
|
Instruction::SetReturnValue(source) => {
|
||||||
|
write!(f, "srv r{}", source)
|
||||||
|
}
|
||||||
|
Instruction::Return(caller_pop_count) => {
|
||||||
|
write!(f, "return (caller_pop_count: {})", caller_pop_count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -63,22 +63,22 @@ impl DvmContext {
|
|||||||
|
|
||||||
pub struct CallFrame<'a> {
|
pub struct CallFrame<'a> {
|
||||||
function_name: Rc<str>,
|
function_name: Rc<str>,
|
||||||
active: bool,
|
|
||||||
instructions: &'a Vec<Instruction>,
|
instructions: &'a Vec<Instruction>,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
stack: Vec<Value>,
|
stack: Vec<Value>,
|
||||||
fp: usize,
|
fp: usize,
|
||||||
|
return_value: Option<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CallFrame<'a> {
|
impl<'a> CallFrame<'a> {
|
||||||
fn new(function_name: Rc<str>, instructions: &'a Vec<Instruction>) -> Self {
|
fn new(function_name: Rc<str>, instructions: &'a Vec<Instruction>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
function_name,
|
function_name,
|
||||||
active: false,
|
|
||||||
instructions,
|
instructions,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
fp: 0,
|
fp: 0,
|
||||||
|
return_value: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,14 +86,6 @@ impl<'a> CallFrame<'a> {
|
|||||||
&self.function_name
|
&self.function_name
|
||||||
}
|
}
|
||||||
|
|
||||||
fn active(&self) -> bool {
|
|
||||||
self.active
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mark_active(&mut self) {
|
|
||||||
self.active = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instructions(&self) -> &'a [Instruction] {
|
fn instructions(&self) -> &'a [Instruction] {
|
||||||
self.instructions
|
self.instructions
|
||||||
}
|
}
|
||||||
@ -121,6 +113,18 @@ impl<'a> CallFrame<'a> {
|
|||||||
fn set_fp(&mut self, fp: usize) {
|
fn set_fp(&mut self, fp: usize) {
|
||||||
self.fp = fp;
|
self.fp = fp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn return_value(&self) -> Option<&Value> {
|
||||||
|
self.return_value.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_return_value(&mut self, return_value: Value) {
|
||||||
|
self.return_value = Some(return_value);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_return_value(&mut self) -> Option<Value> {
|
||||||
|
self.return_value.take()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CallStack<'a> {
|
pub struct CallStack<'a> {
|
||||||
@ -151,6 +155,14 @@ impl<'a> CallStack<'a> {
|
|||||||
&mut self.call_frames[call_frames_len - 1] // dang borrow checker
|
&mut self.call_frames[call_frames_len - 1] // dang borrow checker
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn maybe_top(&self) -> Option<&CallFrame<'a>> {
|
||||||
|
self.call_frames.last()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn maybe_top_mut(&mut self) -> Option<&mut CallFrame<'a>> {
|
||||||
|
self.call_frames.last_mut()
|
||||||
|
}
|
||||||
|
|
||||||
fn penultimate(&self) -> Option<&CallFrame<'a>> {
|
fn penultimate(&self) -> Option<&CallFrame<'a>> {
|
||||||
self.call_frames.get(self.call_frames.len() - 2)
|
self.call_frames.get(self.call_frames.len() - 2)
|
||||||
}
|
}
|
||||||
@ -182,25 +194,28 @@ pub fn call<'a>(
|
|||||||
function.instructions(),
|
function.instructions(),
|
||||||
));
|
));
|
||||||
|
|
||||||
// mark it active
|
|
||||||
call_stack.top_mut().mark_active();
|
|
||||||
|
|
||||||
// put each arg on the stack
|
// put each arg on the stack
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
call_stack.top_mut().stack_mut().push(argument);
|
call_stack.top_mut().stack_mut().push(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
while call_stack.top().ip() < call_stack.top().instructions().len() {
|
while call_stack.maybe_top().is_some()
|
||||||
|
&& call_stack.top().ip() < call_stack.top().instructions().len()
|
||||||
|
{
|
||||||
let instruction = &call_stack.top().instructions()[call_stack.top().ip()];
|
let instruction = &call_stack.top().instructions()[call_stack.top().ip()];
|
||||||
|
// println!("{}", instruction);
|
||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
/* Move instructions */
|
/* Move instructions */
|
||||||
Instruction::MoveRegister(source, destination) => {
|
Instruction::MoveRegister(source, destination) => {
|
||||||
// copy value from one register to another register
|
// copy value from one register to another register
|
||||||
let value = registers[*source].clone();
|
let value = registers[*source].clone();
|
||||||
registers[*destination] = value;
|
registers[*destination] = value;
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Instruction::MoveInt(value, destination) => {
|
Instruction::MoveInt(value, destination) => {
|
||||||
registers[*destination] = Value::Int(*value);
|
registers[*destination] = Value::Int(*value);
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Instruction::MoveStackFrameOffset(offset, destination) => {
|
Instruction::MoveStackFrameOffset(offset, destination) => {
|
||||||
// copy a value offset from the current frame pointer (fp) to a register
|
// copy a value offset from the current frame pointer (fp) to a register
|
||||||
@ -216,6 +231,7 @@ pub fn call<'a>(
|
|||||||
));
|
));
|
||||||
let value = call_stack.top().stack()[value_index].clone();
|
let value = call_stack.top().stack()[value_index].clone();
|
||||||
registers[*destination] = value;
|
registers[*destination] = value;
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push instructions */
|
/* Push instructions */
|
||||||
@ -223,9 +239,11 @@ pub fn call<'a>(
|
|||||||
// copy a value from a register to the top of the stack
|
// copy a value from a register to the top of the stack
|
||||||
let value = registers[*source].clone();
|
let value = registers[*source].clone();
|
||||||
call_stack.top_mut().stack_mut().push(value);
|
call_stack.top_mut().stack_mut().push(value);
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Instruction::PushInt(value) => {
|
Instruction::PushInt(value) => {
|
||||||
call_stack.top_mut().stack_mut().push(Value::Int(*value));
|
call_stack.top_mut().stack_mut().push(Value::Int(*value));
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Instruction::PushStackFrameOffset(offset) => {
|
Instruction::PushStackFrameOffset(offset) => {
|
||||||
// copy a value from somewhere on the stack to the top of the stack
|
// copy a value from somewhere on the stack to the top of the stack
|
||||||
@ -236,6 +254,7 @@ pub fn call<'a>(
|
|||||||
.expect("Overflow when adding offset to fp");
|
.expect("Overflow when adding offset to fp");
|
||||||
let value = call_stack.top().stack()[value_index].clone();
|
let value = call_stack.top().stack()[value_index].clone();
|
||||||
call_stack.top_mut().stack_mut().push(value);
|
call_stack.top_mut().stack_mut().push(value);
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke instructions */
|
/* Invoke instructions */
|
||||||
@ -249,6 +268,9 @@ pub fn call<'a>(
|
|||||||
let mut args =
|
let mut args =
|
||||||
call_stack.top().stack()[call_stack.top().stack().len() - arg_count..].to_vec();
|
call_stack.top().stack()[call_stack.top().stack().len() - arg_count..].to_vec();
|
||||||
|
|
||||||
|
// increment caller frame ip
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
|
|
||||||
// push a new call frame
|
// push a new call frame
|
||||||
call_stack.push(CallFrame::new(
|
call_stack.push(CallFrame::new(
|
||||||
function.name_owned(),
|
function.name_owned(),
|
||||||
@ -274,14 +296,17 @@ pub fn call<'a>(
|
|||||||
let result = platform_function(args);
|
let result = platform_function(args);
|
||||||
match result {
|
match result {
|
||||||
Ok(return_value) => {
|
Ok(return_value) => {
|
||||||
// push return value to top of caller stack
|
// push return value to top of caller stack if it's not null
|
||||||
|
if !matches!(return_value, Value::Null) {
|
||||||
call_stack.top_mut().stack_mut().push(return_value);
|
call_stack.top_mut().stack_mut().push(return_value);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
// Eventually we will have some kind of exception handling
|
// Eventually we will have some kind of exception handling
|
||||||
panic!("{}", error);
|
panic!("{}", error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load constant instructions */
|
/* Load constant instructions */
|
||||||
@ -292,6 +317,7 @@ pub fn call<'a>(
|
|||||||
registers[*destination] = Value::String(string_constant.content_owned());
|
registers[*destination] = Value::String(string_constant.content_owned());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add instructions */
|
/* Add instructions */
|
||||||
@ -300,18 +326,21 @@ pub fn call<'a>(
|
|||||||
let rhs_value = registers[*rhs].unwrap_int();
|
let rhs_value = registers[*rhs].unwrap_int();
|
||||||
let result = lhs_value + rhs_value;
|
let result = lhs_value + rhs_value;
|
||||||
registers[*destination] = Value::Int(result);
|
registers[*destination] = Value::Int(result);
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Instruction::AddStringInt(lhs, rhs, destination) => {
|
Instruction::AddStringInt(lhs, rhs, destination) => {
|
||||||
let lhs_value = registers[*lhs].unwrap_string();
|
let lhs_value = registers[*lhs].unwrap_string();
|
||||||
let rhs_value = registers[*rhs].unwrap_int();
|
let rhs_value = registers[*rhs].unwrap_int();
|
||||||
let formatted = format!("{}{}", lhs_value, rhs_value);
|
let formatted = format!("{}{}", lhs_value, rhs_value);
|
||||||
registers[*destination] = Value::String(Rc::from(formatted));
|
registers[*destination] = Value::String(Rc::from(formatted));
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Instruction::AddStringString(lhs, rhs, destination) => {
|
Instruction::AddStringString(lhs, rhs, destination) => {
|
||||||
let lhs_value = registers[*lhs].unwrap_string();
|
let lhs_value = registers[*lhs].unwrap_string();
|
||||||
let rhs_value = registers[*rhs].unwrap_string();
|
let rhs_value = registers[*rhs].unwrap_string();
|
||||||
let formatted = format!("{}{}", lhs_value, rhs_value);
|
let formatted = format!("{}{}", lhs_value, rhs_value);
|
||||||
registers[*destination] = Value::String(Rc::from(formatted));
|
registers[*destination] = Value::String(Rc::from(formatted));
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop instructions */
|
/* Pop instructions */
|
||||||
@ -320,32 +349,37 @@ pub fn call<'a>(
|
|||||||
if let Some(register) = maybe_register {
|
if let Some(register) = maybe_register {
|
||||||
registers[*register] = value;
|
registers[*register] = value;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call frame bookkeeping
|
|
||||||
let top_frame = call_stack.top();
|
|
||||||
if top_frame.active() {
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
} else {
|
}
|
||||||
// the "top" frame is inactive, which means it was created above
|
|
||||||
// set it to active for next instruction round
|
|
||||||
call_stack.top_mut().mark_active();
|
|
||||||
|
|
||||||
let maybe_penultimate_frame = call_stack.penultimate_mut();
|
/* Return instructions */
|
||||||
match maybe_penultimate_frame {
|
Instruction::SetReturnValue(register) => {
|
||||||
None => {
|
call_stack
|
||||||
panic!("Invariant broken: only one call frame and it's inactive.");
|
.top_mut()
|
||||||
|
.set_return_value(registers[*register].clone());
|
||||||
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
Some(penultimate_frame) => {
|
|
||||||
if penultimate_frame.active() {
|
Instruction::Return(caller_pop_count) => {
|
||||||
penultimate_frame.increment_ip();
|
call_stack.pop(); // pop this frame
|
||||||
} else {
|
let maybe_caller = call_stack.maybe_top_mut();
|
||||||
panic!("Invariant broken: top two call frames are inactive.");
|
if let Some(caller) = maybe_caller {
|
||||||
|
for _ in 0..*caller_pop_count {
|
||||||
|
caller.stack_mut().pop();
|
||||||
|
}
|
||||||
|
if let Some(return_value) = caller.take_return_value() {
|
||||||
|
caller.stack_mut().push(return_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// do not increment ip of the caller; this was done above BEFORE the call
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if let Some(top) = call_stack.maybe_top() {
|
||||||
|
// println!(" stack: {:?}", top.stack());
|
||||||
|
// println!(" registers: {:?}", registers);
|
||||||
|
// println!(" rv: {:?}", top.return_value());
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
None // todo: returning results from main functions
|
None // todo: returning results from main functions
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,12 @@
|
|||||||
extern fn println(message: Any) -> Void
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
fn add(a: Int, b: Int) -> Int
|
fn add(a: Int, b: Int) -> Void
|
||||||
println(a + b)
|
println(a + b)
|
||||||
end
|
end
|
||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
add(1, 2)
|
let x = 1 + 2 + 3
|
||||||
|
add(x, 1)
|
||||||
|
add(x, 2)
|
||||||
|
add(21, 21)
|
||||||
end
|
end
|
||||||
Loading…
Reference in New Issue
Block a user