mirror of
https://github.com/edg-l/edlang.git
synced 2024-11-23 00:18:24 +00:00
feat: implement while
This commit is contained in:
parent
6c83d1e1a9
commit
ce0516651f
|
@ -125,10 +125,13 @@ impl Local {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn temp(ty: TypeInfo) -> Self {
|
pub const fn temp(ty: TypeKind) -> Self {
|
||||||
Self {
|
Self {
|
||||||
span: None,
|
span: None,
|
||||||
ty,
|
ty: TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ty,
|
||||||
|
},
|
||||||
kind: LocalKind::Temp,
|
kind: LocalKind::Temp,
|
||||||
debug_name: None,
|
debug_name: None,
|
||||||
mutable: false,
|
mutable: false,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use edlang_ir::{Body, DefId, Local, ModuleBody, ProgramBody, Statement, TypeInfo, TypeKind};
|
use edlang_ir::{Body, DefId, Local, ModuleBody, ProgramBody, Statement, TypeKind};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Default)]
|
||||||
pub struct IdGenerator {
|
pub struct IdGenerator {
|
||||||
|
@ -72,10 +72,7 @@ impl BodyBuilder {
|
||||||
|
|
||||||
pub fn add_temp_local(&mut self, ty_kind: TypeKind) -> usize {
|
pub fn add_temp_local(&mut self, ty_kind: TypeKind) -> usize {
|
||||||
let id = self.body.locals.len();
|
let id = self.body.locals.len();
|
||||||
self.body.locals.push(Local::temp(TypeInfo {
|
self.body.locals.push(Local::temp(ty_kind));
|
||||||
span: None,
|
|
||||||
kind: ty_kind,
|
|
||||||
}));
|
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use ast::{BinaryOp, ModuleStatement};
|
use ast::{BinaryOp, ModuleStatement, WhileStmt};
|
||||||
use common::{BodyBuilder, BuildCtx};
|
use common::{BodyBuilder, BuildCtx};
|
||||||
use edlang_ast as ast;
|
use edlang_ast as ast;
|
||||||
use edlang_ir as ir;
|
use edlang_ir as ir;
|
||||||
|
@ -155,7 +155,7 @@ fn lower_function(ctx: BuildCtx, func: &ast::Function, module_id: DefId) -> Buil
|
||||||
}
|
}
|
||||||
|
|
||||||
for stmt in &func.body.body {
|
for stmt in &func.body.body {
|
||||||
lower_statement(&mut builder, stmt, &ret_ty);
|
lower_statement(&mut builder, stmt, &ret_ty.kind);
|
||||||
}
|
}
|
||||||
|
|
||||||
let (mut ctx, body) = (builder.ctx, builder.body);
|
let (mut ctx, body) = (builder.ctx, builder.body);
|
||||||
|
@ -164,12 +164,12 @@ fn lower_function(ctx: BuildCtx, func: &ast::Function, module_id: DefId) -> Buil
|
||||||
ctx
|
ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_statement(builder: &mut BodyBuilder, info: &ast::Statement, ret_type: &TypeInfo) {
|
fn lower_statement(builder: &mut BodyBuilder, info: &ast::Statement, ret_type: &TypeKind) {
|
||||||
match info {
|
match info {
|
||||||
ast::Statement::Let(info) => lower_let(builder, info),
|
ast::Statement::Let(info) => lower_let(builder, info),
|
||||||
ast::Statement::Assign(info) => lower_assign(builder, info),
|
ast::Statement::Assign(info) => lower_assign(builder, info),
|
||||||
ast::Statement::For(_) => todo!(),
|
ast::Statement::For(_) => todo!(),
|
||||||
ast::Statement::While(_) => todo!(),
|
ast::Statement::While(info) => lower_while(builder, info, ret_type),
|
||||||
ast::Statement::If(info) => lower_if_stmt(builder, info, ret_type),
|
ast::Statement::If(info) => lower_if_stmt(builder, info, ret_type),
|
||||||
ast::Statement::Return(info) => lower_return(builder, info, ret_type),
|
ast::Statement::Return(info) => lower_return(builder, info, ret_type),
|
||||||
ast::Statement::FnCall(info) => {
|
ast::Statement::FnCall(info) => {
|
||||||
|
@ -178,9 +178,80 @@ fn lower_statement(builder: &mut BodyBuilder, info: &ast::Statement, ret_type: &
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeInfo) {
|
fn lower_while(builder: &mut BodyBuilder, info: &WhileStmt, ret_type: &TypeKind) {
|
||||||
|
let statements = std::mem::take(&mut builder.statements);
|
||||||
|
builder.body.blocks.push(BasicBlock {
|
||||||
|
statements: statements.into(),
|
||||||
|
terminator: Terminator::Target(builder.body.blocks.len() + 1),
|
||||||
|
});
|
||||||
|
|
||||||
|
let (discriminator, discriminator_type) = lower_expr(builder, &info.condition, None);
|
||||||
|
|
||||||
|
let local = builder.add_temp_local(TypeKind::Bool);
|
||||||
|
let place = Place {
|
||||||
|
local,
|
||||||
|
projection: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
builder.statements.push(Statement {
|
||||||
|
span: None,
|
||||||
|
kind: StatementKind::Assign(place.clone(), discriminator),
|
||||||
|
});
|
||||||
|
|
||||||
|
// keep idx to change terminator
|
||||||
|
let check_block_idx = builder.body.blocks.len();
|
||||||
|
|
||||||
|
let statements = std::mem::take(&mut builder.statements);
|
||||||
|
builder.body.blocks.push(BasicBlock {
|
||||||
|
statements: statements.into(),
|
||||||
|
terminator: Terminator::Unreachable,
|
||||||
|
});
|
||||||
|
|
||||||
|
// keep idx for switch targets
|
||||||
|
let first_then_block_idx = builder.body.blocks.len();
|
||||||
|
|
||||||
|
for stmt in &info.block.body {
|
||||||
|
lower_statement(builder, stmt, ret_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keet idx to change terminator if there is no return
|
||||||
|
let last_then_block_idx = if !matches!(
|
||||||
|
builder.body.blocks.last().unwrap().terminator,
|
||||||
|
Terminator::Return
|
||||||
|
) {
|
||||||
|
builder.body.blocks.len();
|
||||||
|
let statements = std::mem::take(&mut builder.statements);
|
||||||
|
let idx = builder.body.blocks.len();
|
||||||
|
builder.body.blocks.push(BasicBlock {
|
||||||
|
statements: statements.into(),
|
||||||
|
terminator: Terminator::Unreachable,
|
||||||
|
});
|
||||||
|
Some(idx)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let otherwise_block_idx = builder.body.blocks.len();
|
||||||
|
|
||||||
|
let targets = SwitchTarget {
|
||||||
|
values: vec![discriminator_type.get_falsy_value()],
|
||||||
|
targets: vec![otherwise_block_idx, first_then_block_idx],
|
||||||
|
};
|
||||||
|
|
||||||
|
let kind = Terminator::SwitchInt {
|
||||||
|
discriminator: Operand::Move(place),
|
||||||
|
targets,
|
||||||
|
};
|
||||||
|
builder.body.blocks[check_block_idx].terminator = kind;
|
||||||
|
|
||||||
|
if let Some(last_then_block_idx) = last_then_block_idx {
|
||||||
|
builder.body.blocks[last_then_block_idx].terminator = Terminator::Target(check_block_idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeKind) {
|
||||||
let cond_ty = find_expr_type(builder, &info.condition).expect("coouldnt find cond type");
|
let cond_ty = find_expr_type(builder, &info.condition).expect("coouldnt find cond type");
|
||||||
let condition = lower_expr(builder, &info.condition, Some(&cond_ty));
|
let (condition, condition_ty) = lower_expr(builder, &info.condition, Some(&cond_ty));
|
||||||
|
|
||||||
let local = builder.add_temp_local(TypeKind::Bool);
|
let local = builder.add_temp_local(TypeKind::Bool);
|
||||||
let place = Place {
|
let place = Place {
|
||||||
|
@ -249,7 +320,7 @@ fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeI
|
||||||
};
|
};
|
||||||
|
|
||||||
let targets = SwitchTarget {
|
let targets = SwitchTarget {
|
||||||
values: vec![TypeKind::Bool.get_falsy_value()],
|
values: vec![condition_ty.get_falsy_value()],
|
||||||
targets: vec![first_else_block_idx, first_then_block_idx],
|
targets: vec![first_else_block_idx, first_then_block_idx],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -271,7 +342,7 @@ fn lower_if_stmt(builder: &mut BodyBuilder, info: &ast::IfStmt, ret_type: &TypeI
|
||||||
|
|
||||||
fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) {
|
fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) {
|
||||||
let ty = lower_type(&builder.ctx, &info.r#type);
|
let ty = lower_type(&builder.ctx, &info.r#type);
|
||||||
let rvalue = lower_expr(builder, &info.value, Some(&ty));
|
let (rvalue, _ty) = lower_expr(builder, &info.value, Some(&ty.kind));
|
||||||
let local_idx = builder.name_to_local.get(&info.name.name).copied().unwrap();
|
let local_idx = builder.name_to_local.get(&info.name.name).copied().unwrap();
|
||||||
builder.statements.push(Statement {
|
builder.statements.push(Statement {
|
||||||
span: Some(info.name.span),
|
span: Some(info.name.span),
|
||||||
|
@ -292,8 +363,8 @@ fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) {
|
||||||
fn lower_assign(builder: &mut BodyBuilder, info: &ast::AssignStmt) {
|
fn lower_assign(builder: &mut BodyBuilder, info: &ast::AssignStmt) {
|
||||||
let local = *builder.name_to_local.get(&info.name.first.name).unwrap();
|
let local = *builder.name_to_local.get(&info.name.first.name).unwrap();
|
||||||
let ty = builder.body.locals[local].ty.clone();
|
let ty = builder.body.locals[local].ty.clone();
|
||||||
let rvalue = lower_expr(builder, &info.value, Some(&ty));
|
let (rvalue, _ty) = lower_expr(builder, &info.value, Some(&ty.kind));
|
||||||
let place = lower_path(builder, &info.name);
|
let (place, _ty) = lower_path(builder, &info.name);
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
builder.statements.push(Statement {
|
||||||
span: Some(info.name.first.span),
|
span: Some(info.name.first.span),
|
||||||
|
@ -301,66 +372,67 @@ fn lower_assign(builder: &mut BodyBuilder, info: &ast::AssignStmt) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option<TypeInfo> {
|
fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option<TypeKind> {
|
||||||
Some(TypeInfo {
|
Some(match info {
|
||||||
span: None,
|
ast::Expression::Value(x) => match x {
|
||||||
kind: match info {
|
ast::ValueExpr::Bool { .. } => TypeKind::Bool,
|
||||||
ast::Expression::Value(x) => match x {
|
ast::ValueExpr::Char { .. } => TypeKind::Char,
|
||||||
ast::ValueExpr::Bool { .. } => TypeKind::Bool,
|
ast::ValueExpr::Int { .. } => return None,
|
||||||
ast::ValueExpr::Char { .. } => TypeKind::Char,
|
ast::ValueExpr::Float { .. } => return None,
|
||||||
ast::ValueExpr::Int { .. } => return None,
|
ast::ValueExpr::Str { .. } => todo!(),
|
||||||
ast::ValueExpr::Float { .. } => return None,
|
ast::ValueExpr::Path(path) => {
|
||||||
ast::ValueExpr::Str { .. } => todo!(),
|
// todo: handle full path
|
||||||
ast::ValueExpr::Path(path) => {
|
builder.get_local(&path.first.name)?.ty.kind.clone()
|
||||||
// todo: handle full path
|
|
||||||
builder.get_local(&path.first.name)?.ty.kind.clone()
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::Expression::FnCall(info) => {
|
|
||||||
let fn_id = {
|
|
||||||
let mod_body = builder.get_module_body();
|
|
||||||
|
|
||||||
if let Some(id) = mod_body.symbols.functions.get(&info.name.name) {
|
|
||||||
*id
|
|
||||||
} else {
|
|
||||||
*mod_body
|
|
||||||
.imports
|
|
||||||
.get(&info.name.name)
|
|
||||||
.expect("function call not found")
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
builder
|
|
||||||
.ctx
|
|
||||||
.body
|
|
||||||
.function_signatures
|
|
||||||
.get(&fn_id)?
|
|
||||||
.1
|
|
||||||
.kind
|
|
||||||
.clone()
|
|
||||||
}
|
|
||||||
ast::Expression::Unary(_, info) => find_expr_type(builder, info)?.kind,
|
|
||||||
ast::Expression::Binary(lhs, op, rhs) => {
|
|
||||||
if matches!(op, BinaryOp::Logic(_, _)) {
|
|
||||||
TypeKind::Bool
|
|
||||||
} else {
|
|
||||||
find_expr_type(builder, lhs)
|
|
||||||
.or(find_expr_type(builder, rhs))?
|
|
||||||
.kind
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
ast::Expression::FnCall(info) => {
|
||||||
|
let fn_id = {
|
||||||
|
let mod_body = builder.get_module_body();
|
||||||
|
|
||||||
|
if let Some(id) = mod_body.symbols.functions.get(&info.name.name) {
|
||||||
|
*id
|
||||||
|
} else {
|
||||||
|
*mod_body
|
||||||
|
.imports
|
||||||
|
.get(&info.name.name)
|
||||||
|
.expect("function call not found")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
builder
|
||||||
|
.ctx
|
||||||
|
.body
|
||||||
|
.function_signatures
|
||||||
|
.get(&fn_id)?
|
||||||
|
.1
|
||||||
|
.kind
|
||||||
|
.clone()
|
||||||
|
}
|
||||||
|
ast::Expression::Unary(_, info) => find_expr_type(builder, info)?,
|
||||||
|
ast::Expression::Binary(lhs, op, rhs) => {
|
||||||
|
if matches!(op, BinaryOp::Logic(_, _)) {
|
||||||
|
TypeKind::Bool
|
||||||
|
} else {
|
||||||
|
find_expr_type(builder, lhs).or(find_expr_type(builder, rhs))?
|
||||||
|
}
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_expr(
|
fn lower_expr(
|
||||||
builder: &mut BodyBuilder,
|
builder: &mut BodyBuilder,
|
||||||
info: &ast::Expression,
|
info: &ast::Expression,
|
||||||
type_hint: Option<&TypeInfo>,
|
type_hint: Option<&TypeKind>,
|
||||||
) -> ir::RValue {
|
) -> (ir::RValue, TypeKind) {
|
||||||
match info {
|
match info {
|
||||||
ast::Expression::Value(info) => ir::RValue::Use(lower_value(builder, info, type_hint)),
|
ast::Expression::Value(info) => {
|
||||||
ast::Expression::FnCall(info) => ir::RValue::Use(lower_fn_call(builder, info)),
|
let (value, ty) = lower_value(builder, info, type_hint);
|
||||||
|
(ir::RValue::Use(value), ty)
|
||||||
|
}
|
||||||
|
ast::Expression::FnCall(info) => {
|
||||||
|
let (value, ty) = lower_fn_call(builder, info);
|
||||||
|
(ir::RValue::Use(value), ty)
|
||||||
|
}
|
||||||
ast::Expression::Unary(_, _) => todo!(),
|
ast::Expression::Unary(_, _) => todo!(),
|
||||||
ast::Expression::Binary(lhs, op, rhs) => {
|
ast::Expression::Binary(lhs, op, rhs) => {
|
||||||
lower_binary_expr(builder, lhs, op, rhs, type_hint)
|
lower_binary_expr(builder, lhs, op, rhs, type_hint)
|
||||||
|
@ -373,23 +445,24 @@ fn lower_binary_expr(
|
||||||
lhs: &ast::Expression,
|
lhs: &ast::Expression,
|
||||||
op: &ast::BinaryOp,
|
op: &ast::BinaryOp,
|
||||||
rhs: &ast::Expression,
|
rhs: &ast::Expression,
|
||||||
type_hint: Option<&TypeInfo>,
|
type_hint: Option<&TypeKind>,
|
||||||
) -> ir::RValue {
|
) -> (ir::RValue, TypeKind) {
|
||||||
let (lhs, lhs_ty) = if type_hint.is_none() {
|
let (lhs, lhs_ty) = if type_hint.is_none() {
|
||||||
let ty = find_expr_type(builder, lhs);
|
let ty = find_expr_type(builder, lhs)
|
||||||
(lower_expr(builder, lhs, ty.as_ref()), ty)
|
.unwrap_or(find_expr_type(builder, rhs).expect("cant find type"));
|
||||||
|
lower_expr(builder, lhs, Some(&ty))
|
||||||
} else {
|
} else {
|
||||||
(lower_expr(builder, lhs, type_hint), type_hint.cloned())
|
lower_expr(builder, lhs, type_hint)
|
||||||
};
|
};
|
||||||
let (rhs, rhs_ty) = if type_hint.is_none() {
|
let (rhs, rhs_ty) = if type_hint.is_none() {
|
||||||
let ty = find_expr_type(builder, rhs);
|
let ty = find_expr_type(builder, rhs).unwrap_or(lhs_ty.clone());
|
||||||
(lower_expr(builder, rhs, ty.as_ref()), ty)
|
lower_expr(builder, rhs, Some(&ty))
|
||||||
} else {
|
} else {
|
||||||
(lower_expr(builder, rhs, type_hint), type_hint.cloned())
|
lower_expr(builder, rhs, type_hint)
|
||||||
};
|
};
|
||||||
|
|
||||||
let lhs_local = builder.add_local(Local::temp(lhs_ty.unwrap().clone()));
|
let lhs_local = builder.add_local(Local::temp(lhs_ty.clone()));
|
||||||
let rhs_local = builder.add_local(Local::temp(rhs_ty.unwrap().clone()));
|
let rhs_local = builder.add_local(Local::temp(rhs_ty.clone()));
|
||||||
let lhs_place = Place {
|
let lhs_place = Place {
|
||||||
local: lhs_local,
|
local: lhs_local,
|
||||||
projection: Default::default(),
|
projection: Default::default(),
|
||||||
|
@ -423,34 +496,46 @@ fn lower_binary_expr(
|
||||||
let rhs = Operand::Move(rhs_place);
|
let rhs = Operand::Move(rhs_place);
|
||||||
|
|
||||||
match op {
|
match op {
|
||||||
ast::BinaryOp::Arith(op, _) => match op {
|
ast::BinaryOp::Arith(op, _) => (
|
||||||
ast::ArithOp::Add => ir::RValue::BinOp(ir::BinOp::Add, lhs, rhs),
|
match op {
|
||||||
ast::ArithOp::Sub => ir::RValue::BinOp(ir::BinOp::Sub, lhs, rhs),
|
ast::ArithOp::Add => ir::RValue::BinOp(ir::BinOp::Add, lhs, rhs),
|
||||||
ast::ArithOp::Mul => ir::RValue::BinOp(ir::BinOp::Mul, lhs, rhs),
|
ast::ArithOp::Sub => ir::RValue::BinOp(ir::BinOp::Sub, lhs, rhs),
|
||||||
ast::ArithOp::Div => ir::RValue::BinOp(ir::BinOp::Div, lhs, rhs),
|
ast::ArithOp::Mul => ir::RValue::BinOp(ir::BinOp::Mul, lhs, rhs),
|
||||||
ast::ArithOp::Mod => ir::RValue::BinOp(ir::BinOp::Rem, lhs, rhs),
|
ast::ArithOp::Div => ir::RValue::BinOp(ir::BinOp::Div, lhs, rhs),
|
||||||
},
|
ast::ArithOp::Mod => ir::RValue::BinOp(ir::BinOp::Rem, lhs, rhs),
|
||||||
ast::BinaryOp::Logic(op, _) => match op {
|
},
|
||||||
ast::LogicOp::And => ir::RValue::LogicOp(ir::LogicalOp::And, lhs, rhs),
|
lhs_ty,
|
||||||
ast::LogicOp::Or => ir::RValue::LogicOp(ir::LogicalOp::Or, lhs, rhs),
|
),
|
||||||
},
|
ast::BinaryOp::Logic(op, _) => (
|
||||||
ast::BinaryOp::Compare(op, _) => match op {
|
match op {
|
||||||
ast::CmpOp::Eq => ir::RValue::BinOp(ir::BinOp::Eq, lhs, rhs),
|
ast::LogicOp::And => ir::RValue::LogicOp(ir::LogicalOp::And, lhs, rhs),
|
||||||
ast::CmpOp::NotEq => ir::RValue::BinOp(ir::BinOp::Ne, lhs, rhs),
|
ast::LogicOp::Or => ir::RValue::LogicOp(ir::LogicalOp::Or, lhs, rhs),
|
||||||
ast::CmpOp::Lt => ir::RValue::BinOp(ir::BinOp::Lt, lhs, rhs),
|
},
|
||||||
ast::CmpOp::LtEq => ir::RValue::BinOp(ir::BinOp::Le, lhs, rhs),
|
TypeKind::Bool,
|
||||||
ast::CmpOp::Gt => ir::RValue::BinOp(ir::BinOp::Gt, lhs, rhs),
|
),
|
||||||
ast::CmpOp::GtEq => ir::RValue::BinOp(ir::BinOp::Ge, lhs, rhs),
|
ast::BinaryOp::Compare(op, _) => (
|
||||||
},
|
match op {
|
||||||
ast::BinaryOp::Bitwise(op, _) => match op {
|
ast::CmpOp::Eq => ir::RValue::BinOp(ir::BinOp::Eq, lhs, rhs),
|
||||||
ast::BitwiseOp::And => ir::RValue::BinOp(ir::BinOp::BitAnd, lhs, rhs),
|
ast::CmpOp::NotEq => ir::RValue::BinOp(ir::BinOp::Ne, lhs, rhs),
|
||||||
ast::BitwiseOp::Or => ir::RValue::BinOp(ir::BinOp::BitOr, lhs, rhs),
|
ast::CmpOp::Lt => ir::RValue::BinOp(ir::BinOp::Lt, lhs, rhs),
|
||||||
ast::BitwiseOp::Xor => ir::RValue::BinOp(ir::BinOp::BitXor, lhs, rhs),
|
ast::CmpOp::LtEq => ir::RValue::BinOp(ir::BinOp::Le, lhs, rhs),
|
||||||
},
|
ast::CmpOp::Gt => ir::RValue::BinOp(ir::BinOp::Gt, lhs, rhs),
|
||||||
|
ast::CmpOp::GtEq => ir::RValue::BinOp(ir::BinOp::Ge, lhs, rhs),
|
||||||
|
},
|
||||||
|
TypeKind::Bool,
|
||||||
|
),
|
||||||
|
ast::BinaryOp::Bitwise(op, _) => (
|
||||||
|
match op {
|
||||||
|
ast::BitwiseOp::And => ir::RValue::BinOp(ir::BinOp::BitAnd, lhs, rhs),
|
||||||
|
ast::BitwiseOp::Or => ir::RValue::BinOp(ir::BinOp::BitOr, lhs, rhs),
|
||||||
|
ast::BitwiseOp::Xor => ir::RValue::BinOp(ir::BinOp::BitXor, lhs, rhs),
|
||||||
|
},
|
||||||
|
lhs_ty,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> Operand {
|
fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> (Operand, TypeKind) {
|
||||||
let fn_id = {
|
let fn_id = {
|
||||||
let mod_body = builder.get_module_body();
|
let mod_body = builder.get_module_body();
|
||||||
|
|
||||||
|
@ -493,11 +578,11 @@ fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> Operand {
|
||||||
let mut args = Vec::new();
|
let mut args = Vec::new();
|
||||||
|
|
||||||
for (arg, arg_ty) in info.params.iter().zip(args_ty) {
|
for (arg, arg_ty) in info.params.iter().zip(args_ty) {
|
||||||
let rvalue = lower_expr(builder, arg, Some(&arg_ty));
|
let (rvalue, _rvalue_ty) = lower_expr(builder, arg, Some(&arg_ty.kind));
|
||||||
args.push(rvalue);
|
args.push(rvalue);
|
||||||
}
|
}
|
||||||
|
|
||||||
let dest_local = builder.add_local(Local::temp(ret_ty));
|
let dest_local = builder.add_local(Local::temp(ret_ty.kind.clone()));
|
||||||
|
|
||||||
let dest_place = Place {
|
let dest_place = Place {
|
||||||
local: dest_local,
|
local: dest_local,
|
||||||
|
@ -520,59 +605,62 @@ fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> Operand {
|
||||||
terminator: kind,
|
terminator: kind,
|
||||||
});
|
});
|
||||||
|
|
||||||
Operand::Move(dest_place)
|
(Operand::Move(dest_place), ret_ty.kind.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_value(
|
fn lower_value(
|
||||||
builder: &mut BodyBuilder,
|
builder: &mut BodyBuilder,
|
||||||
info: &ast::ValueExpr,
|
info: &ast::ValueExpr,
|
||||||
type_hint: Option<&TypeInfo>,
|
type_hint: Option<&TypeKind>,
|
||||||
) -> Operand {
|
) -> (Operand, TypeKind) {
|
||||||
match info {
|
match info {
|
||||||
ast::ValueExpr::Bool { value, span } => ir::Operand::Constant(ir::ConstData {
|
ast::ValueExpr::Bool { value, span } => (
|
||||||
span: Some(*span),
|
ir::Operand::Constant(ir::ConstData {
|
||||||
type_info: ir::TypeInfo {
|
span: Some(*span),
|
||||||
span: None,
|
type_info: ir::TypeInfo {
|
||||||
kind: ir::TypeKind::Bool,
|
span: None,
|
||||||
},
|
kind: ir::TypeKind::Bool,
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::Bool(*value))),
|
},
|
||||||
}),
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::Bool(*value))),
|
||||||
ast::ValueExpr::Char { value, span } => ir::Operand::Constant(ir::ConstData {
|
}),
|
||||||
span: Some(*span),
|
TypeKind::Bool,
|
||||||
type_info: ir::TypeInfo {
|
),
|
||||||
span: None,
|
ast::ValueExpr::Char { value, span } => (
|
||||||
kind: ir::TypeKind::Char,
|
ir::Operand::Constant(ir::ConstData {
|
||||||
},
|
span: Some(*span),
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32((*value) as u32))),
|
type_info: ir::TypeInfo {
|
||||||
}),
|
span: None,
|
||||||
|
kind: ir::TypeKind::Char,
|
||||||
|
},
|
||||||
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32(
|
||||||
|
(*value) as u32,
|
||||||
|
))),
|
||||||
|
}),
|
||||||
|
TypeKind::Char,
|
||||||
|
),
|
||||||
ast::ValueExpr::Int { value, span } => {
|
ast::ValueExpr::Int { value, span } => {
|
||||||
let (ty, val, type_span) = match type_hint {
|
let (ty, val) = match type_hint {
|
||||||
Some(type_hint) => match &type_hint.kind {
|
Some(type_hint) => match &type_hint {
|
||||||
ir::TypeKind::Int(int_type) => match int_type {
|
ir::TypeKind::Int(int_type) => match int_type {
|
||||||
ir::IntTy::I128 => (
|
ir::IntTy::I128 => (
|
||||||
ir::TypeKind::Int(ir::IntTy::I128),
|
ir::TypeKind::Int(ir::IntTy::I128),
|
||||||
ir::ConstValue::I128((*value) as i128),
|
ir::ConstValue::I128((*value) as i128),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::IntTy::I64 => (
|
ir::IntTy::I64 => (
|
||||||
ir::TypeKind::Int(ir::IntTy::I64),
|
ir::TypeKind::Int(ir::IntTy::I64),
|
||||||
ir::ConstValue::I64((*value) as i64),
|
ir::ConstValue::I64((*value) as i64),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::IntTy::I32 => (
|
ir::IntTy::I32 => (
|
||||||
ir::TypeKind::Int(ir::IntTy::I32),
|
ir::TypeKind::Int(ir::IntTy::I32),
|
||||||
ir::ConstValue::I32((*value) as i32),
|
ir::ConstValue::I32((*value) as i32),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::IntTy::I16 => (
|
ir::IntTy::I16 => (
|
||||||
ir::TypeKind::Int(ir::IntTy::I16),
|
ir::TypeKind::Int(ir::IntTy::I16),
|
||||||
ir::ConstValue::I16((*value) as i16),
|
ir::ConstValue::I16((*value) as i16),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::IntTy::I8 => (
|
ir::IntTy::I8 => (
|
||||||
ir::TypeKind::Int(ir::IntTy::I8),
|
ir::TypeKind::Int(ir::IntTy::I8),
|
||||||
ir::ConstValue::I8((*value) as i8),
|
ir::ConstValue::I8((*value) as i8),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::IntTy::Isize => todo!(),
|
ir::IntTy::Isize => todo!(),
|
||||||
},
|
},
|
||||||
|
@ -580,27 +668,22 @@ fn lower_value(
|
||||||
ir::UintTy::U128 => (
|
ir::UintTy::U128 => (
|
||||||
ir::TypeKind::Uint(ir::UintTy::U128),
|
ir::TypeKind::Uint(ir::UintTy::U128),
|
||||||
ir::ConstValue::U128(*value),
|
ir::ConstValue::U128(*value),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::UintTy::U64 => (
|
ir::UintTy::U64 => (
|
||||||
ir::TypeKind::Uint(ir::UintTy::U64),
|
ir::TypeKind::Uint(ir::UintTy::U64),
|
||||||
ir::ConstValue::U64((*value) as u64),
|
ir::ConstValue::U64((*value) as u64),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::UintTy::U32 => (
|
ir::UintTy::U32 => (
|
||||||
ir::TypeKind::Uint(ir::UintTy::U32),
|
ir::TypeKind::Uint(ir::UintTy::U32),
|
||||||
ir::ConstValue::U32((*value) as u32),
|
ir::ConstValue::U32((*value) as u32),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::UintTy::U16 => (
|
ir::UintTy::U16 => (
|
||||||
ir::TypeKind::Uint(ir::UintTy::U16),
|
ir::TypeKind::Uint(ir::UintTy::U16),
|
||||||
ir::ConstValue::U16((*value) as u16),
|
ir::ConstValue::U16((*value) as u16),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
ir::UintTy::U8 => (
|
ir::UintTy::U8 => (
|
||||||
ir::TypeKind::Uint(ir::UintTy::U8),
|
ir::TypeKind::Uint(ir::UintTy::U8),
|
||||||
ir::ConstValue::U8((*value) as u8),
|
ir::ConstValue::U8((*value) as u8),
|
||||||
type_hint.span,
|
|
||||||
),
|
),
|
||||||
_ => todo!(),
|
_ => todo!(),
|
||||||
},
|
},
|
||||||
|
@ -609,38 +692,47 @@ fn lower_value(
|
||||||
None => todo!(),
|
None => todo!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
ir::Operand::Constant(ir::ConstData {
|
(
|
||||||
span: Some(*span),
|
ir::Operand::Constant(ir::ConstData {
|
||||||
type_info: ir::TypeInfo {
|
span: Some(*span),
|
||||||
span: type_span,
|
type_info: ir::TypeInfo {
|
||||||
kind: ty,
|
span: None,
|
||||||
},
|
kind: ty.clone(),
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(val)),
|
},
|
||||||
})
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(val)),
|
||||||
|
}),
|
||||||
|
ty,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ast::ValueExpr::Float { value, span } => match type_hint {
|
ast::ValueExpr::Float { value, span } => match type_hint {
|
||||||
Some(type_hint) => match &type_hint.kind {
|
Some(type_hint) => match &type_hint {
|
||||||
TypeKind::Float(float_ty) => match float_ty {
|
TypeKind::Float(float_ty) => match float_ty {
|
||||||
ir::FloatTy::F32 => ir::Operand::Constant(ir::ConstData {
|
ir::FloatTy::F32 => (
|
||||||
span: Some(*span),
|
ir::Operand::Constant(ir::ConstData {
|
||||||
type_info: ir::TypeInfo {
|
span: Some(*span),
|
||||||
span: type_hint.span,
|
type_info: ir::TypeInfo {
|
||||||
kind: ir::TypeKind::Float(ir::FloatTy::F32),
|
span: None,
|
||||||
},
|
kind: ir::TypeKind::Float(ir::FloatTy::F32),
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::F32(
|
},
|
||||||
value.parse().unwrap(),
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::F32(
|
||||||
))),
|
value.parse().unwrap(),
|
||||||
}),
|
))),
|
||||||
ir::FloatTy::F64 => ir::Operand::Constant(ir::ConstData {
|
}),
|
||||||
span: Some(*span),
|
type_hint.clone(),
|
||||||
type_info: ir::TypeInfo {
|
),
|
||||||
span: type_hint.span,
|
ir::FloatTy::F64 => (
|
||||||
kind: ir::TypeKind::Float(ir::FloatTy::F64),
|
ir::Operand::Constant(ir::ConstData {
|
||||||
},
|
span: Some(*span),
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::F64(
|
type_info: ir::TypeInfo {
|
||||||
value.parse().unwrap(),
|
span: None,
|
||||||
))),
|
kind: ir::TypeKind::Float(ir::FloatTy::F64),
|
||||||
}),
|
},
|
||||||
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::F64(
|
||||||
|
value.parse().unwrap(),
|
||||||
|
))),
|
||||||
|
}),
|
||||||
|
type_hint.clone(),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
_ => unreachable!(),
|
_ => unreachable!(),
|
||||||
},
|
},
|
||||||
|
@ -649,14 +741,15 @@ fn lower_value(
|
||||||
ast::ValueExpr::Str { value: _, span: _ } => todo!(),
|
ast::ValueExpr::Str { value: _, span: _ } => todo!(),
|
||||||
ast::ValueExpr::Path(info) => {
|
ast::ValueExpr::Path(info) => {
|
||||||
// add deref info to path
|
// add deref info to path
|
||||||
Operand::Move(lower_path(builder, info))
|
let (place, ty) = lower_path(builder, info);
|
||||||
|
(Operand::Move(place), ty)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_return(builder: &mut BodyBuilder, info: &ast::ReturnStmt, return_type: &TypeInfo) {
|
fn lower_return(builder: &mut BodyBuilder, info: &ast::ReturnStmt, return_type: &TypeKind) {
|
||||||
if let Some(value_expr) = &info.value {
|
if let Some(value_expr) = &info.value {
|
||||||
let value = lower_expr(builder, value_expr, Some(return_type));
|
let (value, _ty) = lower_expr(builder, value_expr, Some(return_type));
|
||||||
builder.statements.push(Statement {
|
builder.statements.push(Statement {
|
||||||
span: None,
|
span: None,
|
||||||
kind: StatementKind::Assign(
|
kind: StatementKind::Assign(
|
||||||
|
@ -676,16 +769,20 @@ fn lower_return(builder: &mut BodyBuilder, info: &ast::ReturnStmt, return_type:
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> ir::Place {
|
fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> (ir::Place, TypeKind) {
|
||||||
let local = *builder
|
let local = *builder
|
||||||
.name_to_local
|
.name_to_local
|
||||||
.get(&info.first.name)
|
.get(&info.first.name)
|
||||||
.expect("local not found");
|
.expect("local not found");
|
||||||
|
let ty = builder.body.locals[local].ty.kind.clone();
|
||||||
|
|
||||||
Place {
|
(
|
||||||
local,
|
Place {
|
||||||
projection: Default::default(), // todo, field array deref
|
local,
|
||||||
}
|
projection: Default::default(), // todo, field array deref
|
||||||
|
},
|
||||||
|
ty,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lower_type(_ctx: &BuildCtx, t: &ast::Type) -> ir::TypeInfo {
|
pub fn lower_type(_ctx: &BuildCtx, t: &ast::Type) -> ir::TypeInfo {
|
||||||
|
|
Loading…
Reference in a new issue