Compare commits

...

3 Commits

Author SHA1 Message Date
Jesse Brault
734a00ea92 Beginnings of type analysis. 2025-11-22 17:59:08 -06:00
Jesse Brault
8d73a8ea73 Update ast schema. 2025-11-22 16:50:32 -06:00
Jesse Brault
70aea0ba6f Rewrite pretty_print as Display impl; tweaking ir. 2025-11-22 16:31:08 -06:00
20 changed files with 1296 additions and 1021 deletions

View File

@ -135,6 +135,7 @@ fn generate_node_file(build_specs: &[BuildSpec]) -> AstGeneratedFile {
use std::rc::Rc; use std::rc::Rc;
use std::cell::RefCell; use std::cell::RefCell;
use crate::name_analysis::symbol::*; use crate::name_analysis::symbol::*;
use crate::type_analysis::kinds::*;
#(#types)* #(#types)*
}; };

View File

@ -1,7 +1,12 @@
use crate::asm::{AsmBinaryOperator, AsmFunction, AsmInstruction, AsmOperand, ControlUnit, ControlUnitId, VirtualRegisterId}; use crate::asm::{
use crate::ir::{IrAssign, IrBinaryOperation, IrBinaryOperator, IrCall, IrCallType, IrExpression, IrFunction, IrLiteral, IrReturn, IrStatement}; 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::collections::HashMap;
use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
struct AssemblyContext { struct AssemblyContext {
@ -81,7 +86,7 @@ pub fn assemble_ir_function(ir_function: &IrFunction) -> AsmFunction {
assemble_ir_statement(statement, &mut context); assemble_ir_statement(statement, &mut context);
} }
AsmFunction::new(ir_function.name().into(), context.into_control_units()) AsmFunction::new(ir_function.fqn().into(), context.into_control_units())
} }
fn assemble_ir_statement(ir_statement: &IrStatement, context: &mut AssemblyContext) { fn assemble_ir_statement(ir_statement: &IrStatement, context: &mut AssemblyContext) {
@ -113,9 +118,6 @@ fn assemble_ir_assign(ir_assign: &IrAssign, context: &mut AssemblyContext) {
let virtual_register_id = context.get_virtual_register(ir_variable.name()); let virtual_register_id = context.get_virtual_register(ir_variable.name());
AsmOperand::VirtualRegister(virtual_register_id) 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), IrExpression::Literal(ir_literal) => ir_literal_to_asm_operand(ir_literal),
}; };
let destination = context.next_virtual_register(ir_assign.lhs().name()); let destination = context.next_virtual_register(ir_assign.lhs().name());
@ -144,6 +146,7 @@ fn ir_literal_to_asm_operand(ir_literal: &IrLiteral) -> AsmOperand {
IrLiteral::Boolean(b) => AsmOperand::Boolean(*b), IrLiteral::Boolean(b) => AsmOperand::Boolean(*b),
IrLiteral::Float(f) => AsmOperand::Float(*f), IrLiteral::Float(f) => AsmOperand::Float(*f),
IrLiteral::Double(d) => AsmOperand::Double(*d), IrLiteral::Double(d) => AsmOperand::Double(*d),
IrLiteral::String(s) => AsmOperand::String(s.clone()),
} }
} }
@ -159,13 +162,6 @@ fn assemble_ir_call(ir_call: &IrCall, context: &mut AssemblyContext) {
source: AsmOperand::VirtualRegister(variable_register_id), 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 IrExpression::Literal(ir_literal) => context
.current_control_unit_mut() .current_control_unit_mut()
.append_instruction(AsmInstruction::Push { .append_instruction(AsmInstruction::Push {
@ -189,62 +185,48 @@ fn assemble_ir_call(ir_call: &IrCall, context: &mut AssemblyContext) {
fqn: ir_call.function_name_owned(), fqn: ir_call.function_name_owned(),
}) })
} }
IrCallType::PlatformStatic => {}
IrCallType::PlatformObject => {}
} }
} }
fn assemble_ir_return(ir_return: &IrReturn, context: &mut AssemblyContext) { fn assemble_ir_return(ir_return: &IrReturn, context: &mut AssemblyContext) {
let operand = match ir_return.expression() { let operand = ir_return.expression().map(|expression| {
IrExpression::Variable(ir_variable) => { match expression {
let variable_virtual_register_id = context.get_virtual_register(ir_variable.name()); IrExpression::Variable(ir_variable) => {
AsmOperand::VirtualRegister(variable_virtual_register_id) let variable_virtual_register_id = context.get_virtual_register(ir_variable.name());
AsmOperand::VirtualRegister(variable_virtual_register_id)
}
IrExpression::Literal(ir_literal) => ir_literal_to_asm_operand(ir_literal),
} }
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 context
.current_control_unit_mut() .current_control_unit_mut()
.append_instruction(AsmInstruction::Return { operand }); .append_instruction(AsmInstruction::Return { operand });
} }
fn assemble_ir_binary_operation(ir_binary_operation: &IrBinaryOperation, context: &mut AssemblyContext) { fn assemble_ir_binary_operation(
ir_binary_operation: &IrBinaryOperation,
context: &mut AssemblyContext,
) {
let left = match ir_binary_operation.left() { let left = match ir_binary_operation.left() {
IrExpression::Variable(ir_variable) => { IrExpression::Variable(ir_variable) => {
AsmOperand::VirtualRegister(context.get_virtual_register(ir_variable.name())) AsmOperand::VirtualRegister(context.get_virtual_register(ir_variable.name()))
} }
IrExpression::ConstRef(ir_const_ref) => { IrExpression::Literal(ir_literal) => ir_literal_to_asm_operand(ir_literal),
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() { let right = match ir_binary_operation.right() {
IrExpression::Variable(ir_variable) => { IrExpression::Variable(ir_variable) => {
AsmOperand::VirtualRegister(context.get_virtual_register(ir_variable.name())) 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)
} }
IrExpression::Literal(ir_literal) => ir_literal_to_asm_operand(ir_literal),
}; };
let destination = context.next_virtual_register(ir_binary_operation.destination().name()); let destination = context.next_virtual_register(ir_binary_operation.destination().name());
let operator = match ir_binary_operation.operator() { let operator = match ir_binary_operation.operator() {
IrBinaryOperator::Add => { IrBinaryOperator::Add => AsmBinaryOperator::Add,
AsmBinaryOperator::Add IrBinaryOperator::Subtract => AsmBinaryOperator::Subtract,
} IrBinaryOperator::Multiply => AsmBinaryOperator::Multiply,
IrBinaryOperator::Subtract => { IrBinaryOperator::Divide => AsmBinaryOperator::Divide,
AsmBinaryOperator::Subtract
}
IrBinaryOperator::Multiply => {
AsmBinaryOperator::Multiply
}
IrBinaryOperator::Divide => {
AsmBinaryOperator::Divide
}
IrBinaryOperator::Exponent => { IrBinaryOperator::Exponent => {
todo!() todo!()
} }
@ -254,7 +236,9 @@ fn assemble_ir_binary_operation(ir_binary_operation: &IrBinaryOperation, context
destination, destination,
left, left,
right, right,
operator operator,
}; };
context.current_control_unit_mut().append_instruction(instruction); context
.current_control_unit_mut()
.append_instruction(instruction);
} }

View File

@ -79,8 +79,14 @@ pub enum AsmInstruction {
InvokeObject { InvokeObject {
fqn: Rc<str>, fqn: Rc<str>,
}, },
InvokePlatformStatic {
fqn: Rc<str>,
},
InvokePlatformObject {
fqn: Rc<str>,
},
Return { Return {
operand: AsmOperand, operand: Option<AsmOperand>,
}, },
BinaryOperation { BinaryOperation {
destination: VirtualRegisterId, destination: VirtualRegisterId,
@ -120,8 +126,18 @@ impl Display for AsmInstruction {
AsmInstruction::InvokeObject { fqn } => { AsmInstruction::InvokeObject { fqn } => {
write!(f, "invoke_object {}", fqn) write!(f, "invoke_object {}", fqn)
} }
AsmInstruction::InvokePlatformStatic { fqn } => {
write!(f, "invoke_platform_static {}", fqn)
}
AsmInstruction::InvokePlatformObject { fqn } => {
write!(f, "invoke_platform_object {}", fqn)
}
AsmInstruction::Return { operand } => { AsmInstruction::Return { operand } => {
write!(f, "return {}", operand) write!(f, "return")?;
if let Some(operand) = operand {
write!(f, " {}", operand)?;
}
Ok(())
} }
AsmInstruction::BinaryOperation { AsmInstruction::BinaryOperation {
destination, destination,
@ -151,7 +167,7 @@ pub enum AsmOperand {
Float(f32), Float(f32),
Double(f64), Double(f64),
Boolean(bool), Boolean(bool),
Constant { name: Rc<str> }, String(Rc<str>),
VirtualRegister(VirtualRegisterId), VirtualRegister(VirtualRegisterId),
} }
@ -203,8 +219,8 @@ impl Display for AsmOperand {
AsmOperand::Boolean(b) => { AsmOperand::Boolean(b) => {
write!(f, "{}", b) write!(f, "{}", b)
} }
AsmOperand::Constant { name } => { AsmOperand::String(s) => {
write!(f, "<{}>", name) write!(f, "{}", s)
} }
AsmOperand::VirtualRegister(id) => { AsmOperand::VirtualRegister(id) => {
write!(f, "vr{}", id) write!(f, "vr{}", id)

View File

@ -31,6 +31,81 @@ pub mod node {
} }
} }
impl Expression {
pub fn analyzed_kind(&self) -> Kind {
match self {
Expression::Ternary(ternary_expression) => {
todo!()
}
Expression::Or(or_expression) => {todo!()}
Expression::And(and_expression) => {
todo!()
}
Expression::Comparison(comparison_expression) => {
todo!()
}
Expression::Shift(shift_expression) => {
todo!()
}
Expression::Additive(additive_expression) => {
todo!()
}
Expression::Multiplicative(multiplicative_expression) => {
todo!()
}
Expression::Prefix(prefix_expression) => {
todo!()
}
Expression::Suffix(suffix_expression) => {
todo!()
}
Expression::Literal(literal) => {
literal.analyzed_kind()
}
Expression::Identifier(identifier) => {
identifier.analyzed_kind().expect("IdentifierExpression's analyzed_kind not set.").clone()
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(closure) => {
todo!()
}
Expression::List(list_expression) => {
todo!()
}
}
}
}
impl Literal {
pub fn analyzed_kind(&self) -> Kind {
match self {
Literal::IntLiteral(_) => {
Kind::Primitive(PrimitiveKind::Int.into())
}
Literal::LongLiteral(_) => {
Kind::Primitive(PrimitiveKind::Long.into())
}
Literal::DoubleLiteral(_) => {
Kind::Primitive(PrimitiveKind::Double.into())
}
Literal::SingleQuoteString(_) => {
Kind::Primitive(PrimitiveKind::String.into())
}
Literal::DString(_) => {
todo!()
}
Literal::BacktickString(_) => {
todo!()
}
Literal::BooleanLiteral(_) => {
Kind::Primitive(PrimitiveKind::Boolean.into())
}
}
}
}
impl Default for Parameters { impl Default for Parameters {
fn default() -> Self { fn default() -> Self {
Self::new(vec![]) Self::new(vec![])

View File

@ -3,22 +3,25 @@ use deimos::asm::assemble_ir::assemble_ir_function;
use deimos::ast::node::CompilationUnit; use deimos::ast::node::CompilationUnit;
use deimos::ir::lower_ast::lower_compilation_unit; use deimos::ir::lower_ast::lower_compilation_unit;
use deimos::ir::Ir; use deimos::ir::Ir;
use deimos::util::indent_writer::IndentWriter; use deimos::type_analysis::analyze_types;
use std::path::PathBuf; use std::path::PathBuf;
pub fn compile_to_ir( pub fn compile_to_ir(
paths: &[PathBuf], paths: &[PathBuf],
) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> { ) -> Result<Vec<CompilationUnit>, Box<dyn std::error::Error>> {
let compilation_units = name_analysis(&paths)?; let mut compilation_units = name_analysis(&paths)?;
let type_diagnostics = analyze_types(&mut compilation_units);
if !type_diagnostics.is_empty() {
eprintln!("There were type diagnostics")
}
for compilation_unit in &compilation_units { for compilation_unit in &compilation_units {
let cu_irs = lower_compilation_unit(compilation_unit); let cu_irs = lower_compilation_unit(compilation_unit);
let mut out = String::new();
let mut indent_writer = IndentWriter::new(0, " ", &mut out);
for ir in &cu_irs { for ir in &cu_irs {
ir.pretty_print(&mut indent_writer)?; println!("{}", ir)
} }
println!("{}", &out);
for ir in &cu_irs { for ir in &cu_irs {
match ir { match ir {

View File

@ -1,119 +1,139 @@
use crate::ast::node::{AdditiveExpression, AdditiveOperator, Call, Closure, CompilationUnit, Expression, ExpressionList, ExpressionStatement, Function, FunctionBlockBody, FunctionBody, Identifier, Literal, ModuleLevelDeclaration, Statement, SuffixExpression, SuffixOperator, VariableDeclaration}; use crate::ast::node::{
AdditiveExpression, AdditiveOperator, Call, CompilationUnit, Expression, ExpressionStatement,
Function, FunctionBlockBody, FunctionBody, FunctionEqualsBody, Literal, Module,
ModuleLevelDeclaration, Statement, SuffixExpression, SuffixOperator, VariableDeclaration,
};
use crate::ir::{ use crate::ir::{
Ir, IrAssign, IrBinaryOperation, IrBinaryOperator, IrCall, IrCallType, IrConst, IrExpression, Ir, IrAssign, IrBinaryOperation, IrBinaryOperator, IrExpression, IrFunction, IrKind, IrLiteral,
IrFunction, IrKind, IrLiteral, IrPrimitiveKind, IrStatement, IrVariable, IrPrimitiveKind, IrReturn, IrStatement, IrStructKind, IrVariable,
};
use crate::name_analysis::symbol::{
ExpressibleSymbol, ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol,
}; };
use crate::name_analysis::symbol::{ClassSymbol, ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol};
use std::cell::RefCell; use std::cell::RefCell;
use std::collections::HashMap; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use crate::ir::IrStatement::BinaryOperation; use crate::type_analysis::kinds::Kind;
pub fn lower_compilation_unit(compilation_unit: &CompilationUnit) -> Vec<Ir> { struct CuContext {
let mut result: Vec<Ir> = vec![]; irs: Vec<Ir>,
for declaration in compilation_unit.module_level_declarations() {
result.append(&mut lower_module_level_declaration(declaration));
}
result
} }
fn lower_module_level_declaration(declaration: &ModuleLevelDeclaration) -> Vec<Ir> { impl CuContext {
match declaration { pub fn new() -> Self {
ModuleLevelDeclaration::Module(module) => { Self { irs: vec![] }
todo!() }
}
pub fn push_ir(&mut self, ir: Ir) {
self.irs.push(ir);
}
pub fn into_irs(self) -> Vec<Ir> {
self.irs
}
}
pub fn lower_compilation_unit(compilation_unit: &CompilationUnit) -> Vec<Ir> {
let mut context = CuContext::new();
for declaration in compilation_unit.module_level_declarations() {
lower_module_level_declaration(declaration, &mut context);
}
context.into_irs()
}
fn lower_module_level_declaration(
module_level_declaration: &ModuleLevelDeclaration,
cu_context: &mut CuContext,
) {
match module_level_declaration {
ModuleLevelDeclaration::Module(module) => lower_module(module, cu_context),
ModuleLevelDeclaration::Interface(interface) => { ModuleLevelDeclaration::Interface(interface) => {
todo!() todo!()
} }
ModuleLevelDeclaration::Class(class) => { ModuleLevelDeclaration::Class(class) => {
todo!() todo!()
} }
ModuleLevelDeclaration::Function(function) => lower_function(function), ModuleLevelDeclaration::Function(function) => lower_function(function, cu_context),
ModuleLevelDeclaration::PlatformFunction(platform_function) => { ModuleLevelDeclaration::PlatformFunction(platform_function) => {
todo!() todo!()
} }
} }
} }
pub struct LocalsTable { fn lower_module(module: &Module, cu_context: &mut CuContext) {
t_count: usize, for declaration in module.declarations() {
stack_slot_count: usize, lower_module_level_declaration(declaration, cu_context);
stack_slots: HashMap<IrVariable, usize>, }
} }
impl LocalsTable { struct FnContext {
pub fn new() -> Self { t_var_count: usize,
statements: Vec<IrStatement>,
return_type: Option<TypeSymbol>,
}
impl FnContext {
pub fn new(return_type: Option<TypeSymbol>) -> Self {
Self { Self {
t_count: 0, t_var_count: 0,
stack_slot_count: 0, statements: vec![],
stack_slots: HashMap::new(), return_type,
} }
} }
pub fn next_t_var(&mut self) -> IrVariable { pub fn next_t_var(&mut self) -> String {
let t_num = self.t_count; let t_var = format!("__t{}", self.t_var_count);
self.t_count += 1; self.t_var_count += 1;
let t_name = format!("__t{}", t_num);
let t_var = IrVariable::new(&t_name);
self.register_stack_local(&t_var);
t_var t_var
} }
pub fn register_stack_local(&mut self, ir_variable: &IrVariable) { pub fn push_statement(&mut self, statement: IrStatement) {
let stack_slot = self.stack_slot_count; self.statements.push(statement);
self.stack_slot_count += 1;
self.stack_slots.insert(ir_variable.clone(), stack_slot);
} }
pub fn get_stack_slot(&self, ir_variable: &IrVariable) -> usize { pub fn into_statements(self) -> Vec<IrStatement> {
*self.stack_slots.get(ir_variable).unwrap() self.statements
}
pub fn return_type(&self) -> Option<&TypeSymbol> {
self.return_type.as_ref()
} }
} }
fn lower_function(function: &Function) -> Vec<Ir> { fn lower_function(function: &Function, cu_context: &mut CuContext) {
let function_symbol = function.function_symbol().unwrap().borrow(); let function_symbol = function.function_symbol().unwrap().borrow();
let name = function_symbol.fqn_parts_owned().join("::"); let fqn = function_symbol.fqn_formatted();
let parameters = lower_parameter_symbols(function_symbol.parameter_symbols()); let parameters = parameter_symbols_to_ir_kinds(function_symbol.parameter_symbols());
let return_type = lower_type_symbol(function_symbol.return_type().unwrap()); let return_type = type_symbol_to_ir_kind(function_symbol.return_type().unwrap());
let mut locals_table = LocalsTable::new(); let mut fn_context = FnContext::new(function_symbol.return_type_owned());
let (statements, consts) = lower_function_body(function.function_body(), &mut locals_table); lower_function_body(function.function_body(), &mut fn_context);
let ir_function = IrFunction::new(
let mut result: Vec<Ir> = vec![]; &fqn,
result.push(Ir::Function(Box::new(IrFunction::new( function_symbol.is_public(),
name,
parameters, parameters,
Box::new(return_type), return_type,
statements, fn_context.into_statements(),
Box::new(locals_table),
))));
result.append(
&mut consts
.into_iter()
.map(|constant| Ir::Const(Box::new(constant)))
.collect(),
); );
result cu_context.push_ir(Ir::Function(ir_function.into()));
} }
fn lower_parameter_symbols(parameter_symbols: &[Rc<RefCell<ParameterSymbol>>]) -> Vec<IrKind> { fn parameter_symbols_to_ir_kinds(
parameter_symbols: &[Rc<RefCell<ParameterSymbol>>],
) -> Vec<IrKind> {
parameter_symbols parameter_symbols
.iter() .iter()
.map(|parameter_symbol_rc| parameter_symbol_rc.borrow()) .map(|parameter_symbol_rc| parameter_symbol_rc.borrow())
.map(|parameter_symbol| lower_type_symbol(parameter_symbol.type_symbol().unwrap())) .map(|parameter_symbol_ref| {
type_symbol_to_ir_kind(parameter_symbol_ref.type_symbol().unwrap())
})
.collect() .collect()
} }
fn lower_type_symbol(type_symbol: &TypeSymbol) -> IrKind { fn type_symbol_to_ir_kind(type_symbol: &TypeSymbol) -> IrKind {
match type_symbol { match type_symbol {
TypeSymbol::Primitive(primitive_type_symbol) => { TypeSymbol::Primitive(primitive_type_symbol) => {
lower_primitive_type_symbol(primitive_type_symbol) primitive_type_symbol_to_ir_kind(primitive_type_symbol)
}
TypeSymbol::Class(class_type_symbol) => {
todo!()
} }
TypeSymbol::Class(class_symbol) => class_symbol_to_ir_kind(class_symbol.borrow().deref()),
TypeSymbol::Interface(interface_type_symbol) => { TypeSymbol::Interface(interface_type_symbol) => {
todo!() todo!()
} }
@ -123,7 +143,7 @@ fn lower_type_symbol(type_symbol: &TypeSymbol) -> IrKind {
} }
} }
fn lower_primitive_type_symbol(primitive_type_symbol: &PrimitiveTypeSymbol) -> IrKind { fn primitive_type_symbol_to_ir_kind(primitive_type_symbol: &PrimitiveTypeSymbol) -> IrKind {
IrKind::Primitive(Box::new(match primitive_type_symbol { IrKind::Primitive(Box::new(match primitive_type_symbol {
PrimitiveTypeSymbol::Byte => IrPrimitiveKind::I8, PrimitiveTypeSymbol::Byte => IrPrimitiveKind::I8,
PrimitiveTypeSymbol::Char => IrPrimitiveKind::I8, PrimitiveTypeSymbol::Char => IrPrimitiveKind::I8,
@ -134,59 +154,54 @@ fn lower_primitive_type_symbol(primitive_type_symbol: &PrimitiveTypeSymbol) -> I
PrimitiveTypeSymbol::Double => IrPrimitiveKind::Double, PrimitiveTypeSymbol::Double => IrPrimitiveKind::Double,
PrimitiveTypeSymbol::Boolean => IrPrimitiveKind::Boolean, PrimitiveTypeSymbol::Boolean => IrPrimitiveKind::Boolean,
PrimitiveTypeSymbol::String => IrPrimitiveKind::String, PrimitiveTypeSymbol::String => IrPrimitiveKind::String,
PrimitiveTypeSymbol::TypedArray { inner_type } => { PrimitiveTypeSymbol::TypedArray { inner_type } => IrPrimitiveKind::Array(Box::new(
IrPrimitiveKind::Array(Box::new(lower_type_symbol(inner_type.as_ref().unwrap()))) type_symbol_to_ir_kind(inner_type.as_ref().unwrap()),
} )),
PrimitiveTypeSymbol::Any => { PrimitiveTypeSymbol::Any => IrPrimitiveKind::Any,
todo!()
}
PrimitiveTypeSymbol::Void => IrPrimitiveKind::Void, PrimitiveTypeSymbol::Void => IrPrimitiveKind::Void,
})) }))
} }
fn lower_function_body( fn class_symbol_to_ir_kind(class_type_symbol: &ClassSymbol) -> IrKind {
function_body: &FunctionBody, let struct_kind = IrStructKind::new(&class_type_symbol.fqn_formatted());
locals_table: &mut LocalsTable, IrKind::Struct(struct_kind.into())
) -> (Vec<IrStatement>, Vec<IrConst>) { }
fn lower_function_body(function_body: &FunctionBody, fn_context: &mut FnContext) {
match function_body { match function_body {
FunctionBody::FunctionAliasBody(alias_body) => { FunctionBody::FunctionAliasBody(alias_body) => {
todo!() todo!()
} }
FunctionBody::FunctionEqualsBody(equals_body) => { FunctionBody::FunctionEqualsBody(equals_body) => {
todo!() lower_function_equals_body(equals_body, fn_context);
} }
FunctionBody::FunctionBlockBody(block_body) => { FunctionBody::FunctionBlockBody(block_body) => {
lower_function_block_body(block_body, locals_table) lower_function_block_body(block_body, fn_context);
} }
} }
} }
fn lower_function_block_body( fn lower_function_equals_body(body: &FunctionEqualsBody, fn_context: &mut FnContext) {
body: &FunctionBlockBody, todo!()
locals_table: &mut LocalsTable,
) -> (Vec<IrStatement>, Vec<IrConst>) {
let mut statements: Vec<IrStatement> = vec![];
let mut consts: Vec<IrConst> = vec![];
for statement in body.statements() {
statements.append(&mut lower_statement(statement, &mut consts, locals_table));
}
(statements, consts)
} }
fn lower_statement( fn lower_function_block_body(body: &FunctionBlockBody, fn_context: &mut FnContext) {
statement: &Statement, let statement_count = body.statements().count();
consts_pool: &mut Vec<IrConst>, for (i, statement) in body.statements().enumerate() {
locals_table: &mut LocalsTable, lower_statement(statement, fn_context, i == statement_count - 1);
) -> Vec<IrStatement> { }
}
fn lower_statement(statement: &Statement, fn_context: &mut FnContext, is_last: bool) {
match statement { match statement {
Statement::VariableDeclaration(variable_declaration) => { Statement::VariableDeclaration(variable_declaration) => {
lower_variable_declaration(variable_declaration, consts_pool, locals_table) lower_variable_declaration(variable_declaration, fn_context)
} }
Statement::AssignmentStatement(assignment_statement) => { Statement::AssignmentStatement(assignment_statement) => {
todo!() todo!()
} }
Statement::ExpressionStatement(expression_statement) => { Statement::ExpressionStatement(expression_statement) => {
lower_expression_statement(expression_statement, consts_pool, locals_table) lower_expression_statement(expression_statement, fn_context, is_last)
} }
Statement::UseStatement(use_statement) => { Statement::UseStatement(use_statement) => {
todo!() todo!()
@ -205,465 +220,224 @@ fn lower_statement(
fn lower_variable_declaration( fn lower_variable_declaration(
variable_declaration: &VariableDeclaration, variable_declaration: &VariableDeclaration,
consts_pool: &mut Vec<IrConst>, fn_context: &mut FnContext,
locals_table: &mut LocalsTable, ) {
) -> Vec<IrStatement> { let initializer = match variable_declaration.expression() {
let mut result: Vec<IrStatement> = vec![]; Expression::Literal(literal) => literal_to_ir_expression(literal),
let expression_t_var = lower_expression( Expression::Identifier(identifier_expression) => IrExpression::Variable(
variable_declaration.expression().unwrap(), IrVariable::new(identifier_expression.identifier().name()).into(),
&mut result,
consts_pool,
locals_table,
);
let target = IrVariable::new(variable_declaration.identifier().name());
locals_table.register_stack_local(&target);
let assign_stmt = IrAssign::new(
Box::new(target),
Box::new(IrExpression::Variable(Box::new(expression_t_var))),
);
result.push(IrStatement::Assign(assign_stmt));
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,
) -> IrVariable {
match expression {
Expression::Ternary(ternary) => {
todo!()
}
Expression::Or(or) => {
todo!()
}
Expression::And(and) => {
todo!()
}
Expression::Comparison(comparison) => {
todo!()
}
Expression::Shift(shift) => {
todo!()
}
Expression::Additive(additive) => {
lower_additive_expression(additive, target, consts_pool, locals_table)
}
Expression::Multiplicative(multiplicative) => {
todo!()
}
Expression::Prefix(prefix) => {
todo!()
}
Expression::Suffix(suffix) => {
lower_suffix_expression(suffix, target, consts_pool, locals_table)
}
Expression::Literal(literal) => lower_literal(literal, target, consts_pool, locals_table),
Expression::Identifier(identifier_expression) => lower_identifier(
identifier_expression.identifier(),
target,
consts_pool,
locals_table,
), ),
Expression::Fqn(fqn) => { Expression::Fqn(fqn) => {
todo!("Fqn as expressions")
}
_ => expression_to_ir_expression(variable_declaration.expression(), fn_context),
};
let result_variable = IrVariable::new(variable_declaration.identifier().name());
let ir_assign = IrAssign::new(result_variable, initializer);
fn_context.push_statement(IrStatement::Assign(ir_assign.into()));
}
fn literal_to_ir_expression(literal: &Literal) -> IrExpression {
match literal {
Literal::IntLiteral(i) => IrExpression::Literal(IrLiteral::I32(*i).into()),
Literal::LongLiteral(l) => IrExpression::Literal(IrLiteral::I64(*l).into()),
Literal::DoubleLiteral(d) => IrExpression::Literal(IrLiteral::Double(*d).into()),
Literal::SingleQuoteString(s) => {
IrExpression::Literal(IrLiteral::String(Rc::from(s.as_ref())).into())
}
Literal::DString(d_string) => todo!(),
Literal::BacktickString(backtick_string) => {
todo!() todo!()
} }
Expression::Closure(closure) => { Literal::BooleanLiteral(b) => IrExpression::Literal(IrLiteral::Boolean(*b).into()),
}
}
fn expression_to_ir_expression(
expression: &Expression,
fn_context: &mut FnContext,
) -> IrExpression {
IrExpression::Variable(expression_into_ir_variable(expression, fn_context).into())
}
fn expression_into_ir_variable(expression: &Expression, fn_context: &mut FnContext) -> IrVariable {
match expression {
Expression::Ternary(_) => {
todo!() todo!()
} }
Expression::List(list) => { Expression::Or(_) => {
todo!()
}
Expression::And(_) => {
todo!()
}
Expression::Comparison(_) => {
todo!()
}
Expression::Shift(_) => {
todo!()
}
Expression::Additive(additive_expression) => {
additive_expression_into_ir_variable(additive_expression, fn_context)
}
Expression::Multiplicative(_) => {
todo!()
}
Expression::Prefix(_) => {
todo!()
}
Expression::Suffix(suffix_expression) => {
suffix_expression_into_ir_variable(suffix_expression, fn_context)
}
Expression::Literal(literal) => {
let literal_as_ir_expression = literal_to_ir_expression(literal);
let t_var_name = fn_context.next_t_var();
let t_var_ir_variable = IrVariable::new(&t_var_name);
let ir_assign = IrAssign::new(t_var_ir_variable.clone(), literal_as_ir_expression);
fn_context.push_statement(IrStatement::Assign(ir_assign.into()));
t_var_ir_variable
}
Expression::Identifier(identifier_expression) => {
IrVariable::new(identifier_expression.identifier().name())
}
Expression::Fqn(_) => {
todo!("Fqn as expression")
}
Expression::Closure(_) => {
todo!()
}
Expression::List(_) => {
todo!() todo!()
} }
} }
} }
fn lower_suffix_expression( fn additive_expression_into_ir_variable(
suffix_expression: &SuffixExpression, additive_expression: &AdditiveExpression,
target: &mut Vec<IrStatement>, fn_context: &mut FnContext,
consts_pool: &mut Vec<IrConst>, ) -> IrVariable {
locals_table: &mut LocalsTable, let left = expression_to_ir_expression(additive_expression.left(), fn_context);
let right = expression_to_ir_expression(additive_expression.rhs().expression(), fn_context);
let operator = match additive_expression.rhs().operator() {
AdditiveOperator::Add => IrBinaryOperator::Add,
AdditiveOperator::Subtract => IrBinaryOperator::Subtract,
};
let result_variable_name = fn_context.next_t_var();
let result_ir_variable = IrVariable::new(&result_variable_name);
let add_op = IrBinaryOperation::new(result_ir_variable.clone(), left, right, operator);
fn_context.push_statement(IrStatement::BinaryOperation(add_op.into()));
result_ir_variable
}
fn suffix_expression_into_ir_variable(
suffix_expression: &SuffixExpression,
fn_context: &mut FnContext,
) -> IrVariable { ) -> IrVariable {
let receiver_variable = lower_expression(
suffix_expression.expression(),
target,
consts_pool,
locals_table,
);
match suffix_expression.operator() { match suffix_expression.operator() {
SuffixOperator::PlusPlus => { SuffixOperator::PlusPlus => {
let result_var = locals_table.next_t_var(); let result_variable_name = fn_context.next_t_var();
let operation = IrBinaryOperation::new( let result_ir_variable = IrVariable::new(&result_variable_name);
result_var.clone(), let plus_plus_op = IrBinaryOperation::new(
IrExpression::Variable(receiver_variable.into()), result_ir_variable.clone(),
expression_to_ir_expression(suffix_expression.expression(), fn_context),
IrExpression::Literal(IrLiteral::I32(1).into()), IrExpression::Literal(IrLiteral::I32(1).into()),
IrBinaryOperator::Add, IrBinaryOperator::Add,
); );
target.push(IrStatement::BinaryOperation(operation)); fn_context.push_statement(IrStatement::BinaryOperation(plus_plus_op.into()));
result_var result_ir_variable
} }
SuffixOperator::MinusMinus => { SuffixOperator::MinusMinus => {
let result_var = locals_table.next_t_var(); let result_variable_name = fn_context.next_t_var();
let operation = IrBinaryOperation::new( let result_ir_variable = IrVariable::new(&result_variable_name);
result_var.clone(), let plus_plus_op = IrBinaryOperation::new(
IrExpression::Variable(receiver_variable.into()), result_ir_variable.clone(),
expression_to_ir_expression(suffix_expression.expression(), fn_context),
IrExpression::Literal(IrLiteral::I32(1).into()), IrExpression::Literal(IrLiteral::I32(1).into()),
IrBinaryOperator::Subtract, IrBinaryOperator::Subtract, // n.b.
); );
target.push(IrStatement::BinaryOperation(operation)); fn_context.push_statement(IrStatement::BinaryOperation(plus_plus_op.into()));
result_var result_ir_variable
} }
SuffixOperator::ObjectIndex(object_index) => { SuffixOperator::ObjectIndex(object_index) => {
todo!("Object indexing")
}
SuffixOperator::Call(call) => {
todo!() todo!()
} }
SuffixOperator::Call(call) => lower_call(
call,
suffix_expression.expression(),
target,
consts_pool,
locals_table,
),
SuffixOperator::ObjectProperty(object_property) => { SuffixOperator::ObjectProperty(object_property) => {
todo!() todo!()
} }
} }
} }
fn lower_literal( fn lower_expression_statement(
literal: &Literal, expression_statement: &ExpressionStatement,
statements: &mut Vec<IrStatement>, fn_context: &mut FnContext,
consts_pool: &mut Vec<IrConst>, is_last: bool,
locals_table: &mut LocalsTable, ) {
) -> IrVariable { let is_void_return = if let Some(return_type_symbol) = fn_context.return_type() {
match literal { match return_type_symbol {
Literal::IntLiteral(int_literal) => { TypeSymbol::Primitive(primitive_type_symbol) => match primitive_type_symbol {
let t_var = locals_table.next_t_var(); PrimitiveTypeSymbol::Void => true,
let assign_stmt = IrAssign::new( _ => false,
Box::new(t_var.clone()), },
Box::new(IrExpression::Literal(Box::new(IrLiteral::I32( _ => false,
*int_literal,
)))),
);
statements.push(IrStatement::Assign(assign_stmt));
t_var
} }
Literal::LongLiteral(long_literal) => { } else {
false
};
if is_last && !is_void_return {
let return_statement = IrReturn::new(Some(expression_to_ir_expression(
expression_statement.expression(),
fn_context,
)));
fn_context.push_statement(IrStatement::Return(return_statement.into()));
} else {
lower_side_effect_expression(expression_statement.expression(), fn_context);
}
}
fn lower_side_effect_expression(expression: &Expression, fn_context: &mut FnContext) {
match expression {
Expression::Suffix(suffix_expression) => {
lower_side_effect_suffix_expression(suffix_expression, fn_context);
}
_ => {
todo!("Anything other than a suffix expression for side-effects should be eliminated as dead code.")
}
}
}
fn lower_side_effect_suffix_expression(
suffix_expression: &SuffixExpression,
fn_context: &mut FnContext,
) {
match suffix_expression.operator() {
SuffixOperator::PlusPlus => {
todo!() todo!()
} }
Literal::DoubleLiteral(double_literal) => { SuffixOperator::MinusMinus => {
todo!() todo!()
} }
Literal::SingleQuoteString(sq_string) => { SuffixOperator::ObjectIndex(object_index) => {
todo!() todo!()
} }
Literal::DString(d_string) => { SuffixOperator::Call(call) => {
todo!() call_to_ir_expression(call, suffix_expression.expression(), fn_context);
} }
Literal::BacktickString(b_string) => { SuffixOperator::ObjectProperty(object_property) => {
todo!()
}
Literal::BooleanLiteral(boolean_literal) => {
todo!() todo!()
} }
} }
} }
fn lower_call( fn call_to_ir_expression(
call: &Call, call: &Call,
receiver: &Expression, receiver: &Expression,
target: &mut Vec<IrStatement>, fn_context: &mut FnContext,
consts_pool: &mut Vec<IrConst>, ) -> IrExpression {
locals_table: &mut LocalsTable, let function_kind = receiver.analyzed_kind().expect_function();
) -> IrVariable { todo!("Rework AST nodes so that Call and children have a better api")
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

@ -1,134 +0,0 @@
use crate::ir::lower_ast::LocalsTable;
use crate::ir::{IrAllocable, IrAllocate, IrAssign, IrCall, IrExpression, IrFunction, IrLiteral, IrReturn, IrStatement};
use crate::vm::instruction::{Immediate, Instruction, Location};
use std::ops::Deref;
use std::rc::Rc;
pub fn lower_ir_function(ir_function: &IrFunction) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
for statement in ir_function.statements() {
instructions.append(&mut lower_ir_statement(
statement,
ir_function.locals_table(),
));
}
instructions
}
fn lower_ir_statement(ir_statement: &IrStatement, locals_table: &LocalsTable) -> Vec<Instruction> {
match ir_statement {
IrStatement::Allocate(allocate) => lower_ir_allocate(allocate),
IrStatement::Call(call) => lower_ir_call(call, locals_table),
IrStatement::Return(ir_return) => lower_return(ir_return, locals_table),
IrStatement::Assign(assign) => {
lower_ir_assign(assign, locals_table)
}
IrStatement::MakeClosure(make_closure) => {
todo!()
}
IrStatement::BinaryOperation(binary_operation) => {
todo!()
}
}
}
fn lower_ir_allocate(ir_allocate: &IrAllocate) -> Vec<Instruction> {
let allocate_instruction = match ir_allocate.kind_to_alloc() {
IrAllocable::Struct(struct_kind) => Instruction::AllocateObject {
implementation_name: Rc::new(struct_kind.name().to_string()),
destination_register: 0,
},
IrAllocable::Array(array_kind) => {
todo!()
}
};
let push_instruction = Instruction::Push { source_register: 0 };
vec![allocate_instruction, push_instruction]
}
fn lower_ir_call(ir_call: &IrCall, locals_table: &LocalsTable) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
// push args
for argument in ir_call.arguments() {
lower_ir_expression(argument, &mut instructions, locals_table);
}
instructions
}
fn lower_ir_expression(
ir_expression: &IrExpression,
instructions: &mut Vec<Instruction>,
locals_table: &LocalsTable,
) {
match ir_expression {
IrExpression::Variable(variable) => instructions.append(&mut vec![
Instruction::Copy {
source: Location::FramePointer {
offset: locals_table.get_stack_slot(variable) as isize,
},
destination: Location::Register(0),
},
Instruction::Push { source_register: 0 },
]),
IrExpression::ConstRef(const_ref) => {
todo!()
}
IrExpression::Literal(literal) => {
let immediate = match literal.deref() {
IrLiteral::I8(v) => Immediate::I8(*v),
IrLiteral::I16(v) => Immediate::I16(*v),
IrLiteral::I32(v) => Immediate::I32(*v),
IrLiteral::I64(v) => Immediate::I64(*v),
IrLiteral::I128(v) => Immediate::I128(*v),
IrLiteral::ISize(v) => Immediate::ISize(*v),
IrLiteral::U8(v) => Immediate::U8(*v),
IrLiteral::U16(v) => Immediate::U16(*v),
IrLiteral::U32(v) => Immediate::U32(*v),
IrLiteral::U64(v) => Immediate::U64(*v),
IrLiteral::U128(v) => Immediate::U128(*v),
IrLiteral::USize(v) => Immediate::USize(*v),
IrLiteral::Boolean(v) => Immediate::Boolean(*v),
IrLiteral::Float(v) => Immediate::Float(*v),
IrLiteral::Double(v) => Immediate::Double(*v),
};
instructions.append(&mut vec![
Instruction::MoveImmediate {
destination_register: 0,
immediate,
},
Instruction::Push { source_register: 0 },
])
}
}
}
fn lower_return(ir_return: &IrReturn, locals_table: &LocalsTable) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
lower_ir_expression(ir_return.expression(), &mut instructions, locals_table);
instructions.append(&mut vec![
Instruction::Pop {
destination_register: Some(0),
},
Instruction::PopFrame,
Instruction::Push { source_register: 0 },
Instruction::Return,
]);
instructions
}
fn lower_ir_assign(ir_assign: &IrAssign, locals_table: &LocalsTable) -> Vec<Instruction> {
let mut instructions: Vec<Instruction> = vec![];
lower_ir_expression(ir_assign.rhs(), &mut instructions, locals_table);
instructions.append(&mut vec![
Instruction::Pop {
destination_register: Some(0),
},
Instruction::Copy {
source: Location::Register(0),
destination: Location::FramePointer {
offset: locals_table.get_stack_slot(ir_assign.lhs()) as isize,
}
}
]);
instructions
}

View File

@ -1,72 +1,123 @@
use crate::ir::lower_ast::LocalsTable;
use crate::util::indent_writer::IndentWriter;
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::rc::Rc; use std::rc::Rc;
pub mod lower_ast; pub mod lower_ast;
pub mod lower_ir;
pub enum Ir { pub enum Ir {
Struct(Box<IrStruct>), Struct(Box<IrStruct>),
Function(Box<IrFunction>), Function(Box<IrFunction>),
PlatformFunction(Box<IrPlatformFunction>), PlatformFunction(Box<IrPlatformFunction>),
Const(Box<IrConst>),
} }
impl Ir { impl Display for Ir {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { writeln!(
Ir::Struct(ir_struct) => ir_struct.pretty_print(writer), f,
Ir::Function(ir_function) => ir_function.pretty_print(writer), "{}\n",
Ir::PlatformFunction(ir_platform_function) => ir_platform_function.pretty_print(writer), match self {
Ir::Const(ir_const) => ir_const.pretty_print(writer), Ir::Struct(ir_struct) => {
} format!("{}", ir_struct)
}
Ir::Function(ir_function) => {
format!("{}", ir_function)
}
Ir::PlatformFunction(ir_platform_function) => {
format!("{}", ir_platform_function)
}
}
)
} }
} }
pub struct IrStruct { pub struct IrStruct {
name: String, name: Rc<str>,
is_public: bool, is_public: bool,
members: Vec<IrStructMember>, members: Vec<IrStructMember>,
} }
impl IrStruct { impl IrStruct {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { pub fn new(name: &str, is_public: bool, members: Vec<IrStructMember>) -> Self {
Self {
name: name.into(),
is_public,
members,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn name_owned(&self) -> Rc<str> {
self.name.clone()
}
pub fn is_public(&self) -> bool {
self.is_public
}
pub fn members(&self) -> &[IrStructMember] {
&self.members
}
}
impl Display for IrStruct {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_public { if self.is_public {
writer.writeln(&format!("pub struct {} {{", self.name))?; write!(f, "pub ")?;
} else {
writer.writeln(&format!("struct {} {{", self.name))?;
} }
writer.increase_indent(); writeln!(f, "struct {} {{", self.name)?;
for member in &self.members { for member in &self.members {
member.pretty_print(writer)?; writeln!(f, " {}", member)?;
writer.write("\n")?;
} }
writer.decrease_indent(); writeln!(f, "}}")?;
writer.writeln("}")?;
Ok(()) Ok(())
} }
} }
pub struct IrStructMember { pub struct IrStructMember {
name: String, name: Rc<str>,
kind: Box<IrKind>, kind: Box<IrKind>,
is_public: bool, is_public: bool,
is_mut: bool, is_mut: bool,
} }
impl IrStructMember { impl IrStructMember {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { pub fn new(name: &str, kind: IrKind, is_public: bool, is_mut: bool) -> Self {
Self {
name: name.into(),
kind: kind.into(),
is_public,
is_mut,
}
}
pub fn name(&self) -> &str {
&self.name
}
pub fn name_owned(&self) -> Rc<str> {
self.name.clone()
}
pub fn kind(&self) -> &IrKind {
&self.kind
}
pub fn is_public(&self) -> bool {
self.is_public
}
}
impl Display for IrStructMember {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
if self.is_public { if self.is_public {
writer.write("pub ")?; write!(f, "pub ")?;
} }
if self.is_mut { if self.is_mut {
writer.write("mut ")?; write!(f, "mut ")?;
} }
writer.write(&self.name)?; write!(f, "{}: {}", self.name, self.kind)
writer.write(": ")?;
self.kind.pretty_print(writer)?;
Ok(())
} }
} }
@ -75,11 +126,15 @@ pub enum IrKind {
Struct(Box<IrStructKind>), Struct(Box<IrStructKind>),
} }
impl IrKind { impl Display for IrKind {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
IrKind::Primitive(primitive) => primitive.pretty_print(writer), IrKind::Primitive(ir_primitive_kind) => {
IrKind::Struct(struct_kind) => struct_kind.pretty_print(writer), write!(f, "{}", ir_primitive_kind)
}
IrKind::Struct(ir_struct_kind) => {
write!(f, "{}", ir_struct_kind)
}
} }
} }
} }
@ -103,99 +158,115 @@ pub enum IrPrimitiveKind {
Array(Box<IrKind>), Array(Box<IrKind>),
String, String,
Closure(Box<IrClosureKind>), Closure(Box<IrClosureKind>),
Ref(Box<IrKind>),
Any, Any,
Void, Void,
} }
impl IrPrimitiveKind { impl Display for IrPrimitiveKind {
fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { let s = match self {
IrPrimitiveKind::I8 => writer.write("i8"), IrPrimitiveKind::I8 => "i8",
IrPrimitiveKind::I16 => writer.write("i16"), IrPrimitiveKind::I16 => "i16",
IrPrimitiveKind::I32 => writer.write("i32"), IrPrimitiveKind::I32 => "i32",
IrPrimitiveKind::I64 => writer.write("i64"), IrPrimitiveKind::I64 => "i64",
IrPrimitiveKind::I128 => writer.write("i128"), IrPrimitiveKind::I128 => "i128",
IrPrimitiveKind::ISize => writer.write("isize"), IrPrimitiveKind::ISize => "isize",
IrPrimitiveKind::U8 => writer.write("u8"), IrPrimitiveKind::U8 => "u8",
IrPrimitiveKind::U16 => writer.write("u16"), IrPrimitiveKind::U16 => "u16",
IrPrimitiveKind::U32 => writer.write("u32"), IrPrimitiveKind::U32 => "u32",
IrPrimitiveKind::U64 => writer.write("u64"), IrPrimitiveKind::U64 => "u64",
IrPrimitiveKind::U128 => writer.write("u128"), IrPrimitiveKind::U128 => "u128",
IrPrimitiveKind::USize => writer.write("usize"), IrPrimitiveKind::USize => "usize",
IrPrimitiveKind::Float => writer.write("f32"), IrPrimitiveKind::Float => "f32",
IrPrimitiveKind::Double => writer.write("f64"), IrPrimitiveKind::Double => "f64",
IrPrimitiveKind::Boolean => writer.write("boolean"), IrPrimitiveKind::Boolean => "Boolean",
IrPrimitiveKind::Array(kind) => { IrPrimitiveKind::Array(inner_kind) => &format!("Array<{}>", inner_kind),
writer.write("Array<")?; IrPrimitiveKind::String => "String",
kind.pretty_print(writer)?; IrPrimitiveKind::Closure(ir_closure_kind) => &format!("{}", ir_closure_kind),
writer.write(">")?; IrPrimitiveKind::Any => "Any",
Ok(()) IrPrimitiveKind::Void => "Void",
} };
IrPrimitiveKind::String => writer.write("String"), write!(f, "{}", s)
IrPrimitiveKind::Closure(closure_kind) => writer.write("Closure"),
IrPrimitiveKind::Ref(ref_kind) => {
todo!()
}
IrPrimitiveKind::Any => writer.write("Any"),
IrPrimitiveKind::Void => writer.write("Void"),
}
} }
} }
pub struct IrStructKind { pub struct IrStructKind {
name: String, name: Rc<str>,
} }
impl IrStructKind { impl IrStructKind {
pub fn new(name: &str) -> Self { pub fn new(name: &str) -> Self {
Self { Self { name: name.into() }
name: name.to_string(),
}
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { pub fn name_owned(&self) -> Rc<str> {
writer.write(&self.name) self.name.clone()
}
}
impl Display for IrStructKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.name)
} }
} }
pub struct IrClosureKind { pub struct IrClosureKind {
captures_struct_name: String, captures_struct_name: Rc<str>,
parameters: Vec<IrKind>, parameters: Vec<IrKind>,
return_type: Box<IrKind>, return_type: Box<IrKind>,
} }
impl Display for IrClosureKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"Closure |{}| ({}) -> {}",
self.captures_struct_name,
self.parameters
.iter()
.map(|ir_kind| format!("{}", ir_kind))
.collect::<Vec<_>>()
.join(", "),
self.return_type
)
}
}
pub struct IrFunction { pub struct IrFunction {
name: String, fqn: Rc<str>,
is_public: bool,
parameters: Vec<IrKind>, parameters: Vec<IrKind>,
return_type: Box<IrKind>, return_type: Box<IrKind>,
statements: Vec<IrStatement>, statements: Vec<IrStatement>,
locals_table: Box<LocalsTable>,
} }
impl IrFunction { impl IrFunction {
pub fn new( pub fn new(
name: String, fqn: &str,
is_public: bool,
parameters: Vec<IrKind>, parameters: Vec<IrKind>,
return_type: Box<IrKind>, return_type: IrKind,
statements: Vec<IrStatement>, statements: Vec<IrStatement>,
locals_table: Box<LocalsTable>,
) -> Self { ) -> Self {
Self { Self {
name, fqn: fqn.into(),
is_public,
parameters, parameters,
return_type, return_type: return_type.into(),
statements, statements,
locals_table,
} }
} }
pub fn name(&self) -> &str { pub fn fqn(&self) -> &str {
&self.name &self.fqn
}
pub fn fqn_owned(&self) -> Rc<str> {
self.fqn.clone()
} }
pub fn parameters(&self) -> &[IrKind] { pub fn parameters(&self) -> &[IrKind] {
@ -209,76 +280,93 @@ impl IrFunction {
pub fn statements(&self) -> &[IrStatement] { pub fn statements(&self) -> &[IrStatement] {
&self.statements &self.statements
} }
}
pub fn locals_table(&self) -> &LocalsTable { impl Display for IrFunction {
&self.locals_table fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
} if self.is_public {
write!(f, "pub ")?;
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write("fn ")?;
writer.write(&self.name)?;
writer.write("(")?;
for (i, parameter) in self.parameters.iter().enumerate() {
parameter.pretty_print(writer)?;
if i != self.parameters.len() - 1 {
writer.write(", ")?;
}
} }
writer.write(") -> ")?; writeln!(
self.return_type.pretty_print(writer)?; f,
writer.write(" {\n")?; "fn {}({}) -> {} {{",
writer.increase_indent(); self.fqn,
self.parameters
.iter()
.map(|ir_kind| format!("{}", ir_kind))
.collect::<Vec<_>>()
.join(", "),
self.return_type
)?;
for statement in &self.statements { for statement in &self.statements {
statement.pretty_print(writer)?; writeln!(f, " {}", statement)?;
} }
writer.decrease_indent(); writeln!(f, "}}")?;
writer.writeln("}")
}
}
pub struct IrPlatformFunction {
name: String,
parameters: Vec<IrKind>,
return_type: Box<IrKind>,
}
impl IrPlatformFunction {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write("platform fn ")?;
writer.write(&self.name)?;
writer.write("(")?;
for (i, parameter) in self.parameters.iter().enumerate() {
parameter.pretty_print(writer)?;
if i != self.parameters.len() - 1 {
writer.write(", ")?;
}
}
writer.write(") -> ")?;
self.return_type.pretty_print(writer)?;
writer.write("\n")?;
Ok(()) Ok(())
} }
} }
pub enum IrStatement { pub struct IrPlatformFunction {
Allocate(IrAllocate), fqn: Rc<str>,
Call(IrCall), is_public: bool,
Return(IrReturn), parameters: Vec<IrKind>,
Assign(IrAssign), return_type: Box<IrKind>,
MakeClosure(IrMakeClosure),
BinaryOperation(IrBinaryOperation),
} }
impl IrStatement { impl Display for IrPlatformFunction {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { if self.is_public {
IrStatement::Allocate(allocate) => allocate.pretty_print(writer), write!(f, "pub ")?;
IrStatement::Call(call) => call.pretty_print(writer),
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),
} }
writeln!(
f,
"platform fn {}({}) -> {}",
self.fqn,
self.parameters
.iter()
.map(|ir_kind| format!("{}", ir_kind))
.collect::<Vec<_>>()
.join(", "),
self.return_type
)
}
}
pub enum IrStatement {
Allocate(Box<IrAllocate>),
Call(Box<IrCall>),
Return(Box<IrReturn>),
Assign(Box<IrAssign>),
MakeClosure(Box<IrMakeClosure>),
BinaryOperation(Box<IrBinaryOperation>),
}
impl Display for IrStatement {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
IrStatement::Allocate(ir_allocate) => {
format!("{}", ir_allocate)
}
IrStatement::Call(ir_call) => {
format!("{}", ir_call)
}
IrStatement::Return(ir_return) => {
format!("{}", ir_return)
}
IrStatement::Assign(ir_assign) => {
format!("{}", ir_assign)
}
IrStatement::MakeClosure(ir_make_closure) => {
format!("{}", ir_make_closure)
}
IrStatement::BinaryOperation(ir_binary_operation) => {
format!("{}", ir_binary_operation)
}
}
)
} }
} }
@ -287,11 +375,15 @@ pub enum IrAllocable {
Array(Box<IrArrayKind>), Array(Box<IrArrayKind>),
} }
impl IrAllocable { impl Display for IrAllocable {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
IrAllocable::Struct(struct_kind) => struct_kind.pretty_print(writer), IrAllocable::Struct(ir_struct_kind) => {
IrAllocable::Array(array_kind) => array_kind.pretty_print(writer), write!(f, "{}(", ir_struct_kind)
}
IrAllocable::Array(ir_array_kind) => {
write!(f, "{}(", ir_array_kind)
}
} }
} }
} }
@ -301,11 +393,15 @@ pub enum IrArrayKind {
DynamicSize(Box<IrDynamicArrayKind>), DynamicSize(Box<IrDynamicArrayKind>),
} }
impl IrArrayKind { impl Display for IrArrayKind {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
IrArrayKind::StaticSize(static_array_kind) => static_array_kind.pretty_print(writer), IrArrayKind::StaticSize(ir_static_array_kind) => {
IrArrayKind::DynamicSize(dynamic_array_kind) => dynamic_array_kind.pretty_print(writer), write!(f, "{}", ir_static_array_kind)
}
IrArrayKind::DynamicSize(ir_dynamic_array_kind) => {
write!(f, "{}", ir_dynamic_array_kind)
}
} }
} }
} }
@ -315,12 +411,9 @@ pub struct IrStaticArrayKind {
size: usize, size: usize,
} }
impl IrStaticArrayKind { impl Display for IrStaticArrayKind {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writer.write("[")?; write!(f, "Array<{}>[{}]", self.inner_kind, self.size)
self.inner_kind.pretty_print(writer)?;
writer.write(&format!("; {}]", self.size))?;
Ok(())
} }
} }
@ -329,26 +422,33 @@ pub struct IrDynamicArrayKind {
size_expr: Box<IrExpression>, size_expr: Box<IrExpression>,
} }
impl IrDynamicArrayKind { impl Display for IrDynamicArrayKind {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
writer.write("[")?; write!(f, "Array<{}>", self.inner_kind)
self.inner_kind.pretty_print(writer)?;
writer.write("; ")?;
self.size_expr.pretty_print(writer)?;
writer.write("]")?;
Ok(())
} }
} }
pub struct IrAllocate { pub struct IrAllocate {
name: String, result_variable: Rc<str>,
declared_kind: Box<IrAllocable>, declared_kind: Box<IrAllocable>,
kind_to_alloc: Box<IrAllocable>, kind_to_alloc: Box<IrAllocable>,
} }
impl IrAllocate { impl IrAllocate {
pub fn name(&self) -> &str { pub fn new(
&self.name result_variable: &str,
declared_kind: IrAllocable,
kind_to_alloc: IrAllocable,
) -> Self {
Self {
result_variable: result_variable.into(),
declared_kind: declared_kind.into(),
kind_to_alloc: kind_to_alloc.into(),
}
}
pub fn result_variable(&self) -> &str {
&self.result_variable
} }
pub fn declared_kind(&self) -> &IrAllocable { pub fn declared_kind(&self) -> &IrAllocable {
@ -358,13 +458,15 @@ impl IrAllocate {
pub fn kind_to_alloc(&self) -> &IrAllocable { pub fn kind_to_alloc(&self) -> &IrAllocable {
&self.kind_to_alloc &self.kind_to_alloc
} }
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { impl Display for IrAllocate {
writer.write_indented(&format!("let {}: ", self.name))?; fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.declared_kind.pretty_print(writer)?; write!(
writer.write(" = alloc")?; f,
self.kind_to_alloc.pretty_print(writer)?; "{}: {} = alloc {}",
Ok(()) self.result_variable, self.declared_kind, self.kind_to_alloc
)
} }
} }
@ -405,16 +507,15 @@ impl IrBinaryOperation {
pub fn operator(&self) -> &IrBinaryOperator { pub fn operator(&self) -> &IrBinaryOperator {
&self.operator &self.operator
} }
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { impl Display for IrBinaryOperation {
writer.write_indented("")?; fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.destination.pretty_print(writer)?; write!(
writer.write(" = ")?; f,
self.left.pretty_print(writer)?; "{} = {} {} {}",
writer.write(&format!(" {} ", self.operator))?; self.destination, self.left, self.operator, self.right
self.right.pretty_print(writer)?; )
writer.writeln("")?;
Ok(())
} }
} }
@ -448,83 +549,46 @@ impl Display for IrBinaryOperator {
} }
} }
pub enum IrConst {
String(IrStringConst),
StringArray(IrStringArrayConst),
}
impl IrConst {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
todo!()
}
}
pub struct IrStringConst {
name: String,
value: String,
}
pub struct IrStringArrayConst {
name: String,
value: Vec<String>,
}
pub enum IrExpression { pub enum IrExpression {
Variable(Box<IrVariable>), Variable(Box<IrVariable>),
ConstRef(Box<IrConstRef>),
Literal(Box<IrLiteral>), Literal(Box<IrLiteral>),
} }
impl IrExpression { impl Display for IrExpression {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { write!(
IrExpression::Variable(variable) => variable.pretty_print(writer), f,
IrExpression::ConstRef(const_ref) => const_ref.pretty_print(writer), "{}",
IrExpression::Literal(literal) => literal.pretty_print(writer), match self {
} IrExpression::Variable(ir_variable) => {
format!("{}", ir_variable)
}
IrExpression::Literal(ir_literal) => {
format!("{}", ir_literal)
}
}
)
} }
} }
#[derive(Clone, Hash, Eq, PartialEq)] #[derive(Clone, Hash, Eq, PartialEq)]
pub struct IrVariable { pub struct IrVariable {
name: String, name: Rc<str>,
} }
impl IrVariable { impl IrVariable {
pub fn new(name: &str) -> Self { pub fn new(name: &str) -> Self {
Self { Self { name: name.into() }
name: name.to_string(),
}
} }
pub fn name(&self) -> &str { pub fn name(&self) -> &str {
&self.name &self.name
} }
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result {
writer.write(&self.name)
}
} }
pub struct IrConstRef { impl Display for IrVariable {
name: Rc<str>, fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
} write!(f, "{}", self.name)
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)
} }
} }
@ -544,57 +608,63 @@ pub enum IrLiteral {
Boolean(bool), Boolean(bool),
Float(f32), Float(f32),
Double(f64), Double(f64),
String(Rc<str>),
} }
impl IrLiteral { impl Display for IrLiteral {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { write!(
IrLiteral::I8(v) => writer.write(&format!("{}", v)), f,
IrLiteral::I16(v) => writer.write(&format!("{}", v)), "{}",
IrLiteral::I32(v) => writer.write(&format!("{}", v)), match self {
IrLiteral::I64(v) => writer.write(&format!("{}", v)), IrLiteral::I8(i) => format!("{}", *i),
IrLiteral::I128(v) => writer.write(&format!("{}", v)), IrLiteral::I16(i) => format!("{}", *i),
IrLiteral::ISize(v) => writer.write(&format!("{}", v)), IrLiteral::I32(i) => format!("{}", *i),
IrLiteral::U8(v) => writer.write(&format!("{}", v)), IrLiteral::I64(i) => format!("{}", *i),
IrLiteral::U16(v) => writer.write(&format!("{}", v)), IrLiteral::I128(i) => format!("{}", *i),
IrLiteral::U32(v) => writer.write(&format!("{}", v)), IrLiteral::ISize(i) => format!("{}", *i),
IrLiteral::U64(v) => writer.write(&format!("{}", v)), IrLiteral::U8(u) => format!("{}", *u),
IrLiteral::U128(v) => writer.write(&format!("{}", v)), IrLiteral::U16(u) => format!("{}", *u),
IrLiteral::USize(v) => writer.write(&format!("{}", v)), IrLiteral::U32(u) => format!("{}", *u),
IrLiteral::Boolean(v) => writer.write(&format!("{}", v)), IrLiteral::U64(u) => format!("{}", *u),
IrLiteral::Float(v) => writer.write(&format!("{}", v)), IrLiteral::U128(u) => format!("{}", *u),
IrLiteral::Double(v) => writer.write(&format!("{}", v)), IrLiteral::USize(u) => format!("{}", *u),
} IrLiteral::Boolean(b) => format!("{}", *b),
IrLiteral::Float(float) => format!("{}", *float),
IrLiteral::Double(double) => format!("{}", *double),
IrLiteral::String(s) => format!("{}", s),
}
)
} }
} }
pub struct IrCall { pub struct IrCall {
result_name: String, result_variable: Option<Rc<str>>,
declared_type: Box<IrKind>, declared_type: Box<IrKind>,
fqn: Rc<str>, function_fqn: Rc<str>,
call_type: IrCallType, call_type: IrCallType,
arguments: Vec<IrExpression>, arguments: Vec<IrExpression>,
} }
impl IrCall { impl IrCall {
pub fn new( pub fn new(
result_name: &str, result_variable: Option<&str>,
declared_type: Box<IrKind>, declared_type: IrKind,
fqn: &str, fqn: &str,
call_type: IrCallType, call_type: IrCallType,
arguments: Vec<IrExpression>, arguments: Vec<IrExpression>,
) -> Self { ) -> Self {
Self { Self {
result_name: result_name.to_string(), result_variable: result_variable.map(Rc::from),
declared_type, declared_type: declared_type.into(),
fqn: fqn.into(), function_fqn: fqn.into(),
call_type, call_type,
arguments, arguments,
} }
} }
pub fn result_name(&self) -> &str { pub fn result_variable(&self) -> Option<&str> {
&self.result_name self.result_variable.as_ref().map(Rc::as_ref)
} }
pub fn declared_type(&self) -> &IrKind { pub fn declared_type(&self) -> &IrKind {
@ -602,11 +672,11 @@ impl IrCall {
} }
pub fn function_name(&self) -> &str { pub fn function_name(&self) -> &str {
&self.fqn &self.function_fqn
} }
pub fn function_name_owned(&self) -> Rc<str> { pub fn function_name_owned(&self) -> Rc<str> {
self.fqn.clone() self.function_fqn.clone()
} }
pub fn call_type(&self) -> &IrCallType { pub fn call_type(&self) -> &IrCallType {
@ -616,25 +686,51 @@ impl IrCall {
pub fn arguments(&self) -> &[IrExpression] { pub fn arguments(&self) -> &[IrExpression] {
&self.arguments &self.arguments
} }
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { impl Display for IrCall {
writer.write_indented(&format!("{}: ", self.result_name))?; fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.declared_type.pretty_print(writer)?; if let Some(result_variable) = &self.result_variable {
writer.write(&format!(" = call {}(", self.fqn))?; write!(f, "{}: {} = ", result_variable, self.declared_type)?;
for (i, argument) in self.arguments.iter().enumerate() {
argument.pretty_print(writer)?;
if i != self.arguments.len() - 1 {
writer.write(", ")?;
}
} }
writer.write(")\n")?; write!(
Ok(()) f,
"{} {}({})",
self.call_type,
self.function_fqn,
self.arguments
.iter()
.map(|ir_expression| ir_expression.to_string())
.collect::<Vec<_>>()
.join(", ")
)
} }
} }
pub enum IrCallType { pub enum IrCallType {
Static, Static,
Object, Object,
PlatformStatic,
PlatformObject,
}
impl Display for IrCallType {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
IrCallType::Static => {
write!(f, "call_static")
}
IrCallType::Object => {
write!(f, "call_object")
}
IrCallType::PlatformStatic => {
write!(f, "call_platform_static")
}
IrCallType::PlatformObject => {
write!(f, "call_platform_object")
}
}
}
} }
pub struct IrAssign { pub struct IrAssign {
@ -643,8 +739,11 @@ pub struct IrAssign {
} }
impl IrAssign { impl IrAssign {
pub fn new(lhs: Box<IrVariable>, rhs: Box<IrExpression>) -> Self { pub fn new(lhs: IrVariable, rhs: IrExpression) -> Self {
Self { lhs, rhs } Self {
lhs: lhs.into(),
rhs: rhs.into(),
}
} }
pub fn lhs(&self) -> &IrVariable { pub fn lhs(&self) -> &IrVariable {
@ -654,34 +753,36 @@ impl IrAssign {
pub fn rhs(&self) -> &IrExpression { pub fn rhs(&self) -> &IrExpression {
&self.rhs &self.rhs
} }
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { impl Display for IrAssign {
writer.write_indented("")?; fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.lhs.pretty_print(writer)?; write!(f, "{} = {}", self.lhs, self.rhs)
writer.write(" = ")?;
self.rhs.pretty_print(writer)?;
writer.write("\n")?;
Ok(())
} }
} }
pub struct IrReturn { pub struct IrReturn {
expression: Box<IrExpression>, expression: Option<Box<IrExpression>>,
} }
impl IrReturn { impl IrReturn {
pub fn new(expression: Box<IrExpression>) -> Self { pub fn new(expression: Option<IrExpression>) -> Self {
Self { expression } Self {
expression: expression.map(Box::new),
}
} }
pub fn expression(&self) -> &IrExpression { pub fn expression(&self) -> Option<&IrExpression> {
&self.expression self.expression.as_ref().map(Box::as_ref)
} }
}
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { impl Display for IrReturn {
writer.write_indented("return ")?; fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
self.expression.pretty_print(writer)?; write!(f, "return")?;
writer.write("\n")?; if let Some(expression) = &self.expression {
write!(f, " {}", expression)?;
}
Ok(()) Ok(())
} }
} }
@ -690,13 +791,13 @@ pub struct IrMakeClosure {
captures_kind: Option<Box<IrStructKind>>, captures_kind: Option<Box<IrStructKind>>,
parameters: Vec<IrKind>, parameters: Vec<IrKind>,
return_type: Box<IrKind>, return_type: Box<IrKind>,
name: String, result_variable: Rc<str>,
fn_name: String, function_fqn: Rc<str>,
captures_variable: Box<IrVariable>, captures_variable: Box<IrVariable>,
} }
impl IrMakeClosure { impl Display for IrMakeClosure {
pub fn pretty_print(&self, writer: &mut IndentWriter) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
todo!() todo!()
} }
} }

View File

@ -1,6 +1,6 @@
#![feature(new_range_api)] #![feature(new_range_api)]
#![feature(coerce_unsized)]
#![feature(unsize)] #![feature(unsize)]
#![feature(coerce_unsized)]
#![allow(warnings)] #![allow(warnings)]
extern crate core; extern crate core;
@ -13,5 +13,6 @@ pub mod name_analysis;
pub mod object_file; pub mod object_file;
pub mod parser; pub mod parser;
pub mod std_core; pub mod std_core;
pub mod type_analysis;
pub mod util; pub mod util;
pub mod vm; pub mod vm;

View File

@ -529,9 +529,7 @@ fn na_p2_variable_declaration(
} }
// initializer // initializer
if let Some(expression) = variable_declaration.expression_mut() { na_p2_expression(variable_declaration.expression_mut(), symbol_table, diagnostics);
na_p2_expression(expression, symbol_table, diagnostics);
}
} }
fn na_p2_assignment_statement( fn na_p2_assignment_statement(

View File

@ -24,6 +24,10 @@ impl ClassSymbol {
} }
} }
pub fn fqn_formatted(&self) -> String {
self.fqn_parts.join("::")
}
pub fn declared_name(&self) -> &str { pub fn declared_name(&self) -> &str {
self.fqn_parts.last().unwrap() self.fqn_parts.last().unwrap()
} }

