Yay! Hello world via platform function is working.
This commit is contained in:
parent
7c041e40ad
commit
ec18b5d5ba
8
Cargo.lock
generated
8
Cargo.lock
generated
@ -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"
|
||||
|
||||
@ -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
7
dm-std-lib/Cargo.toml
Normal 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
61
dm-std-lib/src/lib.rs
Normal 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)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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"
|
||||
@ -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);
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 = ¶meters[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")
|
||||
|
||||
@ -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> {
|
||||
|
||||
@ -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));
|
||||
|
||||
@ -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;
|
||||
|
||||
41
dmc-lib/src/ast/parameter.rs
Normal file
41
dmc-lib/src/ast/parameter.rs
Normal 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(),
|
||||
)]),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -46,7 +46,7 @@ impl IrCall {
|
||||
}
|
||||
}
|
||||
instructions.push(AsmInstruction::InvokePlatformStatic(
|
||||
InvokePlatformStatic::new(&self.name),
|
||||
InvokePlatformStatic::new(&self.name, todo!()),
|
||||
));
|
||||
instructions
|
||||
}
|
||||
|
||||
@ -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()) {
|
||||
|
||||
@ -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)]
|
||||
|
||||
@ -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
|
||||
}
|
||||
|
||||
|
||||
@ -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>>),
|
||||
}
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -36,4 +36,5 @@ pub enum TokenKind {
|
||||
LongLiteral,
|
||||
String,
|
||||
Extern,
|
||||
Comma,
|
||||
}
|
||||
|
||||
@ -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,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
|
||||
|
||||
@ -1,2 +1,3 @@
|
||||
pub mod instruction;
|
||||
pub mod platform_function;
|
||||
pub mod vm;
|
||||
|
||||
6
dvm-lib/src/platform_function.rs
Normal file
6
dvm-lib/src/platform_function.rs
Normal 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>>;
|
||||
@ -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
|
||||
}
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
extern fn println()
|
||||
extern fn println(message)
|
||||
|
||||
fn main()
|
||||
let x = "Hello, World!"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user