diff --git a/Cargo.toml b/Cargo.toml index 5d68cdcff..afa60c4fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -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 diff --git a/lib/edlang_ast/src/lib.rs b/lib/edlang_ast/src/lib.rs index 56dd3c4b3..b5fabd001 100644 --- a/lib/edlang_ast/src/lib.rs +++ b/lib/edlang_ast/src/lib.rs @@ -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)] diff --git a/lib/edlang_ir/src/lib.rs b/lib/edlang_ir/src/lib.rs index b9e45392c..45e762ef0 100644 --- a/lib/edlang_ir/src/lib.rs +++ b/lib/edlang_ir/src/lib.rs @@ -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, diff --git a/lib/edlang_lowering/src/lib.rs b/lib/edlang_lowering/src/lib.rs index 1dd903aff..c29daf99e 100644 --- a/lib/edlang_lowering/src/lib.rs +++ b/lib/edlang_lowering/src/lib.rs @@ -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 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::, 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)] diff --git a/lib/edlang_parser/src/grammar.lalrpop b/lib/edlang_parser/src/grammar.lalrpop index 29ee8e344..976069c5f 100644 --- a/lib/edlang_parser/src/grammar.lalrpop +++ b/lib/edlang_parser/src/grammar.lalrpop @@ -199,6 +199,10 @@ pub PathSegments: Vec = { pub(crate) PathSegment: ast::PathSegment = { "." => ast::PathSegment::Field(<>), + "." => ast::PathSegment::Method { + value, + span: ast::Span::new(lo, hi), + }, "[" "]" => ast::PathSegment::Index { value, span: ast::Span::new(lo, hi), diff --git a/program b/program new file mode 100755 index 000000000..bac4636d7 Binary files /dev/null and b/program differ