View File

@ -87,6 +87,10 @@ impl FunctionSymbol {
self.return_type.as_ref() self.return_type.as_ref()
} }
pub fn return_type_owned(&self) -> Option<TypeSymbol> {
self.return_type.clone()
}
pub fn set_return_type(&mut self, type_symbol: TypeSymbol) { pub fn set_return_type(&mut self, type_symbol: TypeSymbol) {
self.return_type = Some(type_symbol); self.return_type = Some(type_symbol);
} }

View File

@ -2,12 +2,13 @@ use crate::name_analysis::symbol::source_definition::SourceDefinition;
use crate::name_analysis::symbol::Symbol; use crate::name_analysis::symbol::Symbol;
use std::fmt::{Debug, Formatter}; use std::fmt::{Debug, Formatter};
use std::rc::Rc; use std::rc::Rc;
use crate::type_analysis::kinds::Kind;
#[derive(Clone)]
pub struct VariableSymbol { pub struct VariableSymbol {
declared_name: Rc<str>, declared_name: Rc<str>,
is_mutable: bool, is_mutable: bool,
source_definition: Option<SourceDefinition>, source_definition: Option<SourceDefinition>,
analyzed_kind: Option<Kind>,
} }
impl VariableSymbol { impl VariableSymbol {
@ -20,6 +21,7 @@ impl VariableSymbol {
declared_name: Rc::from(declared_name), declared_name: Rc::from(declared_name),
is_mutable, is_mutable,
source_definition, source_definition,
analyzed_kind: None,
} }
} }
@ -34,6 +36,14 @@ impl VariableSymbol {
pub fn is_mutable(&self) -> bool { pub fn is_mutable(&self) -> bool {
self.is_mutable self.is_mutable
} }
pub fn set_analyzed_kind(&mut self, analyzed_kind: Kind) {
self.analyzed_kind = Some(analyzed_kind);
}
pub fn analyzed_kind(&self) -> Option<&Kind> {
self.analyzed_kind.as_ref()
}
} }
impl Symbol for VariableSymbol { impl Symbol for VariableSymbol {

View File

@ -37,6 +37,9 @@ $defs:
- $ref: "#/$defs/PolymorphicTypeDefinition" - $ref: "#/$defs/PolymorphicTypeDefinition"
- $ref: "#/$defs/PolymorphicEnumLoopBuildDefinition" - $ref: "#/$defs/PolymorphicEnumLoopBuildDefinition"
- $ref: "#/$defs/PolymorphicPassThroughDefinition" - $ref: "#/$defs/PolymorphicPassThroughDefinition"
- $ref: "#/$defs/PolymorphicTreeEnumDefinition"
- $ref: "#/$defs/PolymorphicLeafEnumDefinition"
- $ref: "#/$defs/PolymorphicEnumInnerBuildDefinition"
# Struct # Struct
StructNodeDefinition: StructNodeDefinition:
@ -607,3 +610,88 @@ $defs:
- with - with
required: required:
- node_production - node_production
# Polymorphic Tree Enum
PolymorphicTreeEnumDefinition:
type: object
additionalProperties: false
properties:
polymorphic_tree_enum:
type: object
additionalProperties: false
properties:
kind:
type: string
rules:
type: array
items:
type: string
required:
- kind
- rules
required:
- polymorphic_tree_enum
# Polymorphic Leaf Enum
PolymorphicLeafEnumDefinition:
type: object
additionalProperties: false
properties:
polymorphic_leaf_enum:
type: object
additionalProperties: false
properties:
kind:
type: string
rules:
type: array
items:
type: string
required:
- kind
- rules
required:
- polymorphic_leaf_enum
# Polymorphic Enum Inner Build
PolymorphicEnumInnerBuildDefinition:
type: object
additionalProperties: false
properties:
polymorphic_enum_inner_build:
type: object
additionalProperties: false
properties:
members:
type: array
items:
$ref: "#/$defs/PolymorphicEnumInnerBuildMember"
rules:
type: array
items:
type: string
required:
- members
- rules
required:
- polymorphic_enum_inner_build
PolymorphicEnumInnerBuildMember:
type: object
oneOf:
- type: string
- $ref: "#/$defs/PolymorphicEnumInnerBuildAdvancedMember"
PolymorphicEnumInnerBuildAdvancedMember:
type: object
patternProperties:
"^([A-Z][a-z]*)*$":
type: object
additionalProperties: false
properties:
kind:
type: string
required:
- kind
minProperties: 1
maxProperties: 1

View File

@ -694,9 +694,7 @@ VariableDeclaration:
- type_use: - type_use:
member: member:
optional: true optional: true
- expression: - expression
member:
optional: true
fields: fields:
- variable_symbol: - variable_symbol:
kind: VariableSymbol kind: VariableSymbol
@ -1226,6 +1224,8 @@ IdentifierExpression:
fields: fields:
- expressible_symbol: - expressible_symbol:
kind: ExpressibleSymbol kind: ExpressibleSymbol
- analyzed_kind:
kind: Kind
ListExpression: ListExpression:
struct: struct:
children: children:

View File

@ -0,0 +1,27 @@
use std::fmt::Display;
use std::rc::Rc;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct ClassKind {
fqn: Rc<str>
}
impl ClassKind {
pub fn new(fqn: &str) -> Self {
Self { fqn: fqn.into() }
}
pub fn fqn(&self) -> &str {
&self.fqn
}
pub fn fqn_owned(&self) -> Rc<str> {
self.fqn.clone()
}
}
impl Display for ClassKind {
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
write!(f, "{}", self.fqn)
}
}

View File

@ -0,0 +1,27 @@
use std::fmt::{Display, Formatter};
use std::rc::Rc;
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct FunctionKind {
fqn: Rc<str>,
}
impl FunctionKind {
pub fn new(fqn: &str) -> Self {
Self { fqn: fqn.into() }
}
pub fn fqn(&self) -> &str {
&self.fqn
}
pub fn fqn_owned(&self) -> Rc<str> {
self.fqn.clone()
}
}
impl Display for FunctionKind {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", self.fqn)
}
}

