Yay! Hello world via platform function is working.

This commit is contained in:
Jesse Brault 2026-03-02 18:22:24 -06:00
parent 7c041e40ad
commit ec18b5d5ba
25 changed files with 452 additions and 86 deletions

8
Cargo.lock generated
View File

@ -221,10 +221,18 @@ version = "0.1.0"
dependencies = [
"clap",
"codespan-reporting 0.13.1",
"dm-std-lib",
"dmc-lib",
"dvm-lib",
]
[[package]]
name = "dm-std-lib"
version = "0.1.0"
dependencies = [
"dvm-lib",
]
[[package]]
name = "dmc-lib"
version = "0.1.0"

View File

@ -5,7 +5,7 @@ edition = "2021"
#[[bin]]
#name = "dm"
#path = "src/bin/dvm/main.rs"
#path = "src/bin/dvm/lib"
[[bin]]
name = "dmc"
@ -25,4 +25,4 @@ cst-test-generator = { path = "cst-test-generator" }
[workspace]
resolver = "3"
members = ["ast-generator", "cst-test-generator", "dm", "dmc-lib", "dvm-lib"]
members = ["ast-generator", "cst-test-generator", "dm", "dm-std-lib", "dmc-lib", "dvm-lib"]

7
dm-std-lib/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "dm-std-lib"
version = "0.1.0"
edition = "2024"
[dependencies]
dvm-lib = { path = "../dvm-lib" }

61
dm-std-lib/src/lib.rs Normal file
View File

@ -0,0 +1,61 @@
use dvm_lib::vm::value::Value;
use dvm_lib::vm::{DvmContext, DvmState};
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::rc::Rc;
pub fn add_all_std_core(context: &mut DvmContext) {
let platform_functions = context.platform_functions_mut();
platform_functions.insert(Rc::from("println"), std_core_println);
}
struct StdCoreError {
message: String,
}
impl StdCoreError {
pub fn new(message: &str) -> StdCoreError {
Self {
message: message.into(),
}
}
}
impl Debug for StdCoreError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
todo!()
}
}
impl Display for StdCoreError {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.message)
}
}
impl Error for StdCoreError {}
pub fn std_core_println(
context: &DvmContext,
state: &DvmState,
args: &[Value],
) -> Result<Value, Box<dyn Error>> {
let maybe_to_print = args.get(0);
match maybe_to_print {
None => Err(Box::new(StdCoreError::new("Missing to_print arg"))),
Some(to_print) => {
match to_print {
Value::Int(i) => {
println!("{}", i);
}
Value::String(s) => {
println!("{}", s);
}
Value::Null => {
println!("null");
}
}
Ok(Value::Null)
}
}
}

View File

@ -6,5 +6,6 @@ edition = "2024"
[dependencies]
dmc-lib = { path = "../dmc-lib" }
dvm-lib = { path = "../dvm-lib" }
dm-std-lib = { path = "../dm-std-lib" }
clap = { version = "4.5.60", features = ["derive"] }
codespan-reporting = "0.13.1"

View File

