codegen for impl methods

This commit is contained in:
Edgar 2024-05-05 15:09:24 +02:00
parent 03a244db41
commit b94c6a4e7d
No known key found for this signature in database
GPG key ID: 70ADAE8F35904387
6 changed files with 125 additions and 12 deletions

View file

@ -1,7 +1,8 @@
[workspace]
resolver = "2"
members = [ "bin/edlangc", "edb", "lib/edlang_ast", "lib/edlang_check", "lib/edlang_codegen_llvm", "lib/edlang_driver", "lib/edlang_ir", "lib/edlang_lowering","lib/edlang_parser", "lib/edlang_session", "lib/edlang_span"]
members = [ "bin/edlangc", "edb", "lib/edlang_ast", "lib/edlang_check", "lib/edlang_codegen_llvm",
"lib/edlang_driver", "lib/edlang_ir", "lib/edlang_lowering","lib/edlang_parser", "lib/edlang_session", "lib/edlang_span"]
[profile.release]
lto = true

View file

@ -39,6 +39,7 @@ pub struct PathExpr {
pub enum PathSegment {
Field(Ident),
Index { value: Expression, span: Span },
Method { value: FnCallExpr, span: Span },
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]

View file

@ -111,6 +111,7 @@ impl Body {
#[derive(Debug, Clone)]
pub struct AdtBody {
pub def_id: DefId,
pub mod_id: DefId,
pub is_pub: bool,
pub name: String,
pub variants: Vec<AdtVariant>,

View file

@ -182,6 +182,7 @@ fn lower_struct(
let body = ctx.body.modules.get(&module_id).unwrap();
*body.symbols.structs.get(&info.name.name).unwrap()
},
mod_id: module_id,
is_pub: true, // todo struct pub
name: info.name.name.clone(),
variants: Vec::new(),
@ -591,6 +592,7 @@ fn find_expr_type(builder: &mut BodyBuilder, info: &ast::Expression) -> Option<T
}
}
ast::PathSegment::Index { .. } => todo!(),
ast::PathSegment::Method { .. } => todo!(),
}
}
@ -1000,6 +1002,8 @@ fn lower_fn_call(
let mut args = Vec::new();
assert_eq!(args_ty.len(), info.params.len(), "param length mismatch");
for (arg, arg_ty) in info.params.iter().zip(args_ty) {
let (rvalue, _rvalue_ty, _span) = lower_expr(builder, arg, Some(&arg_ty))?;
args.push(rvalue);
@ -1256,36 +1260,138 @@ fn lower_path(
)?;
let mut ty = builder.body.locals[local].ty.kind.clone();
let mut projection = Vec::new();
let mut place = Place {
local,
projection: Default::default(),
};
for extra in &info.extra {
match extra {
ast::PathSegment::Field(name) => {
// is while fine? auto deref
while let TypeKind::Ref(_, inner) = ty {
projection.push(PlaceElem::Deref);
place.projection.push(PlaceElem::Deref);
ty = inner.kind;
}
if let TypeKind::Struct(id, _name) = ty {
let struct_body = builder.ctx.body.structs.get(&id).unwrap();
let idx = *struct_body.name_to_idx.get(&name.name).unwrap();
projection.push(PlaceElem::Field { field_idx: idx });
place.projection.push(PlaceElem::Field { field_idx: idx });
ty = struct_body.variants[idx].ty.kind.clone();
} else {
unimplemented!()
}
}
ast::PathSegment::Index { .. } => todo!(),
ast::PathSegment::Method { value, span } => {
// is while fine? auto deref
while let TypeKind::Ref(_, inner) = ty {
place.projection.push(PlaceElem::Deref);
ty = inner.kind;
}
if let TypeKind::Struct(id, _name) = &ty {
let struct_body = builder.ctx.body.structs.get(id).unwrap();
let fn_id = *builder
.ctx
.body
.modules
.get(&struct_body.mod_id)
.unwrap()
.symbols
.methods
.get(id)
.unwrap()
.get(&value.name.name)
.expect("couldn't find method");
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, builder.local_module))
.collect::<Result<Vec<_>, LoweringError>>()?;
let ret = ret
.as_ref()
.map(|x| lower_type(&builder.ctx, x, builder.local_module))
.unwrap_or(Ok(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();
assert_eq!(
args_ty.len() - 1,
value.params.len(),
"param length mismatch"
);
for (arg, arg_ty) in value.params.iter().zip(&args_ty[1..]) {
let (rvalue, _rvalue_ty, _span) = lower_expr(builder, arg, Some(arg_ty))?;
args.push(rvalue);
}
// insert self
match &args_ty[0].kind {
TypeKind::Ptr(is_mut, _) | TypeKind::Ref(is_mut, _) => {
args.insert(0, RValue::Ref(*is_mut, Operand::Move(place), *span));
}
_ => {
args.insert(0, RValue::Use(Operand::Move(place), *span));
}
}
let dest_local = builder.add_local(Local::temp(ret_ty.kind.clone()));
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,
destination: place.clone(),
target: Some(target_block),
};
let statements = std::mem::take(&mut builder.statements);
builder.body.blocks.push(BasicBlock {
statements: statements.into(),
terminator: kind,
terminator_span: Some(*span),
});
ty = ret_ty.kind;
} else {
unimplemented!()
}
}
}
}
Ok((
Place {
local,
projection: projection.into(), // todo, array
},
ty,
info.span,
))
Ok((place, ty, info.span))
}
#[allow(clippy::only_used_in_recursion)]

View file

@ -199,6 +199,10 @@ pub PathSegments: Vec<ast::PathSegment> = {
pub(crate) PathSegment: ast::PathSegment = {
"." <Ident> => ast::PathSegment::Field(<>),
<lo:@L> "." <value:FnCallExpr> <hi:@R> => ast::PathSegment::Method {
value,
span: ast::Span::new(lo, hi),
},
<lo:@L> "[" <value:Expression> "]" <hi:@R> => ast::PathSegment::Index {
value,
span: ast::Span::new(lo, hi),

BIN
program Executable file

Binary file not shown.