Introduce asm representation (between ir and vm instructions).

This commit is contained in:
Jesse Brault 2025-11-21 21:38:12 -06:00
parent 9dfdcd716b
commit 026bc68fa7
11 changed files with 1027 additions and 45 deletions

View File

@ -2,4 +2,7 @@ use std::core::println
fn main(args: Array<String>)
let hello = 42
let world = hello + 16
println(hello)
println(world)
end

260
src/asm/assemble_ir.rs Normal file
View File

@ -0,0 +1,260 @@
use crate::asm::{AsmBinaryOperator, AsmFunction, AsmInstruction, AsmOperand, ControlUnit, ControlUnitId, VirtualRegisterId};
use crate::ir::{IrAssign, IrBinaryOperation, IrBinaryOperator, IrCall, IrCallType, IrExpression, IrFunction, IrLiteral, IrReturn, IrStatement};
use std::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc;
struct AssemblyContext {
control_unit_counter: ControlUnitId,
control_units: Vec<ControlUnit>,
virtual_register_counter: VirtualRegisterId,
virtual_registers: HashMap<Rc<str>, VirtualRegisterId>,
}
impl AssemblyContext {
pub fn new() -> Self {
Self {
control_unit_counter: 0,
control_units: Vec::new(),
virtual_register_counter: 0,
virtual_registers: HashMap::new(),
}
}
fn next_control_unit_id(&mut self) -> ControlUnitId {
let id = self.control_unit_counter;
self.control_unit_counter += 1;
id
}
pub fn new_control_unit(&mut self) -> ControlUnitId {
let new_id = self.next_control_unit_id();
self.control_units.push(ControlUnit::new(new_id));
new_id
}
pub fn current_control_unit(&mut self) -> &ControlUnit {
if self.control_units.is_empty() {
self.new_control_unit();
}
self.control_units.last().unwrap()
}
pub fn current_control_unit_mut(&mut self) -> &mut ControlUnit {
if self.control_units.is_empty() {
self.new_control_unit();
}
self.control_units.last_mut().unwrap()
}
pub fn into_control_units(self) -> Vec<ControlUnit> {
self.control_units
}
pub fn get_virtual_register(&self, name: &str) -> VirtualRegisterId {
*self
.virtual_registers
.get(name)
.expect(&format!("Did not set a virtual register for name {}", name))
}
pub fn next_virtual_register(&mut self, name: &str) -> VirtualRegisterId {
if self.virtual_registers.contains_key(name) {
panic!(
"Should not already have a virtual register with name {}",
name
);
}
let virtual_register_id = self.virtual_register_counter;
self.virtual_register_counter += 1;
self.virtual_registers
.insert(name.into(), virtual_register_id);
virtual_register_id
}
}
pub fn assemble_ir_function(ir_function: &IrFunction) -> AsmFunction {
let mut context = AssemblyContext::new();
// body
for statement in ir_function.statements() {
assemble_ir_statement(statement, &mut context);
}
AsmFunction::new(ir_function.name().into(), context.into_control_units())
}
fn assemble_ir_statement(ir_statement: &IrStatement, context: &mut AssemblyContext) {
match ir_statement {
IrStatement::Allocate(_) => {
todo!()
}
IrStatement::Call(ir_call) => {
assemble_ir_call(ir_call, context);
}
IrStatement::Return(ir_return) => {
assemble_ir_return(ir_return, context);
}
IrStatement::Assign(ir_assign) => {
assemble_ir_assign(ir_assign, context);
}
IrStatement::MakeClosure(_) => {
todo!()
}
IrStatement::BinaryOperation(ir_binary_operation) => {
assemble_ir_binary_operation(ir_binary_operation, context)
}
}
}
fn assemble_ir_assign(ir_assign: &IrAssign, context: &mut AssemblyContext) {
let source_operand = match ir_assign.rhs() {
IrExpression::Variable(ir_variable) => {
let virtual_register_id = context.get_virtual_register(ir_variable.name());
AsmOperand::VirtualRegister(virtual_register_id)
}
IrExpression::ConstRef(ir_const_ref) => AsmOperand::Constant {
name: ir_const_ref.name_owned(),
},
IrExpression::Literal(ir_literal) => ir_literal_to_asm_operand(ir_literal),
};
let destination = context.next_virtual_register(ir_assign.lhs().name());
context
.current_control_unit_mut()
.append_instruction(AsmInstruction::Move {
source: source_operand,
destination,
})
}
fn ir_literal_to_asm_operand(ir_literal: &IrLiteral) -> AsmOperand {
match ir_literal {
IrLiteral::I8(i) => AsmOperand::I8(*i),
IrLiteral::I16(i) => AsmOperand::I16(*i),
IrLiteral::I32(i) => AsmOperand::I32(*i),
IrLiteral::I64(i) => AsmOperand::I64(*i),
IrLiteral::I128(i) => AsmOperand::I128(*i),
IrLiteral::ISize(i) => AsmOperand::ISize(*i),
IrLiteral::U8(u) => AsmOperand::U8(*u),
IrLiteral::U16(u) => AsmOperand::U16(*u),
IrLiteral::U32(u) => AsmOperand::U32(*u),
IrLiteral::U64(u) => AsmOperand::U64(*u),
IrLiteral::U128(u) => AsmOperand::U128(*u),
IrLiteral::USize(u) => AsmOperand::USize(*u),
IrLiteral::Boolean(b) => AsmOperand::Boolean(*b),
IrLiteral::Float(f) => AsmOperand::Float(*f),
IrLiteral::Double(d) => AsmOperand::Double(*d),
}
}
fn assemble_ir_call(ir_call: &IrCall, context: &mut AssemblyContext) {
// push args
for argument in ir_call.arguments() {
match argument {
IrExpression::Variable(ir_variable) => {
let variable_register_id = context.get_virtual_register(ir_variable.name());
context
.current_control_unit_mut()
.append_instruction(AsmInstruction::Push {
source: AsmOperand::VirtualRegister(variable_register_id),
})
}
IrExpression::ConstRef(ir_const_ref) => context
.current_control_unit_mut()
.append_instruction(AsmInstruction::Push {
source: AsmOperand::Constant {
name: ir_const_ref.name_owned(),
},
}),
IrExpression::Literal(ir_literal) => context
.current_control_unit_mut()
.append_instruction(AsmInstruction::Push {
source: ir_literal_to_asm_operand(ir_literal),
}),
}
}
// issue call
match ir_call.call_type() {
IrCallType::Static => {
context
.current_control_unit_mut()
.append_instruction(AsmInstruction::InvokeStatic {
fqn: ir_call.function_name_owned(),
});
}
IrCallType::Object => {
context
.current_control_unit_mut()
.append_instruction(AsmInstruction::InvokeObject {
fqn: ir_call.function_name_owned(),
})
}
}
}
fn assemble_ir_return(ir_return: &IrReturn, context: &mut AssemblyContext) {
let operand = match ir_return.expression() {
IrExpression::Variable(ir_variable) => {
let variable_virtual_register_id = context.get_virtual_register(ir_variable.name());
AsmOperand::VirtualRegister(variable_virtual_register_id)
}
IrExpression::ConstRef(ir_const_ref) => AsmOperand::Constant {
name: ir_const_ref.name_owned(),
},
IrExpression::Literal(ir_literal) => ir_literal_to_asm_operand(ir_literal),
};
context
.current_control_unit_mut()
.append_instruction(AsmInstruction::Return { operand });
}
fn assemble_ir_binary_operation(ir_binary_operation: &IrBinaryOperation, context: &mut AssemblyContext) {
let left = match ir_binary_operation.left() {
IrExpression::Variable(ir_variable) => {
AsmOperand::VirtualRegister(context.get_virtual_register(ir_variable.name()))
}
IrExpression::ConstRef(ir_const_ref) => {
unreachable!("Cannot assemble binary operation with a lhs IrConstRef")
}
IrExpression::Literal(ir_literal) => {
ir_literal_to_asm_operand(ir_literal)
}
};
let right = match ir_binary_operation.right() {
IrExpression::Variable(ir_variable) => {
AsmOperand::VirtualRegister(context.get_virtual_register(ir_variable.name()))
},
IrExpression::ConstRef(ir_const_ref) => {
unreachable!("Cannot assemble binary operation with a rhs IrConstRef")
}
IrExpression::Literal(ir_literal) => {
ir_literal_to_asm_operand(ir_literal)
}
};
let destination = context.next_virtual_register(ir_binary_operation.destination().name());
let operator = match ir_binary_operation.operator() {
IrBinaryOperator::Add => {
AsmBinaryOperator::Add
}
IrBinaryOperator::Subtract => {
AsmBinaryOperator::Subtract
}
IrBinaryOperator::Multiply => {
AsmBinaryOperator::Multiply
}
IrBinaryOperator::Divide => {
AsmBinaryOperator::Divide
}
IrBinaryOperator::Exponent => {
todo!()
}
};
let instruction = AsmInstruction::BinaryOperation {
destination,
left,
right,
operator
};
context.current_control_unit_mut().append_instruction(instruction);
}

