End-to-end with register allocation.
This commit is contained in:
parent
1171ce75f9
commit
12c4d0eb83
@ -4,16 +4,15 @@ 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 dm_std_lib::add_all_std_core;
|
||||||
use dmc_lib::ast::module_level_declaration::ModuleLevelDeclaration;
|
|
||||||
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;
|
||||||
use dmc_lib::symbol_table::SymbolTable;
|
use dmc_lib::symbol_table::SymbolTable;
|
||||||
use dvm_lib::vm::constant::{Constant, StringConstant};
|
use dvm_lib::vm::constant::{Constant, StringConstant};
|
||||||
|
use dvm_lib::vm::function::Function;
|
||||||
use dvm_lib::vm::value::Value;
|
use dvm_lib::vm::value::Value;
|
||||||
use dvm_lib::vm::{CallStack, DvmContext, call};
|
use dvm_lib::vm::{CallStack, DvmContext, call};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Debug, Parser)]
|
#[derive(Debug, Parser)]
|
||||||
#[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)]
|
#[command(name = "dm", about = "Deimos", version = "0.1.0", long_about = None)]
|
||||||
@ -57,23 +56,28 @@ fn main() {
|
|||||||
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
let type_check_diagnostics = compilation_unit.type_check(&symbol_table);
|
||||||
check_and_report_diagnostics(&files, script_file_id, &type_check_diagnostics);
|
check_and_report_diagnostics(&files, script_file_id, &type_check_diagnostics);
|
||||||
|
|
||||||
|
let mut ir_functions = compilation_unit.to_ir(&symbol_table);
|
||||||
|
|
||||||
if args.show_ir {
|
if args.show_ir {
|
||||||
for declaration in compilation_unit.declarations() {
|
for ir_function in &ir_functions {
|
||||||
if let ModuleLevelDeclaration::Function(function) = declaration {
|
|
||||||
let mut ir_function = function.to_ir(&symbol_table);
|
|
||||||
let register_assignments = ir_function.assign_registers(args.register_count);
|
|
||||||
println!("{}", ir_function);
|
println!("{}", ir_function);
|
||||||
println!("{:?}", register_assignments);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for ir_function in &mut ir_functions {
|
||||||
|
ir_function.assign_registers(args.register_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut constants_table = ConstantsTable::new();
|
let mut constants_table = ConstantsTable::new();
|
||||||
let asm_functions = compilation_unit.assemble(&symbol_table, &mut constants_table);
|
|
||||||
|
let functions: Vec<Function> = ir_functions
|
||||||
|
.iter()
|
||||||
|
.map(|ir_function| ir_function.assemble(&mut constants_table))
|
||||||
|
.collect();
|
||||||
|
|
||||||
if args.show_asm {
|
if args.show_asm {
|
||||||
for asm_function in &asm_functions {
|
for function in &functions {
|
||||||
println!("{:#?}", asm_function);
|
println!("{}", function);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,19 +86,20 @@ fn main() {
|
|||||||
// add std::core fns
|
// add std::core fns
|
||||||
add_all_std_core(&mut dvm_context);
|
add_all_std_core(&mut dvm_context);
|
||||||
|
|
||||||
for asm_function in &asm_functions {
|
for function in functions {
|
||||||
let function = asm_function.dvm();
|
dvm_context
|
||||||
dvm_context.add_function(function);
|
.functions_mut()
|
||||||
|
.insert(function.name_owned(), function);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (name, content) in &constants_table.string_constants() {
|
for (name, content) in &constants_table.string_constants() {
|
||||||
dvm_context.add_constant(Constant::String(StringConstant::new(
|
dvm_context.constants_mut().insert(
|
||||||
Rc::from(name.clone()),
|
name.clone(),
|
||||||
content.as_str(),
|
Constant::String(StringConstant::new(name.clone(), content.clone())),
|
||||||
)));
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut registers: Vec<Value> = vec![];
|
let mut registers: Vec<Value> = vec![Value::Null; args.register_count];
|
||||||
let mut call_stack = CallStack::new();
|
let mut call_stack = CallStack::new();
|
||||||
|
|
||||||
let result = call(
|
let result = call(
|
||||||
|
|||||||
@ -1,20 +0,0 @@
|
|||||||
use crate::asm::asm_instruction::AsmInstruction;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AsmBlock {
|
|
||||||
name: String,
|
|
||||||
instructions: Vec<AsmInstruction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsmBlock {
|
|
||||||
pub fn new(name: &str, instructions: Vec<AsmInstruction>) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.into(),
|
|
||||||
instructions,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn instructions(&self) -> &[AsmInstruction] {
|
|
||||||
&self.instructions
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,29 +0,0 @@
|
|||||||
use crate::asm::asm_block::AsmBlock;
|
|
||||||
use crate::asm::asm_instruction::AsmInstruction;
|
|
||||||
use dvm_lib::vm::function::Function;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct AsmFunction {
|
|
||||||
name: String,
|
|
||||||
blocks: Vec<AsmBlock>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsmFunction {
|
|
||||||
pub fn new(name: &str, blocks: Vec<AsmBlock>) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.into(),
|
|
||||||
blocks,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Function {
|
|
||||||
// very naive impl
|
|
||||||
let dvm_instructions = self
|
|
||||||
.blocks
|
|
||||||
.iter()
|
|
||||||
.flat_map(|block| block.instructions().iter().map(AsmInstruction::dvm))
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
Function::new(&self.name, dvm_instructions, 16)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,217 +0,0 @@
|
|||||||
use dvm_lib::instruction::Instruction;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum AsmInstruction {
|
|
||||||
Move(Move),
|
|
||||||
Push(Push),
|
|
||||||
Pop(Pop),
|
|
||||||
InvokeStatic(InvokeStatic),
|
|
||||||
InvokePlatformStatic(InvokePlatformStatic),
|
|
||||||
LoadConstant(LoadConstant),
|
|
||||||
Add(Add),
|
|
||||||
SetReturnValue(SetReturnValue),
|
|
||||||
Return(Return),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AsmInstruction {
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
match self {
|
|
||||||
AsmInstruction::Move(asm_move) => asm_move.dvm(),
|
|
||||||
AsmInstruction::Push(push) => push.dvm(),
|
|
||||||
AsmInstruction::Pop(pop) => pop.dvm(),
|
|
||||||
AsmInstruction::InvokeStatic(invoke_static) => invoke_static.dvm(),
|
|
||||||
AsmInstruction::InvokePlatformStatic(invoke_platform_static) => {
|
|
||||||
invoke_platform_static.dvm()
|
|
||||||
}
|
|
||||||
AsmInstruction::LoadConstant(load_constant) => load_constant.dvm(),
|
|
||||||
AsmInstruction::Add(add) => add.dvm(),
|
|
||||||
AsmInstruction::SetReturnValue(set_return_value) => set_return_value.dvm(),
|
|
||||||
AsmInstruction::Return(asm_return) => asm_return.dvm(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum Operand {
|
|
||||||
IntegerLiteral(i32),
|
|
||||||
Register(usize),
|
|
||||||
StackFrameOffset(isize),
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Move {
|
|
||||||
source: Operand,
|
|
||||||
destination_register: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Move {
|
|
||||||
pub fn new(source: Operand, destination_register: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
source,
|
|
||||||
destination_register,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
match self.source {
|
|
||||||
Operand::IntegerLiteral(i) => Instruction::MoveInt(i, self.destination_register),
|
|
||||||
Operand::Register(register) => {
|
|
||||||
Instruction::MoveRegister(register, self.destination_register)
|
|
||||||
}
|
|
||||||
Operand::StackFrameOffset(offset) => {
|
|
||||||
Instruction::MoveStackFrameOffset(offset, self.destination_register)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Push {
|
|
||||||
source: Operand,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Push {
|
|
||||||
pub fn new(source: Operand) -> Self {
|
|
||||||
Self { source }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
match self.source {
|
|
||||||
Operand::IntegerLiteral(i) => Instruction::PushInt(i),
|
|
||||||
Operand::Register(register) => Instruction::PushRegister(register),
|
|
||||||
Operand::StackFrameOffset(offset) => Instruction::PushStackFrameOffset(offset),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Pop {
|
|
||||||
destination_register: Option<usize>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Pop {
|
|
||||||
pub fn new(destination_register: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
destination_register: Some(destination_register),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn empty() -> Self {
|
|
||||||
Self {
|
|
||||||
destination_register: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
Instruction::Pop(self.destination_register)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct InvokeStatic {
|
|
||||||
name: String,
|
|
||||||
arg_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InvokeStatic {
|
|
||||||
pub fn new(name: &str, arg_count: usize) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.into(),
|
|
||||||
arg_count,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
Instruction::InvokeStatic(Rc::from(self.name.clone()), self.arg_count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct InvokePlatformStatic {
|
|
||||||
name: String,
|
|
||||||
arg_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InvokePlatformStatic {
|
|
||||||
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()), self.arg_count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct LoadConstant {
|
|
||||||
name: String,
|
|
||||||
destination_register: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl LoadConstant {
|
|
||||||
pub fn new(name: &str, destination_register: usize) -> Self {
|
|
||||||
LoadConstant {
|
|
||||||
name: name.into(),
|
|
||||||
destination_register,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SetReturnValue {
|
|
||||||
source_register: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl SetReturnValue {
|
|
||||||
pub fn new(source_register: usize) -> Self {
|
|
||||||
Self { source_register }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
Instruction::SetReturnValue(self.source_register)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct Return {
|
|
||||||
caller_pop_count: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Return {
|
|
||||||
pub fn new(caller_pop_count: usize) -> Self {
|
|
||||||
Self { caller_pop_count }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn dvm(&self) -> Instruction {
|
|
||||||
Instruction::Return(self.caller_pop_count)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,47 +0,0 @@
|
|||||||
pub mod asm_block;
|
|
||||||
pub mod asm_function;
|
|
||||||
pub mod asm_instruction;
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod smoke_tests {
|
|
||||||
use crate::asm::asm_function::AsmFunction;
|
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::parser::parse_compilation_unit;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
|
||||||
|
|
||||||
fn assemble(src: &str) -> Vec<AsmFunction> {
|
|
||||||
let parse_result = parse_compilation_unit(src);
|
|
||||||
let mut compilation_unit = match parse_result {
|
|
||||||
Ok(compilation_unit) => compilation_unit,
|
|
||||||
Err(diagnostics) => {
|
|
||||||
for diagnostic in diagnostics {
|
|
||||||
eprintln!("{:?}", diagnostic);
|
|
||||||
}
|
|
||||||
panic!();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mut symbol_table = SymbolTable::new();
|
|
||||||
compilation_unit.gather_declared_names(&mut symbol_table);
|
|
||||||
compilation_unit.check_name_usages(&symbol_table);
|
|
||||||
compilation_unit.type_check(&symbol_table);
|
|
||||||
compilation_unit.assemble(&symbol_table, &mut ConstantsTable::new())
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn multiple_statements() {
|
|
||||||
let asm_functions = assemble(
|
|
||||||
"
|
|
||||||
extern fn println() -> Void
|
|
||||||
fn main()
|
|
||||||
let x = 42
|
|
||||||
println(x)
|
|
||||||
println(16)
|
|
||||||
let y = \"Hello, World!\"
|
|
||||||
println(y)
|
|
||||||
end",
|
|
||||||
);
|
|
||||||
for asm_function in &asm_functions {
|
|
||||||
println!("{:#?}", asm_function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,21 +1,10 @@
|
|||||||
use crate::asm::asm_instruction::{Add, AsmInstruction, LoadConstant, Move, Operand, Pop};
|
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::ast_to_ir_util::expression_to_ir_expression;
|
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_add::IrAdd;
|
use crate::ir::ir_add::IrAdd;
|
||||||
use crate::ir::ir_assign::IrAssign;
|
|
||||||
use crate::ir::ir_expression::IrExpression;
|
|
||||||
use crate::ir::ir_operation::IrOperation;
|
|
||||||
use crate::ir::ir_statement::IrStatement;
|
|
||||||
use crate::ir::ir_variable::IrVariable;
|
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::ExpressibleSymbol;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
pub struct AdditiveExpression {
|
pub struct AdditiveExpression {
|
||||||
lhs: Box<Expression>,
|
lhs: Box<Expression>,
|
||||||
@ -75,111 +64,17 @@ impl AdditiveExpression {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrAdd {
|
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable) -> IrAdd {
|
||||||
let lhs_ir_expression = expression_to_ir_expression(&self.lhs, builder, symbol_table)
|
let lhs_ir_expression = self
|
||||||
|
.lhs
|
||||||
|
.to_ir(builder, symbol_table)
|
||||||
.expect("Attempt to add non-expression");
|
.expect("Attempt to add non-expression");
|
||||||
let rhs_ir_expression = expression_to_ir_expression(&self.rhs, builder, symbol_table)
|
let rhs_ir_expression = self
|
||||||
|
.rhs
|
||||||
|
.to_ir(builder, symbol_table)
|
||||||
.expect("Attempt to add non-expression");
|
.expect("Attempt to add non-expression");
|
||||||
IrAdd::new(lhs_ir_expression, rhs_ir_expression)
|
IrAdd::new(lhs_ir_expression, rhs_ir_expression)
|
||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
pub fn type_info(&self) -> TypeInfo {
|
||||||
self.lhs.type_info().additive_result(&self.rhs.type_info())
|
self.lhs.type_info().additive_result(&self.rhs.type_info())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,114 +0,0 @@
|
|||||||
use crate::asm::asm_block::AsmBlock;
|
|
||||||
use crate::asm::asm_function::AsmFunction;
|
|
||||||
use crate::asm::asm_instruction::AsmInstruction;
|
|
||||||
use crate::source_range::SourceRange;
|
|
||||||
|
|
||||||
pub struct AssembleContext {
|
|
||||||
functions: Vec<AsmFunction>,
|
|
||||||
current_function: Option<FunctionAssembler>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AssembleContext {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
functions: vec![],
|
|
||||||
current_function: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn take_functions(&mut self) -> Vec<AsmFunction> {
|
|
||||||
std::mem::take(&mut self.functions)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_function(&mut self, name: &str, source_range: &SourceRange) {
|
|
||||||
self.current_function = Some(FunctionAssembler::new(name, source_range));
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn complete_function(&mut self) {
|
|
||||||
let mut function_assembler = self.current_function.take().unwrap();
|
|
||||||
function_assembler.complete_block();
|
|
||||||
let asm_function = function_assembler.result();
|
|
||||||
self.functions.push(asm_function);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_block(&mut self, name: &str) {
|
|
||||||
self.current_function.as_mut().unwrap().new_block(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn new_local_register(&mut self) -> usize {
|
|
||||||
self.current_function.as_mut().unwrap().new_local_register()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn instruction(&mut self, to_add: AsmInstruction) {
|
|
||||||
self.current_function.as_mut().unwrap().instruction(to_add);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct FunctionAssembler {
|
|
||||||
name: String,
|
|
||||||
source_range: SourceRange,
|
|
||||||
blocks: Vec<AsmBlock>,
|
|
||||||
current_block: Option<BlockAssembler>,
|
|
||||||
local_register_counter: usize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FunctionAssembler {
|
|
||||||
fn new(name: &str, source_range: &SourceRange) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.into(),
|
|
||||||
source_range: source_range.clone(),
|
|
||||||
blocks: vec![],
|
|
||||||
current_block: None,
|
|
||||||
local_register_counter: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_block(&mut self, name: &str) {
|
|
||||||
let maybe_block_assembler = self.current_block.take();
|
|
||||||
if let Some(mut block_assembler) = maybe_block_assembler {
|
|
||||||
self.blocks.push(block_assembler.result());
|
|
||||||
}
|
|
||||||
self.current_block = Some(BlockAssembler::new(name))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn complete_block(&mut self) {
|
|
||||||
let mut block_assembler = self.current_block.take().unwrap();
|
|
||||||
self.blocks.push(block_assembler.result());
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result(&mut self) -> AsmFunction {
|
|
||||||
AsmFunction::new(&self.name, std::mem::take(&mut self.blocks))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_local_register(&mut self) -> usize {
|
|
||||||
let register = self.local_register_counter;
|
|
||||||
self.local_register_counter += 1;
|
|
||||||
register
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instruction(&mut self, to_add: AsmInstruction) {
|
|
||||||
self.current_block.as_mut().unwrap().instruction(to_add);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct BlockAssembler {
|
|
||||||
name: String,
|
|
||||||
instructions: Vec<AsmInstruction>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl BlockAssembler {
|
|
||||||
fn new(name: &str) -> Self {
|
|
||||||
Self {
|
|
||||||
name: name.into(),
|
|
||||||
instructions: vec![],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instruction(&mut self, to_add: AsmInstruction) {
|
|
||||||
self.instructions.push(to_add);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn result(&mut self) -> AsmBlock {
|
|
||||||
AsmBlock::new(&self.name, std::mem::take(&mut self.instructions))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,65 +0,0 @@
|
|||||||
use crate::ast::expression::Expression;
|
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
|
||||||
use crate::ir::ir_assign::IrAssign;
|
|
||||||
use crate::ir::ir_expression::IrExpression;
|
|
||||||
use crate::ir::ir_operation::IrOperation;
|
|
||||||
use crate::ir::ir_statement::IrStatement;
|
|
||||||
use crate::ir::ir_variable::IrVariable;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub fn expression_to_ir_expression(
|
|
||||||
expression: &Expression,
|
|
||||||
builder: &mut IrBuilder,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
) -> Option<IrExpression> {
|
|
||||||
match expression {
|
|
||||||
Expression::Call(call) => {
|
|
||||||
let ir_call = call.to_ir(builder, symbol_table);
|
|
||||||
if matches!(call.type_info(), TypeInfo::Void) {
|
|
||||||
builder
|
|
||||||
.current_block_mut()
|
|
||||||
.add_statement(IrStatement::Call(ir_call));
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let t_var = IrVariable::new_vr(
|
|
||||||
builder.new_t_var().into(),
|
|
||||||
builder.current_block().id(),
|
|
||||||
call.type_info(),
|
|
||||||
);
|
|
||||||
let as_rc = Rc::new(RefCell::new(t_var));
|
|
||||||
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
|
||||||
builder
|
|
||||||
.current_block_mut()
|
|
||||||
.add_statement(IrStatement::Assign(assign));
|
|
||||||
Some(IrExpression::Variable(as_rc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expression::IntegerLiteral(integer_literal) => {
|
|
||||||
Some(IrExpression::Int(integer_literal.value()))
|
|
||||||
}
|
|
||||||
Expression::String(string_literal) => {
|
|
||||||
Some(IrExpression::String(string_literal.content().into()))
|
|
||||||
}
|
|
||||||
Expression::Identifier(identifier) => {
|
|
||||||
let expressible_symbol = identifier.expressible_symbol();
|
|
||||||
Some(expressible_symbol.ir_expression())
|
|
||||||
}
|
|
||||||
Expression::Additive(additive_expression) => {
|
|
||||||
let ir_add = additive_expression.to_ir(builder, symbol_table);
|
|
||||||
let t_var = IrVariable::new_vr(
|
|
||||||
builder.new_t_var().into(),
|
|
||||||
builder.current_block().id(),
|
|
||||||
additive_expression.type_info(),
|
|
||||||
);
|
|
||||||
let as_rc = Rc::new(RefCell::new(t_var));
|
|
||||||
let assign = IrAssign::new(as_rc.clone(), IrOperation::Add(ir_add));
|
|
||||||
builder
|
|
||||||
.current_block_mut()
|
|
||||||
.add_statement(IrStatement::Assign(assign));
|
|
||||||
Some(IrExpression::Variable(as_rc))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,11 +1,5 @@
|
|||||||
use crate::asm::asm_instruction::{
|
|
||||||
AsmInstruction, InvokePlatformStatic, InvokeStatic, LoadConstant, Operand, Push,
|
|
||||||
};
|
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::ast_to_ir_util::expression_to_ir_expression;
|
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_call::IrCall;
|
use crate::ir::ir_call::IrCall;
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
@ -144,7 +138,7 @@ impl Call {
|
|||||||
let arguments: Vec<IrExpression> = self
|
let arguments: Vec<IrExpression> = self
|
||||||
.arguments
|
.arguments
|
||||||
.iter()
|
.iter()
|
||||||
.map(|argument| expression_to_ir_expression(argument, builder, symbol_table))
|
.map(|argument| argument.to_ir(builder, symbol_table))
|
||||||
.inspect(|expression| {
|
.inspect(|expression| {
|
||||||
if expression.is_none() {
|
if expression.is_none() {
|
||||||
panic!("Attempt to pass non-expression")
|
panic!("Attempt to pass non-expression")
|
||||||
@ -153,88 +147,11 @@ impl Call {
|
|||||||
.map(Option::unwrap)
|
.map(Option::unwrap)
|
||||||
.collect();
|
.collect();
|
||||||
let function_symbol = self.get_callee_symbol();
|
let function_symbol = self.get_callee_symbol();
|
||||||
IrCall::new(function_symbol.borrow().name_owned(), arguments)
|
IrCall::new(
|
||||||
}
|
function_symbol.borrow().name_owned(),
|
||||||
|
arguments,
|
||||||
pub fn assemble(
|
function_symbol.clone(),
|
||||||
&self,
|
)
|
||||||
context: &mut AssembleContext,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
) {
|
|
||||||
// push all args
|
|
||||||
for argument in &self.arguments {
|
|
||||||
match argument {
|
|
||||||
Expression::Call(call) => {
|
|
||||||
call.assemble(context, symbol_table, constants_table); // will leave return val on stack
|
|
||||||
}
|
|
||||||
Expression::IntegerLiteral(integer_literal) => {
|
|
||||||
context.instruction(AsmInstruction::Push(Push::new(Operand::IntegerLiteral(
|
|
||||||
integer_literal.value(),
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
Expression::String(string_literal) => {
|
|
||||||
let name = constants_table.insert_string(string_literal.content());
|
|
||||||
let temp_register = context.new_local_register();
|
|
||||||
context.instruction(AsmInstruction::LoadConstant(LoadConstant::new(
|
|
||||||
&name,
|
|
||||||
temp_register,
|
|
||||||
)));
|
|
||||||
context.instruction(AsmInstruction::Push(Push::new(Operand::Register(
|
|
||||||
temp_register,
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
Expression::Identifier(identifier) => match identifier.expressible_symbol() {
|
|
||||||
ExpressibleSymbol::Function(_) => {
|
|
||||||
panic!("Pushing function symbols not supported.")
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
|
||||||
context.instruction(AsmInstruction::Push(Push::new(
|
|
||||||
Operand::StackFrameOffset(
|
|
||||||
parameter_symbol.borrow().stack_frame_offset(),
|
|
||||||
),
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
|
||||||
context.instruction(AsmInstruction::Push(Push::new(Operand::Register(
|
|
||||||
variable_symbol.borrow().register(),
|
|
||||||
))))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
))));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let function_symbol = match self.callee() {
|
|
||||||
Expression::Identifier(identifier) => {
|
|
||||||
let expressible_symbol = identifier.expressible_symbol();
|
|
||||||
match expressible_symbol {
|
|
||||||
ExpressibleSymbol::Function(function_symbol) => function_symbol.clone(),
|
|
||||||
_ => panic!("Calling things other than functions not yet supported."),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => 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(), arg_count),
|
|
||||||
));
|
|
||||||
} else {
|
|
||||||
let arg_count = function_symbol.parameters().len();
|
|
||||||
context.instruction(AsmInstruction::InvokeStatic(InvokeStatic::new(
|
|
||||||
function_symbol.name(),
|
|
||||||
arg_count,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn source_range(&self) -> &SourceRange {
|
pub fn source_range(&self) -> &SourceRange {
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
use crate::asm::asm_function::AsmFunction;
|
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
use crate::ast::module_level_declaration::ModuleLevelDeclaration;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
pub struct CompilationUnit {
|
pub struct CompilationUnit {
|
||||||
@ -44,15 +42,13 @@ impl CompilationUnit {
|
|||||||
diagnostics
|
diagnostics
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
pub fn to_ir(&self, symbol_table: &SymbolTable) -> Vec<IrFunction> {
|
||||||
&self,
|
let mut ir_functions = vec![];
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
) -> Vec<AsmFunction> {
|
|
||||||
let mut context = AssembleContext::new();
|
|
||||||
for declaration in &self.declarations {
|
for declaration in &self.declarations {
|
||||||
declaration.assemble(&mut context, symbol_table, constants_table);
|
if let ModuleLevelDeclaration::Function(function) = declaration {
|
||||||
}
|
ir_functions.push(function.to_ir(symbol_table));
|
||||||
context.take_functions()
|
}
|
||||||
|
}
|
||||||
|
ir_functions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,11 +2,19 @@ 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;
|
||||||
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::ast::string_literal::StringLiteral;
|
use crate::ast::string_literal::StringLiteral;
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
|
use crate::ir::ir_assign::IrAssign;
|
||||||
|
use crate::ir::ir_expression::IrExpression;
|
||||||
|
use crate::ir::ir_operation::IrOperation;
|
||||||
|
use crate::ir::ir_statement::IrStatement;
|
||||||
|
use crate::ir::ir_variable::IrVariable;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub enum Expression {
|
pub enum Expression {
|
||||||
Call(Call),
|
Call(Call),
|
||||||
@ -83,4 +91,58 @@ impl Expression {
|
|||||||
Expression::Additive(additive_expression) => additive_expression.source_range(),
|
Expression::Additive(additive_expression) => additive_expression.source_range(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn to_ir(
|
||||||
|
&self,
|
||||||
|
builder: &mut IrBuilder,
|
||||||
|
symbol_table: &SymbolTable,
|
||||||
|
) -> Option<IrExpression> {
|
||||||
|
match self {
|
||||||
|
Expression::Call(call) => {
|
||||||
|
let ir_call = call.to_ir(builder, symbol_table);
|
||||||
|
if matches!(call.type_info(), TypeInfo::Void) {
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Call(ir_call));
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
let t_var = IrVariable::new_vr(
|
||||||
|
builder.new_t_var().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
call.type_info(),
|
||||||
|
);
|
||||||
|
let as_rc = Rc::new(RefCell::new(t_var));
|
||||||
|
let assign = IrAssign::new(as_rc.clone(), IrOperation::Call(ir_call));
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Assign(assign));
|
||||||
|
Some(IrExpression::Variable(as_rc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Expression::IntegerLiteral(integer_literal) => {
|
||||||
|
Some(IrExpression::Int(integer_literal.value()))
|
||||||
|
}
|
||||||
|
Expression::String(string_literal) => {
|
||||||
|
Some(IrExpression::String(string_literal.content().into()))
|
||||||
|
}
|
||||||
|
Expression::Identifier(identifier) => {
|
||||||
|
let expressible_symbol = identifier.expressible_symbol();
|
||||||
|
Some(expressible_symbol.ir_expression())
|
||||||
|
}
|
||||||
|
Expression::Additive(additive_expression) => {
|
||||||
|
let ir_add = additive_expression.to_ir(builder, symbol_table);
|
||||||
|
let t_var = IrVariable::new_vr(
|
||||||
|
builder.new_t_var().into(),
|
||||||
|
builder.current_block().id(),
|
||||||
|
additive_expression.type_info(),
|
||||||
|
);
|
||||||
|
let as_rc = Rc::new(RefCell::new(t_var));
|
||||||
|
let assign = IrAssign::new(as_rc.clone(), IrOperation::Add(ir_add));
|
||||||
|
builder
|
||||||
|
.current_block_mut()
|
||||||
|
.add_statement(IrStatement::Assign(assign));
|
||||||
|
Some(IrExpression::Variable(as_rc))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,17 +1,9 @@
|
|||||||
use crate::asm::asm_instruction::{AsmInstruction, Pop, SetReturnValue};
|
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::ast_to_ir_util::expression_to_ir_expression;
|
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_return::IrReturn;
|
use crate::ir::ir_return::IrReturn;
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::symbol::FunctionSymbol;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use crate::type_info::TypeInfo;
|
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub struct ExpressionStatement {
|
pub struct ExpressionStatement {
|
||||||
expression: Box<Expression>,
|
expression: Box<Expression>,
|
||||||
@ -41,50 +33,11 @@ impl ExpressionStatement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable, is_last: bool) {
|
pub fn to_ir(&self, builder: &mut IrBuilder, symbol_table: &SymbolTable, is_last: bool) {
|
||||||
let ir_expression = expression_to_ir_expression(self.expression(), builder, symbol_table);
|
let ir_expression = self.expression.to_ir(builder, symbol_table);
|
||||||
if ir_expression.is_some() && is_last {
|
if ir_expression.is_some() && is_last {
|
||||||
builder
|
builder
|
||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
.add_statement(IrStatement::Return(IrReturn::new(ir_expression)));
|
.add_statement(IrStatement::Return(IrReturn::new(ir_expression)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
|
||||||
&self,
|
|
||||||
context: &mut AssembleContext,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
outer_function_symbol: &Rc<RefCell<FunctionSymbol>>,
|
|
||||||
is_last: bool,
|
|
||||||
) {
|
|
||||||
match self.expression.as_ref() {
|
|
||||||
Expression::Call(call) => {
|
|
||||||
call.assemble(context, symbol_table, constants_table);
|
|
||||||
// if last expression and the return value of the callee isn't void, return that
|
|
||||||
// return value
|
|
||||||
if is_last && !matches!(call.type_info(), TypeInfo::Void) {
|
|
||||||
// move to register
|
|
||||||
let return_value_register = context.new_local_register();
|
|
||||||
context.instruction(AsmInstruction::Pop(Pop::new(return_value_register)));
|
|
||||||
|
|
||||||
// set return value
|
|
||||||
context.instruction(AsmInstruction::SetReturnValue(SetReturnValue::new(
|
|
||||||
return_value_register,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Expression::Additive(additive) => {
|
|
||||||
let result_register = additive.assemble(context, symbol_table, constants_table);
|
|
||||||
if is_last
|
|
||||||
&& !matches!(outer_function_symbol.borrow().return_type(), TypeInfo::Void)
|
|
||||||
{
|
|
||||||
// set return value
|
|
||||||
context.instruction(AsmInstruction::SetReturnValue(SetReturnValue::new(
|
|
||||||
result_register,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,7 @@
|
|||||||
use crate::asm::asm_instruction::{AsmInstruction, Return};
|
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
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::ast::type_use::TypeUse;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_function::IrFunction;
|
use crate::ir::ir_function::IrFunction;
|
||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
@ -165,11 +162,13 @@ impl Function {
|
|||||||
let mut builder = IrBuilder::new();
|
let mut builder = IrBuilder::new();
|
||||||
|
|
||||||
// parameters
|
// parameters
|
||||||
for parameter in &self.parameters {
|
for (i, parameter) in self.parameters.iter().enumerate() {
|
||||||
let parameter_symbol = parameter.parameter_symbol();
|
let parameter_symbol = parameter.parameter_symbol();
|
||||||
|
let stack_offset = (self.parameters.len() as isize).neg() + (i as isize);
|
||||||
let ir_parameter = IrParameter::new(
|
let ir_parameter = IrParameter::new(
|
||||||
parameter_symbol.borrow().name(),
|
parameter_symbol.borrow().name(),
|
||||||
parameter_symbol.borrow().type_info().clone(),
|
parameter_symbol.borrow().type_info().clone(),
|
||||||
|
stack_offset,
|
||||||
);
|
);
|
||||||
let as_rc = Rc::new(ir_parameter);
|
let as_rc = Rc::new(ir_parameter);
|
||||||
builder.parameters_mut().push(as_rc.clone());
|
builder.parameters_mut().push(as_rc.clone());
|
||||||
@ -190,38 +189,10 @@ impl Function {
|
|||||||
.unwrap_or(TypeInfo::Void);
|
.unwrap_or(TypeInfo::Void);
|
||||||
let entry_block = builder.get_block(entry_block_id).clone();
|
let entry_block = builder.get_block(entry_block_id).clone();
|
||||||
IrFunction::new(
|
IrFunction::new(
|
||||||
Rc::from(self.declared_name()),
|
self.function_symbol.as_ref().unwrap().clone(),
|
||||||
builder.parameters(),
|
builder.parameters(),
|
||||||
return_type_info,
|
return_type_info,
|
||||||
entry_block,
|
entry_block,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
|
||||||
&self,
|
|
||||||
context: &mut AssembleContext,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
) {
|
|
||||||
context.new_function(&self.declared_name, &self.declared_name_source_range);
|
|
||||||
context.new_block(&format!("{}_enter", self.declared_name));
|
|
||||||
let function_symbol = self
|
|
||||||
.function_symbol
|
|
||||||
.as_ref()
|
|
||||||
.expect("function_symbol not initialized; did you type check yet?");
|
|
||||||
for (i, statement) in self.statements.iter().enumerate() {
|
|
||||||
let is_last = i == self.statements.len() - 1;
|
|
||||||
statement.assemble(
|
|
||||||
context,
|
|
||||||
symbol_table,
|
|
||||||
constants_table,
|
|
||||||
function_symbol,
|
|
||||||
is_last,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
// return
|
|
||||||
context.instruction(AsmInstruction::Return(Return::new(self.parameters.len())));
|
|
||||||
|
|
||||||
context.complete_function();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,5 @@
|
|||||||
use crate::asm::asm_instruction::{AsmInstruction, LoadConstant, Move, Operand, Pop};
|
|
||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::expression::Expression;
|
use crate::ast::expression::Expression;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::ir::ir_assign::IrAssign;
|
use crate::ir::ir_assign::IrAssign;
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
@ -10,7 +7,7 @@ use crate::ir::ir_operation::IrOperation;
|
|||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVariable;
|
use crate::ir::ir_variable::IrVariable;
|
||||||
use crate::source_range::SourceRange;
|
use crate::source_range::SourceRange;
|
||||||
use crate::symbol::{ExpressibleSymbol, VariableSymbol};
|
use crate::symbol::VariableSymbol;
|
||||||
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
use crate::symbol_table::{SymbolInsertError, SymbolTable};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -121,69 +118,4 @@ impl LetStatement {
|
|||||||
.current_block_mut()
|
.current_block_mut()
|
||||||
.add_statement(IrStatement::Assign(ir_assign));
|
.add_statement(IrStatement::Assign(ir_assign));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
|
||||||
&self,
|
|
||||||
context: &mut AssembleContext,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
) {
|
|
||||||
let destination_register = context.new_local_register();
|
|
||||||
|
|
||||||
// save register to symbol
|
|
||||||
let variable_symbol =
|
|
||||||
symbol_table.get_variable_symbol(self.scope_id.unwrap(), self.declared_name());
|
|
||||||
variable_symbol
|
|
||||||
.borrow_mut()
|
|
||||||
.set_register(destination_register);
|
|
||||||
|
|
||||||
match self.initializer() {
|
|
||||||
Expression::Call(call) => {
|
|
||||||
call.assemble(context, symbol_table, constants_table);
|
|
||||||
context.instruction(AsmInstruction::Pop(Pop::new(destination_register)));
|
|
||||||
}
|
|
||||||
Expression::IntegerLiteral(integer_literal) => {
|
|
||||||
context.instruction(AsmInstruction::Move(Move::new(
|
|
||||||
Operand::IntegerLiteral(integer_literal.value()),
|
|
||||||
destination_register,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Expression::String(string_literal) => {
|
|
||||||
let name = constants_table.insert_string(string_literal.content());
|
|
||||||
context.instruction(AsmInstruction::LoadConstant(LoadConstant::new(
|
|
||||||
&name,
|
|
||||||
destination_register,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Expression::Identifier(identifier) => {
|
|
||||||
let expressible_symbol = identifier.expressible_symbol();
|
|
||||||
match expressible_symbol {
|
|
||||||
ExpressibleSymbol::Function(_) => {
|
|
||||||
panic!("Moving functions to registers not yet supported");
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
|
||||||
context.instruction(AsmInstruction::Move(Move::new(
|
|
||||||
Operand::StackFrameOffset(
|
|
||||||
parameter_symbol.borrow().stack_frame_offset(),
|
|
||||||
),
|
|
||||||
destination_register,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
ExpressibleSymbol::Variable(variable_symbol) => {
|
|
||||||
context.instruction(AsmInstruction::Move(Move::new(
|
|
||||||
Operand::Register(variable_symbol.borrow().register()),
|
|
||||||
destination_register,
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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,6 +1,4 @@
|
|||||||
pub mod additive_expression;
|
pub mod additive_expression;
|
||||||
pub mod assemble_context;
|
|
||||||
mod ast_to_ir_util;
|
|
||||||
pub mod call;
|
pub mod call;
|
||||||
pub mod compilation_unit;
|
pub mod compilation_unit;
|
||||||
pub mod expression;
|
pub mod expression;
|
||||||
@ -10,7 +8,7 @@ pub mod fqn;
|
|||||||
pub mod function;
|
pub mod function;
|
||||||
pub mod identifier;
|
pub mod identifier;
|
||||||
pub mod integer_literal;
|
pub mod integer_literal;
|
||||||
mod ir_builder;
|
pub mod ir_builder;
|
||||||
pub mod let_statement;
|
pub mod let_statement;
|
||||||
pub mod module_level_declaration;
|
pub mod module_level_declaration;
|
||||||
pub mod parameter;
|
pub mod parameter;
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::extern_function::ExternFunction;
|
use crate::ast::extern_function::ExternFunction;
|
||||||
use crate::ast::function::Function;
|
use crate::ast::function::Function;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
|
|
||||||
@ -39,20 +37,4 @@ impl ModuleLevelDeclaration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
|
||||||
&self,
|
|
||||||
context: &mut AssembleContext,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
ModuleLevelDeclaration::Function(function) => {
|
|
||||||
function.assemble(context, symbol_table, constants_table)
|
|
||||||
}
|
|
||||||
ModuleLevelDeclaration::ExternFunction(_) => {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,8 @@
|
|||||||
use crate::ast::assemble_context::AssembleContext;
|
|
||||||
use crate::ast::expression_statement::ExpressionStatement;
|
use crate::ast::expression_statement::ExpressionStatement;
|
||||||
use crate::ast::ir_builder::IrBuilder;
|
use crate::ast::ir_builder::IrBuilder;
|
||||||
use crate::ast::let_statement::LetStatement;
|
use crate::ast::let_statement::LetStatement;
|
||||||
use crate::constants_table::ConstantsTable;
|
|
||||||
use crate::diagnostic::Diagnostic;
|
use crate::diagnostic::Diagnostic;
|
||||||
use crate::symbol::FunctionSymbol;
|
|
||||||
use crate::symbol_table::SymbolTable;
|
use crate::symbol_table::SymbolTable;
|
||||||
use std::cell::RefCell;
|
|
||||||
use std::rc::Rc;
|
|
||||||
|
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
Let(LetStatement),
|
Let(LetStatement),
|
||||||
@ -52,28 +47,4 @@ impl Statement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn assemble(
|
|
||||||
&self,
|
|
||||||
context: &mut AssembleContext,
|
|
||||||
symbol_table: &SymbolTable,
|
|
||||||
constants_table: &mut ConstantsTable,
|
|
||||||
outer_function_symbol: &Rc<RefCell<FunctionSymbol>>,
|
|
||||||
is_last: bool,
|
|
||||||
) {
|
|
||||||
match self {
|
|
||||||
Statement::Let(let_statement) => {
|
|
||||||
let_statement.assemble(context, symbol_table, constants_table);
|
|
||||||
}
|
|
||||||
Statement::Expression(expression_statement) => {
|
|
||||||
expression_statement.assemble(
|
|
||||||
context,
|
|
||||||
symbol_table,
|
|
||||||
constants_table,
|
|
||||||
outer_function_symbol,
|
|
||||||
is_last,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct ConstantsTable {
|
pub struct ConstantsTable {
|
||||||
string_counter: usize,
|
string_counter: usize,
|
||||||
strings_to_names: HashMap<String, String>,
|
strings_to_names: HashMap<Rc<str>, Rc<str>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ConstantsTable {
|
impl ConstantsTable {
|
||||||
@ -13,14 +14,18 @@ impl ConstantsTable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_string(&mut self, s: &str) -> String {
|
pub fn get_or_insert(&mut self, s: &str) -> Rc<str> {
|
||||||
let name = format!("s_{}", self.string_counter);
|
if self.strings_to_names.contains_key(s) {
|
||||||
|
self.strings_to_names.get(s).unwrap().clone()
|
||||||
|
} else {
|
||||||
|
let name: Rc<str> = Rc::from(format!("s_{}", self.string_counter).as_str());
|
||||||
self.string_counter += 1;
|
self.string_counter += 1;
|
||||||
self.strings_to_names.insert(s.into(), name.clone());
|
self.strings_to_names.insert(s.into(), name.clone());
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn string_constants(&self) -> HashMap<String, String> {
|
pub fn string_constants(&self) -> HashMap<Rc<str>, Rc<str>> {
|
||||||
let mut constants = HashMap::new();
|
let mut constants = HashMap::new();
|
||||||
self.strings_to_names.iter().for_each(|(content, name)| {
|
self.strings_to_names.iter().for_each(|(content, name)| {
|
||||||
constants.insert(name.clone(), content.clone());
|
constants.insert(name.clone(), content.clone());
|
||||||
|
|||||||
26
dmc-lib/src/ir/assemble.rs
Normal file
26
dmc-lib/src/ir/assemble.rs
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use dvm_lib::instruction::Instruction;
|
||||||
|
|
||||||
|
pub trait Assemble {
|
||||||
|
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct InstructionsBuilder {
|
||||||
|
instructions: Vec<Instruction>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl InstructionsBuilder {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
instructions: vec![],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push(&mut self, instruction: Instruction) {
|
||||||
|
self.instructions.push(instruction);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take_instructions(&mut self) -> Vec<Instruction> {
|
||||||
|
std::mem::take(&mut self.instructions)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,8 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::VrUser;
|
use crate::ir::register_allocation::VrUser;
|
||||||
|
use dvm_lib::instruction::AddOperand;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
@ -16,6 +18,21 @@ impl IrAdd {
|
|||||||
right: right.into(),
|
right: right.into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn left(&self) -> &IrExpression {
|
||||||
|
&self.left
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn right(&self) -> &IrExpression {
|
||||||
|
&self.right
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn operand_pair(&self, constants_table: &mut ConstantsTable) -> (AddOperand, AddOperand) {
|
||||||
|
(
|
||||||
|
self.left.add_operand(constants_table),
|
||||||
|
self.right.add_operand(constants_table),
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IrAdd {
|
impl Display for IrAdd {
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_operation::IrOperation;
|
use crate::ir::ir_operation::IrOperation;
|
||||||
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
use crate::ir::ir_variable::{IrVariable, IrVariableDescriptor, IrVrVariableDescriptor};
|
||||||
use crate::ir::register_allocation::VrUser;
|
use crate::ir::register_allocation::VrUser;
|
||||||
|
use dvm_lib::instruction::{Instruction, Location};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@ -67,6 +70,34 @@ impl VrUser for IrAssign {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Assemble for IrAssign {
|
||||||
|
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||||
|
let destination = match self.destination.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(vr_variable) => {
|
||||||
|
Location::Register(vr_variable.assigned_register())
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => {
|
||||||
|
Location::StackFrameOffset(stack_variable.offset())
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
match self.initializer.as_ref() {
|
||||||
|
IrOperation::Load(ir_expression) => {
|
||||||
|
let move_operand = ir_expression.move_operand(constants_table);
|
||||||
|
builder.push(Instruction::Move(move_operand, destination));
|
||||||
|
}
|
||||||
|
IrOperation::Add(ir_add) => {
|
||||||
|
let (left, right) = ir_add.operand_pair(constants_table);
|
||||||
|
builder.push(Instruction::Add(left, right, destination));
|
||||||
|
}
|
||||||
|
IrOperation::Call(ir_call) => {
|
||||||
|
ir_call.assemble(builder, constants_table);
|
||||||
|
builder.push(Instruction::Pop(Some(destination)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for IrAssign {
|
impl Display for IrAssign {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(
|
write!(
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_statement::IrStatement;
|
use crate::ir::ir_statement::IrStatement;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::{HasVrUsers, VrUser};
|
use crate::ir::register_allocation::{HasVrUsers, VrUser};
|
||||||
@ -75,6 +77,14 @@ impl VrUser for IrBlock {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Assemble for IrBlock {
|
||||||
|
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||||
|
for statement in &self.statements {
|
||||||
|
statement.assemble(builder, constants_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for IrBlock {
|
impl Display for IrBlock {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
writeln!(f, " {}:", self.debug_label)?;
|
writeln!(f, " {}:", self.debug_label)?;
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::VrUser;
|
use crate::ir::register_allocation::VrUser;
|
||||||
|
use crate::symbol::FunctionSymbol;
|
||||||
|
use dvm_lib::instruction::Instruction;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -8,13 +13,19 @@ use std::rc::Rc;
|
|||||||
pub struct IrCall {
|
pub struct IrCall {
|
||||||
function_name: Rc<str>,
|
function_name: Rc<str>,
|
||||||
arguments: Vec<IrExpression>,
|
arguments: Vec<IrExpression>,
|
||||||
|
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrCall {
|
impl IrCall {
|
||||||
pub fn new(function_name: Rc<str>, arguments: Vec<IrExpression>) -> Self {
|
pub fn new(
|
||||||
|
function_name: Rc<str>,
|
||||||
|
arguments: Vec<IrExpression>,
|
||||||
|
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||||
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
function_name,
|
function_name,
|
||||||
arguments,
|
arguments,
|
||||||
|
function_symbol,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -44,6 +55,29 @@ impl VrUser for IrCall {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Assemble for IrCall {
|
||||||
|
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||||
|
// push all args
|
||||||
|
self.arguments
|
||||||
|
.iter()
|
||||||
|
.map(|ir_expression| ir_expression.push_operand(constants_table))
|
||||||
|
.for_each(|push_operand| builder.push(Instruction::Push(push_operand)));
|
||||||
|
let symbol = self.function_symbol.borrow();
|
||||||
|
if symbol.is_platform() {
|
||||||
|
builder.push(Instruction::InvokePlatformStatic(
|
||||||
|
symbol.name_owned(),
|
||||||
|
symbol.parameters().len(),
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
builder.push(Instruction::InvokeStatic(
|
||||||
|
symbol.name_owned(),
|
||||||
|
symbol.parameters().len(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
// todo: handle function postlude
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for IrCall {
|
impl Display for IrCall {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "{}(", self.function_name)?;
|
write!(f, "{}(", self.function_name)?;
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
use crate::ir::ir_variable::{
|
use crate::ir::ir_variable::{
|
||||||
IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor,
|
IrStackVariableDescriptor, IrVariable, IrVariableDescriptor, IrVrVariableDescriptor,
|
||||||
};
|
};
|
||||||
use crate::ir::register_allocation::VrUser;
|
use crate::ir::register_allocation::VrUser;
|
||||||
|
use crate::type_info::TypeInfo;
|
||||||
|
use dvm_lib::instruction::{AddOperand, Location, MoveOperand, PushOperand, ReturnOperand};
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
@ -15,6 +18,116 @@ pub enum IrExpression {
|
|||||||
String(Rc<str>),
|
String(Rc<str>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IrExpression {
|
||||||
|
pub fn type_info(&self) -> TypeInfo {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => ir_parameter.type_info().clone(),
|
||||||
|
IrExpression::Variable(ir_variable) => ir_variable.borrow().type_info().clone(),
|
||||||
|
IrExpression::Int(_) => TypeInfo::Integer,
|
||||||
|
IrExpression::String(_) => TypeInfo::String,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_operand(&self, constants_table: &mut ConstantsTable) -> MoveOperand {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => {
|
||||||
|
MoveOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||||
|
}
|
||||||
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
||||||
|
MoveOperand::Location(Location::Register(register_variable.assigned_register()))
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => {
|
||||||
|
MoveOperand::Location(Location::StackFrameOffset(stack_variable.offset()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IrExpression::Int(i) => MoveOperand::Int(*i),
|
||||||
|
IrExpression::String(s) => {
|
||||||
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
|
MoveOperand::String(constant_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn push_operand(&self, constants_table: &mut ConstantsTable) -> PushOperand {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => {
|
||||||
|
PushOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||||
|
}
|
||||||
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
||||||
|
PushOperand::Location(Location::Register(register_variable.assigned_register()))
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => {
|
||||||
|
PushOperand::Location(Location::StackFrameOffset(stack_variable.offset()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IrExpression::Int(i) => PushOperand::Int(*i),
|
||||||
|
IrExpression::String(s) => {
|
||||||
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
|
PushOperand::String(constant_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_operand(&self, constants_table: &mut ConstantsTable) -> AddOperand {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => match ir_parameter.type_info() {
|
||||||
|
TypeInfo::Integer | TypeInfo::String => {
|
||||||
|
AddOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||||
|
}
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add non-integer/non-string (found: {})",
|
||||||
|
ir_parameter.type_info()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().type_info() {
|
||||||
|
TypeInfo::Integer | TypeInfo::String => match ir_variable.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
||||||
|
AddOperand::Location(Location::Register(
|
||||||
|
register_variable.assigned_register(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => {
|
||||||
|
AddOperand::Location(Location::StackFrameOffset(stack_variable.offset()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_ => panic!(
|
||||||
|
"Attempt to add non-integer/non-string (found: {})",
|
||||||
|
ir_variable.borrow().type_info()
|
||||||
|
),
|
||||||
|
},
|
||||||
|
IrExpression::Int(i) => AddOperand::Int(*i),
|
||||||
|
IrExpression::String(s) => {
|
||||||
|
let constant_name = constants_table.get_or_insert(s);
|
||||||
|
AddOperand::String(constant_name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn return_operand(&self) -> ReturnOperand {
|
||||||
|
match self {
|
||||||
|
IrExpression::Parameter(ir_parameter) => {
|
||||||
|
ReturnOperand::Location(Location::StackFrameOffset(ir_parameter.stack_offset()))
|
||||||
|
}
|
||||||
|
IrExpression::Variable(ir_variable) => match ir_variable.borrow().descriptor() {
|
||||||
|
IrVariableDescriptor::VirtualRegister(register_variable) => {
|
||||||
|
ReturnOperand::Location(Location::Register(
|
||||||
|
register_variable.assigned_register(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
IrVariableDescriptor::Stack(stack_variable) => {
|
||||||
|
ReturnOperand::Location(Location::StackFrameOffset(stack_variable.offset()))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
IrExpression::Int(i) => ReturnOperand::Int(*i),
|
||||||
|
IrExpression::String(s) => {
|
||||||
|
todo!("String constants")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for IrExpression {
|
impl Display for IrExpression {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@ -1,15 +1,19 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_block::IrBlock;
|
use crate::ir::ir_block::IrBlock;
|
||||||
use crate::ir::ir_parameter::IrParameter;
|
use crate::ir::ir_parameter::IrParameter;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::{HasVrUsers, VrUser};
|
use crate::ir::register_allocation::HasVrUsers;
|
||||||
|
use crate::symbol::FunctionSymbol;
|
||||||
use crate::type_info::TypeInfo;
|
use crate::type_info::TypeInfo;
|
||||||
|
use dvm_lib::vm::function::Function;
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fmt::Display;
|
use std::fmt::Display;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct IrFunction {
|
pub struct IrFunction {
|
||||||
name: Rc<str>,
|
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||||
parameters: Vec<Rc<IrParameter>>,
|
parameters: Vec<Rc<IrParameter>>,
|
||||||
return_type_info: TypeInfo,
|
return_type_info: TypeInfo,
|
||||||
entry: Rc<RefCell<IrBlock>>,
|
entry: Rc<RefCell<IrBlock>>,
|
||||||
@ -17,13 +21,13 @@ pub struct IrFunction {
|
|||||||
|
|
||||||
impl IrFunction {
|
impl IrFunction {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
name: Rc<str>,
|
function_symbol: Rc<RefCell<FunctionSymbol>>,
|
||||||
parameters: &[Rc<IrParameter>],
|
parameters: &[Rc<IrParameter>],
|
||||||
return_type_info: TypeInfo,
|
return_type_info: TypeInfo,
|
||||||
entry: Rc<RefCell<IrBlock>>,
|
entry: Rc<RefCell<IrBlock>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name,
|
function_symbol,
|
||||||
parameters: parameters.to_vec(),
|
parameters: parameters.to_vec(),
|
||||||
return_type_info,
|
return_type_info,
|
||||||
entry,
|
entry,
|
||||||
@ -37,11 +41,22 @@ impl IrFunction {
|
|||||||
) -> HashMap<IrVrVariableDescriptor, usize> {
|
) -> HashMap<IrVrVariableDescriptor, usize> {
|
||||||
self.entry.borrow_mut().assign_registers(register_count)
|
self.entry.borrow_mut().assign_registers(register_count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn assemble(&self, constants_table: &mut ConstantsTable) -> Function {
|
||||||
|
let mut builder = InstructionsBuilder::new();
|
||||||
|
self.entry.borrow().assemble(&mut builder, constants_table);
|
||||||
|
let instructions = builder.take_instructions();
|
||||||
|
Function::new(
|
||||||
|
self.function_symbol.borrow().name_owned(),
|
||||||
|
self.parameters.len(),
|
||||||
|
instructions,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IrFunction {
|
impl Display for IrFunction {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "fn {}(", self.name)?;
|
write!(f, "fn {}(", self.function_symbol.borrow().name())?;
|
||||||
for (i, parameter) in self.parameters.iter().enumerate() {
|
for (i, parameter) in self.parameters.iter().enumerate() {
|
||||||
write!(f, "{}: {}", parameter, parameter.type_info())?;
|
write!(f, "{}: {}", parameter, parameter.type_info())?;
|
||||||
if i < self.parameters.len() - 1 {
|
if i < self.parameters.len() - 1 {
|
||||||
|
|||||||
@ -5,19 +5,25 @@ use std::rc::Rc;
|
|||||||
pub struct IrParameter {
|
pub struct IrParameter {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
type_info: TypeInfo,
|
type_info: TypeInfo,
|
||||||
|
stack_offset: isize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrParameter {
|
impl IrParameter {
|
||||||
pub fn new(name: &str, type_info: TypeInfo) -> Self {
|
pub fn new(name: &str, type_info: TypeInfo, stack_offset: isize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name: name.into(),
|
||||||
type_info,
|
type_info,
|
||||||
|
stack_offset,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn type_info(&self) -> &TypeInfo {
|
pub fn type_info(&self) -> &TypeInfo {
|
||||||
&self.type_info
|
&self.type_info
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stack_offset(&self) -> isize {
|
||||||
|
self.stack_offset
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IrParameter {
|
impl Display for IrParameter {
|
||||||
|
|||||||
@ -1,6 +1,9 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_expression::IrExpression;
|
use crate::ir::ir_expression::IrExpression;
|
||||||
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
use crate::ir::ir_variable::IrVrVariableDescriptor;
|
||||||
use crate::ir::register_allocation::VrUser;
|
use crate::ir::register_allocation::VrUser;
|
||||||
|
use dvm_lib::instruction::Instruction;
|
||||||
use std::collections::{HashMap, HashSet};
|
use std::collections::{HashMap, HashSet};
|
||||||
use std::fmt::{Display, Formatter};
|
use std::fmt::{Display, Formatter};
|
||||||
|
|
||||||
@ -43,6 +46,15 @@ impl VrUser for IrReturn {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Assemble for IrReturn {
|
||||||
|
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||||
|
if let Some(ir_expression) = self.value.as_ref() {
|
||||||
|
builder.push(Instruction::SetReturnValue(ir_expression.return_operand()));
|
||||||
|
}
|
||||||
|
builder.push(Instruction::Return);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for IrReturn {
|
impl Display for IrReturn {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
write!(f, "return")?;
|
write!(f, "return")?;
|
||||||
|
|||||||
@ -1,3 +1,5 @@
|
|||||||
|
use crate::constants_table::ConstantsTable;
|
||||||
|
use crate::ir::assemble::{Assemble, InstructionsBuilder};
|
||||||
use crate::ir::ir_assign::IrAssign;
|
use crate::ir::ir_assign::IrAssign;
|
||||||
use crate::ir::ir_call::IrCall;
|
use crate::ir::ir_call::IrCall;
|
||||||
use crate::ir::ir_return::IrReturn;
|
use crate::ir::ir_return::IrReturn;
|
||||||
@ -61,6 +63,22 @@ impl VrUser for IrStatement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Assemble for IrStatement {
|
||||||
|
fn assemble(&self, builder: &mut InstructionsBuilder, constants_table: &mut ConstantsTable) {
|
||||||
|
match self {
|
||||||
|
IrStatement::Assign(ir_assign) => {
|
||||||
|
ir_assign.assemble(builder, constants_table);
|
||||||
|
}
|
||||||
|
IrStatement::Call(ir_call) => {
|
||||||
|
ir_call.assemble(builder, constants_table);
|
||||||
|
}
|
||||||
|
IrStatement::Return(ir_return) => {
|
||||||
|
ir_return.assemble(builder, constants_table);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Display for IrStatement {
|
impl Display for IrStatement {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|||||||
@ -102,6 +102,10 @@ impl IrVrVariableDescriptor {
|
|||||||
pub fn set_assigned_register(&mut self, register: usize) {
|
pub fn set_assigned_register(&mut self, register: usize) {
|
||||||
self.assigned_register = Some(register);
|
self.assigned_register = Some(register);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn assigned_register(&self) -> usize {
|
||||||
|
self.assigned_register.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IrVrVariableDescriptor {
|
impl Display for IrVrVariableDescriptor {
|
||||||
@ -119,7 +123,7 @@ impl Debug for IrVrVariableDescriptor {
|
|||||||
pub struct IrStackVariableDescriptor {
|
pub struct IrStackVariableDescriptor {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
block_id: usize,
|
block_id: usize,
|
||||||
offset: Option<usize>,
|
offset: Option<isize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IrStackVariableDescriptor {
|
impl IrStackVariableDescriptor {
|
||||||
@ -134,6 +138,10 @@ impl IrStackVariableDescriptor {
|
|||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
&self.name
|
&self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn offset(&self) -> isize {
|
||||||
|
self.offset.unwrap()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for IrStackVariableDescriptor {
|
impl Display for IrStackVariableDescriptor {
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
mod assemble;
|
||||||
pub mod ir_add;
|
pub mod ir_add;
|
||||||
pub mod ir_assign;
|
pub mod ir_assign;
|
||||||
pub mod ir_block;
|
pub mod ir_block;
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
pub mod asm;
|
|
||||||
pub mod ast;
|
pub mod ast;
|
||||||
pub mod constants_table;
|
pub mod constants_table;
|
||||||
pub mod diagnostic;
|
pub mod diagnostic;
|
||||||
|
|||||||
@ -1,57 +1,35 @@
|
|||||||
use std::fmt::Display;
|
use std::fmt::{Display, Formatter};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub type Register = usize;
|
pub type Register = usize;
|
||||||
|
pub type StackFrameOffset = isize;
|
||||||
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 type ArgCount = usize;
|
||||||
pub type CallerPopCount = usize;
|
pub type CallerPopCount = usize;
|
||||||
|
|
||||||
pub enum Instruction {
|
pub enum Instruction {
|
||||||
MoveRegister(Register, Register),
|
Move(MoveOperand, Location),
|
||||||
MoveInt(i32, Register),
|
Push(PushOperand),
|
||||||
MoveStackFrameOffset(isize, Register),
|
|
||||||
|
|
||||||
PushRegister(Register),
|
|
||||||
PushInt(i32),
|
|
||||||
PushStackFrameOffset(isize),
|
|
||||||
|
|
||||||
InvokeStatic(FunctionName, ArgCount),
|
InvokeStatic(FunctionName, ArgCount),
|
||||||
InvokePlatformStatic(FunctionName, ArgCount),
|
InvokePlatformStatic(FunctionName, ArgCount),
|
||||||
|
|
||||||
LoadStringConstant(ConstantName, Register),
|
Add(AddOperand, AddOperand, Location),
|
||||||
|
|
||||||
Pop(Option<Register>),
|
Pop(Option<Location>),
|
||||||
|
|
||||||
AddIntInt(Register, Register, Register),
|
SetReturnValue(ReturnOperand),
|
||||||
AddStringInt(Register, Register, Register),
|
Return,
|
||||||
AddStringString(Register, Register, Register),
|
|
||||||
|
|
||||||
SetReturnValue(Register),
|
|
||||||
Return(CallerPopCount),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for Instruction {
|
impl Display for Instruction {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Instruction::MoveRegister(source, destination) => {
|
Instruction::Move(source, destination) => {
|
||||||
write!(f, "movr r{}, r{}", source, destination)
|
write!(f, "mov {}, {}", source, destination)
|
||||||
}
|
|
||||||
Instruction::MoveInt(i, destination) => {
|
|
||||||
write!(f, "movi {}, r{}", i, destination)
|
|
||||||
}
|
|
||||||
Instruction::MoveStackFrameOffset(offset, destination) => {
|
|
||||||
write!(f, "movsf {}, r{}", offset, destination)
|
|
||||||
}
|
|
||||||
Instruction::PushRegister(source) => {
|
|
||||||
write!(f, "pushr r{}", source)
|
|
||||||
}
|
|
||||||
Instruction::PushInt(i) => {
|
|
||||||
write!(f, "pushi {}", i)
|
|
||||||
}
|
|
||||||
Instruction::PushStackFrameOffset(offset) => {
|
|
||||||
write!(f, "pushsf {}", offset)
|
|
||||||
}
|
}
|
||||||
|
Instruction::Push(source) => write!(f, "push {}", source),
|
||||||
Instruction::InvokeStatic(name, arg_count) => {
|
Instruction::InvokeStatic(name, arg_count) => {
|
||||||
write!(f, "invoke_static {} (arg_count: {})", name, arg_count)
|
write!(f, "invoke_static {} (arg_count: {})", name, arg_count)
|
||||||
}
|
}
|
||||||
@ -62,30 +40,131 @@ impl Display for Instruction {
|
|||||||
name, arg_count
|
name, arg_count
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Instruction::LoadStringConstant(name, destination) => {
|
|
||||||
write!(f, "loadsc {}, r{}", name, destination)
|
|
||||||
}
|
|
||||||
Instruction::Pop(maybe_destination) => {
|
Instruction::Pop(maybe_destination) => {
|
||||||
if let Some(destination) = maybe_destination {
|
if let Some(destination) = maybe_destination {
|
||||||
write!(f, "pop r{}", destination)
|
write!(f, "pop {}", destination)
|
||||||
} else {
|
} else {
|
||||||
write!(f, "pop")
|
write!(f, "pop")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Instruction::AddIntInt(left, right, destination) => {
|
Instruction::Add(left, right, destination) => {
|
||||||
write!(f, "addii r{}, r{}, r{}", left, right, destination)
|
write!(f, "add {}, {}, {}", left, right, destination)
|
||||||
}
|
|
||||||
Instruction::AddStringInt(left, right, destination) => {
|
|
||||||
write!(f, "addsi r{}, r{}, r{}", left, right, destination)
|
|
||||||
}
|
|
||||||
Instruction::AddStringString(left, right, destination) => {
|
|
||||||
write!(f, "addss r{}, r{}, r{}", left, right, destination)
|
|
||||||
}
|
}
|
||||||
Instruction::SetReturnValue(source) => {
|
Instruction::SetReturnValue(source) => {
|
||||||
write!(f, "srv r{}", source)
|
write!(f, "srv {}", source)
|
||||||
}
|
}
|
||||||
Instruction::Return(caller_pop_count) => {
|
Instruction::Return => {
|
||||||
write!(f, "return (caller_pop_count: {})", caller_pop_count)
|
write!(f, "ret")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum Location {
|
||||||
|
Register(Register),
|
||||||
|
StackFrameOffset(StackFrameOffset),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Location {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Location::Register(register) => {
|
||||||
|
write!(f, "r{}", register)
|
||||||
|
}
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
if offset.is_positive() {
|
||||||
|
write!(f, "fp+{}", offset)
|
||||||
|
} else {
|
||||||
|
write!(f, "fp{}", offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum MoveOperand {
|
||||||
|
Location(Location),
|
||||||
|
Int(i32),
|
||||||
|
String(Rc<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for MoveOperand {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
MoveOperand::Location(location) => {
|
||||||
|
write!(f, "{}", location)
|
||||||
|
}
|
||||||
|
MoveOperand::Int(i) => {
|
||||||
|
write!(f, "{}", i)
|
||||||
|
}
|
||||||
|
MoveOperand::String(s) => {
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum PushOperand {
|
||||||
|
Location(Location),
|
||||||
|
Int(i32),
|
||||||
|
String(Rc<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for PushOperand {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
PushOperand::Location(location) => {
|
||||||
|
write!(f, "{}", location)
|
||||||
|
}
|
||||||
|
PushOperand::Int(i) => {
|
||||||
|
write!(f, "{}", i)
|
||||||
|
}
|
||||||
|
PushOperand::String(s) => {
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum AddOperand {
|
||||||
|
Location(Location),
|
||||||
|
Int(i32),
|
||||||
|
String(Rc<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for AddOperand {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
AddOperand::Location(location) => {
|
||||||
|
write!(f, "{}", location)
|
||||||
|
}
|
||||||
|
AddOperand::Int(i) => {
|
||||||
|
write!(f, "{}", i)
|
||||||
|
}
|
||||||
|
AddOperand::String(s) => {
|
||||||
|
write!(f, "{}", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ReturnOperand {
|
||||||
|
Location(Location),
|
||||||
|
Int(i32),
|
||||||
|
String(Rc<str>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for ReturnOperand {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
ReturnOperand::Location(location) => {
|
||||||
|
write!(f, "{}", location)
|
||||||
|
}
|
||||||
|
ReturnOperand::Int(i) => {
|
||||||
|
write!(f, "{}", i)
|
||||||
|
}
|
||||||
|
ReturnOperand::String(s) => {
|
||||||
|
write!(f, "{}", s)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,11 +10,8 @@ pub struct StringConstant {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl StringConstant {
|
impl StringConstant {
|
||||||
pub fn new(name: Rc<str>, content: &str) -> Self {
|
pub fn new(name: Rc<str>, content: Rc<str>) -> Self {
|
||||||
Self {
|
Self { name, content }
|
||||||
name,
|
|
||||||
content: content.into(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &str {
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
use crate::instruction::Instruction;
|
use crate::instruction::Instruction;
|
||||||
|
use std::fmt::Display;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
|
||||||
pub struct Function {
|
pub struct Function {
|
||||||
name: Rc<str>,
|
name: Rc<str>,
|
||||||
|
parameter_count: usize,
|
||||||
instructions: Vec<Instruction>,
|
instructions: Vec<Instruction>,
|
||||||
register_count: usize,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Function {
|
impl Function {
|
||||||
pub fn new(name: &str, instructions: Vec<Instruction>, register_count: usize) -> Self {
|
pub fn new(name: Rc<str>, parameter_count: usize, instructions: Vec<Instruction>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
name: name.into(),
|
name,
|
||||||
|
parameter_count,
|
||||||
instructions,
|
instructions,
|
||||||
register_count,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -24,11 +25,21 @@ impl Function {
|
|||||||
self.name.clone()
|
self.name.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn parameter_count(&self) -> usize {
|
||||||
|
self.parameter_count
|
||||||
|
}
|
||||||
|
|
||||||
pub fn instructions(&self) -> &Vec<Instruction> {
|
pub fn instructions(&self) -> &Vec<Instruction> {
|
||||||
&self.instructions
|
&self.instructions
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn register_count(&self) -> usize {
|
impl Display for Function {
|
||||||
self.register_count
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
writeln!(f, "fn {}", self.name)?;
|
||||||
|
for instruction in &self.instructions {
|
||||||
|
writeln!(f, " {}", instruction)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,6 @@
|
|||||||
use crate::instruction::Instruction;
|
use crate::instruction::{
|
||||||
|
AddOperand, ConstantName, Instruction, Location, MoveOperand, PushOperand, ReturnOperand,
|
||||||
|
};
|
||||||
use crate::platform_function::PlatformFunction;
|
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;
|
||||||
@ -41,28 +43,17 @@ impl DvmContext {
|
|||||||
&mut self.platform_functions
|
&mut self.platform_functions
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated]
|
|
||||||
pub fn add_function(&mut self, function: Function) {
|
|
||||||
self.functions.insert(function.name_owned(), function);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn constants(&self) -> &HashMap<Rc<str>, Constant> {
|
pub fn constants(&self) -> &HashMap<Rc<str>, Constant> {
|
||||||
&self.constants
|
&self.constants
|
||||||
}
|
}
|
||||||
|
|
||||||
#[deprecated]
|
pub fn constants_mut(&mut self) -> &mut HashMap<Rc<str>, Constant> {
|
||||||
pub fn add_constant(&mut self, constant: Constant) {
|
&mut self.constants
|
||||||
match &constant {
|
|
||||||
Constant::String(string_constant) => {
|
|
||||||
self.constants
|
|
||||||
.insert(string_constant.name_owned(), constant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct CallFrame<'a> {
|
pub struct CallFrame<'a> {
|
||||||
function_name: Rc<str>,
|
function: &'a Function,
|
||||||
instructions: &'a Vec<Instruction>,
|
instructions: &'a Vec<Instruction>,
|
||||||
ip: usize,
|
ip: usize,
|
||||||
stack: Vec<Value>,
|
stack: Vec<Value>,
|
||||||
@ -71,10 +62,10 @@ pub struct CallFrame<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> CallFrame<'a> {
|
impl<'a> CallFrame<'a> {
|
||||||
fn new(function_name: Rc<str>, instructions: &'a Vec<Instruction>) -> Self {
|
fn new(function: &'a Function) -> Self {
|
||||||
Self {
|
Self {
|
||||||
function_name,
|
function,
|
||||||
instructions,
|
instructions: function.instructions(),
|
||||||
ip: 0,
|
ip: 0,
|
||||||
stack: vec![],
|
stack: vec![],
|
||||||
fp: 0,
|
fp: 0,
|
||||||
@ -82,8 +73,8 @@ impl<'a> CallFrame<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn function_name(&self) -> &str {
|
fn function(&self) -> &'a Function {
|
||||||
&self.function_name
|
self.function
|
||||||
}
|
}
|
||||||
|
|
||||||
fn instructions(&self) -> &'a [Instruction] {
|
fn instructions(&self) -> &'a [Instruction] {
|
||||||
@ -173,6 +164,55 @@ impl<'a> CallStack<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn load_value<'a>(
|
||||||
|
registers: &'a [Value],
|
||||||
|
stack: &'a [Value],
|
||||||
|
fp: usize,
|
||||||
|
location: &Location,
|
||||||
|
) -> &'a Value {
|
||||||
|
match location {
|
||||||
|
Location::Register(register) => ®isters[*register],
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
let value_index = fp.checked_add_signed(*offset).expect(&format!(
|
||||||
|
"Overflow when adding offset {} to fp {}",
|
||||||
|
*offset, fp
|
||||||
|
));
|
||||||
|
&stack[value_index]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load_constant_value(
|
||||||
|
constants: &HashMap<Rc<str>, Constant>,
|
||||||
|
constant_name: &ConstantName,
|
||||||
|
) -> Value {
|
||||||
|
let constant = &constants[constant_name];
|
||||||
|
match constant {
|
||||||
|
Constant::String(string_constant) => Value::String(string_constant.content_owned()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn put_value(
|
||||||
|
registers: &mut Vec<Value>,
|
||||||
|
stack: &mut Vec<Value>,
|
||||||
|
fp: usize,
|
||||||
|
destination: &Location,
|
||||||
|
value: Value,
|
||||||
|
) {
|
||||||
|
match destination {
|
||||||
|
Location::Register(register) => {
|
||||||
|
registers[*register] = value;
|
||||||
|
}
|
||||||
|
Location::StackFrameOffset(offset) => {
|
||||||
|
let target_index = fp.checked_add_signed(*offset).expect(&format!(
|
||||||
|
"Failed to calculate target index from fp + offset ({} + {})",
|
||||||
|
fp, offset
|
||||||
|
));
|
||||||
|
stack[target_index] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn call<'a>(
|
pub fn call<'a>(
|
||||||
context: &'a DvmContext,
|
context: &'a DvmContext,
|
||||||
registers: &mut Vec<Value>,
|
registers: &mut Vec<Value>,
|
||||||
@ -190,14 +230,8 @@ pub fn call<'a>(
|
|||||||
.get(function_name)
|
.get(function_name)
|
||||||
.expect(&format!("Function {} not found", function_name));
|
.expect(&format!("Function {} not found", function_name));
|
||||||
|
|
||||||
// ensure enough registers
|
|
||||||
registers.resize_with(function.register_count(), Default::default);
|
|
||||||
|
|
||||||
// push call frame
|
// push call frame
|
||||||
call_stack.push(CallFrame::new(
|
call_stack.push(CallFrame::new(function));
|
||||||
function.name_owned(),
|
|
||||||
function.instructions(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// put each arg on the stack
|
// put each arg on the stack
|
||||||
for argument in arguments {
|
for argument in arguments {
|
||||||
@ -214,52 +248,48 @@ pub fn call<'a>(
|
|||||||
|
|
||||||
match instruction {
|
match instruction {
|
||||||
/* Move instructions */
|
/* Move instructions */
|
||||||
Instruction::MoveRegister(source, destination) => {
|
Instruction::Move(source, destination) => {
|
||||||
// copy value from one register to another register
|
// move a value to a destination
|
||||||
let value = registers[*source].clone();
|
// could be a copy or an immediate
|
||||||
registers[*destination] = value;
|
let value = match source {
|
||||||
call_stack.top_mut().increment_ip();
|
MoveOperand::Location(location) => load_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top().stack(),
|
||||||
|
call_stack.top().fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
MoveOperand::Int(i) => Value::Int(*i),
|
||||||
|
MoveOperand::String(constant_name) => {
|
||||||
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
Instruction::MoveInt(value, destination) => {
|
};
|
||||||
registers[*destination] = Value::Int(*value);
|
let fp = call_stack.top().fp();
|
||||||
call_stack.top_mut().increment_ip();
|
put_value(
|
||||||
}
|
registers,
|
||||||
Instruction::MoveStackFrameOffset(offset, destination) => {
|
call_stack.top_mut().stack_mut(),
|
||||||
// copy a value offset from the current frame pointer (fp) to a register
|
fp,
|
||||||
let value_index =
|
destination,
|
||||||
call_stack
|
value,
|
||||||
.top()
|
);
|
||||||
.fp()
|
|
||||||
.checked_add_signed(*offset)
|
|
||||||
.expect(&format!(
|
|
||||||
"Overflow when adding offset {} to fp {}",
|
|
||||||
*offset,
|
|
||||||
call_stack.top().fp()
|
|
||||||
));
|
|
||||||
let value = call_stack.top().stack()[value_index].clone();
|
|
||||||
registers[*destination] = value;
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Push instructions */
|
/* Push instructions */
|
||||||
Instruction::PushRegister(source) => {
|
Instruction::Push(operand) => {
|
||||||
// copy a value from a register to the top of the stack
|
let value = match operand {
|
||||||
let value = registers[*source].clone();
|
PushOperand::Location(location) => load_value(
|
||||||
call_stack.top_mut().stack_mut().push(value);
|
registers,
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top().stack(),
|
||||||
|
call_stack.top().fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
PushOperand::Int(i) => Value::Int(*i),
|
||||||
|
PushOperand::String(constant_name) => {
|
||||||
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
Instruction::PushInt(value) => {
|
};
|
||||||
call_stack.top_mut().stack_mut().push(Value::Int(*value));
|
|
||||||
call_stack.top_mut().increment_ip();
|
|
||||||
}
|
|
||||||
Instruction::PushStackFrameOffset(offset) => {
|
|
||||||
// copy a value from somewhere on the stack to the top of the stack
|
|
||||||
let value_index = call_stack
|
|
||||||
.top()
|
|
||||||
.fp()
|
|
||||||
.checked_add_signed(*offset)
|
|
||||||
.expect("Overflow when adding offset to fp");
|
|
||||||
let value = call_stack.top().stack()[value_index].clone();
|
|
||||||
call_stack.top_mut().stack_mut().push(value);
|
call_stack.top_mut().stack_mut().push(value);
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
@ -279,10 +309,7 @@ pub fn call<'a>(
|
|||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
|
|
||||||
// push a new call frame
|
// push a new call frame
|
||||||
call_stack.push(CallFrame::new(
|
call_stack.push(CallFrame::new(function));
|
||||||
function.name_owned(),
|
|
||||||
function.instructions(),
|
|
||||||
));
|
|
||||||
|
|
||||||
// push args
|
// push args
|
||||||
call_stack.top_mut().stack_mut().append(&mut args);
|
call_stack.top_mut().stack_mut().append(&mut args);
|
||||||
@ -316,62 +343,131 @@ pub fn call<'a>(
|
|||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Load constant instructions */
|
/* Add instructions */
|
||||||
Instruction::LoadStringConstant(constant_name, destination) => {
|
Instruction::Add(left_operand, right_operand, destination) => {
|
||||||
let constant = &context.constants()[constant_name];
|
let left_value = match left_operand {
|
||||||
match constant {
|
AddOperand::Location(location) => load_value(
|
||||||
Constant::String(string_constant) => {
|
registers,
|
||||||
registers[*destination] = Value::String(string_constant.content_owned());
|
call_stack.top().stack(),
|
||||||
|
call_stack.top().fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
AddOperand::Int(i) => Value::Int(*i),
|
||||||
|
AddOperand::String(constant_name) => {
|
||||||
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let right_value = match right_operand {
|
||||||
|
AddOperand::Location(location) => load_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top().stack(),
|
||||||
|
call_stack.top().fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
AddOperand::Int(i) => Value::Int(*i),
|
||||||
|
AddOperand::String(constant_name) => {
|
||||||
|
load_constant_value(context.constants(), constant_name)
|
||||||
}
|
}
|
||||||
call_stack.top_mut().increment_ip();
|
};
|
||||||
|
|
||||||
|
if let Value::Int(left) = left_value {
|
||||||
|
if let Value::Int(right) = right_value {
|
||||||
|
let result = left + right;
|
||||||
|
let fp = call_stack.top().fp();
|
||||||
|
put_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top_mut().stack_mut(),
|
||||||
|
fp,
|
||||||
|
destination,
|
||||||
|
Value::Int(result),
|
||||||
|
);
|
||||||
|
} else if let Value::String(s) = right_value {
|
||||||
|
let result = format!("{}{}", left, s);
|
||||||
|
let fp = call_stack.top().fp();
|
||||||
|
put_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top_mut().stack_mut(),
|
||||||
|
fp,
|
||||||
|
destination,
|
||||||
|
Value::String(result.into()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Attempt to add on non-addable type: {:?}", right_value);
|
||||||
|
}
|
||||||
|
} else if let Value::String(left) = left_value {
|
||||||
|
if let Value::Int(right) = right_value {
|
||||||
|
let result = format!("{}{}", left, right);
|
||||||
|
let fp = call_stack.top().fp();
|
||||||
|
put_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top_mut().stack_mut(),
|
||||||
|
fp,
|
||||||
|
destination,
|
||||||
|
Value::String(result.into()),
|
||||||
|
);
|
||||||
|
} else if let Value::String(right) = right_value {
|
||||||
|
let result = format!("{}{}", left, right);
|
||||||
|
let fp = call_stack.top().fp();
|
||||||
|
put_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top_mut().stack_mut(),
|
||||||
|
fp,
|
||||||
|
destination,
|
||||||
|
Value::String(result.into()),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
panic!("Attempt to add on non-addable type: {:?}", right_value);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
panic!("Attempt to add on non-addable type: {:?}", left_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Add instructions */
|
|
||||||
Instruction::AddIntInt(lhs, rhs, destination) => {
|
|
||||||
let lhs_value = registers[*lhs].unwrap_int();
|
|
||||||
let rhs_value = registers[*rhs].unwrap_int();
|
|
||||||
let result = lhs_value + rhs_value;
|
|
||||||
registers[*destination] = Value::Int(result);
|
|
||||||
call_stack.top_mut().increment_ip();
|
|
||||||
}
|
|
||||||
Instruction::AddStringInt(lhs, rhs, destination) => {
|
|
||||||
let lhs_value = registers[*lhs].unwrap_string();
|
|
||||||
let rhs_value = registers[*rhs].unwrap_int();
|
|
||||||
let formatted = format!("{}{}", lhs_value, rhs_value);
|
|
||||||
registers[*destination] = Value::String(Rc::from(formatted));
|
|
||||||
call_stack.top_mut().increment_ip();
|
|
||||||
}
|
|
||||||
Instruction::AddStringString(lhs, rhs, destination) => {
|
|
||||||
let lhs_value = registers[*lhs].unwrap_string();
|
|
||||||
let rhs_value = registers[*rhs].unwrap_string();
|
|
||||||
let formatted = format!("{}{}", lhs_value, rhs_value);
|
|
||||||
registers[*destination] = Value::String(Rc::from(formatted));
|
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Pop instructions */
|
/* Pop instructions */
|
||||||
Instruction::Pop(maybe_register) => {
|
Instruction::Pop(maybe_location) => {
|
||||||
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
let value = call_stack.top_mut().stack_mut().pop().unwrap();
|
||||||
if let Some(register) = maybe_register {
|
if let Some(location) = maybe_location {
|
||||||
registers[*register] = value;
|
let fp = call_stack.top().fp();
|
||||||
|
put_value(
|
||||||
|
registers,
|
||||||
|
call_stack.top_mut().stack_mut(),
|
||||||
|
fp,
|
||||||
|
location,
|
||||||
|
value,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Return instructions */
|
/* Return instructions */
|
||||||
Instruction::SetReturnValue(register) => {
|
Instruction::SetReturnValue(return_operand) => {
|
||||||
call_stack
|
let value = match return_operand {
|
||||||
.top_mut()
|
ReturnOperand::Location(location) => load_value(
|
||||||
.set_return_value(registers[*register].clone());
|
registers,
|
||||||
|
call_stack.top().stack(),
|
||||||
|
call_stack.top().fp(),
|
||||||
|
location,
|
||||||
|
)
|
||||||
|
.clone(),
|
||||||
|
ReturnOperand::Int(i) => Value::Int(*i),
|
||||||
|
ReturnOperand::String(constant_name) => {
|
||||||
|
load_constant_value(context.constants(), constant_name)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
call_stack.top_mut().set_return_value(value);
|
||||||
call_stack.top_mut().increment_ip();
|
call_stack.top_mut().increment_ip();
|
||||||
}
|
}
|
||||||
|
|
||||||
Instruction::Return(caller_pop_count) => {
|
Instruction::Return => {
|
||||||
let mut callee = call_stack.pop(); // pop this frame
|
let mut callee = call_stack.pop(); // pop this frame
|
||||||
let maybe_caller = call_stack.maybe_top_mut();
|
let maybe_caller = call_stack.maybe_top_mut();
|
||||||
if let Some(caller) = maybe_caller {
|
if let Some(caller) = maybe_caller {
|
||||||
for _ in 0..*caller_pop_count {
|
for _ in 0..callee.function().parameter_count() {
|
||||||
caller.stack_mut().pop();
|
caller.stack_mut().pop();
|
||||||
}
|
}
|
||||||
if let Some(return_value) = callee.take_return_value() {
|
if let Some(return_value) = callee.take_return_value() {
|
||||||
|
|||||||
@ -5,4 +5,6 @@ fn main()
|
|||||||
let b = 2
|
let b = 2
|
||||||
let c = 3
|
let c = 3
|
||||||
let x = a + b + c
|
let x = a + b + c
|
||||||
|
println(x)
|
||||||
|
println(a)
|
||||||
end
|
end
|
||||||
Loading…
Reference in New Issue
Block a user