View File

@ -0,0 +1,40 @@
pub use crate::type_analysis::kinds::class_kind::ClassKind;
pub use crate::type_analysis::kinds::function_kind::FunctionKind;
pub use crate::type_analysis::kinds::primitive_kind::PrimitiveKind;
use std::fmt::Display;
pub mod class_kind;
pub mod function_kind;
pub mod primitive_kind;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum Kind {
Primitive(Box<PrimitiveKind>),
Class(Box<ClassKind>),
Function(Box<FunctionKind>),
}
impl Kind {
pub fn expect_function(&self) -> &FunctionKind {
match self {
Kind::Function(function_kind) => function_kind,
_ => panic!("Expected FunctionKind, found {:?}", self),
}
}
}
impl Display for Kind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Kind::Primitive(primitive_kind) => {
write!(f, "{}", primitive_kind)
}
Kind::Class(class_kind) => {
write!(f, "{}", class_kind)
}
Kind::Function(function_kind) => {
write!(f, "{}", function_kind)
}
}
}
}

View File

@ -0,0 +1,24 @@
use std::fmt::Display;
use crate::type_analysis::kinds::Kind;
#[derive(Debug, Eq, PartialEq, Clone)]
pub enum PrimitiveKind {
Byte,
Char,
Short,
Int,
Long,
Float,
Double,
Boolean,
String,
Array { inner_type: Kind },
Any,
Void,
}
impl Display for PrimitiveKind {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{:?}", self)
}
}