@ -3,6 +3,7 @@ use codespan_reporting::diagnostic::Label;
use codespan_reporting::files::SimpleFiles;
use codespan_reporting::term;
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
use dm_std_lib::add_all_std_core;
use dmc_lib::constants_table::ConstantsTable;
use dmc_lib::diagnostic::Diagnostic;
use dmc_lib::parser::parse_compilation_unit;
@ -59,6 +60,9 @@ fn main() {
let mut dvm_context = DvmContext::new();
// add std::core fns
add_all_std_core(&mut dvm_context);
for asm_function in &asm_functions {
let function = asm_function.dvm();
dvm_context.add_function(function);

View File

@ -103,15 +103,19 @@ impl Pop {
#[derive(Debug)]
pub struct InvokePlatformStatic {
name: String,
arg_count: usize,
}
impl InvokePlatformStatic {
pub fn new(name: &str) -> Self {
Self { name: name.into() }
pub fn new(name: &str, arg_count: usize) -> Self {
Self {
name: name.into(),
arg_count,
}
}
pub fn dvm(&self) -> Instruction {
Instruction::InvokePlatformStatic(Rc::from(self.name.clone()))
Instruction::InvokePlatformStatic(Rc::from(self.name.clone()), self.arg_count)
}
}

View File

@ -62,14 +62,51 @@ impl Call {
}
// check that callee is callable
match self.callee.type_info() {
TypeInfo::Function(_) => {}
let function_symbol = match self.callee.type_info() {
TypeInfo::Function(function_symbol) => function_symbol,
_ => {
diagnostics.push(Diagnostic::new(
"Receiver is not callable",
self.callee.source_range().start(),
self.callee.source_range().end(),
));
return diagnostics;
}
};
// check arguments length
let function_symbol_ref = function_symbol.borrow();
let parameters = function_symbol_ref.parameters();
if parameters.len() != self.arguments.len() {
diagnostics.push(Diagnostic::new(
&format!(
"Wrong number of arguments; expected {} but found {}",
parameters.len(),
self.arguments.len()
),
self.source_range.start(),
self.source_range.end(),
));
}
if !diagnostics.is_empty() {
return diagnostics;
}
// check argument types
for i in 0..parameters.len() {
let parameter = &parameters[i];
let argument = &self.arguments[i];
if parameter.borrow().type_info() != &argument.type_info() {
diagnostics.push(Diagnostic::new(
&format!(
"Mismatched types; expected {} but found {}",
parameter.borrow().type_info(),
argument.type_info()
),
argument.source_range().start(),
argument.source_range().end(),
))
}
}
@ -78,7 +115,7 @@ impl Call {
pub fn type_info(&self) -> TypeInfo {
match self.callee.type_info() {
TypeInfo::Function(function_symbol) => function_symbol.return_type(),
TypeInfo::Function(function_symbol) => function_symbol.borrow().return_type(),
_ => panic!(),
}
}
@ -155,9 +192,11 @@ impl Call {
_ => panic!("Calling things other than identifiers not yet supported."),
};
let function_symbol = function_symbol.borrow();
if function_symbol.is_platform() {
let arg_count = function_symbol.parameters().len();
context.instruction(AsmInstruction::InvokePlatformStatic(
InvokePlatformStatic::new(function_symbol.name()),
InvokePlatformStatic::new(function_symbol.name(), arg_count),
));
} else {
todo!("non-platform invoke")

View File

@ -1,20 +1,29 @@
use crate::ast::assemble_context::AssembleContext;
use crate::ast::parameter::Parameter;
use crate::constants_table::ConstantsTable;
use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange;
use crate::symbol::FunctionSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable};
use std::cell::RefCell;
use std::rc::Rc;
pub struct ExternFunction {
declared_name: String,
declared_name_source_range: SourceRange,
parameters: Vec<Parameter>,
}
impl ExternFunction {
pub fn new(name: &str, declared_name_source_range: SourceRange) -> ExternFunction {
pub fn new(
name: &str,
declared_name_source_range: SourceRange,
parameters: Vec<Parameter>,
) -> ExternFunction {
ExternFunction {
declared_name: name.into(),
declared_name_source_range,
parameters,
}
}
@ -23,26 +32,52 @@ impl ExternFunction {
}
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
&self.declared_name,
&vec![],
true,
));
let mut diagnostics = vec![];
let insert_result =
symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true));
let mut maybe_function_symbol: Option<Rc<RefCell<FunctionSymbol>>> = None;
match insert_result {
Ok(_) => vec![],
Ok(function_symbol) => {
maybe_function_symbol = Some(function_symbol);
}
Err(symbol_insert_error) => match symbol_insert_error {
SymbolInsertError::AlreadyDeclared(already_declared) => {
vec![Diagnostic::new(
diagnostics.push(Diagnostic::new(
&format!(
"Function {} already declared in current scope.",
already_declared.name()
),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
)]
));
}
},
}
symbol_table.push_scope(&format!("extern_function_scope({})", &self.declared_name));
let mut parameter_symbols = vec![];
for parameter in &mut self.parameters {
let parameter_result = parameter.gather_declared_names(symbol_table);
match parameter_result {
Ok(parameter_symbol) => {
parameter_symbols.push(parameter_symbol);
}
Err(mut parameter_diagnostics) => {
diagnostics.append(&mut parameter_diagnostics);
}
}
}
maybe_function_symbol
.unwrap()
.borrow_mut()
.set_parameters(parameter_symbols);
symbol_table.pop_scope();
diagnostics
}
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {

View File

@ -40,11 +40,8 @@ impl Function {
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
let mut diagnostics = vec![];
// insert function symbol
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
self.declared_name(),
&vec![], // todo
false,
));
let insert_result =
symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false));
if let Err(symbol_insert_error) = insert_result {
match symbol_insert_error {
SymbolInsertError::AlreadyDeclared(already_declared) => {
@ -59,6 +56,9 @@ impl Function {
}
}
}
// todo: parameters
symbol_table.push_scope(&format!("function_scope({})", self.declared_name()));
for statement in &mut self.statements {
diagnostics.append(&mut statement.gather_declared_names(symbol_table));

View File

@ -10,5 +10,6 @@ pub mod identifier;
pub mod integer_literal;
pub mod let_statement;
pub mod module_level_declaration;
pub mod parameter;
pub mod statement;
pub mod string_literal;

View File

@ -0,0 +1,41 @@
use crate::diagnostic::Diagnostic;
use crate::source_range::SourceRange;
use crate::symbol::ParameterSymbol;
use crate::symbol_table::{SymbolInsertError, SymbolTable};
use crate::type_info::TypeInfo;
use std::cell::RefCell;
use std::rc::Rc;
pub struct Parameter {
declared_name: String,
declared_name_source_range: SourceRange,
}
impl Parameter {
pub fn new(declared_name: &str, declared_name_source_range: SourceRange) -> Self {
Self {
declared_name: declared_name.into(),
declared_name_source_range,
}
}
pub fn gather_declared_names(
&mut self,
symbol_table: &mut SymbolTable,
) -> Result<Rc<RefCell<ParameterSymbol>>, Vec<Diagnostic>> {
let insert_result = symbol_table.insert_parameter_symbol(ParameterSymbol::new(
&self.declared_name,
TypeInfo::String, // todo
));
match insert_result {
Ok(parameter_symbol) => Ok(parameter_symbol),
Err(symbol_insert_error) => match symbol_insert_error {
SymbolInsertError::AlreadyDeclared(already_declared) => Err(vec![Diagnostic::new(
&format!("Parameter {} already declared.", already_declared.name()),
self.declared_name_source_range.start(),
self.declared_name_source_range.end(),
)]),
},
}
}
}

View File

@ -46,7 +46,7 @@ impl IrCall {
}
}
instructions.push(AsmInstruction::InvokePlatformStatic(
InvokePlatformStatic::new(&self.name),
InvokePlatformStatic::new(&self.name, todo!()),
));
instructions
}

View File

@ -44,6 +44,8 @@ impl<'a> Lexer<'a> {
)
} else if chunk.starts_with("=") {
Token::new(self.position, self.position + 1, TokenKind::Equals)
} else if chunk.starts_with(",") {
Token::new(self.position, self.position + 1, TokenKind::Comma)
} else {
// more than one char token
if chunk.starts_with(|c: char| c.is_ascii_digit()) {

View File

@ -8,6 +8,7 @@ use crate::ast::identifier::Identifier;
use crate::ast::integer_literal::IntegerLiteral;
use crate::ast::let_statement::LetStatement;
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
use crate::ast::parameter::Parameter;
use crate::ast::statement::Statement;
use crate::ast::string_literal::StringLiteral;
use crate::diagnostic::Diagnostic;
@ -138,6 +139,13 @@ impl<'a> Parser<'a> {
}
}
fn peek_lookahead(&self, token_kind: TokenKind) -> bool {
match &self.lookahead {
None => panic!("Unexpected end of input."),
Some(token) => token.kind() == token_kind,
}
}
fn sample_input(&self, start: usize, end: usize) -> &'a str {
&self.input[start..end]
}
@ -251,12 +259,64 @@ impl<'a> Parser<'a> {
self.expect_advance(TokenKind::Fn)?;
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
self.expect_advance(TokenKind::LeftParentheses)?;
// params
self.expect_advance(TokenKind::RightParentheses)?;
// return type
let mut diagnostics = vec![];
let mut maybe_parameters: Option<Vec<Parameter>> = None;
let params_result = self.parameter_list();
match params_result {
Ok(parameters) => {
maybe_parameters = Some(parameters);
}
Err(mut parameter_list_diagnostics) => {
diagnostics.append(&mut parameter_list_diagnostics);
}
}
let right_parentheses_result = self.expect_advance(TokenKind::RightParentheses);
match right_parentheses_result {
Err(mut right_parentheses_diagnostics) => {
diagnostics.append(&mut right_parentheses_diagnostics);
}
Ok(_) => {}
}
if diagnostics.is_empty() {
Ok(ExternFunction::new(
self.token_text(&identifier_token),
SourceRange::new(identifier_token.start(), identifier_token.end()),
maybe_parameters.unwrap(),
))
} else {
Err(diagnostics)
}
}
fn parameter_list(&mut self) -> Result<Vec<Parameter>, Vec<Diagnostic>> {
let mut parameters = vec![];
let mut diagnostics = vec![];
while self.current.is_some() && self.peek_current(TokenKind::Identifier) {
let parameter_result = self.parameter();
match parameter_result {
Ok(parameter) => {
parameters.push(parameter);
}
Err(mut parameter_diagnostics) => {
diagnostics.append(&mut parameter_diagnostics);
}
}
if self.lookahead.is_some() && self.peek_lookahead(TokenKind::Comma) {
self.advance();
}
}
Ok(parameters)
}
fn parameter(&mut self) -> Result<Parameter, Vec<Diagnostic>> {
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
Ok(Parameter::new(
self.token_text(&identifier_token),
SourceRange::new(identifier_token.start(), identifier_token.end()),
))
}
@ -381,9 +441,56 @@ impl<'a> Parser<'a> {
mod smoke_tests {
use super::*;
fn smoke_test(input: &str) {
let parse_result = parse_compilation_unit(input);
match parse_result {
Ok(_) => {}
Err(diagnostics) => {
eprintln!("{:#?}", diagnostics);
panic!("There were diagnostics during parsing");
}
}
}
#[test]
fn forty_two() {
parse_compilation_unit("fn main() 42 end");
smoke_test("fn main() 42 end");
}
#[test]
fn chained_calls() {
smoke_test("fn main() getCl()() end");
}
#[test]
fn extern_fn_with_param() {
smoke_test("extern fn println(message)")
}
}
#[cfg(test)]
mod concrete_tests {
use super::*;
#[test]
fn parses_extern_fn() {
let parse_result = parse_compilation_unit("extern fn println()");
let compilation_unit = match parse_result {
Ok(compilation_unit) => compilation_unit,
Err(diagnostics) => {
for diagnostic in diagnostics {
eprintln!("{:?}", diagnostic);
}
panic!();
}
};
let declarations = compilation_unit.declarations();
assert_eq!(declarations.len(), 1);
let extern_function = match &declarations[0] {
ModuleLevelDeclaration::ExternFunction(extern_function) => extern_function,
_ => panic!(),
};
assert_eq!(extern_function.declared_name(), "println");
}
#[test]
@ -432,37 +539,6 @@ mod smoke_tests {
panic!("Expected expression");
}
}
#[test]
fn chained_calls() {
parse_compilation_unit("fn main() getCl()() end");
}
}
#[cfg(test)]
mod concrete_tests {
use super::*;
#[test]
fn parses_extern_fn() {
let parse_result = parse_compilation_unit("extern fn println()");
let compilation_unit = match parse_result {
Ok(compilation_unit) => compilation_unit,
Err(diagnostics) => {
for diagnostic in diagnostics {
eprintln!("{:?}", diagnostic);
}
panic!();
}
};
let declarations = compilation_unit.declarations();
assert_eq!(declarations.len(), 1);
let extern_function = match &declarations[0] {
ModuleLevelDeclaration::ExternFunction(extern_function) => extern_function,
_ => panic!(),
};
assert_eq!(extern_function.declared_name(), "println");
}
}
#[cfg(test)]

