use crate::ast::node::{ CompilationUnit, Expression, Function, FunctionBlockBody, FunctionBody, Literal, ModuleLevelDeclaration, Statement, VariableDeclaration, }; use crate::ir::{ Ir, IrAssign, IrConst, IrExpression, IrFunction, IrKind, IrLiteral, IrPrimitiveKind, IrStatement, IrVariable, }; use crate::name_analysis::symbol::{ParameterSymbol, PrimitiveTypeSymbol, TypeSymbol}; use std::cell::RefCell; use std::collections::HashMap; use std::rc::Rc; pub fn lower_compilation_unit(compilation_unit: &CompilationUnit) -> Vec { let mut result: Vec = vec![]; 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 { match declaration { ModuleLevelDeclaration::Module(module) => { todo!() } ModuleLevelDeclaration::Interface(interface) => { todo!() } ModuleLevelDeclaration::Class(class) => { todo!() } ModuleLevelDeclaration::Function(function) => lower_function(function), ModuleLevelDeclaration::PlatformFunction(platform_function) => { todo!() } } } pub struct LocalsTable { t_count: usize, stack_slot_count: usize, stack_slots: HashMap, } impl LocalsTable { pub fn new() -> Self { Self { t_count: 0, stack_slot_count: 0, stack_slots: HashMap::new(), } } pub fn next_t_var(&mut self) -> IrVariable { let t_num = self.t_count; self.t_count += 1; let t_name = format!("__t{}", t_num); let t_var = IrVariable::new(&t_name); self.register_stack_local(&t_var); t_var } pub fn register_stack_local(&mut self, ir_variable: &IrVariable) { let stack_slot = self.stack_slot_count; 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() } } fn lower_function(function: &Function) -> Vec { let function_symbol = function.function_symbol().unwrap().borrow(); let name = function_symbol.fqn_parts_owned().join("::"); let parameters = lower_parameter_symbols(function_symbol.parameter_symbols()); let return_type = lower_type_symbol(function_symbol.return_type().unwrap()); let mut locals_table = LocalsTable::new(); let (statements, consts) = lower_function_body(function.function_body(), &mut locals_table); let mut result: Vec = vec![]; result.push(Ir::Function(Box::new(IrFunction::new( name, parameters, Box::new(return_type), statements, Box::new(locals_table), )))); result.append( &mut consts .into_iter() .map(|constant| Ir::Const(Box::new(constant))) .collect(), ); result } fn lower_parameter_symbols(parameter_symbols: &[Rc>]) -> Vec { parameter_symbols .iter() .map(|parameter_symbol_rc| parameter_symbol_rc.borrow()) .map(|parameter_symbol| lower_type_symbol(parameter_symbol.type_symbol().unwrap())) .collect() } fn lower_type_symbol(type_symbol: &TypeSymbol) -> IrKind { match type_symbol { TypeSymbol::Primitive(primitive_type_symbol) => { lower_primitive_type_symbol(primitive_type_symbol) } TypeSymbol::Class(class_type_symbol) => { todo!() } TypeSymbol::Interface(interface_type_symbol) => { todo!() } TypeSymbol::Generic(generic_type_symbol) => { todo!() } } } fn lower_primitive_type_symbol(primitive_type_symbol: &PrimitiveTypeSymbol) -> IrKind { IrKind::Primitive(Box::new(match primitive_type_symbol { PrimitiveTypeSymbol::Byte => IrPrimitiveKind::I8, PrimitiveTypeSymbol::Char => IrPrimitiveKind::I8, PrimitiveTypeSymbol::Short => IrPrimitiveKind::I16, PrimitiveTypeSymbol::Int => IrPrimitiveKind::I32, PrimitiveTypeSymbol::Long => IrPrimitiveKind::I64, PrimitiveTypeSymbol::Float => IrPrimitiveKind::Float, PrimitiveTypeSymbol::Double => IrPrimitiveKind::Double, PrimitiveTypeSymbol::Boolean => IrPrimitiveKind::Boolean, PrimitiveTypeSymbol::String => IrPrimitiveKind::String, PrimitiveTypeSymbol::TypedArray { inner_type } => { IrPrimitiveKind::Array(Box::new(lower_type_symbol(inner_type.as_ref().unwrap()))) } PrimitiveTypeSymbol::Any => { todo!() } PrimitiveTypeSymbol::Void => IrPrimitiveKind::Void, })) } fn lower_function_body( function_body: &FunctionBody, locals_table: &mut LocalsTable ) -> (Vec, Vec) { match function_body { FunctionBody::FunctionAliasBody(alias_body) => { todo!() } FunctionBody::FunctionEqualsBody(equals_body) => { todo!() } FunctionBody::FunctionBlockBody(block_body) => { lower_function_block_body(block_body, locals_table) } } } fn lower_function_block_body( body: &FunctionBlockBody, locals_table: &mut LocalsTable ) -> (Vec, Vec) { let mut statements: Vec = vec![]; let mut consts: Vec = vec![]; for statement in body.statements() { statements.append(&mut lower_statement(statement, &mut consts, locals_table)); } (statements, consts) } fn lower_statement( statement: &Statement, consts_pool: &mut Vec, locals_table: &mut LocalsTable ) -> Vec { match statement { Statement::VariableDeclaration(variable_declaration) => { lower_variable_declaration(variable_declaration, consts_pool, locals_table) } Statement::AssignmentStatement(assignment_statement) => { todo!() } Statement::ExpressionStatement(expression_statement) => { todo!() } Statement::UseStatement(use_statement) => { todo!() } Statement::IfStatement(if_statement) => { todo!() } Statement::WhileStatement(while_statement) => { todo!() } Statement::ForStatement(for_statement) => { todo!() } } } fn lower_variable_declaration( variable_declaration: &VariableDeclaration, consts_pool: &mut Vec, locals_table: &mut LocalsTable ) -> Vec { let mut result: Vec = vec![]; let expression_t_var = lower_expression( variable_declaration.expression().unwrap(), &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( expression: &Expression, target: &mut Vec, consts_pool: &mut Vec, 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) => { todo!() } Expression::Multiplicative(multiplicative) => { todo!() } Expression::Prefix(prefix) => { todo!() } Expression::Suffix(suffix) => { todo!() } Expression::Literal(literal) => lower_literal(literal, target, consts_pool, locals_table), Expression::Identifier(identifier) => { todo!() } Expression::Fqn(fqn) => { todo!() } Expression::Closure(closure) => { todo!() } Expression::List(list) => { todo!() } } } fn lower_literal( literal: &Literal, statements: &mut Vec, consts_pool: &mut Vec, locals_table: &mut LocalsTable ) -> IrVariable { match literal { Literal::IntLiteral(int_literal) => { let t_var = locals_table.next_t_var(); let assign_stmt = IrAssign::new( Box::new(t_var.clone()), Box::new(IrExpression::Literal(Box::new(IrLiteral::I32( *int_literal, )))), ); statements.push(IrStatement::Assign(assign_stmt)); t_var } Literal::LongLiteral(long_literal) => { todo!() } Literal::DoubleLiteral(double_literal) => { todo!() } Literal::SingleQuoteString(sq_string) => { todo!() } Literal::DString(d_string) => { todo!() } Literal::BacktickString(b_string) => { todo!() } Literal::BooleanLiteral(boolean_literal) => { todo!() } } }