240
src/asm/mod.rs Normal file
View File

@ -0,0 +1,240 @@
pub mod assemble_ir;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub type ControlUnitId = usize;
pub type VirtualRegisterId = u32;
pub struct AsmFunction {
fqn: Rc<str>,
control_units: Vec<ControlUnit>,
}
impl AsmFunction {
pub fn new(fqn: Rc<str>, control_units: Vec<ControlUnit>) -> Self {
Self { fqn, control_units }
}
}
impl Display for AsmFunction {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writeln!(f, "fn {}", self.fqn)?;
for control_unit in &self.control_units {
writeln!(f, " #{}:", control_unit.id)?;
for instruction in &control_unit.instructions {
writeln!(f, " {}", instruction)?;
}
}
Ok(())
}
}
pub struct ControlUnit {
id: ControlUnitId,
successor_ids: Vec<ControlUnitId>,
instructions: Vec<AsmInstruction>,
}
impl ControlUnit {
pub fn new(id: ControlUnitId) -> Self {
Self {
id,
successor_ids: vec![],
instructions: vec![],
}
}
pub fn append_instruction(&mut self, instruction: AsmInstruction) {
self.instructions.push(instruction);
}
pub fn append_instructions(&mut self, instructions: Vec<AsmInstruction>) {
self.instructions.extend(instructions);
}
}
pub enum AsmInstruction {
Goto {
control_unit_id: ControlUnitId,
},
Move {
source: AsmOperand,
destination: VirtualRegisterId,
},
Push {
source: AsmOperand,
},
Pop {
destination: VirtualRegisterId,
},
Allocate {
class_name: Rc<str>,
destination: VirtualRegisterId,
},
InvokeStatic {
fqn: Rc<str>,
},
InvokeObject {
fqn: Rc<str>,
},
Return {
operand: AsmOperand,
},
BinaryOperation {
destination: VirtualRegisterId,
left: AsmOperand,
right: AsmOperand,
operator: AsmBinaryOperator,
},
}
impl Display for AsmInstruction {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AsmInstruction::Goto { control_unit_id } => {
write!(f, "goto #{}", control_unit_id)
}
AsmInstruction::Move {
source,
destination,
} => {
write!(f, "move vr{}, {}", destination, source)
}
AsmInstruction::Push { source } => {
write!(f, "push {}", source)
}
AsmInstruction::Pop { destination } => {
write!(f, "pop vr{}", destination)
}
AsmInstruction::Allocate {
class_name,
destination,
} => {
write!(f, "allocate r{}, {}", destination, class_name)
}
AsmInstruction::InvokeStatic { fqn } => {
write!(f, "invoke_static {}", fqn)
}
AsmInstruction::InvokeObject { fqn } => {
write!(f, "invoke_object {}", fqn)
}
AsmInstruction::Return { operand } => {
write!(f, "return {}", operand)
}
AsmInstruction::BinaryOperation {
destination,
left,
right,
operator,
} => {
write!(f, "op{} vr{}, {}, {}", operator, destination, left, right)
}
}
}
}
pub enum AsmOperand {
I8(i8),
I16(i16),
I32(i32),
I64(i64),
I128(i128),
ISize(isize),
U8(u8),
U16(u16),
U32(u32),
U64(u64),
U128(u128),
USize(usize),
Float(f32),
Double(f64),
Boolean(bool),
Constant { name: Rc<str> },
VirtualRegister(VirtualRegisterId),
}
impl Display for AsmOperand {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AsmOperand::I8(i) => {
write!(f, "{}i8", i)
}
AsmOperand::I16(i) => {
write!(f, "{}i16", i)
}
AsmOperand::I32(i) => {
write!(f, "{}i32", i)
}
AsmOperand::I64(i) => {
write!(f, "{}i64", i)
}
AsmOperand::I128(i) => {
write!(f, "{}i128", i)
}
AsmOperand::ISize(i) => {
write!(f, "{}isize", i)
}
AsmOperand::U8(u) => {
write!(f, "{}u8", u)
}
AsmOperand::U16(u) => {
write!(f, "{}u16", u)
}
AsmOperand::U32(u) => {
write!(f, "{}u32", u)
}
AsmOperand::U64(u) => {
write!(f, "{}u64", u)
}
AsmOperand::U128(u) => {
write!(f, "{}u128", u)
}
AsmOperand::USize(u) => {
write!(f, "{}usize", u)
}
AsmOperand::Float(float) => {
write!(f, "{}f32", float)
}
AsmOperand::Double(d) => {
write!(f, "{}f64", d)
}
AsmOperand::Boolean(b) => {
write!(f, "{}", b)
}
AsmOperand::Constant { name } => {
write!(f, "<{}>", name)
}
AsmOperand::VirtualRegister(id) => {
write!(f, "vr{}", id)
}
}
}
}
pub enum AsmBinaryOperator {
Add,
Subtract,
Multiply,
Divide,
}
impl Display for AsmBinaryOperator {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
AsmBinaryOperator::Add => {
write!(f, "+")
}
AsmBinaryOperator::Subtract => {
write!(f, "-")
}
AsmBinaryOperator::Multiply => {
write!(f, "*")
}
AsmBinaryOperator::Divide => {
write!(f, "/")
}
}
}
}

