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 = [
|
dependencies = [
|
||||||
"clap",
|
"clap",
|
||||||
"codespan-reporting 0.13.1",
|
"codespan-reporting 0.13.1",
|
||||||
|
"dm-std-lib",
|
||||||
"dmc-lib",
|
"dmc-lib",
|
||||||
"dvm-lib",
|
"dvm-lib",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "dm-std-lib"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"dvm-lib",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dmc-lib"
|
name = "dmc-lib"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|||||||
@ -5,7 +5,7 @@ edition = "2021"
|
|||||||
|
|
||||||
#[[bin]]
|
#[[bin]]
|
||||||
#name = "dm"
|
#name = "dm"
|
||||||
#path = "src/bin/dvm/main.rs"
|
#path = "src/bin/dvm/lib"
|
||||||
|
|
||||||
[[bin]]
|
[[bin]]
|
||||||
name = "dmc"
|
name = "dmc"
|
||||||
@ -25,4 +25,4 @@ cst-test-generator = { path = "cst-test-generator" }
|
|||||||
|
|
||||||
[workspace]
|
[workspace]
|
||||||
resolver = "3"
|
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]
|
[dependencies]
|
||||||
dmc-lib = { path = "../dmc-lib" }
|
dmc-lib = { path = "../dmc-lib" }
|
||||||
dvm-lib = { path = "../dvm-lib" }
|
dvm-lib = { path = "../dvm-lib" }
|
||||||
|
dm-std-lib = { path = "../dm-std-lib" }
|
||||||
clap = { version = "4.5.60", features = ["derive"] }
|
clap = { version = "4.5.60", features = ["derive"] }
|
||||||
codespan-reporting = "0.13.1"
|
codespan-reporting = "0.13.1"
|
||||||
@ -3,6 +3,7 @@ use codespan_reporting::diagnostic::Label;
|
|||||||
use codespan_reporting::files::SimpleFiles;
|
use codespan_reporting::files::SimpleFiles;
|
||||||
use codespan_reporting::term;
|
use codespan_reporting::term;
|
||||||
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
use codespan_reporting::term::termcolor::{ColorChoice, StandardStream};
|
||||||
|
use dm_std_lib::add_all_std_core;
|
||||||
use dmc_lib::constants_table::ConstantsTable;
|
use dmc_lib::constants_table::ConstantsTable;
|
||||||
use dmc_lib::diagnostic::Diagnostic;
|
use dmc_lib::diagnostic::Diagnostic;
|
||||||
use dmc_lib::parser::parse_compilation_unit;
|
use dmc_lib::parser::parse_compilation_unit;
|
||||||
@ -59,6 +60,9 @@ fn main() {
|
|||||||
|
|
||||||
let mut dvm_context = DvmContext::new();
|
let mut dvm_context = DvmContext::new();
|
||||||
|
|
||||||
|
// add std::core fns
|
||||||
|
add_all_std_core(&mut dvm_context);
|
||||||
|
|
||||||
for asm_function in &asm_functions {
|
for asm_function in &asm_functions {
|
||||||
let function = asm_function.dvm();
|
let function = asm_function.dvm();
|
||||||
dvm_context.add_function(function);
|
dvm_context.add_function(function);
|
||||||
|
|||||||
@ -103,15 +103,19 @@ impl Pop {
|
|||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvokePlatformStatic {
|
pub struct InvokePlatformStatic {
|
||||||
name: String,
|
name: String,
|
||||||
|
arg_count: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InvokePlatformStatic {
|
impl InvokePlatformStatic {
|
||||||
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::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
|
// check that callee is callable
|
||||||
match self.callee.type_info() {
|
let function_symbol = match self.callee.type_info() {
|
||||||
TypeInfo::Function(_) => {}
|
TypeInfo::Function(function_symbol) => function_symbol,
|
||||||
_ => {
|
_ => {
|
||||||
diagnostics.push(Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
"Receiver is not callable",
|
"Receiver is not callable",
|
||||||
self.callee.source_range().start(),
|
self.callee.source_range().start(),
|
||||||
self.callee.source_range().end(),
|
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 {
|
pub fn type_info(&self) -> TypeInfo {
|
||||||
match self.callee.type_info() {
|
match self.callee.type_info() {
|
||||||
TypeInfo::Function(function_symbol) => function_symbol.return_type(),
|
TypeInfo::Function(function_symbol) => function_symbol.borrow().return_type(),
|
||||||
_ => panic!(),
|
_ => panic!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -155,9 +192,11 @@ impl Call {
|
|||||||
_ => panic!("Calling things other than identifiers not yet supported."),
|
_ => panic!("Calling things other than identifiers not yet supported."),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let function_symbol = function_symbol.borrow();
|
||||||
if function_symbol.is_platform() {
|
if function_symbol.is_platform() {
|
||||||
|
let arg_count = function_symbol.parameters().len();
|
||||||
context.instruction(AsmInstruction::InvokePlatformStatic(
|
context.instruction(AsmInstruction::InvokePlatformStatic(
|
||||||
InvokePlatformStatic::new(function_symbol.name()),
|
InvokePlatformStatic::new(function_symbol.name(), arg_count),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
todo!("non-platform invoke")
|
todo!("non-platform invoke")
|
||||||
|
|||||||
@ -1,20 +1,29 @@
|
|||||||
use crate::ast::assemble_context::AssembleContext;
|
use crate::ast::assemble_context::AssembleContext;
|
||||||
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::constants_table::ConstantsTable;
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::FunctionSymbol;
|
use crate::symbol::FunctionSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ExternFunction {
|
pub struct ExternFunction {
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
|
parameters: Vec<Parameter>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternFunction {
|
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 {
|
ExternFunction {
|
||||||
declared_name: name.into(),
|
declared_name: name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
|
parameters,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,26 +32,52 @@ impl ExternFunction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
let mut diagnostics = vec![];
|
||||||
&self.declared_name,
|
|
||||||
&vec![],
|
let insert_result =
|
||||||
true,
|
symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true));
|
||||||
));
|
|
||||||
|
let mut maybe_function_symbol: Option<Rc<RefCell<FunctionSymbol>>> = None;
|
||||||
match insert_result {
|
match insert_result {
|
||||||
Ok(_) => vec![],
|
Ok(function_symbol) => {
|
||||||
|
maybe_function_symbol = Some(function_symbol);
|
||||||
|
}
|
||||||
Err(symbol_insert_error) => match symbol_insert_error {
|
Err(symbol_insert_error) => match symbol_insert_error {
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||||
vec![Diagnostic::new(
|
diagnostics.push(Diagnostic::new(
|
||||||
&format!(
|
&format!(
|
||||||
"Function {} already declared in current scope.",
|
"Function {} already declared in current scope.",
|
||||||
already_declared.name()
|
already_declared.name()
|
||||||
),
|
),
|
||||||
self.declared_name_source_range.start(),
|
self.declared_name_source_range.start(),
|
||||||
self.declared_name_source_range.end(),
|
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> {
|
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> {
|
pub fn gather_declared_names(&mut self, symbol_table: &mut SymbolTable) -> Vec<Diagnostic> {
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
// insert function symbol
|
// insert function symbol
|
||||||
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
let insert_result =
|
||||||
self.declared_name(),
|
symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false));
|
||||||
&vec![], // todo
|
|
||||||
false,
|
|
||||||
));
|
|
||||||
if let Err(symbol_insert_error) = insert_result {
|
if let Err(symbol_insert_error) = insert_result {
|
||||||
match symbol_insert_error {
|
match symbol_insert_error {
|
||||||
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
SymbolInsertError::AlreadyDeclared(already_declared) => {
|
||||||
@ -59,6 +56,9 @@ impl Function {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// todo: parameters
|
||||||
|
|
||||||
symbol_table.push_scope(&format!("function_scope({})", self.declared_name()));
|
symbol_table.push_scope(&format!("function_scope({})", self.declared_name()));
|
||||||
for statement in &mut self.statements {
|
for statement in &mut self.statements {
|
||||||
diagnostics.append(&mut statement.gather_declared_names(symbol_table));
|
diagnostics.append(&mut statement.gather_declared_names(symbol_table));
|
||||||
|
|||||||
@ -10,5 +10,6 @@ pub mod identifier;
|
|||||||
pub mod integer_literal;
|
pub mod integer_literal;
|
||||||
pub mod let_statement;
|
pub mod let_statement;
|
||||||
pub mod module_level_declaration;
|
pub mod module_level_declaration;
|
||||||
|
pub mod parameter;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
pub mod string_literal;
|
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(
|
instructions.push(AsmInstruction::InvokePlatformStatic(
|
||||||
InvokePlatformStatic::new(&self.name),
|
InvokePlatformStatic::new(&self.name, todo!()),
|
||||||
));
|
));
|
||||||
instructions
|
instructions
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,8 @@ impl<'a> Lexer<'a> {
|
|||||||
)
|
)
|
||||||
} else if chunk.starts_with("=") {
|
} else if chunk.starts_with("=") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::Equals)
|
Token::new(self.position, self.position + 1, TokenKind::Equals)
|
||||||
|
} else if chunk.starts_with(",") {
|
||||||
|
Token::new(self.position, self.position + 1, TokenKind::Comma)
|
||||||
} else {
|
} else {
|
||||||
// more than one char token
|
// more than one char token
|
||||||
if chunk.starts_with(|c: char| c.is_ascii_digit()) {
|
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::integer_literal::IntegerLiteral;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
||||||
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
use crate::ast::string_literal::StringLiteral;
|
use crate::ast::string_literal::StringLiteral;
|
||||||
use crate::diagnostic::Diagnostic;
|
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 {
|
fn sample_input(&self, start: usize, end: usize) -> &'a str {
|
||||||
&self.input[start..end]
|
&self.input[start..end]
|
||||||
}
|
}
|
||||||
@ -251,12 +259,64 @@ impl<'a> Parser<'a> {
|
|||||||
self.expect_advance(TokenKind::Fn)?;
|
self.expect_advance(TokenKind::Fn)?;
|
||||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||||
self.expect_advance(TokenKind::LeftParentheses)?;
|
self.expect_advance(TokenKind::LeftParentheses)?;
|
||||||
// params
|
|
||||||
self.expect_advance(TokenKind::RightParentheses)?;
|
let mut diagnostics = vec![];
|
||||||
// return type
|
|
||||||
|
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(
|
Ok(ExternFunction::new(
|
||||||
self.token_text(&identifier_token),
|
self.token_text(&identifier_token),
|
||||||
SourceRange::new(identifier_token.start(), identifier_token.end()),
|
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 {
|
mod smoke_tests {
|
||||||
use super::*;
|
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]
|
#[test]
|
||||||
fn forty_two() {
|
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]
|
#[test]
|
||||||
@ -432,37 +539,6 @@ mod smoke_tests {
|
|||||||
panic!("Expected expression");
|
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)]
|
#[cfg(test)]
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use std::rc::Rc;
|
|||||||
pub struct Scope {
|
pub struct Scope {
|
||||||
debug_name: String,
|
debug_name: String,
|
||||||
parent_id: Option<usize>,
|
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>>>,
|
parameter_symbols: HashMap<Rc<str>, Rc<RefCell<ParameterSymbol>>>,
|
||||||
variable_symbols: HashMap<Rc<str>, Rc<RefCell<VariableSymbol>>>,
|
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
|
&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
|
&mut self.function_symbols
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,16 +4,16 @@ use std::rc::Rc;
|
|||||||
|
|
||||||
pub struct FunctionSymbol {
|
pub struct FunctionSymbol {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
parameters: Vec<Rc<ParameterSymbol>>,
|
|
||||||
is_platform: bool,
|
is_platform: bool,
|
||||||
|
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionSymbol {
|
impl FunctionSymbol {
|
||||||
pub fn new(name: &str, parameters: &[Rc<ParameterSymbol>], is_platform: bool) -> Self {
|
pub fn new(name: &str, is_platform: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
parameters: parameters.into(),
|
|
||||||
is_platform,
|
is_platform,
|
||||||
|
parameters: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,8 +25,12 @@ impl FunctionSymbol {
|
|||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn parameters(&self) -> &[Rc<ParameterSymbol>] {
|
pub fn set_parameters(&mut self, parameters: Vec<Rc<RefCell<ParameterSymbol>>>) {
|
||||||
&self.parameters
|
self.parameters = Some(parameters);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parameters(&self) -> &[Rc<RefCell<ParameterSymbol>>] {
|
||||||
|
self.parameters.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn return_type(&self) -> TypeInfo {
|
pub fn return_type(&self) -> TypeInfo {
|
||||||
@ -111,7 +115,7 @@ impl VariableSymbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub enum ExpressibleSymbol {
|
pub enum ExpressibleSymbol {
|
||||||
Function(Rc<FunctionSymbol>),
|
Function(Rc<RefCell<FunctionSymbol>>),
|
||||||
Parameter(Rc<RefCell<ParameterSymbol>>),
|
Parameter(Rc<RefCell<ParameterSymbol>>),
|
||||||
Variable(Rc<RefCell<VariableSymbol>>),
|
Variable(Rc<RefCell<VariableSymbol>>),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,32 +51,35 @@ impl SymbolTable {
|
|||||||
pub fn insert_function_symbol(
|
pub fn insert_function_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
function_symbol: FunctionSymbol,
|
function_symbol: FunctionSymbol,
|
||||||
) -> Result<(), SymbolInsertError> {
|
) -> Result<Rc<RefCell<FunctionSymbol>>, SymbolInsertError> {
|
||||||
if self.current_scope_has_name(function_symbol.name()) {
|
if self.current_scope_has_name(function_symbol.name()) {
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
||||||
function_symbol.name(),
|
function_symbol.name(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
let name = function_symbol.name_owned();
|
||||||
|
let as_rc = Rc::new(RefCell::new(function_symbol));
|
||||||
|
|
||||||
self.current_scope_mut()
|
self.current_scope_mut()
|
||||||
.function_symbols_mut()
|
.function_symbols_mut()
|
||||||
.insert(function_symbol.name_owned(), Rc::new(function_symbol));
|
.insert(name, as_rc.clone());
|
||||||
Ok(())
|
Ok(as_rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_parameter_symbol(
|
pub fn insert_parameter_symbol(
|
||||||
&mut self,
|
&mut self,
|
||||||
parameter_symbol: ParameterSymbol,
|
parameter_symbol: ParameterSymbol,
|
||||||
) -> Result<(), SymbolInsertError> {
|
) -> Result<Rc<RefCell<ParameterSymbol>>, SymbolInsertError> {
|
||||||
if self.current_scope_has_name(parameter_symbol.name()) {
|
if self.current_scope_has_name(parameter_symbol.name()) {
|
||||||
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
return Err(SymbolInsertError::AlreadyDeclared(AlreadyDeclared::new(
|
||||||
parameter_symbol.name(),
|
parameter_symbol.name(),
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
self.current_scope_mut().parameter_symbols_mut().insert(
|
let as_rc = Rc::new(RefCell::new(parameter_symbol));
|
||||||
parameter_symbol.name_owned(),
|
self.current_scope_mut()
|
||||||
Rc::new(RefCell::new(parameter_symbol)),
|
.parameter_symbols_mut()
|
||||||
);
|
.insert(as_rc.borrow().name_owned(), as_rc.clone());
|
||||||
Ok(())
|
Ok(as_rc)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_variable_symbol(
|
pub fn insert_variable_symbol(
|
||||||
|
|||||||
@ -36,4 +36,5 @@ pub enum TokenKind {
|
|||||||
LongLiteral,
|
LongLiteral,
|
||||||
String,
|
String,
|
||||||
Extern,
|
Extern,
|
||||||
|
Comma,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,43 @@
|
|||||||
use crate::symbol::FunctionSymbol;
|
use crate::symbol::FunctionSymbol;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::fmt::{Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub enum TypeInfo {
|
pub enum TypeInfo {
|
||||||
Integer,
|
Integer,
|
||||||
String,
|
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 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 enum Instruction {
|
pub enum Instruction {
|
||||||
MoveRegister(Register, Register),
|
MoveRegister(Register, Register),
|
||||||
@ -13,7 +14,7 @@ pub enum Instruction {
|
|||||||
PushInt(i32),
|
PushInt(i32),
|
||||||
PushStackFrameOffset(isize),
|
PushStackFrameOffset(isize),
|
||||||
|
|
||||||
InvokePlatformStatic(FunctionName),
|
InvokePlatformStatic(FunctionName, ArgCount),
|
||||||
|
|
||||||
LoadStringConstant(ConstantName, Register),
|
LoadStringConstant(ConstantName, Register),
|
||||||
|
|
||||||
|
|||||||
@ -1,2 +1,3 @@
|
|||||||
pub mod instruction;
|
pub mod instruction;
|
||||||
|
pub mod platform_function;
|
||||||
pub mod vm;
|
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::instruction::Instruction;
|
||||||
|
use crate::platform_function::PlatformFunction;
|
||||||
use crate::vm::constant::Constant;
|
use crate::vm::constant::Constant;
|
||||||
use crate::vm::function::Function;
|
use crate::vm::function::Function;
|
||||||
use crate::vm::value::Value;
|
use crate::vm::value::Value;
|
||||||
@ -11,6 +12,7 @@ pub mod value;
|
|||||||
|
|
||||||
pub struct DvmContext {
|
pub struct DvmContext {
|
||||||
functions: HashMap<Rc<str>, Function>,
|
functions: HashMap<Rc<str>, Function>,
|
||||||
|
platform_functions: HashMap<Rc<str>, PlatformFunction>,
|
||||||
constants: HashMap<Rc<str>, Constant>,
|
constants: HashMap<Rc<str>, Constant>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -18,10 +20,27 @@ impl DvmContext {
|
|||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
functions: HashMap::new(),
|
functions: HashMap::new(),
|
||||||
|
platform_functions: HashMap::new(),
|
||||||
constants: 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) {
|
pub fn add_function(&mut self, function: Function) {
|
||||||
self.functions.insert(function.name_owned(), function);
|
self.functions.insert(function.name_owned(), function);
|
||||||
}
|
}
|
||||||
@ -155,10 +174,28 @@ pub fn call(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke instructions */
|
/* Invoke instructions */
|
||||||
Instruction::InvokePlatformStatic(function_name) => {
|
Instruction::InvokePlatformStatic(function_name, arg_count) => {
|
||||||
if function_name.as_ref() == "println" {
|
let stack = state.stack();
|
||||||
println!("{:?}", state.stack());
|
let args = &stack[stack.len() - arg_count..];
|
||||||
println!("{:?}", state.registers());
|
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();
|
state.increment_ip();
|
||||||
}
|
}
|
||||||
None
|
None // todo: returning results from main functions
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
extern fn println()
|
extern fn println(message)
|
||||||
|
|
||||||
fn main()
|
fn main()
|
||||||
let x = "Hello, World!"
|
let x = "Hello, World!"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user