View File

@ -6,7 +6,7 @@ use std::rc::Rc;
pub struct Scope {
debug_name: String,
parent_id: Option<usize>,
function_symbols: HashMap<Rc<str>, Rc<FunctionSymbol>>,
function_symbols: HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>>,
parameter_symbols: HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>>,
variable_symbols: HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>>,
}
@ -22,11 +22,11 @@ impl Scope {
}
}
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<FunctionSymbol>> {
pub fn function_symbols(&self) -> &HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&self.function_symbols
}
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<FunctionSymbol>> {
pub fn function_symbols_mut(&mut self) -> &mut HashMap<Rc<str>, Rc<RefCell<FunctionSymbol>>> {
&mut self.function_symbols
}

View File

@ -4,16 +4,16 @@ use std::rc::Rc;
pub struct FunctionSymbol {
name: Rc<str>,
parameters: Vec<Rc<ParameterSymbol>>,
is_platform: bool,
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
}
impl FunctionSymbol {
pub fn new(name: &str, parameters: &[Rc<ParameterSymbol>], is_platform: bool) -> Self {
pub fn new(name: &str, is_platform: bool) -> Self {
Self {
name: name.into(),
parameters: parameters.into(),
is_platform,
parameters: None,
}
}
@ -25,8 +25,12 @@ impl FunctionSymbol {
self.name.clone()
}
pub fn parameters(&self) -> &[Rc<ParameterSymbol>] {
&self.parameters
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
self.parameters = Some(parameters);
}
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
self.parameters.as_ref().unwrap()
}
pub fn return_type(&self) -> TypeInfo {
@ -111,7 +115,7 @@ impl VariableSymbol {
}
pub enum ExpressibleSymbol {
Function(Rc<FunctionSymbol>),
Function(Rc<RefCell<FunctionSymbol>>),
Parameter(Rc<RefCell<ParameterSymbol>>),
Variable(Rc<RefCell<VariableSymbol>>),
}

View File

@ -51,32 +51,35 @@ impl SymbolTable {
pub fn insert_function_symbol(
&mut self,
function_symbol: FunctionSymbol,
) -> Result<(), SymbolInsertError> {
) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolInsertError> {
if self.current_scope_has_name(function_symbol.name()) {
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
function_symbol.name(),
)));
}
let name = function_symbol.name_owned();
let as_rc = Rc::new(RefCell::new(function_symbol));
self.current_scope_mut()
.function_symbols_mut()
.insert(function_symbol.name_owned(), Rc::new(function_symbol));
Ok(())
.insert(name, as_rc.clone());
Ok(as_rc)
}
pub fn insert_parameter_symbol(
&mut self,
parameter_symbol: ParameterSymbol,
) -> Result<(), SymbolInsertError> {
) -> Result<Rc<RefCell<ParameterSymbol>>, SymbolInsertError> {
if self.current_scope_has_name(parameter_symbol.name()) {
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
parameter_symbol.name(),
)));
}
self.current_scope_mut().parameter_symbols_mut().insert(
parameter_symbol.name_owned(),
Rc::new(RefCell::new(parameter_symbol)),
);
Ok(())
let as_rc = Rc::new(RefCell::new(parameter_symbol));
self.current_scope_mut()
.parameter_symbols_mut()
.insert(as_rc.borrow().name_owned(), as_rc.clone());
Ok(as_rc)
}
pub fn insert_variable_symbol(

View File

@ -36,4 +36,5 @@ pub enum TokenKind {
LongLiteral,
String,
Extern,
Comma,
}

View File

@ -1,9 +1,43 @@
use crate::symbol::FunctionSymbol;
use std::cell::RefCell;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Clone)]
pub enum TypeInfo {
Integer,
String,
Function(Rc<FunctionSymbol>),
Function(Rc<RefCell<FunctionSymbol>>),
}
impl Display for TypeInfo {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let s = match self {
TypeInfo::Integer => "Int",
TypeInfo::String => "String",
TypeInfo::Function(_) => "fn", // todo
};
write!(f, "{}", s)
}
}
impl PartialEq for &TypeInfo {
fn eq(&self, other: &Self) -> bool {
match self {
TypeInfo::Integer => match other {
TypeInfo::Integer => true,
_ => false,
},
TypeInfo::String => match other {
TypeInfo::String => true,
_ => false,
},
TypeInfo::Function(f0) => match other {
TypeInfo::Function(f1) => {
f0.as_ptr() == f1.as_ptr() // todo
}
_ => false,
},
}
}
}

