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, IrBinaryOperation, IrBinaryOperator, IrCall, IrCallType, IrConst, IrExpression, IrFunction, IrKind, IrLiteral, IrPrimitiveKind, IrStatement, IrVariable, }; use crate::name_analysis::symbol::{ ExpressibleSymbol, 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 { 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) => { lower_expression_statement(expression_statement, consts_pool, locals_table) } 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_statement( expression_statement: &ExpressionStatement, consts_pool: &mut Vec, locals_table: &mut LocalsTable, ) -> Vec { let mut result: Vec = vec![]; lower_expression( expression_statement.expression(), &mut result, consts_pool, locals_table, ); 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) => { 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) => { todo!() } Expression::Closure(closure) => { todo!() } Expression::List(list) => { todo!() } } } fn lower_suffix_expression( suffix_expression: &SuffixExpression, target: &mut Vec, consts_pool: &mut Vec, 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, 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!() } } } fn lower_call( call: &Call, receiver: &Expression, target: &mut Vec, consts_pool: &mut Vec, 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 = 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::>(); 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, consts_pool: &mut Vec, locals_table: &mut LocalsTable, ) -> Vec { let mut results: Vec = 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, consts_pool: &mut Vec, locals_table: &mut LocalsTable, ) -> IrVariable { todo!() } fn lower_identifier( identifier: &Identifier, target: &mut Vec, consts_pool: &mut Vec, locals_table: &mut LocalsTable, ) -> IrVariable { IrVariable::new(identifier.name()) } fn lower_additive_expression( additive: &AdditiveExpression, target: &mut Vec, consts_pool: &mut Vec, 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 }