232
src/type_analysis/mod.rs Normal file
View File

@ -0,0 +1,232 @@
pub mod kinds;
use crate::ast::node::{
AdditiveExpression, CompilationUnit, Expression, ExpressionStatement, Function,
FunctionBlockBody, FunctionBody, IdentifierExpression, ModuleLevelDeclaration, Statement,
VariableDeclaration,
};
use crate::diagnostic::DmDiagnostic;
use crate::name_analysis::symbol::ExpressibleSymbol;
use crate::type_analysis::kinds::class_kind::ClassKind;
use crate::type_analysis::kinds::function_kind::FunctionKind;
use crate::type_analysis::kinds::Kind;
use codespan_reporting::files::Files;
pub fn analyze_types(compilation_units: &mut [CompilationUnit]) -> Vec<DmDiagnostic> {
let mut diagnostics: Vec<DmDiagnostic> = vec![];
for compilation_unit in compilation_units {
ta_compilation_unit(compilation_unit, &mut diagnostics);
}
diagnostics
}
fn ta_compilation_unit(
compilation_unit: &mut CompilationUnit,
diagnostics: &mut Vec<DmDiagnostic>,
) {
for module_level_declaration in compilation_unit.module_level_declarations_mut() {
ta_module_level_declaration(module_level_declaration, diagnostics);
}
}
fn ta_module_level_declaration(
module_level_declaration: &mut ModuleLevelDeclaration,
diagnostics: &mut Vec<DmDiagnostic>,
) {
match module_level_declaration {
ModuleLevelDeclaration::Module(module) => {
todo!()
}
ModuleLevelDeclaration::Interface(interface) => {
todo!()
}
ModuleLevelDeclaration::Class(class) => {
todo!()
}
ModuleLevelDeclaration::Function(function) => {
ta_function(function, diagnostics);
}
ModuleLevelDeclaration::PlatformFunction(platform_function) => {
todo!()
}
}
}
fn ta_function(function: &mut Function, diagnostics: &mut Vec<DmDiagnostic>) {
ta_function_body(function.function_body_mut(), diagnostics);
}
fn ta_function_body(function_body: &mut FunctionBody, diagnostics: &mut Vec<DmDiagnostic>) {
match function_body {
FunctionBody::FunctionAliasBody(function_alias_body) => {
todo!()
}
FunctionBody::FunctionEqualsBody(function_equals_body) => {
todo!()
}
FunctionBody::FunctionBlockBody(function_block_body) => {
ta_function_block_body(function_block_body, diagnostics);
}
}
}
fn ta_function_block_body(
function_block_body: &mut FunctionBlockBody,
diagnostics: &mut Vec<DmDiagnostic>,
) {
for statement in function_block_body.statements_mut() {
ta_statement(statement, diagnostics);
}
}
fn ta_statement(statement: &mut Statement, diagnostics: &mut Vec<DmDiagnostic>) {
match statement {
Statement::VariableDeclaration(variable_declaration) => {
ta_variable_declaration(variable_declaration, diagnostics);
}
Statement::AssignmentStatement(assignment_statement) => {
todo!()
}
Statement::ExpressionStatement(expression_statement) => {
ta_expression_statement(expression_statement, diagnostics);
}
Statement::UseStatement(use_statement) => {
todo!()
}
Statement::IfStatement(if_statement) => {
todo!()
}
Statement::WhileStatement(while_statement) => {
todo!()
}
Statement::ForStatement(for_statement) => {
todo!()
}
}
}
fn ta_variable_declaration(
variable_declaration: &mut VariableDeclaration,
diagnostics: &mut Vec<DmDiagnostic>,
) {
// compute type of initializer
ta_expression(variable_declaration.expression_mut(), diagnostics);
// get type of initializer, and check against to declared type (if present)
// todo
// set type of variable's symbol to analyzed type (initializer type or declared type)
let variable_kind = if let Some(declared_type) = variable_declaration.type_use() {
todo!("declared types on variable declarations")
} else {
variable_declaration.expression().analyzed_kind().clone()
};
variable_declaration
.variable_symbol_mut()
.expect("VariableDeclaration's variable_symbol not set.")
.borrow_mut()
.set_analyzed_kind(variable_kind)
}
fn ta_expression_statement(
expression_statement: &mut ExpressionStatement,
diagnostics: &mut Vec<DmDiagnostic>,
) {
ta_expression(expression_statement.expression_mut(), diagnostics);
}
fn ta_expression(expression: &mut Expression, diagnostics: &mut Vec<DmDiagnostic>) {
match expression {
Expression::Ternary(ternary_expression) => {
todo!()
}
Expression::Or(or_expression) => {
todo!()
}
Expression::And(and_expression) => {
todo!()
}
Expression::Comparison(comparison_expression) => {
todo!()
}
Expression::Shift(shift_expression) => {
todo!()
}
Expression::Additive(additive_expression) => {
ta_additive_expression(additive_expression, diagnostics);
}
Expression::Multiplicative(multiplicative_expression) => {
todo!()
}
Expression::Prefix(prefix_expression) => {
todo!()
}
Expression::Suffix(suffix_expression) => {
todo!()
}
Expression::Literal(literal) => {
// no-op
}
Expression::Identifier(identifier_expression) => {
ta_identifier_expression(identifier_expression);
}
Expression::Fqn(fqn) => {
todo!()
}
Expression::Closure(closure) => {
todo!()
}
Expression::List(list_expression) => {
todo!()
}
}
}
fn ta_additive_expression(
additive_expression: &mut AdditiveExpression,
diagnostics: &mut Vec<DmDiagnostic>,
) {
ta_expression(additive_expression.left_mut(), diagnostics);
ta_expression(additive_expression.rhs_mut().expression_mut(), diagnostics);
let left_kind = additive_expression.left().analyzed_kind();
let right_kind = additive_expression.rhs().expression().analyzed_kind();
if left_kind != right_kind {
diagnostics.push(DmDiagnostic::error().with_message(&format!(
"Incompatible types for additive expression: {} vs. {}",
left_kind, right_kind
)));
todo!("Error file_id and range; set Error type on additive expression")
} else {
todo!("set analyzed type for additive expression")
}
}
fn ta_identifier_expression(identifier_expression: &mut IdentifierExpression) {
let expressible_symbol = identifier_expression
.expressible_symbol()
.expect("IdentifierExpression's expressible_symbol must be set before type analysis.");
let kind = match expressible_symbol {
ExpressibleSymbol::Class(class_symbol) => {
let class_kind = ClassKind::new(&class_symbol.borrow().fqn_formatted());
Kind::Class(class_kind.into())
}
ExpressibleSymbol::Function(function_symbol) => {
let function_kind = FunctionKind::new(&function_symbol.borrow().fqn_formatted());
Kind::Function(function_kind.into())
}
ExpressibleSymbol::ClassMember(class_member_symbol) => {
todo!()
}
ExpressibleSymbol::Parameter(parameter_symbol) => {
todo!()
}
ExpressibleSymbol::Variable(variable_symbol) => variable_symbol
.borrow()
.analyzed_kind()
.expect("VariableSymbol's analyzed_kind not set.")
.clone(),
};
identifier_expression.set_analyzed_kind(kind);
}