View File

@ -3,6 +3,7 @@ use std::rc::Rc;
pub type Register = usize;
pub type ConstantName = Rc<str>;
pub type FunctionName = Rc<str>;
pub type ArgCount = usize;
pub enum Instruction {
MoveRegister(Register, Register),
@ -13,7 +14,7 @@ pub enum Instruction {
PushInt(i32),
PushStackFrameOffset(isize),
InvokePlatformStatic(FunctionName),
InvokePlatformStatic(FunctionName, ArgCount),
LoadStringConstant(ConstantName, Register),

View File

@ -1,2 +1,3 @@
pub mod instruction;
pub mod platform_function;
pub mod vm;

View File

@ -0,0 +1,6 @@
use crate::vm::value::Value;
use crate::vm::{DvmContext, DvmState};
use std::error::Error;
pub type PlatformFunction =
fn(context: &DvmContext, state: &DvmState, args: &[Value]) -> Result<Value, Box<dyn Error>>;

View File

@ -1,4 +1,5 @@
use crate::instruction::Instruction;
use crate::platform_function::PlatformFunction;
use crate::vm::constant::Constant;
use crate::vm::function::Function;
use crate::vm::value::Value;
@ -11,6 +12,7 @@ pub mod value;
pub struct DvmContext {
functions: HashMap<Rc<str>, Function>,
platform_functions: HashMap<Rc<str>, PlatformFunction>,
constants: HashMap<Rc<str>, Constant>,
}
@ -18,10 +20,27 @@ impl DvmContext {
pub fn new() -> Self {
Self {
functions: HashMap::new(),
platform_functions: HashMap::new(),
constants: HashMap::new(),
}
}
pub fn functions(&self) -> &HashMap<Rc<str>, Function> {
&self.functions
}
pub fn functions_mut(&mut self) -> &mut HashMap<Rc<str>, Function> {
&mut self.functions
}
pub fn platform_functions(&self) -> &HashMap<Rc<str>, PlatformFunction> {
&self.platform_functions
}
pub fn platform_functions_mut(&mut self) -> &mut HashMap<Rc<str>, PlatformFunction> {
&mut self.platform_functions
}
pub fn add_function(&mut self, function: Function) {
self.functions.insert(function.name_owned(), function);
}
@ -155,10 +174,28 @@ pub fn call(
}
/* Invoke instructions */
Instruction::InvokePlatformStatic(function_name) => {
if function_name.as_ref() == "println" {
println!("{:?}", state.stack());
println!("{:?}", state.registers());
Instruction::InvokePlatformStatic(function_name, arg_count) => {
let stack = state.stack();
let args = &stack[stack.len() - arg_count..];
let platform_function = context
.platform_functions()
.get(function_name)
.expect(&format!("Platform function {} not found", function_name));
let result = platform_function(context, state, args);
match result {
Ok(return_value) => {
// pop args off the stack
let mut i: usize = 0;
while i < *arg_count {
state.stack_mut().pop();
i += 1;
}
state.stack_mut().push(return_value);
}
Err(error) => {
// Eventually we will have some kind of exception handling
panic!("{}", error);
}
}
}
@ -183,5 +220,5 @@ pub fn call(
}
state.increment_ip();
}
None
None // todo: returning results from main functions
}

View File

@ -1,4 +1,4 @@
extern fn println()
extern fn println(message)
fn main()
let x = "Hello, World!"