View File

@ -1,14 +1,16 @@
use std::path::PathBuf;
use deimos::ast::node::CompilationUnit;
use deimos::ir::Ir;
use deimos::ir::lower_ast::lower_compilation_unit;
use deimos::ir::lower_ir::lower_ir_function;
use deimos::util::indent_writer::IndentWriter;
use crate::name_analysis::name_analysis;
use deimos::asm::assemble_ir::assemble_ir_function;
use deimos::ast::node::CompilationUnit;
use deimos::ir::lower_ast::lower_compilation_unit;
use deimos::ir::Ir;
use deimos::util::indent_writer::IndentWriter;
use std::path::PathBuf;
pub fn compile_to_ir(paths: &[PathBuf]) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
pub fn compile_to_ir(
paths: &[PathBuf],
) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
let compilation_units = name_analysis(&paths)?;
for compilation_unit in &compilation_units {
let cu_irs = lower_compilation_unit(compilation_unit);
let mut out = String::new();
@ -17,17 +19,17 @@ pub fn compile_to_ir(paths: &[PathBuf]) -> Result<Vec<CompilationUnit>, Box<dyn
ir.pretty_print(&mut indent_writer)?;
}
println!("{}", &out);
for ir in &cu_irs {
match ir {
Ir::Function(ir_function) => {
let instructions = lower_ir_function(ir_function);
println!("{:#?}", instructions);
let asm_function = assemble_ir_function(ir_function);
println!("{}", asm_function);
}
_ => {}
}
}
}
Ok(compilation_units)
}
}

