Work on calling conventions and instructions.
This commit is contained in:
parent
e1afb6b43b
commit
3cacde6a4c
@ -1,5 +1,5 @@
|
|||||||
|
use dvm_lib::vm::DvmContext;
|
||||||
use dvm_lib::vm::value::Value;
|
use dvm_lib::vm::value::Value;
|
||||||
use dvm_lib::vm::{DvmContext, DvmState};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fmt::{Debug, Display, Formatter};
|
use std::fmt::{Debug, Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -35,11 +35,7 @@ impl Display for StdCoreError {
|
|||||||
|
|
||||||
impl Error for StdCoreError {}
|
impl Error for StdCoreError {}
|
||||||
|
|
||||||
pub fn std_core_println(
|
pub fn std_core_println(args: &[Value]) -> Result<Value, Box<dyn Error>> {
|
||||||
_context: &DvmContext,
|
|
||||||
_state: &DvmState,
|
|
||||||
args: &[Value],
|
|
||||||
) -> Result<Value, Box<dyn Error>> {
|
|
||||||
let maybe_to_print = args.get(0);
|
let maybe_to_print = args.get(0);
|
||||||
match maybe_to_print {
|
match maybe_to_print {
|
||||||
None => Err(Box::new(StdCoreError::new("Missing to_print arg"))),
|
None => Err(Box::new(StdCoreError::new("Missing to_print arg"))),
|
||||||
|
|||||||
@ -9,7 +9,8 @@ use dmc_lib::diagnostic::Diagnostic;
|
|||||||
use dmc_lib::parser::parse_compilation_unit;
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
use dvm_lib::vm::{DvmContext, DvmState, call};
|
use dvm_lib::vm::value::Value;
|
||||||
|
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
@ -54,7 +55,7 @@ fn main() {
|
|||||||
|
|
||||||
if args.show_asm {
|
if args.show_asm {
|
||||||
for asm_function in &asm_functions {
|
for asm_function in &asm_functions {
|
||||||
println!("{:?}", asm_function);
|
println!("{:#?}", asm_function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,9 +76,16 @@ fn main() {
|
|||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut dvm_state = DvmState::new();
|
let mut registers: Vec<Value> = vec![];
|
||||||
|
let mut call_stack = CallStack::new();
|
||||||
|
|
||||||
let result = call(&dvm_context, &mut dvm_state, "main", vec![]);
|
let result = call(
|
||||||
|
&dvm_context,
|
||||||
|
&mut registers,
|
||||||
|
&mut call_stack,
|
||||||
|
"main",
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
println!("{:?}", result);
|
println!("{:?}", result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -107,15 +107,19 @@ impl Pop {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvokeStatic {
|
pub struct InvokeStatic {
|
||||||
name: String,
|
name: String,
|
||||||
|
arg_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InvokeStatic {
|
impl InvokeStatic {
|
||||||
pub fn new(name: &str) -> Self {
|
pub fn new(name: &str, arg_count: usize) -> Self {
|
||||||
Self { name: name.into() }
|
Self {
|
||||||
|
name: name.into(),
|
||||||
|
arg_count,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
pub fn dvm(&self) -> Instruction {
|
||||||
Instruction::InvokeStatic(Rc::from(self.name.clone()))
|
Instruction::InvokeStatic(Rc::from(self.name.clone()), self.arg_count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -194,8 +194,10 @@ impl Call {
|
|||||||
InvokePlatformStatic::new(function_symbol.name(), arg_count),
|
InvokePlatformStatic::new(function_symbol.name(), arg_count),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
|
let arg_count = function_symbol.parameters().len();
|
||||||
context.instruction(AsmInstruction::InvokeStatic(InvokeStatic::new(
|
context.instruction(AsmInstruction::InvokeStatic(InvokeStatic::new(
|
||||||
function_symbol.name(),
|
function_symbol.name(),
|
||||||
|
arg_count,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ pub enum Instruction {
|
|||||||
PushInt(i32),
|
PushInt(i32),
|
||||||
PushStackFrameOffset(isize),
|
PushStackFrameOffset(isize),
|
||||||
|
|
||||||
InvokeStatic(FunctionName),
|
InvokeStatic(FunctionName, ArgCount),
|
||||||
InvokePlatformStatic(FunctionName, ArgCount),
|
InvokePlatformStatic(FunctionName, ArgCount),
|
||||||
|
|
||||||
LoadStringConstant(ConstantName, Register),
|
LoadStringConstant(ConstantName, Register),
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
use crate::vm::{DvmContext, DvmState};
|
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
|
|
||||||
pub type PlatformFunction =
|
pub type PlatformFunction = fn(args: &[Value]) -> Result<Value, Box<dyn Error>>;
|
||||||
fn(context: &DvmContext, state: &DvmState, args: &[Value]) -> Result<Value, Box<dyn Error>>;
|
|
||||||
|
|||||||
@ -41,6 +41,7 @@ impl DvmContext {
|
|||||||
&mut self.platform_functions
|
&mut self.platform_functions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
pub fn add_function(&mut self, function: Function) {
|
pub fn add_function(&mut self, function: Function) {
|
||||||
self.functions.insert(function.name_owned(), function);
|
self.functions.insert(function.name_owned(), function);
|
||||||
}
|
}
|
||||||
@ -49,6 +50,7 @@ impl DvmContext {
|
|||||||
&self.constants
|
&self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[deprecated]
|
||||||
pub fn add_constant(&mut self, constant: Constant) {
|
pub fn add_constant(&mut self, constant: Constant) {
|
||||||
match &constant {
|
match &constant {
|
||||||
Constant::String(string_constant) => {
|
Constant::String(string_constant) => {
|
||||||
@ -59,63 +61,110 @@ impl DvmContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DvmState {
|
pub struct CallFrame<'a> {
|
||||||
stack: Vec<Value>,
|
function_name: Rc<str>,
|
||||||
registers: Vec<Value>,
|
active: bool,
|
||||||
|
instructions: &'a Vec<Instruction>,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
|
stack: Vec<Value>,
|
||||||
fp: usize,
|
fp: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DvmState {
|
impl<'a> CallFrame<'a> {
|
||||||
pub fn new() -> Self {
|
fn new(function_name: Rc<str>, instructions: &'a Vec<Instruction>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
stack: vec![],
|
function_name,
|
||||||
registers: vec![],
|
active: false,
|
||||||
|
instructions,
|
||||||
ip: 0,
|
ip: 0,
|
||||||
|
stack: vec![],
|
||||||
fp: 0,
|
fp: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack(&self) -> &Vec<Value> {
|
fn function_name(&self) -> &str {
|
||||||
&self.stack
|
&self.function_name
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn stack_mut(&mut self) -> &mut Vec<Value> {
|
fn active(&self) -> bool {
|
||||||
&mut self.stack
|
self.active
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registers(&self) -> &Vec<Value> {
|
fn mark_active(&mut self) {
|
||||||
&self.registers
|
self.active = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn registers_mut(&mut self) -> &mut Vec<Value> {
|
fn instructions(&self) -> &'a [Instruction] {
|
||||||
&mut self.registers
|
self.instructions
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ensure_registers(&mut self, count: usize) {
|
fn ip(&self) -> usize {
|
||||||
self.registers.resize_with(count, Default::default);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn ip(&self) -> usize {
|
|
||||||
self.ip
|
self.ip
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn increment_ip(&mut self) {
|
fn increment_ip(&mut self) {
|
||||||
self.ip += 1;
|
self.ip += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fp(&self) -> usize {
|
fn stack(&self) -> &[Value] {
|
||||||
|
&self.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fn stack_mut(&mut self) -> &mut Vec<Value> {
|
||||||
|
&mut self.stack
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fp(&self) -> usize {
|
||||||
self.fp
|
self.fp
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_fp(&mut self, fp: usize) {
|
fn set_fp(&mut self, fp: usize) {
|
||||||
self.fp = fp;
|
self.fp = fp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn call(
|
pub struct CallStack<'a> {
|
||||||
context: &DvmContext,
|
call_frames: Vec<CallFrame<'a>>,
|
||||||
state: &mut DvmState,
|
}
|
||||||
|
|
||||||
|
impl<'a> CallStack<'a> {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
call_frames: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn push(&mut self, call_frame: CallFrame<'a>) {
|
||||||
|
self.call_frames.push(call_frame);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pop(&mut self) -> CallFrame<'a> {
|
||||||
|
self.call_frames.pop().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top(&self) -> &CallFrame<'a> {
|
||||||
|
&self.call_frames[self.call_frames.len() - 1]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn top_mut(&mut self) -> &mut CallFrame<'a> {
|
||||||
|
let call_frames_len = self.call_frames.len();
|
||||||
|
&mut self.call_frames[call_frames_len - 1] // dang borrow checker
|
||||||
|
}
|
||||||
|
|
||||||
|
fn penultimate(&self) -> Option<&CallFrame<'a>> {
|
||||||
|
self.call_frames.get(self.call_frames.len() - 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn penultimate_mut(&mut self) -> Option<&mut CallFrame<'a>> {
|
||||||
|
let call_frames_len = self.call_frames.len();
|
||||||
|
self.call_frames.get_mut(call_frames_len - 2) // dang borrow checker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn call<'a>(
|
||||||
|
context: &'a DvmContext,
|
||||||
|
registers: &mut Vec<Value>,
|
||||||
|
call_stack: &mut CallStack<'a>,
|
||||||
function_name: &str,
|
function_name: &str,
|
||||||
arguments: Vec<Value>,
|
arguments: Vec<Value>,
|
||||||
) -> Option<Value> {
|
) -> Option<Value> {
|
||||||
@ -124,81 +173,109 @@ pub fn call(
|
|||||||
.get(function_name)
|
.get(function_name)
|
||||||
.expect(&format!("Function {} not found", function_name));
|
.expect(&format!("Function {} not found", function_name));
|
||||||
|
|
||||||
let instructions = function.instructions();
|
// ensure enough registers
|
||||||
state.ensure_registers(function.register_count());
|
registers.resize_with(function.register_count(), Default::default);
|
||||||
|
|
||||||
|
// push call frame
|
||||||
|
call_stack.push(CallFrame::new(
|
||||||
|
function.name_owned(),
|
||||||
|
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 {
|
||||||
state.stack_mut().push(argument);
|
call_stack.top_mut().stack_mut().push(argument);
|
||||||
}
|
}
|
||||||
|
|
||||||
while state.ip() < instructions.len() {
|
while call_stack.top().ip() < call_stack.top().instructions().len() {
|
||||||
let instruction = &instructions[state.ip()];
|
let instruction = &call_stack.top().instructions()[call_stack.top().ip()];
|
||||||
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 = state.registers()[*source].clone();
|
let value = registers[*source].clone();
|
||||||
state.registers_mut()[*destination] = value;
|
registers[*destination] = value;
|
||||||
}
|
}
|
||||||
Instruction::MoveInt(value, destination) => {
|
Instruction::MoveInt(value, destination) => {
|
||||||
state.registers_mut()[*destination] = Value::Int(*value);
|
registers[*destination] = Value::Int(*value);
|
||||||
}
|
}
|
||||||
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
|
||||||
let value_index = state
|
let value_index =
|
||||||
|
call_stack
|
||||||
|
.top()
|
||||||
.fp()
|
.fp()
|
||||||
.checked_add_signed(*offset)
|
.checked_add_signed(*offset)
|
||||||
.expect("Overflow when adding offset to fp");
|
.expect(&format!(
|
||||||
let value = state.stack()[value_index].clone();
|
"Overflow when adding offset {} to fp {}",
|
||||||
state.registers_mut()[*destination] = value;
|
*offset,
|
||||||
|
call_stack.top().fp()
|
||||||
|
));
|
||||||
|
let value = call_stack.top().stack()[value_index].clone();
|
||||||
|
registers[*destination] = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push instructions */
|
/* Push instructions */
|
||||||
Instruction::PushRegister(source) => {
|
Instruction::PushRegister(source) => {
|
||||||
// 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 = state.registers()[*source].clone();
|
let value = registers[*source].clone();
|
||||||
state.stack_mut().push(value);
|
call_stack.top_mut().stack_mut().push(value);
|
||||||
}
|
}
|
||||||
Instruction::PushInt(value) => {
|
Instruction::PushInt(value) => {
|
||||||
state.stack_mut().push(Value::Int(*value));
|
call_stack.top_mut().stack_mut().push(Value::Int(*value));
|
||||||
}
|
}
|
||||||
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
|
||||||
let value_index = state
|
let value_index = call_stack
|
||||||
|
.top()
|
||||||
.fp()
|
.fp()
|
||||||
.checked_add_signed(*offset)
|
.checked_add_signed(*offset)
|
||||||
.expect("Overflow when adding offset to fp");
|
.expect("Overflow when adding offset to fp");
|
||||||
let value = state.stack()[value_index].clone();
|
let value = call_stack.top().stack()[value_index].clone();
|
||||||
state.stack_mut().push(value);
|
call_stack.top_mut().stack_mut().push(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke instructions */
|
/* Invoke instructions */
|
||||||
Instruction::InvokeStatic(function_name) => {
|
Instruction::InvokeStatic(function_name, arg_count) => {
|
||||||
let function = context
|
let function = context
|
||||||
.functions
|
.functions
|
||||||
.get(function_name)
|
.get(function_name)
|
||||||
.expect(&format!("Function {} not found", function_name));
|
.expect(&format!("Function {} not found", function_name));
|
||||||
todo!("Call stack for invoking Deimos-native functions")
|
|
||||||
|
// get args
|
||||||
|
let mut args =
|
||||||
|
call_stack.top().stack()[call_stack.top().stack().len() - arg_count..].to_vec();
|
||||||
|
|
||||||
|
// push a new call frame
|
||||||
|
call_stack.push(CallFrame::new(
|
||||||
|
function.name_owned(),
|
||||||
|
function.instructions(),
|
||||||
|
));
|
||||||
|
|
||||||
|
// push args
|
||||||
|
call_stack.top_mut().stack_mut().append(&mut args);
|
||||||
|
|
||||||
|
// set fp for callee frame
|
||||||
|
let callee_frame = call_stack.top_mut();
|
||||||
|
callee_frame.set_fp(*arg_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::InvokePlatformStatic(function_name, arg_count) => {
|
Instruction::InvokePlatformStatic(function_name, arg_count) => {
|
||||||
let stack = state.stack();
|
|
||||||
let args = &stack[stack.len() - arg_count..];
|
|
||||||
let platform_function = context
|
let platform_function = context
|
||||||
.platform_functions()
|
.platform_functions()
|
||||||
.get(function_name)
|
.get(function_name)
|
||||||
.expect(&format!("Platform function {} not found", function_name));
|
.expect(&format!("Platform function {} not found", function_name));
|
||||||
let result = platform_function(context, state, args);
|
|
||||||
|
let args = &call_stack.top().stack()[call_stack.top().stack().len() - arg_count..];
|
||||||
|
|
||||||
|
let result = platform_function(args);
|
||||||
match result {
|
match result {
|
||||||
Ok(return_value) => {
|
Ok(return_value) => {
|
||||||
// pop args off the stack
|
// push return value to top of caller stack
|
||||||
let mut i: usize = 0;
|
call_stack.top_mut().stack_mut().push(return_value);
|
||||||
while i < *arg_count {
|
|
||||||
state.stack_mut().pop();
|
|
||||||
i += 1;
|
|
||||||
}
|
|
||||||
state.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
|
||||||
@ -212,41 +289,63 @@ pub fn call(
|
|||||||
let constant = &context.constants()[constant_name];
|
let constant = &context.constants()[constant_name];
|
||||||
match constant {
|
match constant {
|
||||||
Constant::String(string_constant) => {
|
Constant::String(string_constant) => {
|
||||||
state.registers_mut()[*destination] =
|
registers[*destination] = Value::String(string_constant.content_owned());
|
||||||
Value::String(string_constant.content_owned());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add instructions */
|
/* Add instructions */
|
||||||
Instruction::AddIntInt(lhs, rhs, destination) => {
|
Instruction::AddIntInt(lhs, rhs, destination) => {
|
||||||
let lhs_value = state.registers()[*lhs].unwrap_int();
|
let lhs_value = registers[*lhs].unwrap_int();
|
||||||
let rhs_value = state.registers()[*rhs].unwrap_int();
|
let rhs_value = registers[*rhs].unwrap_int();
|
||||||
let result = lhs_value + rhs_value;
|
let result = lhs_value + rhs_value;
|
||||||
state.registers_mut()[*destination] = Value::Int(result);
|
registers[*destination] = Value::Int(result);
|
||||||
}
|
}
|
||||||
Instruction::AddStringInt(lhs, rhs, destination) => {
|
Instruction::AddStringInt(lhs, rhs, destination) => {
|
||||||
let lhs_value = state.registers()[*lhs].unwrap_string();
|
let lhs_value = registers[*lhs].unwrap_string();
|
||||||
let rhs_value = state.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);
|
||||||
state.registers_mut()[*destination] = Value::String(Rc::from(formatted));
|
registers[*destination] = Value::String(Rc::from(formatted));
|
||||||
}
|
}
|
||||||
Instruction::AddStringString(lhs, rhs, destination) => {
|
Instruction::AddStringString(lhs, rhs, destination) => {
|
||||||
let lhs_value = state.registers()[*lhs].unwrap_string();
|
let lhs_value = registers[*lhs].unwrap_string();
|
||||||
let rhs_value = state.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);
|
||||||
state.registers_mut()[*destination] = Value::String(Rc::from(formatted));
|
registers[*destination] = Value::String(Rc::from(formatted));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop instructions */
|
/* Pop instructions */
|
||||||
Instruction::Pop(maybe_register) => {
|
Instruction::Pop(maybe_register) => {
|
||||||
let value = state.stack_mut().pop().unwrap();
|
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
||||||
if let Some(register) = maybe_register {
|
if let Some(register) = maybe_register {
|
||||||
state.registers_mut()[*register] = value;
|
registers[*register] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Call frame bookkeeping
|
||||||
|
let top_frame = call_stack.top();
|
||||||
|
if top_frame.active() {
|
||||||
|
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();
|
||||||
|
match maybe_penultimate_frame {
|
||||||
|
None => {
|
||||||
|
panic!("Invariant broken: only one call frame and it's inactive.");
|
||||||
|
}
|
||||||
|
Some(penultimate_frame) => {
|
||||||
|
if penultimate_frame.active() {
|
||||||
|
penultimate_frame.increment_ip();
|
||||||
|
} else {
|
||||||
|
panic!("Invariant broken: top two call frames are inactive.");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
state.increment_ip();
|
|
||||||
}
|
}
|
||||||
None // todo: returning results from main functions
|
None // todo: returning results from main functions
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,14 +17,14 @@ impl Value {
|
|||||||
pub fn unwrap_int(&self) -> i32 {
|
pub fn unwrap_int(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
Value::Int(i) => *i,
|
Value::Int(i) => *i,
|
||||||
_ => panic!(),
|
_ => panic!("Attempt to unwrap Int; found {:?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unwrap_string(&self) -> &Rc<str> {
|
pub fn unwrap_string(&self) -> &Rc<str> {
|
||||||
match self {
|
match self {
|
||||||
Value::String(s) => s,
|
Value::String(s) => s,
|
||||||
_ => panic!(),
|
_ => panic!("Attempt to unwrap String; found {:?}", self),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
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) -> Int
|
||||||
a + b
|
println(a + b)
|
||||||
end
|
end
|
||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
println(add(1, 2))
|
add(1, 2)
|
||||||
end
|
end
|
||||||
Loading…
Reference in New Issue
Block a user