670 lines
21 KiB
Rust
670 lines
21 KiB
Rust
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<Ir> {
|
|
let mut result: Vec<Ir> = 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<Ir> {
|
|
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<IrVariable, usize>,
|
|
}
|
|
|
|
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<Ir> {
|
|
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<Ir> = 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<RefCell<ParameterSymbol>>]) -> Vec<IrKind> {
|
|
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<IrStatement>, Vec<IrConst>) {
|
|
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<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(
|
|
statement: &Statement,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> Vec<IrStatement> {
|
|
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<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> Vec<IrStatement> {
|
|
let mut result: Vec<IrStatement> = 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<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) => {
|
|
todo!()
|
|
}
|
|
Expression::Closure(closure) => {
|
|
todo!()
|
|
}
|
|
Expression::List(list) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lower_suffix_expression(
|
|
suffix_expression: &SuffixExpression,
|
|
target: &mut Vec<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> IrVariable {
|
|
let receiver_variable = lower_expression(
|
|
suffix_expression.expression(),
|
|
target,
|
|
consts_pool,
|
|
locals_table,
|
|
);
|
|
match suffix_expression.operator() {
|
|
SuffixOperator::PlusPlus => {
|
|
let result_var = locals_table.next_t_var();
|
|
let operation = IrBinaryOperation::new(
|
|
result_var.clone(),
|
|
IrExpression::Variable(receiver_variable.into()),
|
|
IrExpression::Literal(IrLiteral::I32(1).into()),
|
|
IrBinaryOperator::Add,
|
|
);
|
|
target.push(IrStatement::BinaryOperation(operation));
|
|
result_var
|
|
}
|
|
SuffixOperator::MinusMinus => {
|
|
let result_var = locals_table.next_t_var();
|
|
let operation = IrBinaryOperation::new(
|
|
result_var.clone(),
|
|
IrExpression::Variable(receiver_variable.into()),
|
|
IrExpression::Literal(IrLiteral::I32(1).into()),
|
|
IrBinaryOperator::Subtract,
|
|
);
|
|
target.push(IrStatement::BinaryOperation(operation));
|
|
result_var
|
|
}
|
|
SuffixOperator::ObjectIndex(object_index) => {
|
|
todo!()
|
|
}
|
|
SuffixOperator::Call(call) => lower_call(
|
|
call,
|
|
suffix_expression.expression(),
|
|
target,
|
|
consts_pool,
|
|
locals_table,
|
|
),
|
|
SuffixOperator::ObjectProperty(object_property) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
|
|
fn lower_literal(
|
|
literal: &Literal,
|
|
statements: &mut Vec<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> 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<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> IrVariable {
|
|
let fqn = match receiver {
|
|
Expression::Ternary(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Or(_) => {
|
|
todo!()
|
|
}
|
|
Expression::And(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Comparison(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Shift(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Additive(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Multiplicative(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Prefix(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Suffix(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Literal(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Identifier(identifier_expression) => {
|
|
match identifier_expression.expressible_symbol().unwrap() {
|
|
ExpressibleSymbol::Class(class_symbol) => {
|
|
todo!()
|
|
}
|
|
ExpressibleSymbol::Function(function_symbol) => {
|
|
function_symbol.borrow().fqn_formatted()
|
|
}
|
|
ExpressibleSymbol::ClassMember(class_member_symbol) => {
|
|
todo!()
|
|
}
|
|
ExpressibleSymbol::Parameter(parameter_symbol) => {
|
|
todo!()
|
|
}
|
|
ExpressibleSymbol::Variable(variable_symbol) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
Expression::Fqn(fqn) => {
|
|
todo!()
|
|
}
|
|
Expression::Closure(_) => {
|
|
todo!()
|
|
}
|
|
Expression::List(_) => {
|
|
todo!()
|
|
}
|
|
};
|
|
let declared_type = match receiver {
|
|
Expression::Ternary(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Or(_) => {
|
|
todo!()
|
|
}
|
|
Expression::And(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Comparison(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Shift(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Additive(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Multiplicative(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Prefix(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Suffix(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Literal(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Identifier(identifier_expression) => {
|
|
match identifier_expression.expressible_symbol().unwrap() {
|
|
ExpressibleSymbol::Class(_) => {
|
|
todo!()
|
|
}
|
|
ExpressibleSymbol::Function(function_symbol) => {
|
|
match function_symbol.borrow().return_type().expect(&format!(
|
|
"Expected return type for fn {}",
|
|
function_symbol.borrow().fqn_formatted()
|
|
)) {
|
|
TypeSymbol::Primitive(primitive_type_symbol) => match primitive_type_symbol
|
|
{
|
|
PrimitiveTypeSymbol::Byte => {
|
|
IrKind::Primitive(IrPrimitiveKind::I8.into())
|
|
}
|
|
PrimitiveTypeSymbol::Char => {
|
|
todo!()
|
|
}
|
|
PrimitiveTypeSymbol::Short => {
|
|
IrKind::Primitive(IrPrimitiveKind::I16.into())
|
|
}
|
|
PrimitiveTypeSymbol::Int => {
|
|
IrKind::Primitive(IrPrimitiveKind::I32.into())
|
|
}
|
|
PrimitiveTypeSymbol::Long => {
|
|
IrKind::Primitive(IrPrimitiveKind::I64.into())
|
|
}
|
|
PrimitiveTypeSymbol::Float => {
|
|
IrKind::Primitive(IrPrimitiveKind::Float.into())
|
|
}
|
|
PrimitiveTypeSymbol::Double => {
|
|
IrKind::Primitive(IrPrimitiveKind::Double.into())
|
|
}
|
|
PrimitiveTypeSymbol::Boolean => {
|
|
IrKind::Primitive(IrPrimitiveKind::Boolean.into())
|
|
}
|
|
PrimitiveTypeSymbol::String => {
|
|
IrKind::Primitive(IrPrimitiveKind::String.into())
|
|
}
|
|
PrimitiveTypeSymbol::TypedArray { inner_type } => {
|
|
todo!()
|
|
}
|
|
PrimitiveTypeSymbol::Any => {
|
|
IrKind::Primitive(IrPrimitiveKind::Any.into())
|
|
}
|
|
PrimitiveTypeSymbol::Void => {
|
|
IrKind::Primitive(IrPrimitiveKind::Void.into())
|
|
}
|
|
},
|
|
TypeSymbol::Class(class_symbol) => {
|
|
todo!()
|
|
}
|
|
TypeSymbol::Interface(interface_symbol) => {
|
|
todo!()
|
|
}
|
|
TypeSymbol::Generic(generic_symbol) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
ExpressibleSymbol::ClassMember(_) => {
|
|
todo!()
|
|
}
|
|
ExpressibleSymbol::Parameter(_) => {
|
|
todo!()
|
|
}
|
|
ExpressibleSymbol::Variable(_) => {
|
|
todo!()
|
|
}
|
|
}
|
|
}
|
|
Expression::Fqn(_) => {
|
|
todo!()
|
|
}
|
|
Expression::Closure(_) => {
|
|
todo!()
|
|
}
|
|
Expression::List(_) => {
|
|
todo!()
|
|
}
|
|
};
|
|
|
|
let arg_vars = match call {
|
|
Call::ParenthesesCall(p_call) => {
|
|
let mut arg_vars: Vec<IrVariable> = vec![];
|
|
if let Some(expression_list) = p_call.expression_list() {
|
|
arg_vars.append(&mut lower_expression_list(
|
|
expression_list,
|
|
target,
|
|
consts_pool,
|
|
locals_table,
|
|
));
|
|
}
|
|
if let Some(closure) = p_call.closure() {
|
|
arg_vars.push(lower_closure(closure, target, consts_pool, locals_table));
|
|
}
|
|
arg_vars
|
|
}
|
|
Call::ClosureOnlyCall(c_call) => {
|
|
vec![lower_closure(
|
|
c_call.closure(),
|
|
target,
|
|
consts_pool,
|
|
locals_table,
|
|
)]
|
|
}
|
|
};
|
|
let arg_expressions = arg_vars
|
|
.iter()
|
|
.map(|ir_variable| IrExpression::Variable(ir_variable.clone().into()))
|
|
.collect::<Vec<_>>();
|
|
|
|
let result_var = locals_table.next_t_var();
|
|
let call = IrCall::new(
|
|
result_var.name(),
|
|
declared_type.into(),
|
|
&fqn,
|
|
IrCallType::Static,
|
|
arg_expressions,
|
|
);
|
|
target.push(IrStatement::Call(call));
|
|
result_var
|
|
}
|
|
|
|
fn lower_expression_list(
|
|
expression_list: &ExpressionList,
|
|
target: &mut Vec<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> Vec<IrVariable> {
|
|
let mut results: Vec<IrVariable> = vec![];
|
|
for expression in expression_list.expressions() {
|
|
results.push(lower_expression(
|
|
expression,
|
|
target,
|
|
consts_pool,
|
|
locals_table,
|
|
));
|
|
}
|
|
results
|
|
}
|
|
|
|
fn lower_closure(
|
|
closure: &Closure,
|
|
target: &mut Vec<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> IrVariable {
|
|
todo!()
|
|
}
|
|
|
|
fn lower_identifier(
|
|
identifier: &Identifier,
|
|
target: &mut Vec<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> IrVariable {
|
|
IrVariable::new(identifier.name())
|
|
}
|
|
|
|
fn lower_additive_expression(
|
|
additive: &AdditiveExpression,
|
|
target: &mut Vec<IrStatement>,
|
|
consts_pool: &mut Vec<IrConst>,
|
|
locals_table: &mut LocalsTable,
|
|
) -> IrVariable {
|
|
let left_var = lower_expression(additive.left(), target, consts_pool, locals_table);
|
|
let right_var = lower_expression(additive.rhs().expression(), target, consts_pool, locals_table);
|
|
let destination = locals_table.next_t_var();
|
|
let operator = match additive.rhs().operator() {
|
|
AdditiveOperator::Add => {
|
|
IrBinaryOperator::Add
|
|
}
|
|
AdditiveOperator::Subtract => {
|
|
IrBinaryOperator::Subtract
|
|
}
|
|
};
|
|
let operation = IrBinaryOperation::new(
|
|
destination.clone(),
|
|
IrExpression::Variable(left_var.into()),
|
|
IrExpression::Variable(right_var.into()),
|
|
operator
|
|
);
|
|
target.push(IrStatement::BinaryOperation(operation));
|
|
destination
|
|
}
|