View File

@ -1,15 +1,15 @@
use crate::ast::node::{
CompilationUnit, Expression, Function, FunctionBlockBody, FunctionBody, Literal,
ModuleLevelDeclaration, Statement, VariableDeclaration,
};
use crate::ast::node::{AdditiveExpression, AdditiveOperator, Call, Closure, CompilationUnit, Expression, ExpressionList, ExpressionStatement, Function, FunctionBlockBody, FunctionBody, Identifier, Literal, ModuleLevelDeclaration, Statement, SuffixExpression, SuffixOperator, VariableDeclaration};
use crate::ir::{
Ir, IrAssign, IrConst, IrExpression, IrFunction, IrKind, IrLiteral, IrPrimitiveKind,
IrStatement, IrVariable,
Ir, IrAssign, IrBinaryOperation, IrBinaryOperator, IrCall, IrCallType, IrConst, IrExpression,
IrFunction, IrKind, IrLiteral, IrPrimitiveKind, IrStatement, IrVariable,
};
use crate::name_analysis::symbol::{
ExpressibleSymbol, ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol,
};
use crate::name_analysis::symbol::{ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol};
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use crate::ir::IrStatement::BinaryOperation;
pub fn lower_compilation_unit(compilation_unit: &CompilationUnit) -> Vec<Ir> {
let mut result: Vec<Ir> = vec![];
@ -66,7 +66,7 @@ impl LocalsTable {
self.stack_slot_count += 1;
self.stack_slots.insert(ir_variable.clone(), stack_slot);
}
pub fn get_stack_slot(&self, ir_variable: &IrVariable) -> usize {
*self.stack_slots.get(ir_variable).unwrap()
}
@ -146,7 +146,7 @@ fn lower_primitive_type_symbol(primitive_type_symbol: &PrimitiveTypeSymbol) -> I
fn lower_function_body(
function_body: &FunctionBody,
locals_table: &mut LocalsTable
locals_table: &mut LocalsTable,
) -> (Vec<IrStatement>, Vec<IrConst>) {
match function_body {
FunctionBody::FunctionAliasBody(alias_body) => {
@ -163,7 +163,7 @@ fn lower_function_body(
fn lower_function_block_body(
body: &FunctionBlockBody,
locals_table: &mut LocalsTable
locals_table: &mut LocalsTable,
) -> (Vec<IrStatement>, Vec<IrConst>) {
let mut statements: Vec<IrStatement> = vec![];
let mut consts: Vec<IrConst> = vec![];
@ -176,7 +176,7 @@ fn lower_function_block_body(
fn lower_statement(
statement: &Statement,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
locals_table: &mut LocalsTable,
) -> Vec<IrStatement> {
match statement {
Statement::VariableDeclaration(variable_declaration) => {
@ -186,7 +186,7 @@ fn lower_statement(
todo!()
}
Statement::ExpressionStatement(expression_statement) => {
todo!()
lower_expression_statement(expression_statement, consts_pool, locals_table)
}
Statement::UseStatement(use_statement) => {
todo!()
@ -206,7 +206,7 @@ fn lower_statement(
fn lower_variable_declaration(
variable_declaration: &VariableDeclaration,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
locals_table: &mut LocalsTable,
) -> Vec<IrStatement> {
let mut result: Vec<IrStatement> = vec![];
let expression_t_var = lower_expression(
@ -225,11 +225,26 @@ fn lower_variable_declaration(
result
}
fn lower_expression_statement(
expression_statement: &ExpressionStatement,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> Vec<IrStatement> {
let mut result: Vec<IrStatement> = vec![];
lower_expression(
expression_statement.expression(),
&mut result,
consts_pool,
locals_table,
);
result
}
fn lower_expression(
expression: &Expression,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
locals_table: &mut LocalsTable,
) -> IrVariable {
match expression {
Expression::Ternary(ternary) => {
@ -248,7 +263,7 @@ fn lower_expression(
todo!()
}
Expression::Additive(additive) => {
todo!()
lower_additive_expression(additive, target, consts_pool, locals_table)
}
Expression::Multiplicative(multiplicative) => {
todo!()
@ -257,12 +272,15 @@ fn lower_expression(
todo!()
}
Expression::Suffix(suffix) => {
todo!()
lower_suffix_expression(suffix, target, consts_pool, locals_table)
}
Expression::Literal(literal) => lower_literal(literal, target, consts_pool, locals_table),
Expression::Identifier(identifier) => {
todo!()
}
Expression::Identifier(identifier_expression) => lower_identifier(
identifier_expression.identifier(),
target,
consts_pool,
locals_table,
),
Expression::Fqn(fqn) => {
todo!()
}
@ -275,11 +293,62 @@ fn lower_expression(
}
}
fn lower_suffix_expression(
suffix_expression: &SuffixExpression,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> IrVariable {
let receiver_variable = lower_expression(
suffix_expression.expression(),
target,
consts_pool,
locals_table,
);
match suffix_expression.operator() {
SuffixOperator::PlusPlus => {
let result_var = locals_table.next_t_var();
let operation = IrBinaryOperation::new(
result_var.clone(),
IrExpression::Variable(receiver_variable.into()),
IrExpression::Literal(IrLiteral::I32(1).into()),
IrBinaryOperator::Add,
);
target.push(IrStatement::BinaryOperation(operation));
result_var
}
SuffixOperator::MinusMinus => {
let result_var = locals_table.next_t_var();
let operation = IrBinaryOperation::new(
result_var.clone(),
IrExpression::Variable(receiver_variable.into()),
IrExpression::Literal(IrLiteral::I32(1).into()),
IrBinaryOperator::Subtract,
);
target.push(IrStatement::BinaryOperation(operation));
result_var
}
SuffixOperator::ObjectIndex(object_index) => {
todo!()
}
SuffixOperator::Call(call) => lower_call(
call,
suffix_expression.expression(),
target,
consts_pool,
locals_table,
),
SuffixOperator::ObjectProperty(object_property) => {
todo!()
}
}
}
fn lower_literal(
literal: &Literal,
statements: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable
locals_table: &mut LocalsTable,
) -> IrVariable {
match literal {
Literal::IntLiteral(int_literal) => {
@ -313,3 +382,288 @@ fn lower_literal(
}
}
}
fn lower_call(
call: &Call,
receiver: &Expression,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> IrVariable {
let fqn = match receiver {
Expression::Ternary(_) => {
todo!()
}
Expression::Or(_) => {
todo!()
}
Expression::And(_) => {
todo!()
}
Expression::Comparison(_) => {
todo!()
}
Expression::Shift(_) => {
todo!()
}
Expression::Additive(_) => {
todo!()
}
Expression::Multiplicative(_) => {
todo!()
}
Expression::Prefix(_) => {
todo!()
}
Expression::Suffix(_) => {
todo!()
}
Expression::Literal(_) => {
todo!()
}
Expression::Identifier(identifier_expression) => {
match identifier_expression.expressible_symbol().unwrap() {
ExpressibleSymbol::Class(class_symbol) => {
todo!()
}
ExpressibleSymbol::Function(function_symbol) => {
function_symbol.borrow().fqn_formatted()
}
ExpressibleSymbol::ClassMember(class_member_symbol) => {
todo!()
}
ExpressibleSymbol::Parameter(parameter_symbol) => {
todo!()
}
ExpressibleSymbol::Variable(variable_symbol) => {
todo!()
}
}
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(_) => {
todo!()
}
Expression::List(_) => {
todo!()
}
};
let declared_type = match receiver {
Expression::Ternary(_) => {
todo!()
}
Expression::Or(_) => {
todo!()
}
Expression::And(_) => {
todo!()
}
Expression::Comparison(_) => {
todo!()
}
Expression::Shift(_) => {
todo!()
}
Expression::Additive(_) => {
todo!()
}
Expression::Multiplicative(_) => {
todo!()
}
Expression::Prefix(_) => {
todo!()
}
Expression::Suffix(_) => {
todo!()
}
Expression::Literal(_) => {
todo!()
}
Expression::Identifier(identifier_expression) => {
match identifier_expression.expressible_symbol().unwrap() {
ExpressibleSymbol::Class(_) => {
todo!()
}
ExpressibleSymbol::Function(function_symbol) => {
match function_symbol.borrow().return_type().expect(&format!(
"Expected return type for fn {}",
function_symbol.borrow().fqn_formatted()
)) {
TypeSymbol::Primitive(primitive_type_symbol) => match primitive_type_symbol
{
PrimitiveTypeSymbol::Byte => {
IrKind::Primitive(IrPrimitiveKind::I8.into())
}
PrimitiveTypeSymbol::Char => {
todo!()
}
PrimitiveTypeSymbol::Short => {
IrKind::Primitive(IrPrimitiveKind::I16.into())
}
PrimitiveTypeSymbol::Int => {
IrKind::Primitive(IrPrimitiveKind::I32.into())
}
PrimitiveTypeSymbol::Long => {
IrKind::Primitive(IrPrimitiveKind::I64.into())
}
PrimitiveTypeSymbol::Float => {
IrKind::Primitive(IrPrimitiveKind::Float.into())
}
PrimitiveTypeSymbol::Double => {
IrKind::Primitive(IrPrimitiveKind::Double.into())
}
PrimitiveTypeSymbol::Boolean => {
IrKind::Primitive(IrPrimitiveKind::Boolean.into())
}
PrimitiveTypeSymbol::String => {
IrKind::Primitive(IrPrimitiveKind::String.into())
}
PrimitiveTypeSymbol::TypedArray { inner_type } => {
todo!()
}
PrimitiveTypeSymbol::Any => {
IrKind::Primitive(IrPrimitiveKind::Any.into())
}
PrimitiveTypeSymbol::Void => {
IrKind::Primitive(IrPrimitiveKind::Void.into())
}
},
TypeSymbol::Class(class_symbol) => {
todo!()
}
TypeSymbol::Interface(interface_symbol) => {
todo!()
}
TypeSymbol::Generic(generic_symbol) => {
todo!()
}
}
}
ExpressibleSymbol::ClassMember(_) => {
todo!()
}
ExpressibleSymbol::Parameter(_) => {
todo!()
}
ExpressibleSymbol::Variable(_) => {
todo!()
}
}
}
Expression::Fqn(_) => {
todo!()
}
Expression::Closure(_) => {
todo!()
}
Expression::List(_) => {
todo!()
}
};
let arg_vars = match call {
Call::ParenthesesCall(p_call) => {
let mut arg_vars: Vec<IrVariable> = vec![];
if let Some(expression_list) = p_call.expression_list() {
arg_vars.append(&mut lower_expression_list(
expression_list,
target,
consts_pool,
locals_table,
));
}
if let Some(closure) = p_call.closure() {
arg_vars.push(lower_closure(closure, target, consts_pool, locals_table));
}
arg_vars
}
Call::ClosureOnlyCall(c_call) => {
vec![lower_closure(
c_call.closure(),
target,
consts_pool,
locals_table,
)]
}
};
let arg_expressions = arg_vars
.iter()
.map(|ir_variable| IrExpression::Variable(ir_variable.clone().into()))
.collect::<Vec<_>>();
let result_var = locals_table.next_t_var();
let call = IrCall::new(
result_var.name(),
declared_type.into(),
&fqn,
IrCallType::Static,
arg_expressions,
);
target.push(IrStatement::Call(call));
result_var
}
fn lower_expression_list(
expression_list: &ExpressionList,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> Vec<IrVariable> {
let mut results: Vec<IrVariable> = vec![];
for expression in expression_list.expressions() {
results.push(lower_expression(
expression,
target,
consts_pool,
locals_table,
));
}
results
}
fn lower_closure(
closure: &Closure,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> IrVariable {
todo!()
}
fn lower_identifier(
identifier: &Identifier,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> IrVariable {
IrVariable::new(identifier.name())
}
fn lower_additive_expression(
additive: &AdditiveExpression,
target: &mut Vec<IrStatement>,
consts_pool: &mut Vec<IrConst>,
locals_table: &mut LocalsTable,
) -> IrVariable {
let left_var = lower_expression(additive.left(), target, consts_pool, locals_table);
let right_var = lower_expression(additive.rhs().expression(), target, consts_pool, locals_table);
let destination = locals_table.next_t_var();
let operator = match additive.rhs().operator() {
AdditiveOperator::Add => {
IrBinaryOperator::Add
}
AdditiveOperator::Subtract => {
IrBinaryOperator::Subtract
}
};
let operation = IrBinaryOperation::new(
destination.clone(),
IrExpression::Variable(left_var.into()),
IrExpression::Variable(right_var.into()),
operator
);
target.push(IrStatement::BinaryOperation(operation));
destination
}

View File

@ -26,6 +26,9 @@ fn lower_ir_statement(ir_statement: &IrStatement, locals_table: &LocalsTable) ->
IrStatement::MakeClosure(make_closure) => {
todo!()
}
IrStatement::BinaryOperation(binary_operation) => {
todo!()
}
}
}

View File

@ -1,5 +1,7 @@
use crate::ir::lower_ast::LocalsTable;
use crate::util::indent_writer::IndentWriter;
use std::fmt::{Display, Formatter};
use std::rc::Rc;
pub mod lower_ast;
pub mod lower_ir;
@ -102,6 +104,7 @@ pub enum IrPrimitiveKind {
String,
Closure(Box<IrClosureKind>),
Ref(Box<IrKind>),
Any,
Void,
}
@ -134,6 +137,7 @@ impl IrPrimitiveKind {
IrPrimitiveKind::Ref(ref_kind) => {
todo!()
}
IrPrimitiveKind::Any => writer.write("Any"),
IrPrimitiveKind::Void => writer.write("Void"),
}
}
@ -262,6 +266,7 @@ pub enum IrStatement {
Return(IrReturn),
Assign(IrAssign),
MakeClosure(IrMakeClosure),
BinaryOperation(IrBinaryOperation),
}
impl IrStatement {
@ -272,6 +277,7 @@ impl IrStatement {
IrStatement::Return(ir_return) => ir_return.pretty_print(writer),
IrStatement::Assign(assign) => assign.pretty_print(writer),
IrStatement::MakeClosure(make_closure) => make_closure.pretty_print(writer),
IrStatement::BinaryOperation(binary_operation) => binary_operation.pretty_print(writer),
}
}
}
@ -362,6 +368,86 @@ impl IrAllocate {
}
}
pub struct IrBinaryOperation {
destination: Box<IrVariable>,
left: Box<IrExpression>,
right: Box<IrExpression>,
operator: IrBinaryOperator,
}
impl IrBinaryOperation {
pub fn new(
destination: IrVariable,
left: IrExpression,
right: IrExpression,
operator: IrBinaryOperator,
) -> Self {
Self {
destination: destination.into(),
left: left.into(),
right: right.into(),
operator,
}
}
pub fn destination(&self) -> &IrVariable {
&self.destination
}
pub fn left(&self) -> &IrExpression {
&self.left
}
pub fn right(&self) -> &IrExpression {
&self.right
}
pub fn operator(&self) -> &IrBinaryOperator {
&self.operator
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write_indented("")?;
self.destination.pretty_print(writer)?;
writer.write(" = ")?;
self.left.pretty_print(writer)?;
writer.write(&format!(" {} ", self.operator))?;
self.right.pretty_print(writer)?;
writer.writeln("")?;
Ok(())
}
}
pub enum IrBinaryOperator {
Add,
Subtract,
Multiply,
Divide,
Exponent,
}
impl Display for IrBinaryOperator {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IrBinaryOperator::Add => {
write!(f, "+")
}
IrBinaryOperator::Subtract => {
write!(f, "-")
}
IrBinaryOperator::Multiply => {
write!(f, "*")
}
IrBinaryOperator::Divide => {
write!(f, "/")
}
IrBinaryOperator::Exponent => {
write!(f, "^")
}
}
}
}
pub enum IrConst {
String(IrStringConst),
StringArray(IrStringArrayConst),
@ -421,10 +507,22 @@ impl IrVariable {
}
pub struct IrConstRef {
name: String,
name: Rc<str>,
}
impl IrConstRef {
pub fn new(name: Rc<str>) -> Self {
Self { name }
}
pub fn name(&self) -> &str {
&self.name
}
pub fn name_owned(&self) -> Rc<str> {
self.name.clone()
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write(&self.name)
}
@ -473,7 +571,8 @@ impl IrLiteral {
pub struct IrCall {
result_name: String,
declared_type: Box<IrKind>,
function_name: String,
fqn: Rc<str>,
call_type: IrCallType,
arguments: Vec<IrExpression>,
}
@ -481,13 +580,15 @@ impl IrCall {
pub fn new(
result_name: &str,
declared_type: Box<IrKind>,
function_name: &str,
fqn: &str,
call_type: IrCallType,
arguments: Vec<IrExpression>,
) -> Self {
Self {
result_name: result_name.to_string(),
declared_type,
function_name: function_name.to_string(),
fqn: fqn.into(),
call_type,
arguments,
}
}
@ -501,7 +602,15 @@ impl IrCall {
}
pub fn function_name(&self) -> &str {
&self.function_name
&self.fqn
}
pub fn function_name_owned(&self) -> Rc<str> {
self.fqn.clone()
}
pub fn call_type(&self) -> &IrCallType {
&self.call_type
}
pub fn arguments(&self) -> &[IrExpression] {
@ -509,9 +618,9 @@ impl IrCall {
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write_indented(&format!("let {}: ", self.result_name))?;
writer.write_indented(&format!("{}: ", self.result_name))?;
self.declared_type.pretty_print(writer)?;
writer.write(&format!(" = call {}(", self.function_name))?;
writer.write(&format!(" = call {}(", self.fqn))?;
for (i, argument) in self.arguments.iter().enumerate() {
argument.pretty_print(writer)?;
if i != self.arguments.len() - 1 {
@ -523,6 +632,11 @@ impl IrCall {
}
}
pub enum IrCallType {
Static,
Object,
}
pub struct IrAssign {
lhs: Box<IrVariable>,
rhs: Box<IrExpression>,
@ -532,11 +646,11 @@ impl IrAssign {
pub fn new(lhs: Box<IrVariable>, rhs: Box<IrExpression>) -> Self {
Self { lhs, rhs }
}
pub fn lhs(&self) -> &IrVariable {
&self.lhs
}
pub fn rhs(&self) -> &IrExpression {
&self.rhs
}
@ -560,7 +674,7 @@ impl IrReturn {
Self { expression }
}
pub fn expression(&self) -> &Box<IrExpression> {
pub fn expression(&self) -> &IrExpression {
&self.expression
}

View File

@ -4,6 +4,7 @@
#![allow(warnings)]
extern crate core;
pub mod asm;
pub mod ast;
pub mod diagnostic;
pub mod ir;

View File

@ -629,7 +629,8 @@ fn na_p2_expression(
todo!()
}
Expression::Additive(additive) => {
todo!()
na_p2_expression(additive.left_mut(), symbol_table, diagnostics);
na_p2_expression(additive.rhs_mut().expression_mut(), symbol_table, diagnostics);
}
Expression::Multiplicative(multiplicative) => {
todo!()

View File

@ -50,6 +50,10 @@ impl FunctionSymbol {
return_type,
}
}
pub fn fqn_formatted(&self) -> String {
self.fqn_parts.join("::")
}
pub fn fqn_parts_owned(&self) -> Vec<Rc<str>> {
self.fqn_parts.to_vec()

View File

@ -24,7 +24,7 @@ pub fn add_std_core_symbols(symbol_table: &mut SymbolTable) -> Result<(), Symbol
true,
None,
&vec![Rc::new(RefCell::new(println_msg_symbol))],
None,
Some(TypeSymbol::Primitive(PrimitiveTypeSymbol::Void)),
);
symbol_table.register_function_symbol(println_symbol);