Much work on adding and calling.
This commit is contained in:
parent
81ceeeadb8
commit
e1afb6b43b
@ -6,8 +6,10 @@ pub enum AsmInstruction {
|
|||||||
Move(Move),
|
Move(Move),
|
||||||
Push(Push),
|
Push(Push),
|
||||||
Pop(Pop),
|
Pop(Pop),
|
||||||
|
InvokeStatic(InvokeStatic),
|
||||||
InvokePlatformStatic(InvokePlatformStatic),
|
InvokePlatformStatic(InvokePlatformStatic),
|
||||||
LoadConstant(LoadConstant),
|
LoadConstant(LoadConstant),
|
||||||
|
Add(Add),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AsmInstruction {
|
impl AsmInstruction {
|
||||||
@ -16,10 +18,12 @@ impl AsmInstruction {
|
|||||||
AsmInstruction::Move(asm_move) => asm_move.dvm(),
|
AsmInstruction::Move(asm_move) => asm_move.dvm(),
|
||||||
AsmInstruction::Push(push) => push.dvm(),
|
AsmInstruction::Push(push) => push.dvm(),
|
||||||
AsmInstruction::Pop(pop) => pop.dvm(),
|
AsmInstruction::Pop(pop) => pop.dvm(),
|
||||||
|
AsmInstruction::InvokeStatic(invoke_static) => invoke_static.dvm(),
|
||||||
AsmInstruction::InvokePlatformStatic(invoke_platform_static) => {
|
AsmInstruction::InvokePlatformStatic(invoke_platform_static) => {
|
||||||
invoke_platform_static.dvm()
|
invoke_platform_static.dvm()
|
||||||
}
|
}
|
||||||
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
||||||
|
AsmInstruction::Add(add) => add.dvm(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -100,6 +104,21 @@ impl Pop {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct InvokeStatic {
|
||||||
|
name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InvokeStatic {
|
||||||
|
pub fn new(name: &str) -> Self {
|
||||||
|
Self { name: name.into() }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
Instruction::InvokeStatic(Rc::from(self.name.clone()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct InvokePlatformStatic {
|
pub struct InvokePlatformStatic {
|
||||||
name: String,
|
name: String,
|
||||||
@ -137,3 +156,24 @@ impl LoadConstant {
|
|||||||
Instruction::LoadStringConstant(Rc::from(self.name.clone()), self.destination_register)
|
Instruction::LoadStringConstant(Rc::from(self.name.clone()), self.destination_register)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Add {
|
||||||
|
IntInt(usize, usize, usize),
|
||||||
|
StringString(usize, usize, usize),
|
||||||
|
StringInt(usize, usize, usize),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Add {
|
||||||
|
pub fn dvm(&self) -> Instruction {
|
||||||
|
match self {
|
||||||
|
Add::IntInt(lhs, rhs, destination) => Instruction::AddIntInt(*lhs, *rhs, *destination),
|
||||||
|
Add::StringString(lhs, rhs, destination) => {
|
||||||
|
Instruction::AddStringString(*lhs, *rhs, *destination)
|
||||||
|
}
|
||||||
|
Add::StringInt(lhs, rhs, destination) => {
|
||||||
|
Instruction::AddStringInt(*lhs, *rhs, *destination)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
173
dmc-lib/src/ast/additive_expression.rs
Normal file
173
dmc-lib/src/ast/additive_expression.rs
Normal file
@ -0,0 +1,173 @@
|
|||||||
|
use crate::asm::asm_instruction::{Add, AsmInstruction, LoadConstant, Move, Operand, Pop};
|
||||||
|
use crate::ast::assemble_context::AssembleContext;
|
||||||
|
use crate::ast::expression::Expression;
|
||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::symbol::ExpressibleSymbol;
|
||||||
|
use crate::symbol_table::SymbolTable;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
|
pub struct AdditiveExpression {
|
||||||
|
lhs: Box<Expression>,
|
||||||
|
rhs: Box<Expression>,
|
||||||
|
source_range: SourceRange,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AdditiveExpression {
|
||||||
|
pub fn new(lhs: Expression, rhs: Expression, source_range: SourceRange) -> Self {
|
||||||
|
Self {
|
||||||
|
lhs: lhs.into(),
|
||||||
|
rhs: rhs.into(),
|
||||||
|
source_range,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn gather_declared_names(
|
||||||
|
&mut self,
|
||||||
|
symbol_table: &mut SymbolTable,
|
||||||
|
) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics = vec![];
|
||||||
|
diagnostics.append(&mut self.lhs.gather_declared_names(symbol_table));
|
||||||
|
diagnostics.append(&mut self.rhs.gather_declared_names(symbol_table));
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn check_name_usages(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
let mut diagnostics = vec![];
|
||||||
|
diagnostics.append(&mut self.lhs.check_name_usages(symbol_table));
|
||||||
|
diagnostics.append(&mut self.rhs.check_name_usages(symbol_table));
|
||||||
|
if diagnostics.is_empty() {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(diagnostics)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Result<(), Vec<Diagnostic>> {
|
||||||
|
self.lhs.type_check(symbol_table);
|
||||||
|
self.rhs.type_check(symbol_table);
|
||||||
|
|
||||||
|
let lhs_type_info = self.lhs.type_info();
|
||||||
|
let rhs_type_info = self.rhs.type_info();
|
||||||
|
if lhs_type_info.can_add(&rhs_type_info) {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(vec![Diagnostic::new(
|
||||||
|
&format!("Cannot add {} to {}", lhs_type_info, rhs_type_info),
|
||||||
|
self.source_range.start(),
|
||||||
|
self.source_range.end(),
|
||||||
|
)])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn assemble_side(
|
||||||
|
expression: &Expression,
|
||||||
|
context: &mut AssembleContext,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
constants_table: &mut ConstantsTable,
|
||||||
|
) -> usize {
|
||||||
|
match expression {
|
||||||
|
Expression::Call(call) => {
|
||||||
|
call.assemble(context, symbol_table, constants_table);
|
||||||
|
let register = context.new_local_register();
|
||||||
|
context.instruction(AsmInstruction::Pop(Pop::new(register)));
|
||||||
|
register
|
||||||
|
}
|
||||||
|
Expression::IntegerLiteral(integer_literal) => {
|
||||||
|
let register = context.new_local_register();
|
||||||
|
context.instruction(AsmInstruction::Move(Move::new(
|
||||||
|
Operand::IntegerLiteral(integer_literal.value()),
|
||||||
|
register,
|
||||||
|
)));
|
||||||
|
register
|
||||||
|
}
|
||||||
|
Expression::String(string_literal) => {
|
||||||
|
let register = context.new_local_register();
|
||||||
|
let constant_name = constants_table.insert_string(string_literal.content());
|
||||||
|
context.instruction(AsmInstruction::LoadConstant(LoadConstant::new(
|
||||||
|
&constant_name,
|
||||||
|
register,
|
||||||
|
)));
|
||||||
|
register
|
||||||
|
}
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
let register = context.new_local_register();
|
||||||
|
match identifier.expressible_symbol() {
|
||||||
|
ExpressibleSymbol::Function(_) => unreachable!(),
|
||||||
|
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
||||||
|
let offset = parameter_symbol.borrow().stack_frame_offset();
|
||||||
|
context.instruction(AsmInstruction::Move(Move::new(
|
||||||
|
Operand::StackFrameOffset(offset),
|
||||||
|
register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
ExpressibleSymbol::Variable(variable_symbol) => {
|
||||||
|
context.instruction(AsmInstruction::Move(Move::new(
|
||||||
|
Operand::Register(variable_symbol.borrow().register()),
|
||||||
|
register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
register
|
||||||
|
}
|
||||||
|
Expression::Additive(additive_expression) => {
|
||||||
|
additive_expression.assemble(context, symbol_table, constants_table)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn assemble(
|
||||||
|
&self,
|
||||||
|
context: &mut AssembleContext,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
constants_table: &mut ConstantsTable,
|
||||||
|
) -> usize {
|
||||||
|
let lhs_register = Self::assemble_side(&self.lhs, context, symbol_table, constants_table);
|
||||||
|
let rhs_register = Self::assemble_side(&self.rhs, context, symbol_table, constants_table);
|
||||||
|
let result_register = context.new_local_register();
|
||||||
|
match self.lhs.type_info() {
|
||||||
|
TypeInfo::Integer => match self.rhs.type_info() {
|
||||||
|
TypeInfo::Integer => {
|
||||||
|
context.instruction(AsmInstruction::Add(Add::IntInt(
|
||||||
|
lhs_register,
|
||||||
|
rhs_register,
|
||||||
|
result_register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
TypeInfo::String => match self.rhs.type_info() {
|
||||||
|
TypeInfo::Integer => {
|
||||||
|
context.instruction(AsmInstruction::Add(Add::StringInt(
|
||||||
|
lhs_register,
|
||||||
|
rhs_register,
|
||||||
|
result_register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
TypeInfo::String => {
|
||||||
|
context.instruction(AsmInstruction::Add(Add::StringString(
|
||||||
|
lhs_register,
|
||||||
|
rhs_register,
|
||||||
|
result_register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
result_register
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn type_info(&self) -> TypeInfo {
|
||||||
|
self.lhs.type_info().additive_result(&self.rhs.type_info())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
|
&self.source_range
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::asm::asm_instruction::{
|
use crate::asm::asm_instruction::{
|
||||||
AsmInstruction, InvokePlatformStatic, LoadConstant, Operand, Push,
|
AsmInstruction, InvokePlatformStatic, InvokeStatic, LoadConstant, Operand, Push,
|
||||||
};
|
};
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
use crate::ast::assemble_context::AssembleContext;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
@ -166,6 +166,13 @@ impl Call {
|
|||||||
))))
|
))))
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
Expression::Additive(additive_expression) => {
|
||||||
|
let result_register =
|
||||||
|
additive_expression.assemble(context, symbol_table, constants_table);
|
||||||
|
context.instruction(AsmInstruction::Push(Push::new(Operand::Register(
|
||||||
|
result_register,
|
||||||
|
))));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,7 +194,9 @@ impl Call {
|
|||||||
InvokePlatformStatic::new(function_symbol.name(), arg_count),
|
InvokePlatformStatic::new(function_symbol.name(), arg_count),
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
todo!("non-platform invoke")
|
context.instruction(AsmInstruction::InvokeStatic(InvokeStatic::new(
|
||||||
|
function_symbol.name(),
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::ast::additive_expression::AdditiveExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::identifier::Identifier;
|
use crate::ast::identifier::Identifier;
|
||||||
use crate::ast::integer_literal::IntegerLiteral;
|
use crate::ast::integer_literal::IntegerLiteral;
|
||||||
@ -12,6 +13,7 @@ pub enum Expression {
|
|||||||
IntegerLiteral(IntegerLiteral),
|
IntegerLiteral(IntegerLiteral),
|
||||||
String(StringLiteral),
|
String(StringLiteral),
|
||||||
Identifier(Identifier),
|
Identifier(Identifier),
|
||||||
|
Additive(AdditiveExpression),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Expression {
|
impl Expression {
|
||||||
@ -19,6 +21,14 @@ impl Expression {
|
|||||||
match self {
|
match self {
|
||||||
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
Expression::Call(call) => call.gather_declared_names(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
Expression::Identifier(identifier) => identifier.gather_declared_names(symbol_table),
|
||||||
|
Expression::Additive(additive_expression) => {
|
||||||
|
match additive_expression.gather_declared_names(symbol_table) {
|
||||||
|
Ok(_) => {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
Err(diagnostics) => diagnostics,
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,6 +37,14 @@ impl Expression {
|
|||||||
match self {
|
match self {
|
||||||
Expression::Call(call) => call.check_name_usages(symbol_table),
|
Expression::Call(call) => call.check_name_usages(symbol_table),
|
||||||
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
Expression::Identifier(identifier) => identifier.check_name_usages(symbol_table),
|
||||||
|
Expression::Additive(additive_expression) => {
|
||||||
|
match additive_expression.check_name_usages(symbol_table) {
|
||||||
|
Ok(_) => {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
Err(diagnostics) => diagnostics,
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -34,6 +52,14 @@ impl Expression {
|
|||||||
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
pub fn type_check(&mut self, symbol_table: &SymbolTable) -> Vec<Diagnostic> {
|
||||||
match self {
|
match self {
|
||||||
Expression::Call(call) => call.type_check(symbol_table),
|
Expression::Call(call) => call.type_check(symbol_table),
|
||||||
|
Expression::Additive(additive_expression) => {
|
||||||
|
match additive_expression.type_check(symbol_table) {
|
||||||
|
Ok(_) => {
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
Err(diagnostics) => diagnostics,
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => vec![],
|
_ => vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,6 +70,7 @@ impl Expression {
|
|||||||
Expression::IntegerLiteral(_) => TypeInfo::Integer,
|
Expression::IntegerLiteral(_) => TypeInfo::Integer,
|
||||||
Expression::String(_) => TypeInfo::String,
|
Expression::String(_) => TypeInfo::String,
|
||||||
Expression::Identifier(identifier) => identifier.type_info(),
|
Expression::Identifier(identifier) => identifier.type_info(),
|
||||||
|
Expression::Additive(additive_expression) => additive_expression.type_info(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,6 +80,7 @@ impl Expression {
|
|||||||
Expression::IntegerLiteral(integer_literal) => integer_literal.source_range(),
|
Expression::IntegerLiteral(integer_literal) => integer_literal.source_range(),
|
||||||
Expression::String(string_literal) => string_literal.source_range(),
|
Expression::String(string_literal) => string_literal.source_range(),
|
||||||
Expression::Identifier(identifier) => identifier.source_range(),
|
Expression::Identifier(identifier) => identifier.source_range(),
|
||||||
|
Expression::Additive(additive_expression) => additive_expression.source_range(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -41,6 +41,9 @@ impl ExpressionStatement {
|
|||||||
Expression::Call(call) => {
|
Expression::Call(call) => {
|
||||||
call.assemble(context, symbol_table, constants_table);
|
call.assemble(context, symbol_table, constants_table);
|
||||||
}
|
}
|
||||||
|
Expression::Additive(additive) => {
|
||||||
|
additive.assemble(context, symbol_table, constants_table);
|
||||||
|
}
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
|
use crate::ast::type_use::TypeUse;
|
||||||
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;
|
||||||
@ -8,6 +9,7 @@ pub struct ExternFunction {
|
|||||||
declared_name: String,
|
declared_name: String,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
|
return_type: TypeUse,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExternFunction {
|
impl ExternFunction {
|
||||||
@ -15,11 +17,13 @@ impl ExternFunction {
|
|||||||
name: &str,
|
name: &str,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
|
return_type: TypeUse,
|
||||||
) -> ExternFunction {
|
) -> ExternFunction {
|
||||||
ExternFunction {
|
ExternFunction {
|
||||||
declared_name: name.into(),
|
declared_name: name.into(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
parameters,
|
parameters,
|
||||||
|
return_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,8 +34,11 @@ 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 mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
let insert_result =
|
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||||
symbol_table.insert_function_symbol(FunctionSymbol::new(&self.declared_name, true));
|
&self.declared_name,
|
||||||
|
true,
|
||||||
|
self.return_type.to_type_info(),
|
||||||
|
));
|
||||||
|
|
||||||
let function_symbol = match insert_result {
|
let function_symbol = match insert_result {
|
||||||
Ok(function_symbol) => function_symbol,
|
Ok(function_symbol) => function_symbol,
|
||||||
|
|||||||
@ -1,16 +1,20 @@
|
|||||||
use crate::ast::assemble_context::AssembleContext;
|
use crate::ast::assemble_context::AssembleContext;
|
||||||
use crate::ast::parameter::Parameter;
|
use crate::ast::parameter::Parameter;
|
||||||
use crate::ast::statement::Statement;
|
use crate::ast::statement::Statement;
|
||||||
|
use crate::ast::type_use::TypeUse;
|
||||||
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 crate::type_info::TypeInfo;
|
||||||
|
use std::ops::Neg;
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
|
return_type: Option<TypeUse>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -19,12 +23,14 @@ impl Function {
|
|||||||
declared_name: &str,
|
declared_name: &str,
|
||||||
declared_name_source_range: SourceRange,
|
declared_name_source_range: SourceRange,
|
||||||
parameters: Vec<Parameter>,
|
parameters: Vec<Parameter>,
|
||||||
|
return_type: Option<TypeUse>,
|
||||||
statements: Vec<Statement>,
|
statements: Vec<Statement>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
declared_name: declared_name.to_string(),
|
declared_name: declared_name.to_string(),
|
||||||
declared_name_source_range,
|
declared_name_source_range,
|
||||||
parameters,
|
parameters,
|
||||||
|
return_type,
|
||||||
statements,
|
statements,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -41,8 +47,14 @@ impl Function {
|
|||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
// insert function symbol
|
// insert function symbol
|
||||||
let insert_result =
|
let insert_result = symbol_table.insert_function_symbol(FunctionSymbol::new(
|
||||||
symbol_table.insert_function_symbol(FunctionSymbol::new(self.declared_name(), false));
|
self.declared_name(),
|
||||||
|
false,
|
||||||
|
self.return_type
|
||||||
|
.as_ref()
|
||||||
|
.map(|return_type| return_type.to_type_info())
|
||||||
|
.unwrap_or(TypeInfo::Void),
|
||||||
|
));
|
||||||
|
|
||||||
// get function symbol if successful
|
// get function symbol if successful
|
||||||
let function_symbol = match insert_result {
|
let function_symbol = match insert_result {
|
||||||
@ -67,9 +79,14 @@ impl Function {
|
|||||||
// handle parameters
|
// handle parameters
|
||||||
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
|
symbol_table.push_scope(&format!("parameter_scope({})", self.declared_name));
|
||||||
let mut parameter_symbols = vec![];
|
let mut parameter_symbols = vec![];
|
||||||
for parameter in &mut self.parameters {
|
let parameter_count = self.parameters.len();
|
||||||
|
let stack_frame_offset_base = (parameter_count as isize).neg();
|
||||||
|
for (i, parameter) in self.parameters.iter_mut().enumerate() {
|
||||||
match parameter.gather_declared_names(symbol_table) {
|
match parameter.gather_declared_names(symbol_table) {
|
||||||
Ok(parameter_symbol) => {
|
Ok(parameter_symbol) => {
|
||||||
|
parameter_symbol
|
||||||
|
.borrow_mut()
|
||||||
|
.set_stack_frame_offset(stack_frame_offset_base + (i as isize));
|
||||||
parameter_symbols.push(parameter_symbol);
|
parameter_symbols.push(parameter_symbol);
|
||||||
}
|
}
|
||||||
Err(mut parameter_diagnostics) => {
|
Err(mut parameter_diagnostics) => {
|
||||||
@ -144,6 +161,7 @@ impl Function {
|
|||||||
for statement in &self.statements {
|
for statement in &self.statements {
|
||||||
statement.assemble(context, symbol_table, constants_table);
|
statement.assemble(context, symbol_table, constants_table);
|
||||||
}
|
}
|
||||||
|
// todo: function exit, including popping passed args and pushing return value
|
||||||
context.complete_function();
|
context.complete_function();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -130,6 +130,13 @@ impl LetStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expression::Additive(additive) => {
|
||||||
|
let result_register = additive.assemble(context, symbol_table, constants_table);
|
||||||
|
context.instruction(AsmInstruction::Move(Move::new(
|
||||||
|
Operand::Register(result_register),
|
||||||
|
destination_register,
|
||||||
|
)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
pub mod additive_expression;
|
||||||
pub mod assemble_context;
|
pub mod assemble_context;
|
||||||
pub mod call;
|
pub mod call;
|
||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
|
||||||
pub struct TypeUse {
|
pub struct TypeUse {
|
||||||
declared_name: String,
|
declared_name: String,
|
||||||
@ -16,4 +17,8 @@ impl TypeUse {
|
|||||||
pub fn declared_name(&self) -> &str {
|
pub fn declared_name(&self) -> &str {
|
||||||
&self.declared_name
|
&self.declared_name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_type_info(&self) -> TypeInfo {
|
||||||
|
TypeInfo::from_declared_name(self.declared_name())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,9 @@ impl<'a> Lexer<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let token = if chunk.starts_with("(") {
|
let token = if chunk.starts_with("->") {
|
||||||
|
Token::new(self.position, self.position + 2, TokenKind::RightArrow)
|
||||||
|
} else if chunk.starts_with("(") {
|
||||||
Token::new(self.position, self.position + 1, TokenKind::LeftParentheses)
|
Token::new(self.position, self.position + 1, TokenKind::LeftParentheses)
|
||||||
} else if chunk.starts_with(")") {
|
} else if chunk.starts_with(")") {
|
||||||
Token::new(
|
Token::new(
|
||||||
@ -42,6 +44,8 @@ impl<'a> Lexer<'a> {
|
|||||||
self.position + 1,
|
self.position + 1,
|
||||||
TokenKind::RightParentheses,
|
TokenKind::RightParentheses,
|
||||||
)
|
)
|
||||||
|
} else if chunk.starts_with("+") {
|
||||||
|
Token::new(self.position, self.position + 1, TokenKind::Plus)
|
||||||
} 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(",") {
|
} else if chunk.starts_with(",") {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
use crate::ast::additive_expression::AdditiveExpression;
|
||||||
use crate::ast::call::Call;
|
use crate::ast::call::Call;
|
||||||
use crate::ast::compilation_unit::CompilationUnit;
|
use crate::ast::compilation_unit::CompilationUnit;
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
@ -218,13 +219,26 @@ impl<'a> Parser<'a> {
|
|||||||
fn function(&mut self) -> Result<Function, Vec<Diagnostic>> {
|
fn function(&mut self) -> Result<Function, Vec<Diagnostic>> {
|
||||||
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)?;
|
||||||
|
|
||||||
let parameters = self.parameter_list()?;
|
let parameters = self.parameter_list()?;
|
||||||
|
|
||||||
self.expect_advance(TokenKind::RightParentheses)?;
|
self.expect_advance(TokenKind::RightParentheses)?;
|
||||||
let mut statements = vec![];
|
|
||||||
let mut diagnostics = vec![];
|
let mut diagnostics = vec![];
|
||||||
|
|
||||||
|
let return_type = if self.current.is_some() && self.peek_current(TokenKind::RightArrow) {
|
||||||
|
match self.return_type() {
|
||||||
|
Ok(type_use) => Some(type_use),
|
||||||
|
Err(mut return_type_diagnostics) => {
|
||||||
|
diagnostics.append(&mut return_type_diagnostics);
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut statements = vec![];
|
||||||
while self.current.is_some() && !self.peek_current(TokenKind::End) {
|
while self.current.is_some() && !self.peek_current(TokenKind::End) {
|
||||||
let statement_result = self.statement();
|
let statement_result = self.statement();
|
||||||
match statement_result {
|
match statement_result {
|
||||||
@ -251,6 +265,7 @@ impl<'a> Parser<'a> {
|
|||||||
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()),
|
||||||
parameters,
|
parameters,
|
||||||
|
return_type,
|
||||||
statements,
|
statements,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
@ -285,11 +300,14 @@ impl<'a> Parser<'a> {
|
|||||||
Ok(_) => {}
|
Ok(_) => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let return_type = self.return_type()?;
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
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(),
|
maybe_parameters.unwrap(),
|
||||||
|
return_type,
|
||||||
))
|
))
|
||||||
} else {
|
} else {
|
||||||
Err(diagnostics)
|
Err(diagnostics)
|
||||||
@ -331,6 +349,11 @@ impl<'a> Parser<'a> {
|
|||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn return_type(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
||||||
|
self.expect_advance(TokenKind::RightArrow)?;
|
||||||
|
self.type_use()
|
||||||
|
}
|
||||||
|
|
||||||
fn type_use(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
fn type_use(&mut self) -> Result<TypeUse, Vec<Diagnostic>> {
|
||||||
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
let identifier_token = self.expect_advance(TokenKind::Identifier)?;
|
||||||
Ok(TypeUse::new(
|
Ok(TypeUse::new(
|
||||||
@ -364,96 +387,102 @@ impl<'a> Parser<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
fn expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
let current = self.get_current().clone(); // I don't love this clone
|
self.additive_expression()
|
||||||
let mut diagnostics = vec![];
|
}
|
||||||
let mut expression = match current.kind() {
|
|
||||||
|
fn additive_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
|
let mut result = self.suffix_expression()?;
|
||||||
|
while self.current.is_some() {
|
||||||
|
let current = self.get_current();
|
||||||
|
match current.kind() {
|
||||||
|
TokenKind::Plus => {
|
||||||
|
self.advance(); // plus
|
||||||
|
let rhs = self.expression()?;
|
||||||
|
let source_range =
|
||||||
|
SourceRange::new(result.source_range().start(), rhs.source_range().end());
|
||||||
|
result =
|
||||||
|
Expression::Additive(AdditiveExpression::new(result, rhs, source_range));
|
||||||
|
}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn suffix_expression(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
|
let mut result = self.expression_base()?;
|
||||||
|
while self.current.is_some() {
|
||||||
|
let current = self.get_current();
|
||||||
|
match current.kind() {
|
||||||
|
TokenKind::LeftParentheses => {
|
||||||
|
result = Expression::Call(self.call(result)?);
|
||||||
|
}
|
||||||
|
_ => break,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn expression_base(&mut self) -> Result<Expression, Vec<Diagnostic>> {
|
||||||
|
let current = self.get_current();
|
||||||
|
match current.kind() {
|
||||||
TokenKind::IntegerLiteral => {
|
TokenKind::IntegerLiteral => {
|
||||||
let raw = self.token_text(¤t);
|
let raw = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance();
|
||||||
Expression::IntegerLiteral(IntegerLiteral::new(
|
Ok(Expression::IntegerLiteral(IntegerLiteral::new(
|
||||||
i32::from_str(raw).unwrap(),
|
i32::from_str(raw).unwrap(),
|
||||||
source_range,
|
source_range,
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
TokenKind::String => {
|
TokenKind::String => {
|
||||||
let with_quotes = self.token_text(¤t);
|
let with_quotes = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance();
|
||||||
Expression::String(StringLiteral::new(
|
Ok(Expression::String(StringLiteral::new(
|
||||||
&with_quotes[1..with_quotes.len() - 1],
|
&with_quotes[1..with_quotes.len() - 1],
|
||||||
source_range,
|
source_range,
|
||||||
))
|
)))
|
||||||
}
|
}
|
||||||
TokenKind::Identifier => {
|
TokenKind::Identifier => {
|
||||||
let declared_name = self.token_text(¤t);
|
let declared_name = self.token_text(¤t);
|
||||||
let source_range = SourceRange::new(current.start(), current.end());
|
let source_range = SourceRange::new(current.start(), current.end());
|
||||||
self.advance();
|
self.advance();
|
||||||
Expression::Identifier(Identifier::new(declared_name, source_range))
|
Ok(Expression::Identifier(Identifier::new(
|
||||||
|
declared_name,
|
||||||
|
source_range,
|
||||||
|
)))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => unreachable!(),
|
||||||
diagnostics.push(Diagnostic::new(
|
|
||||||
&format!(
|
|
||||||
"Expected any of {:?} but found {:?}",
|
|
||||||
[
|
|
||||||
TokenKind::IntegerLiteral,
|
|
||||||
TokenKind::String,
|
|
||||||
TokenKind::Identifier
|
|
||||||
],
|
|
||||||
current.kind()
|
|
||||||
),
|
|
||||||
current.start(),
|
|
||||||
current.end(),
|
|
||||||
));
|
|
||||||
|
|
||||||
self.advance_until(&[
|
|
||||||
TokenKind::IntegerLiteral,
|
|
||||||
TokenKind::String,
|
|
||||||
TokenKind::Identifier,
|
|
||||||
]);
|
|
||||||
if self.current.is_some() {
|
|
||||||
let try_again_result = self.expression();
|
|
||||||
match try_again_result {
|
|
||||||
Ok(expression) => expression,
|
|
||||||
Err(mut try_again_diagnostics) => {
|
|
||||||
diagnostics.append(&mut try_again_diagnostics);
|
|
||||||
return Err(diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(diagnostics);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// postfixes
|
|
||||||
while let Some(current) = &self.current {
|
|
||||||
match current.kind() {
|
|
||||||
TokenKind::LeftParentheses => {
|
|
||||||
expression = Expression::Call(self.call(expression)?);
|
|
||||||
}
|
|
||||||
_ => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if diagnostics.is_empty() {
|
|
||||||
Ok(expression)
|
|
||||||
} else {
|
|
||||||
Err(diagnostics)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn call(&mut self, callee: Expression) -> Result<Call, Vec<Diagnostic>> {
|
fn call(&mut self, callee: Expression) -> Result<Call, Vec<Diagnostic>> {
|
||||||
self.expect_advance(TokenKind::LeftParentheses)?;
|
self.expect_advance(TokenKind::LeftParentheses)?;
|
||||||
let mut arguments = vec![];
|
let mut arguments = vec![];
|
||||||
while self.current.is_some() && !self.peek_current(TokenKind::RightParentheses) {
|
if let Some(current) = &self.current {
|
||||||
arguments.push(self.expression()?);
|
if matches!(
|
||||||
|
current.kind(),
|
||||||
|
TokenKind::IntegerLiteral | TokenKind::String | TokenKind::Identifier
|
||||||
|
) {
|
||||||
|
arguments.append(&mut self.expression_list()?);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
let right_parentheses_token = self.expect_advance(TokenKind::RightParentheses)?;
|
let right_parentheses_token = self.expect_advance(TokenKind::RightParentheses)?;
|
||||||
let source_range =
|
let source_range =
|
||||||
SourceRange::new(callee.source_range().start(), right_parentheses_token.end());
|
SourceRange::new(callee.source_range().start(), right_parentheses_token.end());
|
||||||
Ok(Call::new(callee, arguments, source_range))
|
Ok(Call::new(callee, arguments, source_range))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn expression_list(&mut self) -> Result<Vec<Expression>, Vec<Diagnostic>> {
|
||||||
|
let mut expressions = vec![];
|
||||||
|
expressions.push(self.expression()?);
|
||||||
|
while self.current.is_some() && self.peek_current(TokenKind::Comma) {
|
||||||
|
self.advance(); // comma
|
||||||
|
expressions.push(self.expression()?);
|
||||||
|
}
|
||||||
|
Ok(expressions)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -483,7 +512,7 @@ mod smoke_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn extern_fn_with_param() {
|
fn extern_fn_with_param() {
|
||||||
smoke_test("extern fn println(message: Any)");
|
smoke_test("extern fn println(message: Any) -> Void");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -495,6 +524,21 @@ mod smoke_tests {
|
|||||||
fn fn_with_params() {
|
fn fn_with_params() {
|
||||||
smoke_test("fn foo(bar: Int, baz: Int) end");
|
smoke_test("fn foo(bar: Int, baz: Int) end");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn return_type() {
|
||||||
|
smoke_test("fn foo() -> Int end")
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn extern_return_type() {
|
||||||
|
smoke_test("extern fn foo() -> Int");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn add_two_numbers() {
|
||||||
|
smoke_test("fn main() 1 + 2 end");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -503,7 +547,7 @@ mod concrete_tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn parses_extern_fn() {
|
fn parses_extern_fn() {
|
||||||
let parse_result = parse_compilation_unit("extern fn println()");
|
let parse_result = parse_compilation_unit("extern fn println() -> Void");
|
||||||
let compilation_unit = match parse_result {
|
let compilation_unit = match parse_result {
|
||||||
Ok(compilation_unit) => compilation_unit,
|
Ok(compilation_unit) => compilation_unit,
|
||||||
Err(diagnostics) => {
|
Err(diagnostics) => {
|
||||||
|
|||||||
@ -6,14 +6,16 @@ pub struct FunctionSymbol {
|
|||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
is_platform: bool,
|
is_platform: bool,
|
||||||
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
parameters: Option<Vec<Rc<RefCell<ParameterSymbol>>>>,
|
||||||
|
return_type: TypeInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl FunctionSymbol {
|
impl FunctionSymbol {
|
||||||
pub fn new(name: &str, is_platform: bool) -> Self {
|
pub fn new(name: &str, is_platform: bool, return_type: TypeInfo) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
is_platform,
|
is_platform,
|
||||||
parameters: None,
|
parameters: None,
|
||||||
|
return_type,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,7 +36,7 @@ impl FunctionSymbol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn return_type(&self) -> TypeInfo {
|
pub fn return_type(&self) -> TypeInfo {
|
||||||
todo!()
|
self.return_type.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_platform(&self) -> bool {
|
pub fn is_platform(&self) -> bool {
|
||||||
|
|||||||
@ -38,4 +38,6 @@ pub enum TokenKind {
|
|||||||
Extern,
|
Extern,
|
||||||
Comma,
|
Comma,
|
||||||
Colon,
|
Colon,
|
||||||
|
RightArrow,
|
||||||
|
Plus,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,6 +9,7 @@ pub enum TypeInfo {
|
|||||||
Integer,
|
Integer,
|
||||||
String,
|
String,
|
||||||
Function(Rc<RefCell<FunctionSymbol>>),
|
Function(Rc<RefCell<FunctionSymbol>>),
|
||||||
|
Void,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for TypeInfo {
|
impl Display for TypeInfo {
|
||||||
@ -24,6 +25,7 @@ impl Display for TypeInfo {
|
|||||||
}
|
}
|
||||||
write!(f, ")")
|
write!(f, ")")
|
||||||
}
|
}
|
||||||
|
TypeInfo::Void => write!(f, "Void"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,6 +37,7 @@ impl TypeInfo {
|
|||||||
"Any" => TypeInfo::Any,
|
"Any" => TypeInfo::Any,
|
||||||
"Int" => TypeInfo::Integer,
|
"Int" => TypeInfo::Integer,
|
||||||
"String" => TypeInfo::String,
|
"String" => TypeInfo::String,
|
||||||
|
"Void" => TypeInfo::Void,
|
||||||
_ => panic!("Unknown type: {}", declared_name),
|
_ => panic!("Unknown type: {}", declared_name),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,6 +54,25 @@ impl TypeInfo {
|
|||||||
TypeInfo::Function(_) => {
|
TypeInfo::Function(_) => {
|
||||||
unimplemented!("Type matching on Functions not yet supported.")
|
unimplemented!("Type matching on Functions not yet supported.")
|
||||||
}
|
}
|
||||||
|
TypeInfo::Void => {
|
||||||
|
matches!(other, TypeInfo::Void)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn can_add(&self, rhs: &Self) -> bool {
|
||||||
|
match self {
|
||||||
|
TypeInfo::Integer => matches!(rhs, TypeInfo::Integer),
|
||||||
|
TypeInfo::String => matches!(rhs, TypeInfo::String | TypeInfo::Integer),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn additive_result(&self, _rhs: &Self) -> TypeInfo {
|
||||||
|
match self {
|
||||||
|
TypeInfo::Integer => TypeInfo::Integer,
|
||||||
|
TypeInfo::String => TypeInfo::String,
|
||||||
|
_ => panic!("Adding things other than integers and strings not yet supported"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,9 +14,14 @@ pub enum Instruction {
|
|||||||
PushInt(i32),
|
PushInt(i32),
|
||||||
PushStackFrameOffset(isize),
|
PushStackFrameOffset(isize),
|
||||||
|
|
||||||
|
InvokeStatic(FunctionName),
|
||||||
InvokePlatformStatic(FunctionName, ArgCount),
|
InvokePlatformStatic(FunctionName, ArgCount),
|
||||||
|
|
||||||
LoadStringConstant(ConstantName, Register),
|
LoadStringConstant(ConstantName, Register),
|
||||||
|
|
||||||
Pop(Option<Register>),
|
Pop(Option<Register>),
|
||||||
|
|
||||||
|
AddIntInt(Register, Register, Register),
|
||||||
|
AddStringInt(Register, Register, Register),
|
||||||
|
AddStringString(Register, Register, Register),
|
||||||
}
|
}
|
||||||
|
|||||||
@ -174,6 +174,14 @@ pub fn call(
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Invoke instructions */
|
/* Invoke instructions */
|
||||||
|
Instruction::InvokeStatic(function_name) => {
|
||||||
|
let function = context
|
||||||
|
.functions
|
||||||
|
.get(function_name)
|
||||||
|
.expect(&format!("Function {} not found", function_name));
|
||||||
|
todo!("Call stack for invoking Deimos-native functions")
|
||||||
|
}
|
||||||
|
|
||||||
Instruction::InvokePlatformStatic(function_name, arg_count) => {
|
Instruction::InvokePlatformStatic(function_name, arg_count) => {
|
||||||
let stack = state.stack();
|
let stack = state.stack();
|
||||||
let args = &stack[stack.len() - arg_count..];
|
let args = &stack[stack.len() - arg_count..];
|
||||||
@ -210,6 +218,26 @@ pub fn call(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Add instructions */
|
||||||
|
Instruction::AddIntInt(lhs, rhs, destination) => {
|
||||||
|
let lhs_value = state.registers()[*lhs].unwrap_int();
|
||||||
|
let rhs_value = state.registers()[*rhs].unwrap_int();
|
||||||
|
let result = lhs_value + rhs_value;
|
||||||
|
state.registers_mut()[*destination] = Value::Int(result);
|
||||||
|
}
|
||||||
|
Instruction::AddStringInt(lhs, rhs, destination) => {
|
||||||
|
let lhs_value = state.registers()[*lhs].unwrap_string();
|
||||||
|
let rhs_value = state.registers()[*rhs].unwrap_int();
|
||||||
|
let formatted = format!("{}{}", lhs_value, rhs_value);
|
||||||
|
state.registers_mut()[*destination] = Value::String(Rc::from(formatted));
|
||||||
|
}
|
||||||
|
Instruction::AddStringString(lhs, rhs, destination) => {
|
||||||
|
let lhs_value = state.registers()[*lhs].unwrap_string();
|
||||||
|
let rhs_value = state.registers()[*rhs].unwrap_string();
|
||||||
|
let formatted = format!("{}{}", lhs_value, rhs_value);
|
||||||
|
state.registers_mut()[*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 = state.stack_mut().pop().unwrap();
|
||||||
|
|||||||
@ -12,3 +12,19 @@ impl Default for Value {
|
|||||||
Value::Null
|
Value::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Value {
|
||||||
|
pub fn unwrap_int(&self) -> i32 {
|
||||||
|
match self {
|
||||||
|
Value::Int(i) => *i,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unwrap_string(&self) -> &Rc<str> {
|
||||||
|
match self {
|
||||||
|
Value::String(s) => s,
|
||||||
|
_ => panic!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
5
examples/add.dm
Normal file
5
examples/add.dm
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
println(6 + 7)
|
||||||
|
end
|
||||||
9
examples/call.dm
Normal file
9
examples/call.dm
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
extern fn println(message: Any) -> Void
|
||||||
|
|
||||||
|
fn add(a: Int, b: Int) -> Int
|
||||||
|
a + b
|
||||||
|
end
|
||||||
|
|
||||||
|
fn main()
|
||||||
|
println(add(1, 2))
|
||||||
|
end
|
||||||
Loading…
Reference in New Issue
Block a user