From 24a3aed360adfc72c3845a20b45970db25dddb9b Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 24 Nov 2024 16:17:57 +0100 Subject: [PATCH] implementing struct method for non generic contexts --- lang/src/son.rs | 321 +++++++++++++++---------- lang/tests/son_tests_struct_scopes.txt | 7 + 2 files changed, 201 insertions(+), 127 deletions(-) diff --git a/lang/src/son.rs b/lang/src/son.rs index 359205ea..3b7cef51 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -27,6 +27,7 @@ use { }, hashbrown::hash_map, hbbytecode::DisasmError, + std::intrinsics::vtable_size, }; const VOID: Nid = 0; @@ -2954,125 +2955,10 @@ impl<'a> Codegen<'a> { None } Expr::Field { target, name, pos } => { - let mut vtarget = self.raw_expr(target)?; - self.strip_var(&mut vtarget); - self.implicit_unwrap(pos, &mut vtarget); - let tty = vtarget.ty; - - match self.tys.base_of(tty).unwrap_or(tty).expand() { - ty::Kind::Module(m) => { - match self.find_type(pos, self.ci.file, m, Err(name)).expand() { - ty::Kind::NEVER => Value::NEVER, - ty::Kind::Global(global) => self.gen_global(global), - ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), - v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), - } - } - ty::Kind::Enum(e) => { - let intrnd = self.tys.names.project(name); - self.gen_enum_variant(pos, e, intrnd) - } - ty::Kind::Struct(s) => { - let Struct { ast, file, .. } = self.tys.ins.structs[s]; - if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) { - Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) - } else if let Expr::Struct { - fields: [.., CommentOr::Or(Err(scope))], .. - } = ast.get(&self.files[file.index()]) - && let ty = self.find_type_low( - pos, - self.ci.file, - file, - Some((s.into(), scope)), - Err(name), - ) - && ty != ty::Id::NEVER - { - todo!() - } else { - let field_list = self - .tys - .struct_fields(s) - .iter() - .map(|f| self.tys.names.ident_str(f.name)) - .intersperse("', '") - .collect::(); - self.error( - pos, - fa!( - "the '{}' does not have this field, \ - but it does have '{field_list}'", - self.ty_display(tty) - ), - ); - Value::NEVER - } - } - ty::Kind::TYPE => match ty::Id::from(match self.ci.nodes[vtarget.id].kind { - Kind::CInt { value } => value as u64, - _ => unreachable!(), - }) - .expand() - { - ty::Kind::Struct(s) => { - let Struct { ast, file, .. } = self.tys.ins.structs[s]; - let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } = - ast.get(&self.files[file.index()]) - else { - self.error( - pos, - fa!("'{}' has not declarations", self.ty_display(s.into())), - ); - return Value::NEVER; - }; - - match self - .find_type_low( - pos, - self.ci.file, - file, - Some((s.into(), scope)), - Err(name), - ) - .expand() - { - ty::Kind::NEVER => Value::NEVER, - ty::Kind::Global(global) => self.gen_global(global), - ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), - v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), - } - } - ty::Kind::Module(m) => { - match self.find_type(pos, self.ci.file, m, Err(name)).expand() { - ty::Kind::NEVER => Value::NEVER, - ty::Kind::Global(global) => self.gen_global(global), - ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), - v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), - } - } - ty => { - self.error( - pos, - fa!( - "accesing scope on '{}' is not supported yet", - self.ty_display(ty.compress()) - ), - ); - Value::NEVER - } - }, - _ => { - self.error( - pos, - fa!( - "the '{}' is not a struct, or pointer to one, or enum, \ - fo field access does not make sense", - self.ty_display(tty) - ), - ); - Value::NEVER - } - } + self.gen_field(ctx, target, pos, name)?.ok().or_else(|| { + self.error(pos, "method can not be used like this"); + Value::NEVER + }) } Expr::UnOp { op: TokenKind::Band, val, pos } => { let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) }; @@ -4158,6 +4044,126 @@ impl<'a> Codegen<'a> { } } + fn gen_field( + &mut self, + ctx: Ctx, + target: &Expr, + pos: Pos, + name: &str, + ) -> Option> { + let mut vtarget = self.raw_expr(target)?; + self.strip_var(&mut vtarget); + self.implicit_unwrap(pos, &mut vtarget); + let tty = vtarget.ty; + + match self.tys.base_of(tty).unwrap_or(tty).expand() { + ty::Kind::Module(m) => match self.find_type(pos, self.ci.file, m, Err(name)).expand() { + ty::Kind::NEVER => Value::NEVER, + ty::Kind::Global(global) => self.gen_global(global), + ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), + v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), + }, + ty::Kind::Enum(e) => { + let intrnd = self.tys.names.project(name); + self.gen_enum_variant(pos, e, intrnd) + } + ty::Kind::Struct(s) => { + let Struct { ast, file, .. } = self.tys.ins.structs[s]; + if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) { + Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) + } else if let Expr::Struct { fields: [.., CommentOr::Or(Err(scope))], .. } = + ast.get(&self.files[file.index()]) + && let ty = self.find_type_low( + pos, + self.ci.file, + file, + Some((s.into(), scope)), + Err(name), + ) + && let ty::Kind::Func(_) = ty.expand() + { + return Some(Err((ty, vtarget))); + } else { + let field_list = self + .tys + .struct_fields(s) + .iter() + .map(|f| self.tys.names.ident_str(f.name)) + .intersperse("', '") + .collect::(); + self.error( + pos, + fa!( + "the '{}' does not have this field, \ + but it does have '{field_list}'", + self.ty_display(tty) + ), + ); + Value::NEVER + } + } + ty::Kind::TYPE => match ty::Id::from(match self.ci.nodes[vtarget.id].kind { + Kind::CInt { value } => value as u64, + _ => unreachable!(), + }) + .expand() + { + ty::Kind::Struct(s) => { + let Struct { ast, file, .. } = self.tys.ins.structs[s]; + let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } = + ast.get(&self.files[file.index()]) + else { + self.error( + pos, + fa!("'{}' has not declarations", self.ty_display(s.into())), + ); + return Value::NEVER.map(Ok); + }; + + match self + .find_type_low(pos, self.ci.file, file, Some((s.into(), scope)), Err(name)) + .expand() + { + ty::Kind::NEVER => Value::NEVER, + ty::Kind::Global(global) => self.gen_global(global), + ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), + v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), + } + } + ty::Kind::Module(m) => { + match self.find_type(pos, self.ci.file, m, Err(name)).expand() { + ty::Kind::NEVER => Value::NEVER, + ty::Kind::Global(global) => self.gen_global(global), + ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), + v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), + } + } + ty => { + self.error( + pos, + fa!( + "accesing scope on '{}' is not supported yet", + self.ty_display(ty.compress()) + ), + ); + Value::NEVER + } + }, + _ => { + self.error( + pos, + fa!( + "the '{}' is not a struct, or pointer to one, or enum, \ + fo field access does not make sense", + self.ty_display(tty) + ), + ); + Value::NEVER + } + } + .map(Ok) + } + fn close_if(&mut self, lcntrl: Nid, rcntrl: Nid, mut then_scope: Scope) -> Option { if lcntrl == Nid::MAX && rcntrl == Nid::MAX { then_scope.clear(&mut self.ci.nodes); @@ -4231,12 +4237,25 @@ impl<'a> Codegen<'a> { } fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option { - let mut ty = self.expr(func)?; - self.assert_ty(func.pos(), &mut ty, ty::Id::TYPE, "function"); - let ty = ty::Id::from(match self.ci.nodes[ty.id].kind { - Kind::CInt { value } => value as u64, - _ => unreachable!(), - }); + let (ty, mut caller) = match *func { + Expr::Field { target, pos, name } => { + match self.gen_field(Ctx::default(), target, pos, name)? { + Ok(mut fexpr) => { + self.assert_ty(func.pos(), &mut fexpr, ty::Id::TYPE, "function"); + ( + ty::Id::from(match self.ci.nodes[fexpr.id].kind { + Kind::CInt { value } => value as u64, + _ => unreachable!(), + }), + None, + ) + } + Err((ty, val)) => (ty, Some(val)), + } + } + ref e => (self.ty(e), None), + }; + let ty::Kind::Func(mut fu) = ty.expand() else { self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty))); return Value::NEVER; @@ -4250,14 +4269,15 @@ impl<'a> Codegen<'a> { let ast = &self.files[file.index()]; let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() }; - if args.len() != cargs.len() { + let arg_count = args.len() + caller.is_some() as usize; + if arg_count != cargs.len() { self.error( func.pos(), fa!( "expected {} function argumenr{}, got {}", cargs.len(), if cargs.len() == 1 { "" } else { "s" }, - args.len() + arg_count ), ); } @@ -4273,6 +4293,32 @@ impl<'a> Codegen<'a> { if is_inline || inline { let var_base = self.ci.scope.vars.len(); let aclass_base = self.ci.scope.aclasses.len(); + + if let Some(caller) = &mut caller + && let (Some(Arg::Value(ty)), Some(carg)) = (tys.next(self.tys), cargs.next()) + { + match (caller.ty.is_pointer(), ty.is_pointer()) { + (true, false) => { + caller.ty = self.tys.base_of(caller.ty).unwrap(); + caller.ptr = true; + } + (false, true) => { + caller.ty = self.tys.make_ptr(caller.ty); + caller.ptr = false; + } + _ => {} + } + + self.assert_ty(func.pos(), caller, ty, "caller"); + self.ci.scope.vars.push(Variable::new( + carg.id, + ty, + caller.ptr, + caller.id, + &mut self.ci.nodes, + )) + } + while let (Some(aty), Some(arg)) = (tys.next(self.tys), args.next()) { let carg = cargs.next().unwrap(); let var = match aty { @@ -4356,6 +4402,27 @@ impl<'a> Codegen<'a> { self.make_func_reachable(fu); let mut inps = Vc::from([NEVER]); let mut clobbered_aliases = BitSet::default(); + + if let Some(caller) = &mut caller + && let (Some(Arg::Value(ty)), Some(carg)) = (tys.next(self.tys), cargs.next()) + { + match (caller.ty.is_pointer(), ty.is_pointer()) { + (true, false) => { + caller.ty = self.tys.base_of(caller.ty).unwrap(); + caller.ptr = true; + } + (false, true) => { + caller.ty = self.tys.make_ptr(caller.ty); + caller.ptr = false; + } + _ => {} + } + self.assert_ty(func.pos(), caller, ty, fa!("caller argument {}", carg.name)); + self.add_clobbers(*caller, &mut clobbered_aliases); + self.ci.nodes.lock(caller.id); + inps.push(caller.id); + } + while let (Some(ty), Some(arg)) = (tys.next(self.tys), args.next()) { let carg = cargs.next().unwrap(); let Arg::Value(ty) = ty else { continue }; diff --git a/lang/tests/son_tests_struct_scopes.txt b/lang/tests/son_tests_struct_scopes.txt index e69de29b..47c0a5ed 100644 --- a/lang/tests/son_tests_struct_scopes.txt +++ b/lang/tests/son_tests_struct_scopes.txt @@ -0,0 +1,7 @@ +main: + LI64 r13, 1d + CP r1, r13 + JALA r0, r31, 0a +code size: 32 +ret: 1 +status: Ok(())