This commit is contained in:
Edgar 2024-02-08 11:58:10 +01:00
parent 572f1aee09
commit 997f9b4dab
No known key found for this signature in database
GPG key ID: 70ADAE8F35904387
12 changed files with 950 additions and 663 deletions

1
Cargo.lock generated
View file

@ -370,6 +370,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"edlang_ast", "edlang_ast",
"edlang_ir", "edlang_ir",
"tracing",
] ]
[[package]] [[package]]

View file

@ -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,

View file

@ -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()
} }

View file

@ -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.

View file

@ -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"))?;

View file

@ -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,
} }

View file

@ -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

View file

@ -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)
} }
} }

View file

@ -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),

View 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
}

View file

@ -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),
} }

View file

@ -86,6 +86,8 @@ pub enum Token {
Semicolon, Semicolon,
#[token(":")] #[token(":")]
Colon, Colon,
#[token("::")]
DoubleColon,
#[token("->")] #[token("->")]
Arrow, Arrow,
#[token(",")] #[token(",")]