mirror of
https://github.com/edg-l/edlang.git
synced 2024-11-22 16:08:24 +00:00
.
This commit is contained in:
parent
572f1aee09
commit
997f9b4dab
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -370,6 +370,7 @@ version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"edlang_ast",
|
"edlang_ast",
|
||||||
"edlang_ir",
|
"edlang_ir",
|
||||||
|
"tracing",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
@ -18,7 +18,7 @@ pub enum ModuleStatement {
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct Import {
|
pub struct Import {
|
||||||
pub path: PathExpr,
|
pub module: Vec<Ident>,
|
||||||
/// If symbols is empty then the last path ident is the symbol.
|
/// If symbols is empty then the last path ident is the symbol.
|
||||||
pub symbols: Vec<Ident>,
|
pub symbols: Vec<Ident>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
|
|
|
@ -4,24 +4,22 @@ use edlang_ir as ir;
|
||||||
use edlang_ir::DefId;
|
use edlang_ir::DefId;
|
||||||
use edlang_session::Session;
|
use edlang_session::Session;
|
||||||
use inkwell::{
|
use inkwell::{
|
||||||
attributes::Attribute,
|
|
||||||
builder::{Builder, BuilderError},
|
builder::{Builder, BuilderError},
|
||||||
context::Context,
|
context::Context,
|
||||||
debug_info::{DICompileUnit, DebugInfoBuilder},
|
debug_info::{DICompileUnit, DebugInfoBuilder},
|
||||||
module::Module,
|
module::Module,
|
||||||
targets::{InitializationConfig, Target, TargetData, TargetMachine, TargetTriple},
|
targets::{InitializationConfig, Target, TargetData, TargetMachine},
|
||||||
types::{AnyType, BasicMetadataTypeEnum, BasicType},
|
types::{AnyType, BasicMetadataTypeEnum, BasicType},
|
||||||
values::{AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, PointerValue},
|
values::{BasicValue, BasicValueEnum, PointerValue},
|
||||||
};
|
};
|
||||||
use ir::{ConstData, Operand, TypeInfo, ValueTree};
|
use ir::{ModuleBody, ProgramBody, TypeInfo, ValueTree};
|
||||||
use tracing::info;
|
use tracing::info;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
struct CompileCtx<'a> {
|
struct CompileCtx<'a> {
|
||||||
context: &'a Context,
|
context: &'a Context,
|
||||||
session: &'a Session,
|
session: &'a Session,
|
||||||
modules: &'a HashMap<DefId, ir::ModuleBody>,
|
program: &'a ProgramBody,
|
||||||
symbols: &'a HashMap<DefId, String>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ModuleCompileCtx<'ctx, 'm> {
|
struct ModuleCompileCtx<'ctx, 'm> {
|
||||||
|
@ -31,21 +29,23 @@ struct ModuleCompileCtx<'ctx, 'm> {
|
||||||
di_builder: DebugInfoBuilder<'ctx>,
|
di_builder: DebugInfoBuilder<'ctx>,
|
||||||
di_unit: DICompileUnit<'ctx>,
|
di_unit: DICompileUnit<'ctx>,
|
||||||
target_data: TargetData,
|
target_data: TargetData,
|
||||||
|
module_id: DefId,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn compile(
|
impl<'ctx, 'm> ModuleCompileCtx<'ctx, 'm> {
|
||||||
session: &Session,
|
pub fn get_module_body(&self) -> &ModuleBody {
|
||||||
modules: &HashMap<DefId, ir::ModuleBody>,
|
self.ctx.program.modules.get(&self.module_id).unwrap()
|
||||||
symbols: &HashMap<DefId, String>,
|
}
|
||||||
) -> Result<PathBuf, Box<dyn Error>> {
|
}
|
||||||
|
|
||||||
|
pub fn compile(session: &Session, program: &ProgramBody) -> Result<PathBuf, Box<dyn Error>> {
|
||||||
let context = Context::create();
|
let context = Context::create();
|
||||||
let builder = context.create_builder();
|
let builder = context.create_builder();
|
||||||
|
|
||||||
let ctx = CompileCtx {
|
let ctx = CompileCtx {
|
||||||
context: &context,
|
context: &context,
|
||||||
session,
|
session,
|
||||||
modules,
|
program,
|
||||||
symbols,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut llvm_modules = Vec::new();
|
let mut llvm_modules = Vec::new();
|
||||||
|
@ -68,9 +68,9 @@ pub fn compile(
|
||||||
|
|
||||||
let filename = session.file_path.file_name().unwrap().to_string_lossy();
|
let filename = session.file_path.file_name().unwrap().to_string_lossy();
|
||||||
let dir = session.file_path.parent().unwrap().to_string_lossy();
|
let dir = session.file_path.parent().unwrap().to_string_lossy();
|
||||||
for (id, module) in modules.iter() {
|
for module_id in program.top_level_modules.iter() {
|
||||||
let name = ctx.symbols.get(id).unwrap();
|
let module = ctx.program.modules.get(module_id).unwrap();
|
||||||
let llvm_module = context.create_module(name);
|
let llvm_module = context.create_module(&module.name);
|
||||||
llvm_module.set_source_file_name(&filename);
|
llvm_module.set_source_file_name(&filename);
|
||||||
llvm_module.set_triple(&triple);
|
llvm_module.set_triple(&triple);
|
||||||
let (di_builder, di_unit) = llvm_module.create_debug_info_builder(
|
let (di_builder, di_unit) = llvm_module.create_debug_info_builder(
|
||||||
|
@ -84,7 +84,7 @@ pub fn compile(
|
||||||
1,
|
1,
|
||||||
"", // split name
|
"", // split name
|
||||||
inkwell::debug_info::DWARFEmissionKind::Full,
|
inkwell::debug_info::DWARFEmissionKind::Full,
|
||||||
module.module_id.module_id.try_into().unwrap(), // compile unit id?
|
module.module_id.program_id.try_into().unwrap(), // compile unit id?
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
"",
|
"",
|
||||||
|
@ -98,9 +98,10 @@ pub fn compile(
|
||||||
di_unit,
|
di_unit,
|
||||||
builder: &builder,
|
builder: &builder,
|
||||||
target_data: machine.get_target_data(),
|
target_data: machine.get_target_data(),
|
||||||
|
module_id: *module_id,
|
||||||
};
|
};
|
||||||
|
|
||||||
compile_module(&module_ctx, module);
|
compile_module(&module_ctx, *module_id);
|
||||||
|
|
||||||
module_ctx.module.verify()?;
|
module_ctx.module.verify()?;
|
||||||
|
|
||||||
|
@ -125,37 +126,36 @@ pub fn compile(
|
||||||
Ok(session.output_file.with_extension("o"))
|
Ok(session.output_file.with_extension("o"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_module(ctx: &ModuleCompileCtx, module: &ir::ModuleBody) {
|
fn compile_module(ctx: &ModuleCompileCtx, module_id: DefId) {
|
||||||
|
let module = ctx.ctx.program.modules.get(&module_id).unwrap();
|
||||||
info!("compiling module");
|
info!("compiling module");
|
||||||
for (_fn_id, func) in module.functions.iter() {
|
for id in module.functions.iter() {
|
||||||
compile_fn_signature(ctx, func);
|
compile_fn_signature(ctx, *id);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (_fn_id, func) in module.functions.iter() {
|
for id in module.functions.iter() {
|
||||||
compile_fn(ctx, func).unwrap();
|
compile_fn(ctx, *id).unwrap();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_fn_signature(ctx: &ModuleCompileCtx, body: &ir::Body) {
|
fn compile_fn_signature(ctx: &ModuleCompileCtx, fn_id: DefId) {
|
||||||
let name = ctx.ctx.symbols.get(&body.def_id).unwrap();
|
let (arg_types, ret_type) = ctx.ctx.program.function_signatures.get(&fn_id).unwrap();
|
||||||
info!("compiling fn sig: {}", name);
|
let body = ctx.ctx.program.functions.get(&fn_id).unwrap();
|
||||||
|
info!("compiling fn sig: {}", body.name);
|
||||||
|
|
||||||
let (args, ret_type) = { (body.get_args(), body.ret_type.clone()) };
|
let args: Vec<BasicMetadataTypeEnum> = arg_types
|
||||||
|
|
||||||
let args: Vec<BasicMetadataTypeEnum> = args
|
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| compile_basic_type(ctx, &x.ty).into())
|
.map(|x| compile_basic_type(ctx, x).into())
|
||||||
.collect();
|
.collect();
|
||||||
// let ret_type = compile_basic_type(ctx, &ret_type);
|
|
||||||
|
|
||||||
let fn_type = if let ir::TypeKind::Unit = ret_type.kind {
|
let fn_type = if let ir::TypeKind::Unit = ret_type.kind {
|
||||||
ctx.ctx.context.void_type().fn_type(&args, false)
|
ctx.ctx.context.void_type().fn_type(&args, false)
|
||||||
} else {
|
} else {
|
||||||
compile_basic_type(ctx, &ret_type).fn_type(&args, false)
|
compile_basic_type(ctx, ret_type).fn_type(&args, false)
|
||||||
};
|
};
|
||||||
|
|
||||||
let fn_value = ctx.module.add_function(
|
let fn_value = ctx.module.add_function(
|
||||||
name,
|
&body.name,
|
||||||
fn_type,
|
fn_type,
|
||||||
Some(if body.is_extern {
|
Some(if body.is_extern {
|
||||||
inkwell::module::Linkage::AvailableExternally
|
inkwell::module::Linkage::AvailableExternally
|
||||||
|
@ -173,12 +173,11 @@ fn compile_fn_signature(ctx: &ModuleCompileCtx, body: &ir::Body) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile_fn(ctx: &ModuleCompileCtx, body: &ir::Body) -> Result<(), BuilderError> {
|
fn compile_fn(ctx: &ModuleCompileCtx, fn_id: DefId) -> Result<(), BuilderError> {
|
||||||
let name = ctx.ctx.symbols.get(&body.def_id).unwrap();
|
let body = ctx.ctx.program.functions.get(&fn_id).unwrap();
|
||||||
info!("compiling fn body: {}", name);
|
info!("compiling fn body: {}", body.name);
|
||||||
// let (args, ret_type) = { (body.get_args(), body.ret_type.clone().unwrap()) };
|
|
||||||
|
|
||||||
let fn_value = ctx.module.get_function(name).unwrap();
|
let fn_value = ctx.module.get_function(&body.name).unwrap();
|
||||||
|
|
||||||
let block = ctx.ctx.context.append_basic_block(fn_value, "entry");
|
let block = ctx.ctx.context.append_basic_block(fn_value, "entry");
|
||||||
ctx.builder.position_at_end(block);
|
ctx.builder.position_at_end(block);
|
||||||
|
@ -236,21 +235,11 @@ fn compile_fn(ctx: &ModuleCompileCtx, body: &ir::Body) -> Result<(), BuilderErro
|
||||||
for stmt in &block.statements {
|
for stmt in &block.statements {
|
||||||
info!("compiling stmt");
|
info!("compiling stmt");
|
||||||
match &stmt.kind {
|
match &stmt.kind {
|
||||||
ir::StatementKind::Assign(place, rvalue) => match rvalue {
|
ir::StatementKind::Assign(place, rvalue) => {
|
||||||
ir::RValue::Use(op) => {
|
let (value, _value_ty) = compile_rvalue(ctx, fn_id, &locals, rvalue)?;
|
||||||
let value = compile_load_operand(ctx, body, &locals, op)?.0;
|
ctx.builder
|
||||||
ctx.builder
|
.build_store(*locals.get(&place.local).unwrap(), value)?;
|
||||||
.build_store(*locals.get(&place.local).unwrap(), value)?;
|
}
|
||||||
}
|
|
||||||
ir::RValue::Ref(_, _) => todo!(),
|
|
||||||
ir::RValue::BinOp(op, lhs, rhs) => {
|
|
||||||
let value = compile_bin_op(ctx, body, &locals, *op, lhs, rhs)?;
|
|
||||||
ctx.builder
|
|
||||||
.build_store(*locals.get(&place.local).unwrap(), value)?;
|
|
||||||
}
|
|
||||||
ir::RValue::LogicOp(_, _, _) => todo!(),
|
|
||||||
ir::RValue::UnOp(_, _) => todo!(),
|
|
||||||
},
|
|
||||||
ir::StatementKind::StorageLive(_) => {
|
ir::StatementKind::StorageLive(_) => {
|
||||||
// https://llvm.org/docs/LangRef.html#int-lifestart
|
// https://llvm.org/docs/LangRef.html#int-lifestart
|
||||||
}
|
}
|
||||||
|
@ -278,44 +267,28 @@ fn compile_fn(ctx: &ModuleCompileCtx, body: &ir::Body) -> Result<(), BuilderErro
|
||||||
ir::Terminator::Call {
|
ir::Terminator::Call {
|
||||||
func,
|
func,
|
||||||
args,
|
args,
|
||||||
dest,
|
destination: dest,
|
||||||
target,
|
target,
|
||||||
} => {
|
} => {
|
||||||
if let Operand::Constant(c) = func {
|
let target_fn_body = ctx.ctx.program.functions.get(func).unwrap();
|
||||||
if let ir::TypeKind::FnDef(fn_id, generics) = &c.type_info.kind {
|
let fn_value = ctx.module.get_function(&target_fn_body.name).unwrap();
|
||||||
let fn_symbol = ctx.ctx.symbols.get(fn_id).unwrap();
|
let args: Vec<_> = args
|
||||||
let fn_value = ctx.module.get_function(fn_symbol).unwrap();
|
.iter()
|
||||||
let args: Vec<_> = args
|
.map(|x| compile_rvalue(ctx, fn_id, &locals, x).unwrap().0.into())
|
||||||
.iter()
|
.collect();
|
||||||
.map(|x| {
|
let result = ctx.builder.build_call(fn_value, &args, "")?;
|
||||||
compile_load_operand(ctx, body, &locals, x)
|
|
||||||
.unwrap()
|
|
||||||
.0
|
|
||||||
.into()
|
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
let result = ctx.builder.build_call(fn_value, &args, "")?;
|
|
||||||
|
|
||||||
if let Some(dest) = dest {
|
let is_void = matches!(body.locals[dest.local].ty.kind, ir::TypeKind::Unit);
|
||||||
let is_void =
|
|
||||||
matches!(body.locals[dest.local].ty.kind, ir::TypeKind::Unit);
|
|
||||||
|
|
||||||
if !is_void {
|
if !is_void {
|
||||||
ctx.builder.build_store(
|
ctx.builder.build_store(
|
||||||
*locals.get(&dest.local).unwrap(),
|
*locals.get(&dest.local).unwrap(),
|
||||||
result.try_as_basic_value().expect_left("value was right"),
|
result.try_as_basic_value().expect_left("value was right"),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(target) = target {
|
if let Some(target) = target {
|
||||||
ctx.builder.build_unconditional_branch(blocks[*target])?;
|
ctx.builder.build_unconditional_branch(blocks[*target])?;
|
||||||
}
|
|
||||||
} else {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
todo!()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ir::Terminator::Unreachable => {
|
ir::Terminator::Unreachable => {
|
||||||
|
@ -329,21 +302,21 @@ fn compile_fn(ctx: &ModuleCompileCtx, body: &ir::Body) -> Result<(), BuilderErro
|
||||||
|
|
||||||
fn compile_bin_op<'ctx>(
|
fn compile_bin_op<'ctx>(
|
||||||
ctx: &ModuleCompileCtx<'ctx, '_>,
|
ctx: &ModuleCompileCtx<'ctx, '_>,
|
||||||
body: &ir::Body,
|
fn_id: DefId,
|
||||||
locals: &HashMap<usize, PointerValue<'ctx>>,
|
locals: &HashMap<usize, PointerValue<'ctx>>,
|
||||||
op: ir::BinOp,
|
op: ir::BinOp,
|
||||||
lhs: &ir::Operand,
|
lhs: &ir::Operand,
|
||||||
rhs: &ir::Operand,
|
rhs: &ir::Operand,
|
||||||
) -> Result<BasicValueEnum<'ctx>, BuilderError> {
|
) -> Result<(BasicValueEnum<'ctx>, TypeInfo), BuilderError> {
|
||||||
let (lhs_value, lhs_ty) = compile_load_operand(ctx, body, locals, lhs)?;
|
let (lhs_value, lhs_ty) = compile_load_operand(ctx, fn_id, locals, lhs)?;
|
||||||
let (rhs_value, _rhs_ty) = compile_load_operand(ctx, body, locals, rhs)?;
|
let (rhs_value, _rhs_ty) = compile_load_operand(ctx, fn_id, locals, rhs)?;
|
||||||
|
|
||||||
let is_float = matches!(lhs_ty.kind, ir::TypeKind::Float(_));
|
let is_float = matches!(lhs_ty.kind, ir::TypeKind::Float(_));
|
||||||
let is_signed = matches!(lhs_ty.kind, ir::TypeKind::Int(_));
|
let is_signed = matches!(lhs_ty.kind, ir::TypeKind::Int(_));
|
||||||
|
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
ir::BinOp::Add => {
|
ir::BinOp::Add => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_add(
|
.build_float_add(
|
||||||
lhs_value.into_float_value(),
|
lhs_value.into_float_value(),
|
||||||
|
@ -355,10 +328,11 @@ fn compile_bin_op<'ctx>(
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_int_add(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
.build_int_add(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(value, lhs_ty)
|
||||||
}
|
}
|
||||||
ir::BinOp::Sub => {
|
ir::BinOp::Sub => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_sub(
|
.build_float_sub(
|
||||||
lhs_value.into_float_value(),
|
lhs_value.into_float_value(),
|
||||||
|
@ -370,10 +344,11 @@ fn compile_bin_op<'ctx>(
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_int_sub(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
.build_int_sub(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(value, lhs_ty)
|
||||||
}
|
}
|
||||||
ir::BinOp::Mul => {
|
ir::BinOp::Mul => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_mul(
|
.build_float_mul(
|
||||||
lhs_value.into_float_value(),
|
lhs_value.into_float_value(),
|
||||||
|
@ -385,10 +360,11 @@ fn compile_bin_op<'ctx>(
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_int_add(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
.build_int_add(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(value, lhs_ty)
|
||||||
}
|
}
|
||||||
ir::BinOp::Div => {
|
ir::BinOp::Div => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_div(
|
.build_float_div(
|
||||||
lhs_value.into_float_value(),
|
lhs_value.into_float_value(),
|
||||||
|
@ -412,10 +388,11 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(value, lhs_ty)
|
||||||
}
|
}
|
||||||
ir::BinOp::Rem => {
|
ir::BinOp::Rem => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_rem(
|
.build_float_rem(
|
||||||
lhs_value.into_float_value(),
|
lhs_value.into_float_value(),
|
||||||
|
@ -439,35 +416,46 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(value, lhs_ty)
|
||||||
}
|
}
|
||||||
ir::BinOp::BitXor => ctx
|
ir::BinOp::BitXor => (
|
||||||
.builder
|
ctx.builder
|
||||||
.build_xor(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
.build_xor(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
.as_basic_value_enum(),
|
.as_basic_value_enum(),
|
||||||
ir::BinOp::BitAnd => ctx
|
lhs_ty,
|
||||||
.builder
|
),
|
||||||
.build_and(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
ir::BinOp::BitAnd => (
|
||||||
.as_basic_value_enum(),
|
ctx.builder
|
||||||
ir::BinOp::BitOr => ctx
|
.build_and(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
.builder
|
.as_basic_value_enum(),
|
||||||
.build_or(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
lhs_ty,
|
||||||
.as_basic_value_enum(),
|
),
|
||||||
ir::BinOp::Shl => ctx
|
ir::BinOp::BitOr => (
|
||||||
.builder
|
ctx.builder
|
||||||
.build_left_shift(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
.build_or(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
.as_basic_value_enum(),
|
.as_basic_value_enum(),
|
||||||
ir::BinOp::Shr => ctx
|
lhs_ty,
|
||||||
.builder
|
),
|
||||||
.build_right_shift(
|
ir::BinOp::Shl => (
|
||||||
lhs_value.into_int_value(),
|
ctx.builder
|
||||||
rhs_value.into_int_value(),
|
.build_left_shift(lhs_value.into_int_value(), rhs_value.into_int_value(), "")?
|
||||||
is_signed,
|
.as_basic_value_enum(),
|
||||||
"",
|
lhs_ty,
|
||||||
)?
|
),
|
||||||
.as_basic_value_enum(),
|
ir::BinOp::Shr => (
|
||||||
|
ctx.builder
|
||||||
|
.build_right_shift(
|
||||||
|
lhs_value.into_int_value(),
|
||||||
|
rhs_value.into_int_value(),
|
||||||
|
is_signed,
|
||||||
|
"",
|
||||||
|
)?
|
||||||
|
.as_basic_value_enum(),
|
||||||
|
lhs_ty,
|
||||||
|
),
|
||||||
ir::BinOp::Eq => {
|
ir::BinOp::Eq => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::OEQ,
|
inkwell::FloatPredicate::OEQ,
|
||||||
|
@ -485,10 +473,17 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(
|
||||||
|
value,
|
||||||
|
TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ir::BinOp::Lt => {
|
ir::BinOp::Lt => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::OLT,
|
inkwell::FloatPredicate::OLT,
|
||||||
|
@ -510,10 +505,17 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(
|
||||||
|
value,
|
||||||
|
TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ir::BinOp::Le => {
|
ir::BinOp::Le => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::OLE,
|
inkwell::FloatPredicate::OLE,
|
||||||
|
@ -535,10 +537,17 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(
|
||||||
|
value,
|
||||||
|
TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ir::BinOp::Ne => {
|
ir::BinOp::Ne => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::ONE,
|
inkwell::FloatPredicate::ONE,
|
||||||
|
@ -556,10 +565,17 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(
|
||||||
|
value,
|
||||||
|
TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ir::BinOp::Ge => {
|
ir::BinOp::Ge => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::OGE,
|
inkwell::FloatPredicate::OGE,
|
||||||
|
@ -581,10 +597,17 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(
|
||||||
|
value,
|
||||||
|
TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ir::BinOp::Gt => {
|
ir::BinOp::Gt => {
|
||||||
if is_float {
|
let value = if is_float {
|
||||||
ctx.builder
|
ctx.builder
|
||||||
.build_float_compare(
|
.build_float_compare(
|
||||||
inkwell::FloatPredicate::OGT,
|
inkwell::FloatPredicate::OGT,
|
||||||
|
@ -606,19 +629,42 @@ fn compile_bin_op<'ctx>(
|
||||||
"",
|
"",
|
||||||
)?
|
)?
|
||||||
.as_basic_value_enum()
|
.as_basic_value_enum()
|
||||||
}
|
};
|
||||||
|
(
|
||||||
|
value,
|
||||||
|
TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Bool,
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
ir::BinOp::Offset => todo!(),
|
ir::BinOp::Offset => todo!(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compile_rvalue<'ctx>(
|
||||||
|
ctx: &ModuleCompileCtx<'ctx, '_>,
|
||||||
|
fn_id: DefId,
|
||||||
|
locals: &HashMap<usize, PointerValue<'ctx>>,
|
||||||
|
rvalue: &ir::RValue,
|
||||||
|
) -> Result<(BasicValueEnum<'ctx>, TypeInfo), BuilderError> {
|
||||||
|
Ok(match rvalue {
|
||||||
|
ir::RValue::Use(op) => compile_load_operand(ctx, fn_id, locals, op)?,
|
||||||
|
ir::RValue::Ref(_, _) => todo!(),
|
||||||
|
ir::RValue::BinOp(op, lhs, rhs) => compile_bin_op(ctx, fn_id, locals, *op, lhs, rhs)?,
|
||||||
|
ir::RValue::LogicOp(_, _, _) => todo!(),
|
||||||
|
ir::RValue::UnOp(_, _) => todo!(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn compile_load_operand<'ctx>(
|
fn compile_load_operand<'ctx>(
|
||||||
ctx: &ModuleCompileCtx<'ctx, '_>,
|
ctx: &ModuleCompileCtx<'ctx, '_>,
|
||||||
body: &ir::Body,
|
fn_id: DefId,
|
||||||
locals: &HashMap<usize, PointerValue<'ctx>>,
|
locals: &HashMap<usize, PointerValue<'ctx>>,
|
||||||
op: &ir::Operand,
|
op: &ir::Operand,
|
||||||
) -> Result<(BasicValueEnum<'ctx>, TypeInfo), BuilderError> {
|
) -> Result<(BasicValueEnum<'ctx>, TypeInfo), BuilderError> {
|
||||||
// todo: implement projection
|
// todo: implement projection
|
||||||
|
let body = ctx.ctx.program.functions.get(&fn_id).unwrap();
|
||||||
Ok(match op {
|
Ok(match op {
|
||||||
ir::Operand::Copy(place) => {
|
ir::Operand::Copy(place) => {
|
||||||
let pointee_ty = compile_basic_type(ctx, &body.locals[place.local].ty);
|
let pointee_ty = compile_basic_type(ctx, &body.locals[place.local].ty);
|
||||||
|
@ -715,23 +761,13 @@ fn compile_type<'a>(
|
||||||
match &ty.kind {
|
match &ty.kind {
|
||||||
ir::TypeKind::Unit => context.void_type().as_any_type_enum(),
|
ir::TypeKind::Unit => context.void_type().as_any_type_enum(),
|
||||||
ir::TypeKind::FnDef(def_id, _generic_args) => {
|
ir::TypeKind::FnDef(def_id, _generic_args) => {
|
||||||
let (args, ret_type) = {
|
let (args, ret_type) = { ctx.ctx.program.function_signatures.get(def_id).unwrap() };
|
||||||
let fn_body = ctx
|
|
||||||
.ctx
|
|
||||||
.modules
|
|
||||||
.get(&def_id.get_module_defid())
|
|
||||||
.unwrap()
|
|
||||||
.functions
|
|
||||||
.get(def_id)
|
|
||||||
.unwrap();
|
|
||||||
(fn_body.get_args(), fn_body.ret_type.clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
let args: Vec<BasicMetadataTypeEnum> = args
|
let args: Vec<BasicMetadataTypeEnum> = args
|
||||||
.iter()
|
.iter()
|
||||||
.map(|x| compile_basic_type(ctx, &x.ty).into())
|
.map(|x| compile_basic_type(ctx, x).into())
|
||||||
.collect();
|
.collect();
|
||||||
let ret_type = compile_basic_type(ctx, &ret_type);
|
let ret_type = compile_basic_type(ctx, ret_type);
|
||||||
|
|
||||||
ret_type.fn_type(&args, false).as_any_type_enum()
|
ret_type.fn_type(&args, false).as_any_type_enum()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,18 +1,10 @@
|
||||||
#![allow(clippy::too_many_arguments)]
|
#![allow(clippy::too_many_arguments)]
|
||||||
|
|
||||||
use edlang_ir as ir;
|
use edlang_ir as ir;
|
||||||
use std::{
|
use std::path::PathBuf;
|
||||||
collections::HashMap,
|
|
||||||
ffi::{CStr, CString},
|
|
||||||
mem::MaybeUninit,
|
|
||||||
path::PathBuf,
|
|
||||||
ptr::{addr_of_mut, null_mut},
|
|
||||||
sync::OnceLock,
|
|
||||||
};
|
|
||||||
|
|
||||||
use edlang_session::{OptLevel, Session};
|
use edlang_session::Session;
|
||||||
use inkwell::context::Context;
|
use ir::ProgramBody;
|
||||||
use ir::DefId;
|
|
||||||
/*
|
/*
|
||||||
use llvm_sys::{
|
use llvm_sys::{
|
||||||
core::{LLVMContextCreate, LLVMContextDispose, LLVMDisposeMessage, LLVMDisposeModule},
|
core::{LLVMContextCreate, LLVMContextDispose, LLVMDisposeMessage, LLVMDisposeModule},
|
||||||
|
@ -34,10 +26,9 @@ pub mod linker;
|
||||||
|
|
||||||
pub fn compile(
|
pub fn compile(
|
||||||
session: &Session,
|
session: &Session,
|
||||||
modules: &HashMap<DefId, ir::ModuleBody>,
|
program: &ProgramBody,
|
||||||
symbols: HashMap<DefId, String>,
|
|
||||||
) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
) -> Result<PathBuf, Box<dyn std::error::Error>> {
|
||||||
codegen::compile(session, modules, &symbols)
|
codegen::compile(session, program)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Converts a module to an object.
|
// Converts a module to an object.
|
||||||
|
|
|
@ -88,14 +88,14 @@ pub fn main() -> Result<(), Box<dyn Error>> {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let (symbols, module_irs) = lower_modules(&[module.clone()]);
|
let program_ir = lower_modules(&[module.clone()]);
|
||||||
|
|
||||||
if args.ir {
|
if args.ir {
|
||||||
println!("{:#?}", module_irs);
|
println!("{:#?}", program_ir);
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let object_path = edlang_codegen_mlir::compile(&session, &module_irs, symbols)?;
|
let object_path = edlang_codegen_mlir::compile(&session, &program_ir)?;
|
||||||
|
|
||||||
if session.library {
|
if session.library {
|
||||||
link_shared_lib(&object_path, &session.output_file.with_extension("so"))?;
|
link_shared_lib(&object_path, &session.output_file.with_extension("so"))?;
|
||||||
|
|
|
@ -1,42 +1,69 @@
|
||||||
// Based on a cfg
|
// Based on a cfg
|
||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::{BTreeMap, HashSet};
|
||||||
|
|
||||||
use edlang_span::Span;
|
use edlang_span::Span;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
|
||||||
pub mod scalar_int;
|
pub mod scalar_int;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct SymbolTable {
|
||||||
|
pub symbols: BTreeMap<DefId, String>,
|
||||||
|
pub modules: BTreeMap<String, DefId>,
|
||||||
|
pub functions: BTreeMap<String, DefId>,
|
||||||
|
pub constants: BTreeMap<String, DefId>,
|
||||||
|
pub structs: BTreeMap<String, DefId>,
|
||||||
|
pub types: BTreeMap<String, DefId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Default)]
|
||||||
|
pub struct ProgramBody {
|
||||||
|
pub top_level_module_names: BTreeMap<String, DefId>,
|
||||||
|
/// The top level modules.
|
||||||
|
pub top_level_modules: Vec<DefId>,
|
||||||
|
/// All the modules in a flat map.
|
||||||
|
pub modules: BTreeMap<DefId, ModuleBody>,
|
||||||
|
/// This stores all the functions from all modules
|
||||||
|
pub functions: BTreeMap<DefId, Body>,
|
||||||
|
/// The function signatures.
|
||||||
|
pub function_signatures: BTreeMap<DefId, (Vec<TypeInfo>, TypeInfo)>,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct ModuleBody {
|
pub struct ModuleBody {
|
||||||
pub module_id: DefId,
|
pub module_id: DefId,
|
||||||
pub functions: BTreeMap<DefId, Body>,
|
pub parent_ids: Vec<DefId>,
|
||||||
pub modules: BTreeMap<DefId, Self>,
|
pub name: String,
|
||||||
|
pub symbols: SymbolTable,
|
||||||
|
/// Functions defined in this module.
|
||||||
|
pub functions: HashSet<DefId>,
|
||||||
|
/// Structs defined in this module.
|
||||||
|
pub structs: HashSet<DefId>,
|
||||||
|
/// Types defined in this module.
|
||||||
|
pub types: HashSet<DefId>,
|
||||||
|
/// Constants defined in this module.
|
||||||
|
pub constants: HashSet<DefId>,
|
||||||
|
/// Submodules defined in this module.
|
||||||
|
pub modules: HashSet<DefId>,
|
||||||
|
/// Imported items. symbol -> id
|
||||||
|
pub imports: BTreeMap<String, DefId>,
|
||||||
pub span: Span,
|
pub span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Definition id.
|
/// Definition id.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
|
||||||
pub struct DefId {
|
pub struct DefId {
|
||||||
pub module_id: usize,
|
pub program_id: usize,
|
||||||
pub id: usize,
|
pub id: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DefId {
|
|
||||||
pub fn get_module_defid(&self) -> Self {
|
|
||||||
Self {
|
|
||||||
module_id: self.module_id,
|
|
||||||
id: 0,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Body {
|
pub struct Body {
|
||||||
pub def_id: DefId,
|
pub def_id: DefId,
|
||||||
pub is_pub: bool,
|
pub is_pub: bool,
|
||||||
pub is_extern: bool,
|
pub is_extern: bool,
|
||||||
pub ret_type: TypeInfo,
|
pub name: String,
|
||||||
pub locals: SmallVec<[Local; 4]>,
|
pub locals: SmallVec<[Local; 4]>,
|
||||||
pub blocks: SmallVec<[BasicBlock; 8]>,
|
pub blocks: SmallVec<[BasicBlock; 8]>,
|
||||||
pub fn_span: Span,
|
pub fn_span: Span,
|
||||||
|
@ -68,7 +95,6 @@ pub struct DebugInfo {
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct BasicBlock {
|
pub struct BasicBlock {
|
||||||
pub id: usize,
|
|
||||||
pub statements: SmallVec<[Statement; 8]>,
|
pub statements: SmallVec<[Statement; 8]>,
|
||||||
pub terminator: Terminator,
|
pub terminator: Terminator,
|
||||||
}
|
}
|
||||||
|
@ -77,10 +103,39 @@ pub struct BasicBlock {
|
||||||
pub struct Local {
|
pub struct Local {
|
||||||
pub mutable: bool,
|
pub mutable: bool,
|
||||||
pub span: Option<Span>,
|
pub span: Option<Span>,
|
||||||
|
pub debug_name: Option<String>,
|
||||||
pub ty: TypeInfo,
|
pub ty: TypeInfo,
|
||||||
pub kind: LocalKind,
|
pub kind: LocalKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Local {
|
||||||
|
pub fn new(
|
||||||
|
span: Option<Span>,
|
||||||
|
kind: LocalKind,
|
||||||
|
ty: TypeInfo,
|
||||||
|
debug_name: Option<String>,
|
||||||
|
mutable: bool,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
span,
|
||||||
|
kind,
|
||||||
|
ty,
|
||||||
|
debug_name,
|
||||||
|
mutable,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const fn temp(ty: TypeInfo) -> Self {
|
||||||
|
Self {
|
||||||
|
span: None,
|
||||||
|
ty,
|
||||||
|
kind: LocalKind::Temp,
|
||||||
|
debug_name: None,
|
||||||
|
mutable: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum LocalKind {
|
pub enum LocalKind {
|
||||||
Temp,
|
Temp,
|
||||||
|
@ -107,10 +162,14 @@ pub enum Terminator {
|
||||||
Return,
|
Return,
|
||||||
Switch,
|
Switch,
|
||||||
Call {
|
Call {
|
||||||
func: Operand,
|
/// The function to call.
|
||||||
args: Vec<Operand>,
|
func: DefId,
|
||||||
dest: Option<Place>,
|
/// The arguments.
|
||||||
target: Option<usize>, // block
|
args: Vec<RValue>,
|
||||||
|
/// The place in memory to store the return value of the function call.
|
||||||
|
destination: Place,
|
||||||
|
/// What basic block to jump to after the function call, if the function is non-diverging (i.e it returns control back).
|
||||||
|
target: Option<usize>,
|
||||||
},
|
},
|
||||||
Unreachable,
|
Unreachable,
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,3 +8,4 @@ edition = "2021"
|
||||||
[dependencies]
|
[dependencies]
|
||||||
edlang_ast = { version = "0.1.0", path = "../edlang_ast" }
|
edlang_ast = { version = "0.1.0", path = "../edlang_ast" }
|
||||||
edlang_ir = { version = "0.1.0", path = "../edlang_ir" }
|
edlang_ir = { version = "0.1.0", path = "../edlang_ir" }
|
||||||
|
tracing.workspace = true
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use edlang_ir::{Body, DefId, Local, Statement, TypeInfo};
|
use edlang_ir::{Body, DefId, Local, ModuleBody, ProgramBody, Statement, TypeInfo, 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 {
|
||||||
|
@ -23,7 +23,7 @@ impl IdGenerator {
|
||||||
|
|
||||||
pub fn module_defid(&self) -> DefId {
|
pub fn module_defid(&self) -> DefId {
|
||||||
DefId {
|
DefId {
|
||||||
module_id: self.module_id,
|
program_id: self.module_id,
|
||||||
id: 0,
|
id: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ impl IdGenerator {
|
||||||
let id = self.next_id();
|
let id = self.next_id();
|
||||||
|
|
||||||
DefId {
|
DefId {
|
||||||
module_id: self.module_id,
|
program_id: self.module_id,
|
||||||
id,
|
id,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,18 +47,9 @@ impl IdGenerator {
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct BuildCtx {
|
pub struct BuildCtx {
|
||||||
pub module_name_to_id: HashMap<String, DefId>,
|
pub body: ProgramBody,
|
||||||
pub modules: HashMap<DefId, ModuleCtx>,
|
pub unresolved_function_signatures:
|
||||||
pub functions: HashMap<DefId, Body>,
|
HashMap<DefId, (Vec<edlang_ast::Type>, Option<edlang_ast::Type>)>,
|
||||||
pub gen: IdGenerator,
|
|
||||||
pub symbol_names: HashMap<DefId, String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
|
||||||
pub struct ModuleCtx {
|
|
||||||
pub id: DefId,
|
|
||||||
pub func_name_to_id: HashMap<String, DefId>,
|
|
||||||
pub functions: HashMap<DefId, (Vec<TypeInfo>, TypeInfo)>,
|
|
||||||
pub gen: IdGenerator,
|
pub gen: IdGenerator,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -67,8 +58,8 @@ pub struct BodyBuilder {
|
||||||
pub local_module: DefId,
|
pub local_module: DefId,
|
||||||
pub body: Body,
|
pub body: Body,
|
||||||
pub statements: Vec<Statement>,
|
pub statements: Vec<Statement>,
|
||||||
pub locals: HashMap<String, usize>,
|
pub name_to_local: HashMap<String, usize>,
|
||||||
pub ret_local: Option<usize>,
|
pub ret_local: usize,
|
||||||
pub ctx: BuildCtx,
|
pub ctx: BuildCtx,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,27 +69,21 @@ impl BodyBuilder {
|
||||||
self.body.locals.push(local);
|
self.body.locals.push(local);
|
||||||
id
|
id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn add_temp_local(&mut self, ty_kind: TypeKind) -> usize {
|
||||||
|
let id = self.body.locals.len();
|
||||||
|
self.body.locals.push(Local::temp(TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ty_kind,
|
||||||
|
}));
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_local(&self, name: &str) -> Option<&Local> {
|
pub fn get_local(&self, name: &str) -> Option<&Local> {
|
||||||
self.body.locals.get(*(self.locals.get(name)?))
|
self.body.locals.get(*(self.name_to_local.get(name)?))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_current_module(&self) -> &ModuleCtx {
|
pub fn get_module_body(&self) -> &ModuleBody {
|
||||||
self.ctx
|
self.ctx.body.modules.get(&self.local_module).unwrap()
|
||||||
.modules
|
|
||||||
.get(&self.local_module)
|
|
||||||
.expect("current module should exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_current_module_mut(&mut self) -> &mut ModuleCtx {
|
|
||||||
self.ctx
|
|
||||||
.modules
|
|
||||||
.get_mut(&self.local_module)
|
|
||||||
.expect("current module should exist")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn get_fn_by_name(&self, name: &str) -> Option<&(Vec<TypeInfo>, TypeInfo)> {
|
|
||||||
let id = self.get_current_module().func_name_to_id.get(name)?;
|
|
||||||
let f = self.get_current_module().functions.get(&id)?;
|
|
||||||
Some(f)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,222 +1,196 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use common::{BodyBuilder, BuildCtx, IdGenerator, ModuleCtx};
|
use ast::ModuleStatement;
|
||||||
|
use common::{BodyBuilder, BuildCtx, IdGenerator};
|
||||||
use edlang_ast as ast;
|
use edlang_ast as ast;
|
||||||
use edlang_ir as ir;
|
use edlang_ir as ir;
|
||||||
use ir::{ConstData, ConstKind, DefId, Local, Operand, Place, Statement, Terminator, TypeInfo};
|
use ir::{
|
||||||
|
BasicBlock, Body, ConstData, ConstKind, DefId, Local, LocalKind, Operand, Place, ProgramBody,
|
||||||
|
RValue, Statement, StatementKind, Terminator, TypeInfo, TypeKind,
|
||||||
|
};
|
||||||
|
|
||||||
mod common;
|
mod common;
|
||||||
|
mod prepass;
|
||||||
|
|
||||||
pub fn lower_modules(
|
pub fn lower_modules(modules: &[ast::Module]) -> ProgramBody {
|
||||||
modules: &[ast::Module],
|
|
||||||
) -> (HashMap<DefId, String>, HashMap<DefId, ir::ModuleBody>) {
|
|
||||||
let mut ctx = BuildCtx::default();
|
let mut ctx = BuildCtx::default();
|
||||||
|
|
||||||
for m in modules {
|
// resolve symbols
|
||||||
let module_id = ctx.gen.module_defid();
|
|
||||||
ctx.module_name_to_id
|
|
||||||
.insert(m.name.name.clone(), ctx.gen.module_defid());
|
|
||||||
ctx.symbol_names.insert(module_id, m.name.name.clone());
|
|
||||||
|
|
||||||
ctx.modules.insert(
|
|
||||||
module_id,
|
|
||||||
ModuleCtx {
|
|
||||||
id: module_id,
|
|
||||||
gen: IdGenerator::new(module_id.module_id),
|
|
||||||
..Default::default()
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
ctx.gen.next_module_defid();
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut lowered_modules = HashMap::with_capacity(modules.len());
|
|
||||||
|
|
||||||
// todo: maybe should do a prepass here populating all symbols
|
|
||||||
|
|
||||||
for module in modules {
|
for module in modules {
|
||||||
let ir;
|
ctx = prepass::prepass_module(ctx, module);
|
||||||
(ctx, ir) = lower_module(ctx, module);
|
|
||||||
lowered_modules.insert(ir.module_id, ir);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
(ctx.symbol_names, lowered_modules)
|
// resolve imports
|
||||||
|
for module in modules {
|
||||||
|
ctx = prepass::prepass_imports(ctx, module);
|
||||||
|
}
|
||||||
|
|
||||||
|
for mod_def in modules {
|
||||||
|
let id = *ctx
|
||||||
|
.body
|
||||||
|
.top_level_module_names
|
||||||
|
.get(&mod_def.name.name)
|
||||||
|
.expect("module should exist");
|
||||||
|
|
||||||
|
ctx = lower_module(ctx, mod_def, id);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_module(mut ctx: BuildCtx, module: &ast::Module) -> (BuildCtx, ir::ModuleBody) {
|
fn lower_module(mut ctx: BuildCtx, module: &ast::Module, id: DefId) -> BuildCtx {
|
||||||
let module_id = *ctx.module_name_to_id.get(&module.name.name).unwrap();
|
let body = ctx.body.modules.get(&id).unwrap();
|
||||||
let mut body = ir::ModuleBody {
|
|
||||||
module_id,
|
|
||||||
functions: Default::default(),
|
|
||||||
modules: Default::default(),
|
|
||||||
span: module.span,
|
|
||||||
};
|
|
||||||
|
|
||||||
for stmt in &module.contents {
|
// fill fn sigs
|
||||||
match stmt {
|
for content in &module.contents {
|
||||||
ast::ModuleStatement::Function(func) => {
|
if let ModuleStatement::Function(fn_def) = content {
|
||||||
let next_id = {
|
let fn_id = *body.symbols.functions.get(&fn_def.name.name).unwrap();
|
||||||
let module_ctx = ctx.modules.get_mut(&module_id).unwrap();
|
|
||||||
let next_id = module_ctx.gen.next_defid();
|
let mut args = Vec::new();
|
||||||
module_ctx
|
let ret_type;
|
||||||
.func_name_to_id
|
|
||||||
.insert(func.name.name.clone(), next_id);
|
for arg in &fn_def.params {
|
||||||
ctx.symbol_names.insert(next_id, func.name.name.clone());
|
let ty = lower_type(&ctx, &arg.arg_type);
|
||||||
next_id
|
args.push(ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(ty) = &fn_def.return_type {
|
||||||
|
ret_type = lower_type(&ctx, ty);
|
||||||
|
} else {
|
||||||
|
ret_type = TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: ir::TypeKind::Unit,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut args = Vec::new();
|
|
||||||
let ret_type;
|
|
||||||
|
|
||||||
if let Some(ret) = func.return_type.as_ref() {
|
|
||||||
ret_type = lower_type(&mut ctx, ret);
|
|
||||||
} else {
|
|
||||||
ret_type = TypeInfo {
|
|
||||||
span: None,
|
|
||||||
kind: ir::TypeKind::Unit,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
for arg in &func.params {
|
|
||||||
let ty = lower_type(&mut ctx, &arg.arg_type);
|
|
||||||
args.push(ty);
|
|
||||||
}
|
|
||||||
|
|
||||||
let module_ctx = ctx.modules.get_mut(&module_id).unwrap();
|
|
||||||
module_ctx.functions.insert(next_id, (args, ret_type));
|
|
||||||
}
|
}
|
||||||
ast::ModuleStatement::Constant(_) => todo!(),
|
|
||||||
ast::ModuleStatement::Struct(_) => todo!(),
|
ctx.body.function_signatures.insert(fn_id, (args, ret_type));
|
||||||
ast::ModuleStatement::Module(_) => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for stmt in &module.contents {
|
for content in &module.contents {
|
||||||
match stmt {
|
match content {
|
||||||
ast::ModuleStatement::Function(func) => {
|
ModuleStatement::Constant(_) => todo!(),
|
||||||
let (res, new_ctx) = lower_function(ctx, func, body.module_id);
|
ModuleStatement::Function(fn_def) => {
|
||||||
body.functions.insert(res.def_id, res);
|
ctx = lower_function(ctx, fn_def, id);
|
||||||
ctx = new_ctx;
|
|
||||||
}
|
}
|
||||||
ast::ModuleStatement::Constant(_) => todo!(),
|
ModuleStatement::Struct(_) => todo!(),
|
||||||
ast::ModuleStatement::Struct(_) => todo!(),
|
// ModuleStatement::Type(_) => todo!(),
|
||||||
ast::ModuleStatement::Module(_) => todo!(),
|
ModuleStatement::Module(_mod_def) => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(ctx, body)
|
ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_function(
|
fn lower_function(ctx: BuildCtx, func: &ast::Function, module_id: DefId) -> BuildCtx {
|
||||||
mut ctx: BuildCtx,
|
|
||||||
func: &ast::Function,
|
|
||||||
module_id: DefId,
|
|
||||||
) -> (ir::Body, BuildCtx) {
|
|
||||||
let def_id = *ctx
|
|
||||||
.modules
|
|
||||||
.get(&module_id)
|
|
||||||
.unwrap()
|
|
||||||
.func_name_to_id
|
|
||||||
.get(&func.name.name)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let body = ir::Body {
|
|
||||||
def_id,
|
|
||||||
ret_type: func
|
|
||||||
.return_type
|
|
||||||
.as_ref()
|
|
||||||
.map(|x| lower_type(&mut ctx, x))
|
|
||||||
.unwrap_or_else(|| TypeInfo {
|
|
||||||
span: None,
|
|
||||||
kind: ir::TypeKind::Unit,
|
|
||||||
}),
|
|
||||||
locals: Default::default(),
|
|
||||||
blocks: Default::default(),
|
|
||||||
fn_span: func.span,
|
|
||||||
is_pub: func.is_public,
|
|
||||||
is_extern: func.is_extern,
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut builder = BodyBuilder {
|
let mut builder = BodyBuilder {
|
||||||
body,
|
body: Body {
|
||||||
statements: Vec::new(),
|
blocks: Default::default(),
|
||||||
locals: HashMap::new(),
|
locals: Default::default(),
|
||||||
ret_local: None,
|
name: func.name.name.clone(),
|
||||||
ctx,
|
def_id: {
|
||||||
|
let body = ctx.body.modules.get(&module_id).unwrap();
|
||||||
|
*body.symbols.functions.get(&func.name.name).unwrap()
|
||||||
|
},
|
||||||
|
is_pub: func.is_public,
|
||||||
|
is_extern: func.is_extern,
|
||||||
|
fn_span: func.span,
|
||||||
|
},
|
||||||
local_module: module_id,
|
local_module: module_id,
|
||||||
|
ret_local: 0,
|
||||||
|
name_to_local: HashMap::new(),
|
||||||
|
statements: Vec::new(),
|
||||||
|
ctx,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let fn_id = builder.body.def_id;
|
||||||
|
|
||||||
|
let (args_ty, ret_ty) = builder
|
||||||
|
.ctx
|
||||||
|
.body
|
||||||
|
.function_signatures
|
||||||
|
.get(&fn_id)
|
||||||
|
.unwrap()
|
||||||
|
.clone();
|
||||||
|
|
||||||
// store args ret
|
// store args ret
|
||||||
|
|
||||||
if let Some(ret_type) = func.return_type.as_ref() {
|
builder.ret_local = builder.body.locals.len();
|
||||||
let ty = lower_type(&mut builder.ctx, ret_type);
|
builder.body.locals.push(Local::new(
|
||||||
|
None,
|
||||||
|
LocalKind::ReturnPointer,
|
||||||
|
ret_ty.clone(),
|
||||||
|
None,
|
||||||
|
false,
|
||||||
|
));
|
||||||
|
|
||||||
let local = Local {
|
for (arg, ty) in func.params.iter().zip(args_ty) {
|
||||||
mutable: false,
|
|
||||||
span: None,
|
|
||||||
ty,
|
|
||||||
kind: ir::LocalKind::ReturnPointer,
|
|
||||||
};
|
|
||||||
|
|
||||||
builder.ret_local = Some(builder.body.locals.len());
|
|
||||||
builder.body.locals.push(local);
|
|
||||||
}
|
|
||||||
|
|
||||||
for arg in &func.params {
|
|
||||||
let ty = lower_type(&mut builder.ctx, &arg.arg_type);
|
|
||||||
let local = Local {
|
|
||||||
mutable: false,
|
|
||||||
span: Some(arg.span),
|
|
||||||
ty,
|
|
||||||
kind: ir::LocalKind::Arg,
|
|
||||||
};
|
|
||||||
builder
|
builder
|
||||||
.locals
|
.name_to_local
|
||||||
.insert(arg.name.name.clone(), builder.locals.len());
|
.insert(arg.name.name.clone(), builder.body.locals.len());
|
||||||
builder.body.locals.push(local);
|
builder.body.locals.push(Local::new(
|
||||||
|
Some(arg.name.span),
|
||||||
|
LocalKind::Arg,
|
||||||
|
ty,
|
||||||
|
Some(arg.name.name.clone()),
|
||||||
|
false,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get all user defined locals
|
||||||
for stmt in &func.body.body {
|
for stmt in &func.body.body {
|
||||||
match stmt {
|
if let ast::Statement::Let(info) = stmt {
|
||||||
ast::Statement::Let(info) => lower_let(&mut builder, info),
|
let ty = lower_type(&builder.ctx, &info.r#type);
|
||||||
ast::Statement::Assign(info) => lower_assign(&mut builder, info),
|
builder
|
||||||
ast::Statement::For(_) => todo!(),
|
.name_to_local
|
||||||
ast::Statement::While(_) => todo!(),
|
.insert(info.name.name.clone(), builder.body.locals.len());
|
||||||
ast::Statement::If(_) => todo!(),
|
builder.body.locals.push(Local::new(
|
||||||
ast::Statement::Return(info) => lower_return(&mut builder, info),
|
Some(info.name.span),
|
||||||
ast::Statement::FnCall(info) => {
|
LocalKind::Temp,
|
||||||
lower_fn_call_no_ret(&mut builder, info);
|
ty,
|
||||||
}
|
Some(info.name.name.clone()),
|
||||||
|
info.is_mut,
|
||||||
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(builder.body, builder.ctx)
|
for stmt in &func.body.body {
|
||||||
|
lower_statement(&mut builder, stmt, &ret_ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
let (mut ctx, body) = (builder.ctx, builder.body);
|
||||||
|
ctx.unresolved_function_signatures.remove(&body.def_id);
|
||||||
|
ctx.body.functions.insert(body.def_id, body);
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_statement(builder: &mut BodyBuilder, info: &ast::Statement, ret_type: &TypeInfo) {
|
||||||
|
match info {
|
||||||
|
ast::Statement::Let(info) => lower_let(builder, info),
|
||||||
|
ast::Statement::Assign(info) => lower_assign(builder, info),
|
||||||
|
ast::Statement::For(_) => todo!(),
|
||||||
|
ast::Statement::While(_) => todo!(),
|
||||||
|
ast::Statement::If(_) => todo!(),
|
||||||
|
ast::Statement::Return(info) => lower_return(builder, info, ret_type),
|
||||||
|
ast::Statement::FnCall(info) => {
|
||||||
|
lower_fn_call(builder, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) {
|
fn lower_let(builder: &mut BodyBuilder, info: &ast::LetStmt) {
|
||||||
let ty = lower_type(&mut 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 = lower_expr(builder, &info.value, Some(&ty));
|
||||||
|
let local_idx = builder.name_to_local.get(&info.name.name).copied().unwrap();
|
||||||
let local = ir::Local {
|
builder.statements.push(Statement {
|
||||||
mutable: info.is_mut,
|
span: Some(info.name.span),
|
||||||
span: Some(info.span),
|
kind: StatementKind::StorageLive(local_idx),
|
||||||
ty: lower_type(&mut builder.ctx, &info.r#type),
|
|
||||||
kind: ir::LocalKind::Temp,
|
|
||||||
};
|
|
||||||
|
|
||||||
let id = builder.body.locals.len();
|
|
||||||
builder.locals.insert(info.name.name.clone(), id);
|
|
||||||
builder.body.locals.push(local);
|
|
||||||
|
|
||||||
builder.statements.push(ir::Statement {
|
|
||||||
span: Some(info.span),
|
|
||||||
kind: ir::StatementKind::StorageLive(id),
|
|
||||||
});
|
});
|
||||||
builder.statements.push(ir::Statement {
|
builder.statements.push(Statement {
|
||||||
span: Some(info.span),
|
span: Some(info.name.span),
|
||||||
kind: ir::StatementKind::Assign(
|
kind: StatementKind::Assign(
|
||||||
Place {
|
Place {
|
||||||
local: id,
|
local: local_idx,
|
||||||
projection: Default::default(),
|
projection: Default::default(),
|
||||||
},
|
},
|
||||||
rvalue,
|
rvalue,
|
||||||
|
@ -225,14 +199,14 @@ 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.locals.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 = lower_expr(builder, &info.value, Some(&ty));
|
||||||
let place = lower_path(builder, &info.name);
|
let place = lower_path(builder, &info.name);
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
builder.statements.push(Statement {
|
||||||
span: Some(info.span),
|
span: Some(info.name.first.span),
|
||||||
kind: ir::StatementKind::Assign(place, rvalue),
|
kind: StatementKind::Assign(place, rvalue),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -259,261 +233,140 @@ fn lower_binary_expr(
|
||||||
type_hint: Option<&TypeInfo>,
|
type_hint: Option<&TypeInfo>,
|
||||||
) -> ir::RValue {
|
) -> ir::RValue {
|
||||||
let expr_type = type_hint.expect("type hint needed");
|
let expr_type = type_hint.expect("type hint needed");
|
||||||
let lhs = {
|
let lhs = lower_expr(builder, lhs, type_hint);
|
||||||
let rvalue = lower_expr(builder, lhs, type_hint);
|
let rhs = lower_expr(builder, rhs, type_hint);
|
||||||
let local = builder.add_local(Local {
|
|
||||||
mutable: false,
|
|
||||||
span: None,
|
|
||||||
ty: expr_type.clone(),
|
|
||||||
kind: ir::LocalKind::Temp,
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
let local_ty = expr_type;
|
||||||
span: None,
|
let lhs_local = builder.add_local(Local::temp(local_ty.clone()));
|
||||||
kind: ir::StatementKind::StorageLive(local),
|
let rhs_local = builder.add_local(Local::temp(local_ty.clone()));
|
||||||
});
|
let lhs_place = Place {
|
||||||
|
local: lhs_local,
|
||||||
let place = Place {
|
projection: Default::default(),
|
||||||
local,
|
|
||||||
projection: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::Assign(place.clone(), rvalue),
|
|
||||||
});
|
|
||||||
|
|
||||||
place
|
|
||||||
};
|
};
|
||||||
let rhs = {
|
let rhs_place = Place {
|
||||||
let rvalue = lower_expr(builder, rhs, type_hint);
|
local: lhs_local,
|
||||||
let local = builder.add_local(Local {
|
|
||||||
mutable: false,
|
|
||||||
span: None,
|
|
||||||
ty: expr_type.clone(),
|
|
||||||
kind: ir::LocalKind::Temp,
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::StorageLive(local),
|
|
||||||
});
|
|
||||||
|
|
||||||
let place = Place {
|
|
||||||
local,
|
|
||||||
projection: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::Assign(place.clone(), rvalue),
|
|
||||||
});
|
|
||||||
|
|
||||||
place
|
|
||||||
};
|
|
||||||
|
|
||||||
match op {
|
|
||||||
ast::BinaryOp::Arith(op, _) => match op {
|
|
||||||
ast::ArithOp::Add => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Add, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::ArithOp::Sub => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Sub, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::ArithOp::Mul => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Mul, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::ArithOp::Div => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Div, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::ArithOp::Mod => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Rem, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::BinaryOp::Logic(op, _) => match op {
|
|
||||||
ast::LogicOp::And => {
|
|
||||||
ir::RValue::LogicOp(ir::LogicalOp::And, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::LogicOp::Or => {
|
|
||||||
ir::RValue::LogicOp(ir::LogicalOp::Or, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::BinaryOp::Compare(op, _) => match op {
|
|
||||||
ast::CmpOp::Eq => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Eq, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::CmpOp::NotEq => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Ne, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::CmpOp::Lt => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Lt, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::CmpOp::LtEq => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Le, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::CmpOp::Gt => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Gt, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::CmpOp::GtEq => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::Ge, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
ast::BinaryOp::Bitwise(op, _) => match op {
|
|
||||||
ast::BitwiseOp::And => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::BitAnd, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::BitwiseOp::Or => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::BitOr, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
ast::BitwiseOp::Xor => {
|
|
||||||
ir::RValue::BinOp(ir::BinOp::BitXor, Operand::Move(lhs), Operand::Move(rhs))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_fn_call_no_ret(builder: &mut BodyBuilder, info: &ast::FnCallExpr) {
|
|
||||||
let (arg_types, _ret_type) = builder.get_fn_by_name(&info.name.name).unwrap().clone();
|
|
||||||
|
|
||||||
let mut args = Vec::new();
|
|
||||||
|
|
||||||
for (expr, ty) in info.params.iter().zip(arg_types) {
|
|
||||||
let rvalue = lower_expr(builder, expr, Some(&ty));
|
|
||||||
|
|
||||||
let local = builder.add_local(Local {
|
|
||||||
mutable: false,
|
|
||||||
span: None,
|
|
||||||
ty,
|
|
||||||
kind: ir::LocalKind::Temp,
|
|
||||||
});
|
|
||||||
|
|
||||||
let place = Place {
|
|
||||||
local,
|
|
||||||
projection: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::StorageLive(local),
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::Assign(place.clone(), rvalue),
|
|
||||||
});
|
|
||||||
|
|
||||||
args.push(Operand::Move(place))
|
|
||||||
}
|
|
||||||
|
|
||||||
let fn_id = *builder
|
|
||||||
.get_current_module()
|
|
||||||
.func_name_to_id
|
|
||||||
.get(&info.name.name)
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let next_block = builder.body.blocks.len() + 1;
|
|
||||||
|
|
||||||
let terminator = Terminator::Call {
|
|
||||||
func: Operand::Constant(ConstData {
|
|
||||||
span: Some(info.span),
|
|
||||||
type_info: TypeInfo {
|
|
||||||
span: None,
|
|
||||||
kind: ir::TypeKind::FnDef(fn_id, vec![]),
|
|
||||||
},
|
|
||||||
kind: ConstKind::ZeroSized,
|
|
||||||
}),
|
|
||||||
args,
|
|
||||||
dest: None,
|
|
||||||
target: Some(next_block),
|
|
||||||
};
|
|
||||||
|
|
||||||
let statements = std::mem::take(&mut builder.statements);
|
|
||||||
|
|
||||||
builder.body.blocks.push(ir::BasicBlock {
|
|
||||||
id: builder.body.blocks.len(),
|
|
||||||
statements: statements.into(),
|
|
||||||
terminator,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> ir::Operand {
|
|
||||||
let (arg_types, ret_type) = builder.get_fn_by_name(&info.name.name).unwrap().clone();
|
|
||||||
|
|
||||||
let mut args = Vec::new();
|
|
||||||
|
|
||||||
let target_local = builder.add_local(Local {
|
|
||||||
mutable: false,
|
|
||||||
span: None,
|
|
||||||
ty: ret_type,
|
|
||||||
kind: ir::LocalKind::Temp,
|
|
||||||
});
|
|
||||||
|
|
||||||
let dest_place = Place {
|
|
||||||
local: target_local,
|
|
||||||
projection: Default::default(),
|
projection: Default::default(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for (expr, ty) in info.params.iter().zip(arg_types) {
|
builder.statements.push(Statement {
|
||||||
let rvalue = lower_expr(builder, expr, Some(&ty));
|
span: None,
|
||||||
|
kind: StatementKind::StorageLive(lhs_local),
|
||||||
let local = builder.add_local(Local {
|
});
|
||||||
mutable: false,
|
|
||||||
span: None,
|
|
||||||
ty,
|
|
||||||
kind: ir::LocalKind::Temp,
|
|
||||||
});
|
|
||||||
|
|
||||||
let place = Place {
|
|
||||||
local,
|
|
||||||
projection: Default::default(),
|
|
||||||
};
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::StorageLive(local),
|
|
||||||
});
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
|
||||||
span: None,
|
|
||||||
kind: ir::StatementKind::Assign(place.clone(), rvalue),
|
|
||||||
});
|
|
||||||
|
|
||||||
args.push(Operand::Move(place))
|
|
||||||
}
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
builder.statements.push(Statement {
|
||||||
span: None,
|
span: None,
|
||||||
kind: ir::StatementKind::StorageLive(target_local),
|
kind: StatementKind::Assign(lhs_place.clone(), lhs),
|
||||||
});
|
});
|
||||||
|
|
||||||
let fn_id = *builder
|
builder.statements.push(Statement {
|
||||||
.get_current_module()
|
span: None,
|
||||||
.func_name_to_id
|
kind: StatementKind::StorageLive(rhs_local),
|
||||||
.get(&info.name.name)
|
});
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let next_block = builder.body.blocks.len() + 1;
|
builder.statements.push(Statement {
|
||||||
|
span: None,
|
||||||
|
kind: StatementKind::Assign(rhs_place.clone(), rhs),
|
||||||
|
});
|
||||||
|
|
||||||
let terminator = Terminator::Call {
|
let lhs = Operand::Move(lhs_place);
|
||||||
func: Operand::Constant(ConstData {
|
let rhs = Operand::Move(rhs_place);
|
||||||
span: Some(info.span),
|
|
||||||
type_info: TypeInfo {
|
match op {
|
||||||
span: None,
|
ast::BinaryOp::Arith(op, _) => match op {
|
||||||
kind: ir::TypeKind::FnDef(fn_id, vec![]),
|
ast::ArithOp::Add => ir::RValue::BinOp(ir::BinOp::Add, lhs, rhs),
|
||||||
},
|
ast::ArithOp::Sub => ir::RValue::BinOp(ir::BinOp::Sub, lhs, rhs),
|
||||||
kind: ConstKind::ZeroSized,
|
ast::ArithOp::Mul => ir::RValue::BinOp(ir::BinOp::Mul, 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),
|
||||||
|
ast::LogicOp::Or => ir::RValue::LogicOp(ir::LogicalOp::Or, lhs, rhs),
|
||||||
|
},
|
||||||
|
ast::BinaryOp::Compare(op, _) => match op {
|
||||||
|
ast::CmpOp::Eq => ir::RValue::BinOp(ir::BinOp::Eq, lhs, rhs),
|
||||||
|
ast::CmpOp::NotEq => ir::RValue::BinOp(ir::BinOp::Ne, lhs, rhs),
|
||||||
|
ast::CmpOp::Lt => ir::RValue::BinOp(ir::BinOp::Lt, 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),
|
||||||
|
},
|
||||||
|
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),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lower_fn_call(builder: &mut BodyBuilder, info: &ast::FnCallExpr) -> Operand {
|
||||||
|
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")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let (args_ty, ret_ty) = {
|
||||||
|
if let Some(x) = builder.ctx.body.function_signatures.get(&fn_id).cloned() {
|
||||||
|
x
|
||||||
|
} else {
|
||||||
|
let (args, ret) = builder
|
||||||
|
.ctx
|
||||||
|
.unresolved_function_signatures
|
||||||
|
.get(&fn_id)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let args: Vec<_> = args.iter().map(|x| lower_type(&builder.ctx, x)).collect();
|
||||||
|
let ret = ret
|
||||||
|
.as_ref()
|
||||||
|
.map(|x| lower_type(&builder.ctx, x))
|
||||||
|
.unwrap_or(TypeInfo {
|
||||||
|
span: None,
|
||||||
|
kind: TypeKind::Unit,
|
||||||
|
});
|
||||||
|
builder
|
||||||
|
.ctx
|
||||||
|
.body
|
||||||
|
.function_signatures
|
||||||
|
.insert(fn_id, (args.clone(), ret.clone()));
|
||||||
|
(args, ret)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut args = Vec::new();
|
||||||
|
|
||||||
|
for (arg, arg_ty) in info.params.iter().zip(args_ty) {
|
||||||
|
let rvalue = lower_expr(builder, arg, Some(&arg_ty));
|
||||||
|
args.push(rvalue);
|
||||||
|
}
|
||||||
|
|
||||||
|
let dest_local = builder.add_local(Local::temp(ret_ty));
|
||||||
|
|
||||||
|
let dest_place = Place {
|
||||||
|
local: dest_local,
|
||||||
|
projection: Default::default(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let target_block = builder.body.blocks.len() + 1;
|
||||||
|
|
||||||
|
// todo: check if function is diverging such as exit().
|
||||||
|
let kind = Terminator::Call {
|
||||||
|
func: fn_id,
|
||||||
args,
|
args,
|
||||||
dest: Some(dest_place.clone()),
|
destination: dest_place.clone(),
|
||||||
target: Some(next_block),
|
target: Some(target_block),
|
||||||
};
|
};
|
||||||
|
|
||||||
let statements = std::mem::take(&mut builder.statements);
|
let statements = std::mem::take(&mut builder.statements);
|
||||||
|
builder.body.blocks.push(BasicBlock {
|
||||||
builder.body.blocks.push(ir::BasicBlock {
|
|
||||||
id: builder.body.blocks.len(),
|
|
||||||
statements: statements.into(),
|
statements: statements.into(),
|
||||||
terminator,
|
terminator: kind,
|
||||||
});
|
});
|
||||||
|
|
||||||
Operand::Move(dest_place)
|
Operand::Move(dest_place)
|
||||||
|
@ -542,51 +395,61 @@ fn lower_value(
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32((*value) as u32))),
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::U32((*value) as u32))),
|
||||||
}),
|
}),
|
||||||
ast::ValueExpr::Int { value, span } => {
|
ast::ValueExpr::Int { value, span } => {
|
||||||
let (ty, val) = match type_hint {
|
let (ty, val, type_span) = match type_hint {
|
||||||
Some(type_hint) => match &type_hint.kind {
|
Some(type_hint) => match &type_hint.kind {
|
||||||
ir::TypeKind::Int(type_hint) => match type_hint {
|
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!(),
|
||||||
},
|
},
|
||||||
ir::TypeKind::Uint(type_hint) => match type_hint {
|
ir::TypeKind::Uint(int_type) => match int_type {
|
||||||
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!(),
|
||||||
},
|
},
|
||||||
|
@ -598,14 +461,41 @@ fn lower_value(
|
||||||
ir::Operand::Constant(ir::ConstData {
|
ir::Operand::Constant(ir::ConstData {
|
||||||
span: Some(*span),
|
span: Some(*span),
|
||||||
type_info: ir::TypeInfo {
|
type_info: ir::TypeInfo {
|
||||||
span: None,
|
span: type_span,
|
||||||
kind: ty,
|
kind: ty,
|
||||||
},
|
},
|
||||||
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(val)),
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(val)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
ast::ValueExpr::Float { value, span } => todo!(),
|
ast::ValueExpr::Float { value, span } => match type_hint {
|
||||||
ast::ValueExpr::Str { value, span } => todo!(),
|
Some(type_hint) => match &type_hint.kind {
|
||||||
|
TypeKind::Float(float_ty) => match float_ty {
|
||||||
|
ir::FloatTy::F32 => ir::Operand::Constant(ir::ConstData {
|
||||||
|
span: Some(*span),
|
||||||
|
type_info: ir::TypeInfo {
|
||||||
|
span: type_hint.span,
|
||||||
|
kind: ir::TypeKind::Float(ir::FloatTy::F32),
|
||||||
|
},
|
||||||
|
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_info: ir::TypeInfo {
|
||||||
|
span: type_hint.span,
|
||||||
|
kind: ir::TypeKind::Float(ir::FloatTy::F64),
|
||||||
|
},
|
||||||
|
kind: ir::ConstKind::Value(ir::ValueTree::Leaf(ir::ConstValue::F64(
|
||||||
|
value.parse().unwrap(),
|
||||||
|
))),
|
||||||
|
}),
|
||||||
|
},
|
||||||
|
_ => unreachable!(),
|
||||||
|
},
|
||||||
|
None => 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))
|
Operand::Move(lower_path(builder, info))
|
||||||
|
@ -613,36 +503,31 @@ fn lower_value(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_return(builder: &mut BodyBuilder, info: &ast::ReturnStmt) {
|
fn lower_return(builder: &mut BodyBuilder, info: &ast::ReturnStmt, return_type: &TypeInfo) {
|
||||||
let ret_type = builder.body.ret_type.clone();
|
if let Some(value_expr) = &info.value {
|
||||||
if let Some(value) = &info.value {
|
let value = lower_expr(builder, value_expr, Some(return_type));
|
||||||
let rvalue = lower_expr(builder, value, Some(&ret_type));
|
|
||||||
let ret_local = builder.ret_local.unwrap();
|
|
||||||
|
|
||||||
builder.statements.push(Statement {
|
builder.statements.push(Statement {
|
||||||
span: Some(info.span),
|
span: None,
|
||||||
kind: ir::StatementKind::Assign(
|
kind: StatementKind::Assign(
|
||||||
Place {
|
Place {
|
||||||
local: ret_local,
|
local: builder.ret_local,
|
||||||
projection: Default::default(),
|
projection: Default::default(),
|
||||||
},
|
},
|
||||||
rvalue,
|
value,
|
||||||
),
|
),
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let statements = std::mem::take(&mut builder.statements);
|
let statements = std::mem::take(&mut builder.statements);
|
||||||
|
builder.body.blocks.push(BasicBlock {
|
||||||
builder.body.blocks.push(ir::BasicBlock {
|
|
||||||
id: builder.body.blocks.len(),
|
|
||||||
statements: statements.into(),
|
statements: statements.into(),
|
||||||
terminator: ir::Terminator::Return,
|
terminator: Terminator::Return,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> ir::Place {
|
fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> ir::Place {
|
||||||
let local = *builder
|
let local = *builder
|
||||||
.locals
|
.name_to_local
|
||||||
.get(&info.first.name)
|
.get(&info.first.name)
|
||||||
.expect("local not found");
|
.expect("local not found");
|
||||||
|
|
||||||
|
@ -652,7 +537,7 @@ fn lower_path(builder: &mut BodyBuilder, info: &ast::PathExpr) -> ir::Place {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lower_type(_ctx: &mut BuildCtx, t: &ast::Type) -> ir::TypeInfo {
|
pub fn lower_type(_ctx: &BuildCtx, t: &ast::Type) -> ir::TypeInfo {
|
||||||
match t.name.name.as_str() {
|
match t.name.name.as_str() {
|
||||||
"()" => ir::TypeInfo {
|
"()" => ir::TypeInfo {
|
||||||
span: Some(t.span),
|
span: Some(t.span),
|
||||||
|
|
316
lib/edlang_lowering/src/prepass.rs
Normal file
316
lib/edlang_lowering/src/prepass.rs
Normal file
|
@ -0,0 +1,316 @@
|
||||||
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
use crate::DefId;
|
||||||
|
|
||||||
|
use super::common::BuildCtx;
|
||||||
|
use edlang_ast as ast;
|
||||||
|
use edlang_ir::ModuleBody;
|
||||||
|
|
||||||
|
pub fn prepass_module(mut ctx: BuildCtx, mod_def: &ast::Module) -> BuildCtx {
|
||||||
|
let module_id = ctx.gen.next_defid();
|
||||||
|
tracing::debug!("running ir prepass on module {:?}", module_id);
|
||||||
|
|
||||||
|
ctx.body
|
||||||
|
.top_level_module_names
|
||||||
|
.insert(mod_def.name.name.clone(), module_id);
|
||||||
|
|
||||||
|
ctx.body.modules.insert(
|
||||||
|
module_id,
|
||||||
|
ModuleBody {
|
||||||
|
module_id,
|
||||||
|
parent_ids: vec![],
|
||||||
|
name: mod_def.name.name.clone(),
|
||||||
|
symbols: Default::default(),
|
||||||
|
modules: Default::default(),
|
||||||
|
functions: Default::default(),
|
||||||
|
structs: Default::default(),
|
||||||
|
types: Default::default(),
|
||||||
|
constants: Default::default(),
|
||||||
|
imports: Default::default(),
|
||||||
|
span: mod_def.span,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut gen = ctx.gen;
|
||||||
|
let current_module = ctx
|
||||||
|
.body
|
||||||
|
.modules
|
||||||
|
.get_mut(&module_id)
|
||||||
|
.expect("module should exist");
|
||||||
|
|
||||||
|
for ct in &mod_def.contents {
|
||||||
|
match ct {
|
||||||
|
ast::ModuleStatement::Constant(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
current_module
|
||||||
|
.symbols
|
||||||
|
.constants
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
current_module.constants.insert(next_id);
|
||||||
|
}
|
||||||
|
ast::ModuleStatement::Function(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
current_module
|
||||||
|
.symbols
|
||||||
|
.functions
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
current_module.functions.insert(next_id);
|
||||||
|
ctx.unresolved_function_signatures.insert(
|
||||||
|
next_id,
|
||||||
|
(
|
||||||
|
info.params.iter().map(|x| &x.arg_type).cloned().collect(),
|
||||||
|
info.return_type.clone(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ast::ModuleStatement::Struct(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
current_module
|
||||||
|
.symbols
|
||||||
|
.structs
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
current_module.structs.insert(next_id);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
ast::ModuleStatement::Type(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
current_module
|
||||||
|
.symbols
|
||||||
|
.types
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
current_module.types.insert(next_id);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
ast::ModuleStatement::Module(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
current_module
|
||||||
|
.symbols
|
||||||
|
.modules
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
current_module.modules.insert(next_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.gen = gen;
|
||||||
|
}
|
||||||
|
|
||||||
|
for ct in &mod_def.contents {
|
||||||
|
if let ast::ModuleStatement::Module(info) = ct {
|
||||||
|
let current_module = ctx
|
||||||
|
.body
|
||||||
|
.modules
|
||||||
|
.get_mut(&module_id)
|
||||||
|
.expect("module should exist");
|
||||||
|
|
||||||
|
let next_id = *current_module.symbols.modules.get(&info.name.name).unwrap();
|
||||||
|
ctx = prepass_sub_module(ctx, &[module_id], next_id, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepass_sub_module(
|
||||||
|
mut ctx: BuildCtx,
|
||||||
|
parent_ids: &[DefId],
|
||||||
|
module_id: DefId,
|
||||||
|
mod_def: &ast::Module,
|
||||||
|
) -> BuildCtx {
|
||||||
|
tracing::debug!("running ir prepass on submodule {:?}", module_id);
|
||||||
|
let mut submodule_parents_ids = parent_ids.to_vec();
|
||||||
|
submodule_parents_ids.push(module_id);
|
||||||
|
|
||||||
|
{
|
||||||
|
let mut gen = ctx.gen;
|
||||||
|
let mut submodule = ModuleBody {
|
||||||
|
module_id,
|
||||||
|
name: mod_def.name.name.clone(),
|
||||||
|
parent_ids: parent_ids.to_vec(),
|
||||||
|
imports: Default::default(),
|
||||||
|
symbols: Default::default(),
|
||||||
|
modules: Default::default(),
|
||||||
|
functions: Default::default(),
|
||||||
|
structs: Default::default(),
|
||||||
|
types: Default::default(),
|
||||||
|
constants: Default::default(),
|
||||||
|
span: mod_def.span,
|
||||||
|
};
|
||||||
|
|
||||||
|
for ct in &mod_def.contents {
|
||||||
|
match ct {
|
||||||
|
ast::ModuleStatement::Constant(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
submodule
|
||||||
|
.symbols
|
||||||
|
.constants
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
submodule.constants.insert(next_id);
|
||||||
|
}
|
||||||
|
ast::ModuleStatement::Function(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
submodule
|
||||||
|
.symbols
|
||||||
|
.functions
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
submodule.functions.insert(next_id);
|
||||||
|
ctx.unresolved_function_signatures.insert(
|
||||||
|
next_id,
|
||||||
|
(
|
||||||
|
info.params.iter().map(|x| &x.arg_type).cloned().collect(),
|
||||||
|
info.return_type.clone(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
ast::ModuleStatement::Struct(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
submodule
|
||||||
|
.symbols
|
||||||
|
.structs
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
submodule.structs.insert(next_id);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
ast::ModuleStatement::Type(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
submodule
|
||||||
|
.symbols
|
||||||
|
.types
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
submodule.types.insert(next_id);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
ast::ModuleStatement::Module(info) => {
|
||||||
|
let next_id = gen.next_defid();
|
||||||
|
submodule
|
||||||
|
.symbols
|
||||||
|
.modules
|
||||||
|
.insert(info.name.name.clone(), next_id);
|
||||||
|
submodule.modules.insert(next_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.gen = gen;
|
||||||
|
|
||||||
|
ctx.body.modules.insert(module_id, submodule);
|
||||||
|
}
|
||||||
|
|
||||||
|
for ct in &mod_def.contents {
|
||||||
|
if let ast::ModuleStatement::Module(info) = ct {
|
||||||
|
let next_id = ctx.gen.next_defid();
|
||||||
|
ctx = prepass_sub_module(ctx, &submodule_parents_ids, next_id, info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepass_imports(mut ctx: BuildCtx, mod_def: &ast::Module) -> BuildCtx {
|
||||||
|
let mod_id = *ctx
|
||||||
|
.body
|
||||||
|
.top_level_module_names
|
||||||
|
.get(&mod_def.name.name)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for import in &mod_def.imports {
|
||||||
|
let imported_module_id = ctx
|
||||||
|
.body
|
||||||
|
.top_level_module_names
|
||||||
|
.get(&import.module[0].name)
|
||||||
|
.expect("import module not found");
|
||||||
|
let mut imported_module = ctx.body.modules.get(imported_module_id).unwrap();
|
||||||
|
|
||||||
|
for x in import.module.iter().skip(1) {
|
||||||
|
let imported_module_id = imported_module.symbols.modules.get(&x.name).unwrap();
|
||||||
|
imported_module = ctx.body.modules.get(imported_module_id).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut imports = HashMap::new();
|
||||||
|
|
||||||
|
for sym in &import.symbols {
|
||||||
|
if let Some(id) = imported_module.symbols.functions.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else if let Some(id) = imported_module.symbols.structs.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else if let Some(id) = imported_module.symbols.types.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else if let Some(id) = imported_module.symbols.constants.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else {
|
||||||
|
panic!("import symbol not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body
|
||||||
|
.modules
|
||||||
|
.get_mut(&mod_id)
|
||||||
|
.unwrap()
|
||||||
|
.imports
|
||||||
|
.extend(imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
for c in &mod_def.contents {
|
||||||
|
if let ast::ModuleStatement::Module(info) = c {
|
||||||
|
ctx = prepass_imports_submodule(ctx, info, mod_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn prepass_imports_submodule(
|
||||||
|
mut ctx: BuildCtx,
|
||||||
|
mod_def: &ast::Module,
|
||||||
|
parent_id: DefId,
|
||||||
|
) -> BuildCtx {
|
||||||
|
let mod_id = *ctx
|
||||||
|
.body
|
||||||
|
.modules
|
||||||
|
.get(&parent_id)
|
||||||
|
.unwrap()
|
||||||
|
.symbols
|
||||||
|
.modules
|
||||||
|
.get(&mod_def.name.name)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
for import in &mod_def.imports {
|
||||||
|
let imported_module_id = ctx
|
||||||
|
.body
|
||||||
|
.top_level_module_names
|
||||||
|
.get(&import.module[0].name)
|
||||||
|
.expect("import module not found");
|
||||||
|
let mut imported_module = ctx.body.modules.get(imported_module_id).unwrap();
|
||||||
|
|
||||||
|
for x in import.module.iter().skip(1) {
|
||||||
|
let imported_module_id = imported_module.symbols.modules.get(&x.name).unwrap();
|
||||||
|
imported_module = ctx.body.modules.get(imported_module_id).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut imports = HashMap::new();
|
||||||
|
|
||||||
|
for sym in &import.symbols {
|
||||||
|
if let Some(id) = imported_module.symbols.functions.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else if let Some(id) = imported_module.symbols.structs.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else if let Some(id) = imported_module.symbols.types.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else if let Some(id) = imported_module.symbols.constants.get(&sym.name) {
|
||||||
|
imports.insert(sym.name.clone(), *id);
|
||||||
|
} else {
|
||||||
|
panic!("import symbol not found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.body
|
||||||
|
.modules
|
||||||
|
.get_mut(&mod_id)
|
||||||
|
.unwrap()
|
||||||
|
.imports
|
||||||
|
.extend(imports);
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx
|
||||||
|
}
|
|
@ -45,6 +45,7 @@ extern {
|
||||||
"=" => Token::Assign,
|
"=" => Token::Assign,
|
||||||
";" => Token::Semicolon,
|
";" => Token::Semicolon,
|
||||||
":" => Token::Colon,
|
":" => Token::Colon,
|
||||||
|
"::" => Token::DoubleColon,
|
||||||
"->" => Token::Arrow,
|
"->" => Token::Arrow,
|
||||||
"," => Token::Coma,
|
"," => Token::Coma,
|
||||||
"<" => Token::LessThanSign,
|
"<" => Token::LessThanSign,
|
||||||
|
@ -104,6 +105,16 @@ SemiColon<T>: Vec<T> = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
DoubleColon<T>: Vec<T> = {
|
||||||
|
<mut v:(<T> "::")*> <e:T?> => match e {
|
||||||
|
None => v,
|
||||||
|
Some(e) => {
|
||||||
|
v.push(e);
|
||||||
|
v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
PlusSeparated<T>: Vec<T> = {
|
PlusSeparated<T>: Vec<T> = {
|
||||||
<mut v:(<T> "+")*> <e:T?> => match e {
|
<mut v:(<T> "+")*> <e:T?> => match e {
|
||||||
None => v,
|
None => v,
|
||||||
|
@ -383,8 +394,8 @@ pub(crate) Struct: ast::Struct = {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) Import: ast::Import = {
|
pub(crate) Import: ast::Import = {
|
||||||
<lo:@L> "use" <path:PathExpr> <symbols:("{" <Comma<Ident>> "}")?> ";" <hi:@R> => ast::Import {
|
<lo:@L> "use" <module:DoubleColon<Ident>> <symbols:("{" <Comma<Ident>> "}")?> ";" <hi:@R> => ast::Import {
|
||||||
path,
|
module,
|
||||||
symbols: symbols.unwrap_or(vec![]),
|
symbols: symbols.unwrap_or(vec![]),
|
||||||
span: ast::Span::new(lo, hi),
|
span: ast::Span::new(lo, hi),
|
||||||
}
|
}
|
||||||
|
|
|
@ -86,6 +86,8 @@ pub enum Token {
|
||||||
Semicolon,
|
Semicolon,
|
||||||
#[token(":")]
|
#[token(":")]
|
||||||
Colon,
|
Colon,
|
||||||
|
#[token("::")]
|
||||||
|
DoubleColon,
|
||||||
#[token("->")]
|
#[token("->")]
|
||||||
Arrow,
|
Arrow,
|
||||||
#[token(",")]
|
#[token(",")]
|
||||||
|
|
Loading…
Reference in a new issue