grade-irgen-small.sh 스크립트에서 switch.c 예제까지 통과하는 상태
This commit is contained in:
static
2025-04-06 13:10:36 +00:00
parent 88f6f9471b
commit b1de106aeb

View File

@@ -38,8 +38,10 @@ use core::cmp::Ordering;
use core::convert::TryFrom;
use core::{fmt, mem};
use std::collections::{BTreeMap, HashMap};
use std::fmt::Binary;
use std::ops::Deref;
use ir::BlockExit;
use itertools::izip;
use lang_c::ast::*;
use lang_c::driver::Parse;
@@ -590,7 +592,921 @@ impl IrgenFunc<'_> {
bid_continue: Option<ir::BlockId>,
bid_break: Option<ir::BlockId>,
) -> Result<(), IrgenError> {
todo!()
match stmt {
Statement::Labeled(stmt) => Err(IrgenError::new(
stmt.node.label.write_string(),
IrgenErrorMessage::Misc {
message: "label statement not within a switch".to_string(),
},
)),
Statement::Compound(items) => {
self.enter_scope();
for item in items {
match &item.node {
BlockItem::Declaration(decl) => self
.translate_decl(&decl.node, context)
.map_err(|e| IrgenError::new(decl.write_string(), e))?,
BlockItem::StaticAssert(_) => {
panic!("BlockItem::StaticAssert is unsupported")
}
BlockItem::Statement(stmt) => {
self.translate_stmt(&stmt.node, context, bid_continue, bid_break)?
}
}
}
self.exit_scope();
Ok(())
}
Statement::Expression(expr) => {
if let Some(expr) = expr {
let _unused = self
.translate_expr_rvalue(&expr.node, context)
.map_err(|e| IrgenError::new(expr.write_string(), e))?;
}
Ok(())
}
Statement::If(stmt) => {
let stmt = &stmt.node;
let then_bid = self.alloc_bid();
let else_bid = self.alloc_bid();
let end_bid = self.alloc_bid();
self.translate_condition(
&stmt.condition.node,
mem::replace(context, Context::new(end_bid)),
then_bid,
else_bid,
)
.map_err(|e| IrgenError::new(stmt.condition.write_string(), e))?;
let mut then_context = Context::new(then_bid);
self.translate_stmt(
&stmt.then_statement.node,
&mut then_context,
bid_continue,
bid_break,
)?;
self.insert_block(
then_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(end_bid, Vec::new()),
},
);
let mut else_context = Context::new(else_bid);
if let Some(else_stmt) = &stmt.else_statement {
self.translate_stmt(
&else_stmt.node,
&mut else_context,
bid_continue,
bid_break,
)?;
}
self.insert_block(
else_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(end_bid, Vec::new()),
},
);
Ok(())
}
Statement::Switch(stmt) => {
let stmt = &stmt.node;
let value = self
.translate_expr_rvalue(&stmt.expression.node, context)
.map_err(|e| IrgenError::new(stmt.expression.write_string(), e))?;
let end_bid = self.alloc_bid();
let (cases, default_bid) =
self.translate_switch_body(&stmt.statement.node, end_bid)?;
self.insert_block(
mem::replace(context, Context::new(end_bid)),
ir::BlockExit::Switch {
value,
default: ir::JumpArg::new(default_bid, Vec::new()),
cases,
},
);
Ok(())
}
Statement::While(stmt) => {
let stmt = &stmt.node;
let cond_bid = self.alloc_bid();
self.insert_block(
mem::replace(context, Context::new(cond_bid)),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(cond_bid, Vec::new()),
},
);
let body_bid = self.alloc_bid();
let end_bid = self.alloc_bid();
self.translate_condition(
&stmt.expression.node,
mem::replace(context, Context::new(end_bid)),
body_bid,
end_bid,
);
self.enter_scope();
let mut body_context = Context::new(body_bid);
self.translate_stmt(
&stmt.statement.node,
&mut body_context,
Some(cond_bid),
Some(end_bid),
)?;
self.insert_block(
body_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(cond_bid, Vec::new()),
},
);
self.exit_scope();
Ok(())
}
Statement::DoWhile(stmt) => {
let stmt = &stmt.node;
let body_bid = self.alloc_bid();
self.insert_block(
mem::replace(context, Context::new(body_bid)),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(body_bid, Vec::new()),
},
);
self.enter_scope();
let cond_bid = self.alloc_bid();
let end_bid = self.alloc_bid();
self.translate_stmt(&stmt.statement.node, context, Some(cond_bid), Some(end_bid))?;
self.exit_scope();
self.insert_block(
mem::replace(context, Context::new(cond_bid)),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(cond_bid, Vec::new()),
},
);
self.translate_condition(
&stmt.expression.node,
mem::replace(context, Context::new(end_bid)),
body_bid,
end_bid,
)
.map_err(|e| IrgenError::new(stmt.expression.write_string(), e))?;
Ok(())
}
Statement::For(stmt) => {
let stmt = &stmt.node;
let init_bid = self.alloc_bid();
self.insert_block(
mem::replace(context, Context::new(init_bid)),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(init_bid, Vec::new()),
},
);
self.enter_scope();
self.translate_for_initializer(&stmt.initializer.node, context)
.map_err(|e| IrgenError::new(stmt.initializer.write_string(), e))?;
let cond_bid = self.alloc_bid();
self.insert_block(
mem::replace(context, Context::new(cond_bid)),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(cond_bid, Vec::new()),
},
);
let body_bid = self.alloc_bid();
let step_bid = self.alloc_bid();
let end_bid = self.alloc_bid();
self.translate_opt_condition(
&stmt.condition,
mem::replace(context, Context::new(end_bid)),
body_bid,
end_bid,
)
.map_err(|e| IrgenError::new(stmt.condition.write_string(), e))?;
self.enter_scope();
let mut body_context = Context::new(body_bid);
self.translate_stmt(
&stmt.statement.node,
&mut body_context,
Some(step_bid),
Some(end_bid),
)?;
self.exit_scope();
self.insert_block(
body_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(step_bid, Vec::new()),
},
);
let mut step_context = Context::new(step_bid);
if let Some(step_expr) = &stmt.step {
let _unused = self
.translate_expr_rvalue(&step_expr.node, &mut step_context)
.map_err(|e| IrgenError::new(stmt.step.write_string(), e))?;
}
self.insert_block(
step_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(cond_bid, Vec::new()),
},
);
Ok(())
}
Statement::Continue => {
let bid_continue = bid_continue.ok_or_else(|| {
IrgenError::new(
"continue;".to_string(),
IrgenErrorMessage::Misc {
message: "continue statement not within a loop".to_string(),
},
)
})?;
let next_context = Context::new(self.alloc_bid());
self.insert_block(
mem::replace(context, next_context),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(bid_continue, Vec::new()),
},
);
Ok(())
}
Statement::Break => {
let bid_break = bid_break.ok_or_else(|| {
IrgenError::new(
"break;".to_string(),
IrgenErrorMessage::Misc {
message: "break statement not within a loop".to_string(),
},
)
})?;
let next_context = Context::new(self.alloc_bid());
self.insert_block(
mem::replace(context, next_context),
ir::BlockExit::Jump {
arg: ir::JumpArg::new(bid_break, Vec::new()),
},
);
Ok(())
}
Statement::Return(expr) => {
let value = match expr {
Some(expr) => self
.translate_expr_rvalue(&expr.node, context)
.map_err(|e| IrgenError::new(expr.write_string(), e))?,
None => ir::Operand::constant(ir::Constant::unit()),
};
let value = self
.translate_typecast(value, self.return_type.clone(), context)
.map_err(|e| IrgenError::new(expr.write_string(), e))?;
let end_bid = self.alloc_bid();
self.insert_block(
mem::replace(context, Context::new(end_bid)),
ir::BlockExit::Return { value },
);
Ok(())
}
_ => todo!("e"),
}
}
fn translate_decl(
&mut self,
decl: &Declaration,
context: &mut Context,
) -> Result<(), IrgenErrorMessage> {
let (base_dtype, is_typedef) =
ir::Dtype::try_from_ast_declaration_specifiers(&decl.specifiers)
.map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?;
assert!(!is_typedef);
for init_decl in &decl.declarators {
let declarator = &init_decl.node.declarator.node;
let name = name_of_declarator(declarator);
let dtype = base_dtype
.clone()
.with_ast_declarator(declarator)
.and_then(|dtype| dtype.deref().clone().resolve_typedefs(self.typedefs)) // TODO: Why?
.map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?;
match &dtype {
ir::Dtype::Unit { .. } => todo!("f"),
ir::Dtype::Int { .. }
| ir::Dtype::Float { .. }
| ir::Dtype::Pointer { .. }
| ir::Dtype::Array { .. } => {
let value = if let Some(initializer) = &init_decl.node.initializer {
Some(self.translate_initializer(&initializer.node, context)?)
} else {
None
};
let _unused = self.translate_alloc(name, &dtype, value, context)?;
}
ir::Dtype::Function { .. } => todo!("g"),
ir::Dtype::Struct { .. } => todo!("h"),
ir::Dtype::Typedef { .. } => unreachable!(),
}
}
Ok(())
}
fn translate_initializer(
&mut self,
initializer: &Initializer,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
match initializer {
Initializer::Expression(expr) => self.translate_expr_rvalue(&expr.node, context),
Initializer::List(_) => panic!("Initializer::List is unsupported"),
}
}
fn translate_expr_rvalue(
&mut self,
expr: &Expression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
match expr {
Expression::Identifier(identifier) => {
let ptr = self.lookup_symbol_table(&identifier.node.name)?;
let ptr_dtype = ptr.dtype();
let ptr_inner = ptr_dtype.get_pointer_inner().unwrap();
if ptr_inner.get_function_inner().is_some() {
Ok(ptr)
} else if let Some(array_inner) = ptr_inner.get_array_inner() {
self.convert_array_to_pointer(ptr, array_inner, context)
} else {
context.insert_instruction(ir::Instruction::Load { ptr })
}
}
Expression::Constant(constant) => Ok(ir::Operand::constant(
ir::Constant::try_from(&constant.node).unwrap(),
)),
Expression::Cast(cast) => {
let target_dtype = ir::Dtype::try_from(&cast.node.type_name.node)
.map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?;
let target_dtype = target_dtype
.resolve_typedefs(self.typedefs)
.map_err(|e| IrgenErrorMessage::InvalidDtype { dtype_error: e })?;
let operand = self.translate_expr_rvalue(&cast.node.expression.node, context)?;
self.translate_typecast(operand, target_dtype, context)
}
Expression::Call(call) => self.translate_func_call(&call.node, context),
Expression::BinaryOperator(binary) => self.translate_binary_op(
&binary.node.operator.node,
&binary.node.lhs.node,
&binary.node.rhs.node,
context,
),
Expression::UnaryOperator(unary) => self.translate_unary_op(
&unary.node.operator.node,
&unary.node.operand.node,
context,
),
Expression::Conditional(cond) => self.translate_conditional(&cond.node, context),
_ => todo!("c"),
}
}
fn translate_conditional(
&mut self,
cond: &ConditionalExpression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
let then_bid = self.alloc_bid();
let else_bid = self.alloc_bid();
let end_bid = self.alloc_bid();
self.translate_condition(
&cond.condition.node,
mem::replace(context, Context::new(end_bid)),
then_bid,
else_bid,
)?;
let mut then_context = Context::new(then_bid);
let then_val = self.translate_expr_rvalue(&cond.then_expression.node, &mut then_context)?;
let mut else_context = Context::new(else_bid);
let else_val = self.translate_expr_rvalue(&cond.else_expression.node, &mut else_context)?;
// println!("conditional: {} {}", cond.then_expression.write_string(), cond.else_expression.write_string());
let merged_dtype = self.merge_dtype(then_val.dtype(), else_val.dtype());
let then_val =
self.translate_typecast(then_val, merged_dtype.clone(), &mut then_context)?;
let else_val =
self.translate_typecast(else_val, merged_dtype.clone(), &mut else_context)?;
let var = self.alloc_tempid();
let ptr = self.translate_alloc(var, &merged_dtype.clone(), None, context)?;
let _unused = then_context.insert_instruction(ir::Instruction::Store {
ptr: ptr.clone(),
value: then_val,
})?;
self.insert_block(
then_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(end_bid, Vec::new()),
},
);
let _unused = else_context.insert_instruction(ir::Instruction::Store {
ptr: ptr.clone(),
value: else_val,
})?;
self.insert_block(
else_context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(end_bid, Vec::new()),
},
);
let r = context.insert_instruction(ir::Instruction::Load { ptr: ptr.clone() })?;
// println!("ptr: {}, rtype: {}", ptr.dtype(), r.dtype());
Ok(r)
}
fn merge_dtype(&self, lhs_dtype: ir::Dtype, rhs_dtype: ir::Dtype) -> ir::Dtype {
if lhs_dtype == rhs_dtype {
lhs_dtype
} else {
match (&lhs_dtype, &rhs_dtype) {
(&ir::Dtype::DOUBLE, _) => lhs_dtype,
(_, &ir::Dtype::DOUBLE) => rhs_dtype,
(&ir::Dtype::FLOAT, _) => lhs_dtype,
(_, &ir::Dtype::FLOAT) => rhs_dtype,
(
ir::Dtype::Int {
width: lhs_width,
is_signed: lhs_is_signed,
is_const: lhs_is_const,
},
ir::Dtype::Int {
width: rhs_width,
is_signed: rhs_is_signed,
is_const: rhs_is_const,
},
) => {
if lhs_is_signed == rhs_is_signed {
if lhs_width > rhs_width {
lhs_dtype
} else {
rhs_dtype
}
} else if !lhs_is_signed {
if lhs_width >= rhs_width {
lhs_dtype
} else {
rhs_dtype
}
} else if lhs_width <= rhs_width {
rhs_dtype
} else {
lhs_dtype
}
}
_ => {
// println!("merge failed: {} {}", lhs_dtype, rhs_dtype);
todo!("merge")
}
}
}
}
fn translate_binary_op(
&mut self,
op: &BinaryOperator,
lhs: &Expression,
rhs: &Expression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
match op {
BinaryOperator::Assign => {
let lhs = self.translate_expr_lvalue(lhs, context)?;
let rhs = self.translate_expr_rvalue(rhs, context)?;
let _unused = context.insert_instruction(ir::Instruction::Store {
ptr: lhs,
value: rhs.clone(),
})?;
Ok(rhs)
}
BinaryOperator::AssignPlus => {
let rhs = self.translate_binary_op(&BinaryOperator::Plus, lhs, rhs, context)?;
let lhs = self.translate_expr_lvalue(lhs, context)?;
let _unused = context.insert_instruction(ir::Instruction::Store {
ptr: lhs,
value: rhs.clone(),
})?;
Ok(rhs)
}
BinaryOperator::AssignMinus => {
let rhs = self.translate_binary_op(&BinaryOperator::Minus, lhs, rhs, context)?;
let lhs = self.translate_expr_lvalue(lhs, context)?;
let _unused = context.insert_instruction(ir::Instruction::Store {
ptr: lhs,
value: rhs.clone(),
})?;
Ok(rhs)
}
_ => {
let lhs = self.translate_expr_rvalue(lhs, context)?;
let rhs = self.translate_expr_rvalue(rhs, context)?;
let operand_dtype = self.merge_dtype(lhs.dtype(), rhs.dtype());
let result_dtype = match op {
BinaryOperator::Less
| BinaryOperator::Greater
| BinaryOperator::LessOrEqual
| BinaryOperator::GreaterOrEqual
| BinaryOperator::Equals
| BinaryOperator::NotEquals => ir::Dtype::BOOL,
_ => operand_dtype.clone(),
};
let lhs = self.translate_typecast(lhs, operand_dtype.clone(), context)?;
let rhs = self.translate_typecast(rhs, operand_dtype.clone(), context)?;
context.insert_instruction(ir::Instruction::BinOp {
op: op.clone(),
lhs,
rhs,
dtype: result_dtype,
})
}
}
}
fn translate_unary_op(
&mut self,
op: &UnaryOperator,
operand: &Expression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
match op {
UnaryOperator::PreIncrement => {
let lhs = self.translate_expr_rvalue(operand, context)?;
let dtype = lhs.dtype();
let rhs = context.insert_instruction(ir::Instruction::BinOp {
op: BinaryOperator::Plus,
lhs,
rhs: ir::Operand::constant(ir::Constant::int(1, dtype.clone())),
dtype: dtype.clone(),
})?;
let lhs = self.translate_expr_lvalue(operand, context)?;
let _unused = context.insert_instruction(ir::Instruction::Store {
ptr: lhs,
value: rhs.clone(),
})?;
Ok(rhs)
}
UnaryOperator::Complement => {
let lhs = self.translate_expr_rvalue(operand, context)?;
let dtype = lhs.dtype();
context.insert_instruction(ir::Instruction::BinOp {
op: BinaryOperator::BitwiseXor,
lhs,
rhs: ir::Operand::constant(ir::Constant::int(u128::MAX, dtype.clone())),
dtype: dtype.clone(),
})
}
UnaryOperator::Plus | UnaryOperator::Minus | UnaryOperator::Negate => {
let operand = self.translate_expr_rvalue(operand, context)?;
let dtype = operand.dtype();
context.insert_instruction(ir::Instruction::UnaryOp {
op: op.clone(),
operand,
dtype,
})
}
_ => todo!("unary op"),
}
}
fn lookup_symbol_table(&self, name: &String) -> Result<ir::Operand, IrgenErrorMessage> {
for layer in self.symbol_table.iter().rev() {
if let Some(ptr) = layer.get(name) {
return Ok(ptr.clone());
}
}
Err(IrgenErrorMessage::RequireLvalue {
message: format!("Undefined symbol {name}"),
})
}
fn convert_array_to_pointer(
&mut self,
ptr: ir::Operand,
array_inner: &ir::Dtype,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
todo!("array to pointer")
}
fn translate_condition(
&mut self,
condition: &Expression,
mut context: Context,
then_bid: ir::BlockId,
else_bid: ir::BlockId,
) -> Result<(), IrgenErrorMessage> {
let condition = self.translate_expr_rvalue(condition, &mut context)?;
let condition = self.translate_typecast_to_bool(condition, &mut context)?;
self.insert_block(
context,
ir::BlockExit::ConditionalJump {
condition,
arg_then: ir::JumpArg::new(then_bid, Vec::new()),
arg_else: ir::JumpArg::new(else_bid, Vec::new()),
},
);
Ok(())
}
fn translate_switch_body(
&mut self,
stmt: &Statement,
end_bid: ir::BlockId,
) -> Result<(Vec<(ir::Constant, ir::JumpArg)>, ir::BlockId), IrgenError> {
let mut cases = Vec::new();
let mut default = None;
let items = if let Statement::Compound(items) = stmt {
items
} else {
panic!("`Statement` in the `switch` is unsupported except `Statement::Compound`")
};
self.enter_scope();
for item in items {
match &item.node {
BlockItem::Statement(stmt) => {
self.translate_switch_body_inner(
&stmt.node,
&mut cases,
&mut default,
end_bid,
)?;
}
_ => panic!("is unsupported"),
}
}
self.exit_scope();
let default = default.unwrap_or(end_bid);
Ok((cases, default))
}
fn translate_switch_body_inner(
&mut self,
stmt: &Statement,
cases: &mut Vec<(ir::Constant, ir::JumpArg)>,
default: &mut Option<ir::BlockId>,
end_bid: ir::BlockId,
) -> Result<(), IrgenError> {
let stmt = if let Statement::Labeled(stmt) = stmt {
&stmt.node
} else {
panic!(
"`BlockItem::Statement` in the `Statement::Compound` of the `switch` is unsupported except `Statement::Labeled`"
)
};
let bid = self.alloc_bid();
let case = self.translate_switch_body_label_statement(stmt, bid, end_bid)?;
if let Some(case) = case {
if !case.is_integer_constant() {
return Err(IrgenError::new(
stmt.label.write_string(),
IrgenErrorMessage::Misc {
message: "expression is not an integer constant expression".to_string(),
},
));
}
if cases.iter().any(|(c, _)| &case == c) {
return Err(IrgenError::new(
stmt.label.write_string(),
IrgenErrorMessage::Misc {
message: "duplicate case value".to_string(),
},
));
}
cases.push((case, ir::JumpArg::new(bid, Vec::new())));
} else {
if default.is_some() {
return Err(IrgenError::new(
stmt.label.write_string(),
IrgenErrorMessage::Misc {
message: "previous default already exists".to_string(),
},
));
}
*default = Some(bid);
}
Ok(())
}
fn translate_switch_body_label_statement(
&mut self,
stmt: &LabeledStatement,
bid: ir::BlockId,
end_bid: ir::BlockId,
) -> Result<Option<ir::Constant>, IrgenError> {
let case = match &stmt.label.node {
Label::Identifier(_) => panic!("`Label::Identifier` is unsupported"),
Label::Case(expr) => {
let constant = ir::Constant::try_from(&expr.node).map_err(|_| {
IrgenError::new(
expr.write_string(),
IrgenErrorMessage::Misc {
message: "case label does not reduce to an integer constant"
.to_string(),
},
)
})?;
Some(constant)
}
Label::Default => None,
_ => unreachable!(),
};
let items = if let Statement::Compound(items) = &stmt.statement.node {
items
} else {
panic!("`Statement` in the `label` is unsupported except `Sattement::Compound`")
};
self.enter_scope();
let (last, items) = items
.split_last()
.expect("`Statement::Compound` has no item");
let mut context = Context::new(bid);
for item in items {
match &item.node {
BlockItem::Declaration(decl) => self
.translate_decl(&decl.node, &mut context)
.map_err(|e| IrgenError::new(decl.write_string(), e))?,
BlockItem::Statement(stmt) => {
self.translate_stmt(&stmt.node, &mut context, None, None)?;
}
_ => panic!("is unsupported"),
}
}
let stmt = if let BlockItem::Statement(stmt) = &last.node {
&stmt.node
} else {
panic!(
"`BlockItem` in the `Statement::Compound` of the `label` is unsupported except `BlockItem::Statement`"
)
};
assert_eq!(
stmt,
&Statement::Break,
"the last `BlockItem` in the `Statement::Compound` of the `label` must be `Statement::Break`"
);
self.insert_block(
context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(end_bid, Vec::new()),
},
);
self.exit_scope();
Ok(case)
}
fn translate_for_initializer(
&mut self,
initializer: &ForInitializer,
context: &mut Context,
) -> Result<(), IrgenErrorMessage> {
match initializer {
ForInitializer::Empty => (),
ForInitializer::Expression(expr) => {
let _unused = self.translate_expr_rvalue(&expr.node, context)?;
}
ForInitializer::Declaration(decl) => {
return self.translate_decl(&decl.node, context);
}
ForInitializer::StaticAssert(_) => {
panic!("ForInitializer::StaticAssert is unsupported")
}
}
Ok(())
}
fn translate_opt_condition(
&mut self,
condition: &Option<Box<Node<Expression>>>,
context: Context,
body_bid: ir::BlockId,
end_bid: ir::BlockId,
) -> Result<(), IrgenErrorMessage> {
if let Some(condition) = condition {
self.translate_condition(&condition.node, context, body_bid, end_bid)
} else {
self.insert_block(
context,
ir::BlockExit::Jump {
arg: ir::JumpArg::new(body_bid, Vec::new()),
},
);
Ok(())
}
}
fn translate_expr_lvalue(
&mut self,
expr: &Expression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
match expr {
Expression::Identifier(identifier) => self.lookup_symbol_table(&identifier.node.name),
Expression::UnaryOperator(unary) => match &unary.node.operator.node {
UnaryOperator::Indirection => self.translate_expr_rvalue(&unary.node.operand.node, context),
_ => Err(IrgenErrorMessage::Misc { message: "This error occurred at `IrgenFunc::translate_expr_lvalue`".to_string() })
}
Expression::BinaryOperator(binary) => match &binary.node.operator.node {
BinaryOperator::Index => self.translate_index_op(&binary.node.lhs.node, &binary.node.rhs.node, context),
_ => Err(IrgenErrorMessage::Misc { message: "binary operator expression cannot be used as l-value except index operator expression".to_string() }),
}
_ => todo!("expr lvalue")
}
}
fn translate_index_op(
&mut self,
lhs: &Expression,
rhs: &Expression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
todo!("index op")
}
fn translate_func_call(
&mut self,
call: &CallExpression,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
let callee = self.translate_expr_rvalue(&call.callee.node, context)?;
let function_pointer_type = callee.dtype();
let function = function_pointer_type.get_pointer_inner().ok_or_else(|| {
IrgenErrorMessage::NeedFunctionOrFunctionPointer {
callee: callee.clone(),
}
})?;
let (return_type, parameters) = function.get_function_inner().ok_or_else(|| {
IrgenErrorMessage::NeedFunctionOrFunctionPointer {
callee: callee.clone(),
}
})?;
let args = call
.arguments
.iter()
.map(|a| self.translate_expr_rvalue(&a.node, context))
.collect::<Result<Vec<_>, _>>()?;
if args.len() != parameters.len() {
return Err(IrgenErrorMessage::Misc {
message: format!("too few arguments to function `{}`", "TODO"),
});
}
let args = izip!(args, parameters)
.map(|(a, p)| self.translate_typecast(a, p.clone(), context))
.collect::<Result<Vec<_>, _>>()?;
let return_type = return_type.clone().set_const(false);
context.insert_instruction(ir::Instruction::Call {
callee,
args,
return_type,
})
}
/// Translate initial parameter declarations of the functions to IR.
@@ -666,7 +1582,59 @@ impl IrgenFunc<'_> {
name_of_params: &[String],
context: &mut Context,
) -> Result<(), IrgenErrorMessage> {
todo!()
for (i, (dtype, var)) in izip!(&signature.params, name_of_params).enumerate() {
let value = Some(ir::Operand::register(
ir::RegisterId::arg(bid_init, i),
dtype.clone(),
));
let _unused = self.translate_alloc(var.clone(), dtype, value, context)?;
self.phinodes_init
.push(Named::new(Some(var.clone()), dtype.clone()));
}
Ok(())
}
fn translate_alloc(
&mut self,
var: String,
dtype: &ir::Dtype,
value: Option<ir::Operand>,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
let rid = self.insert_alloc(Named::new(Some(var.clone()), dtype.clone()));
let ptr = ir::Operand::register(rid, ir::Dtype::pointer(dtype.clone()));
self.insert_symbol_table_entry(var, ptr.clone())?;
if let Some(value) = value {
let value = self.translate_typecast(value, dtype.clone(), context)?;
context.insert_instruction(ir::Instruction::Store { ptr, value })
} else {
Ok(ptr)
}
}
fn translate_typecast(
&mut self,
value: ir::Operand,
dtype: ir::Dtype,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
if value.dtype() == dtype {
return Ok(value);
}
context.insert_instruction(ir::Instruction::TypeCast {
value,
target_dtype: dtype,
})
}
fn translate_typecast_to_bool(
&mut self,
value: ir::Operand,
context: &mut Context,
) -> Result<ir::Operand, IrgenErrorMessage> {
self.translate_typecast(value, ir::Dtype::BOOL, context) // TODO: Right?
}
}