diff --git a/lang/README.md b/lang/README.md index 1c41806..dd31484 100644 --- a/lang/README.md +++ b/lang/README.md @@ -212,6 +212,35 @@ odher_pass := fn(t: Ty2): Ty2 { } ``` +#### struct_scopes +```hb +$zr := 0 + +Struct := struct { + a: uint, + b: uint, + + $zero := Self.(zr, zr) + + $new := fn(a: uint, b: uint): Self return .(a, b) + + $swap := fn(s: ^Self): void { + t := s.a + s.a = s.b + s.b = t + } + + $diff := fn(s: Self): uint return s.a - s.b +} + +main := fn(): uint { + z := Struct.zero + z += Struct.new(1, 2) + z.swap() + return z.diff() +} +``` + #### enums ```hb Enum := enum {A, B, C} diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index 54574e7..3d8a43d 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -3,7 +3,10 @@ use { lexer::{self, Lexer, TokenKind}, parser::{self, CommentOr, CtorField, EnumField, Expr, Poser, Radix, StructField}, }, - core::fmt::{self}, + core::{ + fmt::{self}, + mem, + }, }; pub fn display_radix(radix: Radix, mut value: u64, buf: &mut [u8; 64]) -> &str { @@ -64,8 +67,8 @@ fn token_group(kind: TokenKind) -> TokenGroup { Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss | ShrAss | ShlAss => TG::Assign, DQuote | Quote => TG::String, - Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed | True - | False | Null | Match | Enum => TG::Keyword, + Slf | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed + | True | False | Null | Match | Enum => TG::Keyword, } } @@ -198,12 +201,18 @@ impl<'a> Formatter<'a> { return f.write_str(end); } - writeln!(f)?; - self.depth += 1; + if !end.is_empty() { + writeln!(f)?; + } + + self.depth += !end.is_empty() as usize; + let mut already_indented = end.is_empty(); let res = (|| { for (i, stmt) in list.iter().enumerate() { - for _ in 0..self.depth { - f.write_str("\t")?; + if !mem::take(&mut already_indented) { + for _ in 0..self.depth { + f.write_str("\t")?; + } } let add_sep = fmt(self, stmt, f)?; if add_sep { @@ -225,12 +234,14 @@ impl<'a> Formatter<'a> { } Ok(()) })(); - self.depth -= 1; + self.depth -= !end.is_empty() as usize; - for _ in 0..self.depth { - f.write_str("\t")?; + if !end.is_empty() { + for _ in 0..self.depth { + f.write_str("\t")?; + } + f.write_str(end)?; } - f.write_str(end)?; res } @@ -269,6 +280,7 @@ impl<'a> Formatter<'a> { f.write_str("$: ")?; self.fmt(value, f) } + Expr::Slf { .. } => f.write_str("Self"), Expr::String { literal, .. } => f.write_str(literal), Expr::Comment { literal, .. } => f.write_str(literal), Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"), @@ -292,11 +304,15 @@ impl<'a> Formatter<'a> { f.write_str("struct {")?; self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| { match field { - CommentOr::Or(StructField { name, ty, .. }) => { + CommentOr::Or(Ok(StructField { name, ty, .. })) => { f.write_str(name)?; f.write_str(": ")?; s.fmt(ty, f)? } + CommentOr::Or(Err(scope)) => { + s.fmt_list(f, true, "", "", scope, Self::fmt)?; + return Ok(false); + } CommentOr::Comment { literal, .. } => { f.write_str(literal)?; f.write_str("\n")?; @@ -570,6 +586,7 @@ pub mod test { let mut ctx = Ctx::default(); let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader); + log::info!("{}", ctx.errors.borrow()); let mut output = String::new(); write!(output, "{ast}").unwrap(); diff --git a/lang/src/lexer.rs b/lang/src/lexer.rs index ee4e04d..b11e56e 100644 --- a/lang/src/lexer.rs +++ b/lang/src/lexer.rs @@ -136,6 +136,7 @@ pub enum TokenKind { Under = b'_', Tick = b'`', + Slf, Return, If, Match, @@ -302,6 +303,7 @@ gen_token_kind! { Eof, Directive, #[keywords] + Slf = b"Self", Return = b"return", If = b"if", Match = b"match", @@ -401,6 +403,10 @@ impl<'a> Lexer<'a> { unsafe { core::str::from_utf8_unchecked(&self.source[tok]) } } + pub fn taste(&self) -> Token { + Lexer { pos: self.pos, source: self.source }.eat() + } + fn peek(&self) -> Option { if core::intrinsics::unlikely(self.pos >= self.source.len() as u32) { None diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 0de1fd8..e8a9446 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -503,8 +503,8 @@ pub mod ty { Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg, Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg, Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack, - Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_) => { - unreachable!() + c @ (Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_)) => { + unreachable!("{c:?}") } } } @@ -823,6 +823,7 @@ pub struct Sig { #[derive(Default, Clone, Copy)] struct Func { file: Module, + parent: ty::Id, name: Ident, base: Option, expr: ExprRef, @@ -859,6 +860,7 @@ pub struct Const { ast: ExprRef, name: Ident, file: Module, + parent: ty::Id, } // TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27) @@ -915,6 +917,7 @@ struct Struct { captures: ty::Tuple, explicit_alignment: Option, field_start: u32, + ast: ExprRef, } #[derive(PartialEq, Eq, Hash, Clone, Copy)] diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 4b4878d..9ca1922 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -300,8 +300,10 @@ impl<'a, 'b> Parser<'a, 'b> { let token @ Token { start: pos, .. } = self.next(); let prev_boundary = self.ns_bound; let prev_captured = self.ctx.captured.len(); + let mut must_trail = false; let mut expr = match token.kind { T::Ct => E::Ct { pos, value: self.ptr_expr()? }, + T::Slf => E::Slf { pos }, T::Directive if self.lexer.slice(token.range()) == "use" => { self.expect_advance(TokenKind::LParen)?; let str = self.expect_advance(TokenKind::DQuote)?; @@ -374,14 +376,19 @@ impl<'a, 'b> Parser<'a, 'b> { let tok = s.token; Some(if s.advance_if(T::Comment) { CommentOr::Comment { literal: s.tok_str(tok), pos: tok.start } - } else { + } else if s.lexer.taste().kind == T::Colon { let name = s.expect_advance(T::Ident)?; s.expect_advance(T::Colon)?; - CommentOr::Or(StructField { + CommentOr::Or(Ok(StructField { pos: name.start, name: s.tok_str(name), ty: s.expr()?, - }) + })) + } else { + must_trail = true; + CommentOr::Or(Err( + s.collect_list_low(T::Semi, T::RBrace, true, |s| s.expr_low(true)) + )) }) }) }, @@ -400,7 +407,7 @@ impl<'a, 'b> Parser<'a, 'b> { } pos }, - trailing_comma: core::mem::take(&mut self.trailing_sep), + trailing_comma: core::mem::take(&mut self.trailing_sep) || must_trail, }, T::Enum => E::Enum { pos, @@ -578,7 +585,7 @@ impl<'a, 'b> Parser<'a, 'b> { } } - if matches!(token.kind, T::Loop | T::LBrace | T::Fn) { + if matches!(token.kind, T::Loop | T::LBrace | T::Fn | T::Struct) { self.pop_scope(frame); } @@ -651,11 +658,21 @@ impl<'a, 'b> Parser<'a, 'b> { &mut self, delim: TokenKind, end: TokenKind, + f: impl FnMut(&mut Self) -> Option, + ) -> &'a [T] { + self.collect_list_low(delim, end, false, f) + } + + fn collect_list_low( + &mut self, + delim: TokenKind, + end: TokenKind, + keep_end: bool, mut f: impl FnMut(&mut Self) -> Option, ) -> &'a [T] { let mut trailing_sep = false; let mut view = self.ctx.stack.view(); - 'o: while !self.advance_if(end) { + 'o: while (keep_end && self.token.kind != end) || (!keep_end && !self.advance_if(end)) { let val = match f(self) { Some(val) => val, None => { @@ -833,6 +850,10 @@ generate_expr! { pos: Pos, value: &'a Self, }, + /// `'Self'` + Slf { + pos: Pos, + }, /// `'"([^"]|\\")"'` String { pos: Pos, @@ -931,7 +952,7 @@ generate_expr! { /// `'struct' LIST('{', ',', '}', Ident ':' Expr)` Struct { pos: Pos, - fields: &'a [CommentOr<'a, StructField<'a>>], + fields: &'a [CommentOr<'a, Result, &'a[Self]>>], captured: &'a [Ident], trailing_comma: bool, packed: bool, @@ -1112,6 +1133,18 @@ pub trait Poser { fn posi(&self) -> Pos; } +impl Poser for Result { + fn posi(&self) -> Pos { + self.as_ref().map_or_else(Poser::posi, Poser::posi) + } +} + +impl Poser for &[T] { + fn posi(&self) -> Pos { + self[0].posi() + } +} + impl Poser for Pos { fn posi(&self) -> Pos { *self @@ -1312,12 +1345,7 @@ impl Ast { } pub fn find_decl(&self, id: Result) -> Option<(&Expr, Ident)> { - self.exprs().iter().find_map(|expr| match expr { - Expr::BinOp { left, op: TokenKind::Decl, .. } => { - left.declares(id, &self.file).map(|id| (expr, id)) - } - _ => None, - }) + find_decl(self.exprs(), &self.file, id) } pub fn ident_str(&self, ident: Ident) -> &str { @@ -1325,6 +1353,19 @@ impl Ast { } } +pub fn find_decl<'a>( + exprs: &'a [Expr<'a>], + file: &str, + id: Result, +) -> Option<(&'a Expr<'a>, Ident)> { + exprs.iter().find_map(|expr| match expr { + Expr::BinOp { left, op: TokenKind::Decl, .. } => { + left.declares(id, file).map(|id| (expr, id)) + } + _ => None, + }) +} + impl Default for Ast { fn default() -> Self { Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader)) diff --git a/lang/src/son.rs b/lang/src/son.rs index 1ecb0f9..359205e 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -2342,6 +2342,7 @@ impl Scope { #[derive(Default, Clone)] pub struct ItemCtx { file: Module, + parent: ty::Id, pos: Vec, ret: Option, task_base: usize, @@ -2356,7 +2357,7 @@ pub struct ItemCtx { } impl ItemCtx { - fn init(&mut self, file: Module, ret: Option, task_base: usize) { + fn init(&mut self, file: Module, parent: ty::Id, ret: Option, task_base: usize) { debug_assert_eq!(self.loops.len(), 0); debug_assert_eq!(self.scope.vars.len(), 0); debug_assert_eq!(self.scope.aclasses.len(), 0); @@ -2366,6 +2367,7 @@ impl ItemCtx { debug_assert_eq!(self.inline_aclass_base, 0); self.file = file; + self.parent = parent; self.ret = ret; self.task_base = task_base; @@ -2433,6 +2435,7 @@ impl Pool { fn push_ci( &mut self, file: Module, + parent: ty::Id, ret: Option, task_base: usize, target: &mut ItemCtx, @@ -2443,7 +2446,7 @@ impl Pool { self.cis.push(ItemCtx::default()); mem::swap(self.cis.last_mut().unwrap(), target); } - target.init(file, ret, task_base); + target.init(file, parent, ret, task_base); self.used_cis += 1; } @@ -2718,10 +2721,11 @@ impl<'a> Codegen<'a> { self.ci.nodes[region].kind != Kind::Load || self.ci.nodes[region].kind == Kind::Stck || self.ci.nodes[region].ty.is_pointer(), - "{:?} {} {}", + "{:?} {} {} {:?}", self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID)), self.file().path, - self.ty_display(self.ci.nodes[region].ty) + self.ty_display(self.ci.nodes[region].ty), + self.ci.nodes[region], ); debug_assert!(self.ci.nodes[region].kind != Kind::Stre); let (index, _) = self.ci.nodes.aclass_index(region); @@ -2820,7 +2824,7 @@ impl<'a> Codegen<'a> { ty::Kind::NEVER => Value::NEVER, ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), - _ => Some(Value::new(Nid::MAX).ty(decl)), + _ => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, decl)), } } Expr::Comment { .. } => Some(Value::VOID), @@ -2863,9 +2867,9 @@ impl<'a> Codegen<'a> { let expected = *self.ci.ret.get_or_insert(value.ty); self.assert_ty(pos, &mut value, expected, "return value"); - self.strip_ptr(&mut value); if self.ci.inline_depth == 0 { + self.strip_ptr(&mut value); debug_assert_ne!(self.ci.ctrl.get(), VOID); let mut inps = Vc::from([self.ci.ctrl.get(), value.id]); for (i, aclass) in self.ci.scope.aclasses.iter_mut().enumerate() { @@ -2930,10 +2934,7 @@ impl<'a> Codegen<'a> { .for_each(|v| v.remove(&mut self.ci.nodes)); let repl = StrongRef::new(NEVER, &mut self.ci.nodes); - let (index, _) = self - .ci - .nodes - .aclass_index(*self.ci.nodes[value.id].inputs.get(1).unwrap_or(&VOID)); + let (index, _) = self.ci.nodes.aclass_index(value.id); let aclass = (self.ci.inline_aclass_base <= index) .then(|| self.ci.scope.aclasses[index].dup(&mut self.ci.nodes)); self.ci.inline_ret = @@ -2964,7 +2965,7 @@ impl<'a> Codegen<'a> { ty::Kind::NEVER => Value::NEVER, ty::Kind::Global(global) => self.gen_global(global), ty::Kind::Const(cnst) => self.gen_const(cnst, ctx), - v => Some(Value::new(Nid::MAX).ty(v.compress())), + v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())), } } ty::Kind::Enum(e) => { @@ -2972,7 +2973,23 @@ impl<'a> Codegen<'a> { self.gen_enum_variant(pos, e, intrnd) } ty::Kind::Struct(s) => { - let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) else { + 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) @@ -2984,15 +3001,66 @@ impl<'a> Codegen<'a> { pos, fa!( "the '{}' does not have this field, \ - but it does have '{field_list}'", + but it does have '{field_list}'", self.ty_display(tty) ), ); - return Value::NEVER; - }; - - Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty)) + 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, @@ -3203,11 +3271,13 @@ impl<'a> Codegen<'a> { Some(bop) } ty::Kind::Struct(s) if op.is_homogenous() => { + debug_assert!(lhs.ptr); self.ci.nodes.lock(lhs.id); let rhs = self.raw_expr_ctx(right, Ctx::default().with_ty(lhs.ty)); self.ci.nodes.unlock(lhs.id); let mut rhs = rhs?; self.strip_var(&mut rhs); + debug_assert!(rhs.ptr); self.assert_ty(pos, &mut rhs, lhs.ty, "struct operand"); let dst = self.new_stack(pos, lhs.ty); self.struct_op(left.pos(), op, s, dst, lhs.id, rhs.id); @@ -4082,8 +4152,8 @@ impl<'a> Codegen<'a> { Some(Value::VOID) } ref e => { - self.error_unhandled_ast(e, "bruh"); - Value::NEVER + let ty = self.ty(e); + Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, ty)) } } } @@ -4161,7 +4231,12 @@ impl<'a> Codegen<'a> { } fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option { - let ty = self.ty(func); + 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::Kind::Func(mut fu) = ty.expand() else { self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty))); return Value::NEVER; @@ -4333,7 +4408,8 @@ impl<'a> Codegen<'a> { fn gen_const(&mut self, cnst: ty::Const, ctx: Ctx) -> Option { let c = &self.tys.ins.consts[cnst]; - let prev = mem::replace(&mut self.ci.file, c.file); + let prev_file = mem::replace(&mut self.ci.file, c.file); + let prev_parent = mem::replace(&mut self.ci.parent, c.parent); let f = &self.files[c.file.index()]; let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() }; @@ -4344,7 +4420,8 @@ impl<'a> Codegen<'a> { }) .unwrap_or_else(|_| unreachable!())?; self.strip_var(&mut value); - self.ci.file = prev; + self.ci.file = prev_file; + self.ci.parent = prev_parent; Some(value) } @@ -4475,7 +4552,7 @@ impl<'a> Codegen<'a> { } fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option { - let Func { file, expr, sig, .. } = self.tys.ins.funcs[*func]; + let Func { file, expr, sig, parent, .. } = self.tys.ins.funcs[*func]; let fast = &self.files[file.index()]; let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else { unreachable!(); @@ -4488,7 +4565,7 @@ impl<'a> Codegen<'a> { let base = self.ci.scope.vars.len(); for (arg, carg) in args.iter().zip(cargs) { - let ty = self.ty_in(file, &carg.ty); + let ty = self.ty_in(file, parent, &carg.ty); self.tys.tmp.args.push(ty); let sym = parser::find_symbol(&fast.symbols, carg.id); @@ -4526,7 +4603,7 @@ impl<'a> Codegen<'a> { self.error(pos, "function instance has too many arguments"); return None; }; - let ret = self.ty_in(file, ret); + let ret = self.ty_in(file, parent, ret); self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes)); @@ -4695,7 +4772,7 @@ impl<'a> Codegen<'a> { let ast = &self.files[file.index()]; let expr = func.expr.get(ast); - self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci); + self.pool.push_ci(file, func.parent, Some(sig.ret), 0, &mut self.ci); let prev_err_len = self.errors.borrow().len(); log::info!("{}", self.ast_display(expr)); @@ -4852,11 +4929,11 @@ impl<'a> Codegen<'a> { } fn ty(&mut self, expr: &Expr) -> ty::Id { - self.ty_in(self.ci.file, expr) + self.ty_in(self.ci.file, self.ci.parent, expr) } - fn ty_in(&mut self, file: Module, expr: &Expr) -> ty::Id { - self.parse_ty(file, expr, None) + fn ty_in(&mut self, file: Module, parent: ty::Id, expr: &Expr) -> ty::Id { + self.parse_ty(TyScope { file, parent, name: None }, expr) } fn ty_display(&self, ty: ty::Id) -> ty::Display { @@ -5117,7 +5194,7 @@ impl<'a> Codegen<'a> { _ => unreachable!(), }) .collect::>(); - self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci); + self.pool.push_ci(file, self.ci.parent, Some(ret), self.tys.tasks.len(), &mut self.ci); self.ci.scope.vars = scope .into_iter() .map(|(v, id)| { @@ -5170,7 +5247,7 @@ impl<'a> Codegen<'a> { let gid = self.tys.ins.globals.push(Global { file, name, ..Default::default() }); - self.pool.push_ci(file, None, self.tys.tasks.len(), &mut self.ci); + self.pool.push_ci(file, self.ci.parent, None, self.tys.tasks.len(), &mut self.ci); let prev_err_len = self.errors.borrow().len(); self.expr(&(Expr::Return { pos: expr.pos(), val: Some(expr) })); @@ -5216,6 +5293,17 @@ impl<'a> Codegen<'a> { from_file: Module, file: Module, id: Result, + ) -> ty::Id { + self.find_type_low(pos, from_file, file, None, id) + } + + fn find_type_low( + &mut self, + pos: Pos, + from_file: Module, + file: Module, + subscope: Option<(ty::Id, &[Expr])>, + id: Result, ) -> ty::Id { let ty = if let Ok(id) = id && let Some(ty) = self.find_local_ty(id) @@ -5229,7 +5317,9 @@ impl<'a> Codegen<'a> { } else { let f = &self.files[file.index()]; - let Some((expr @ Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else { + let Some((expr @ Expr::BinOp { left, right, .. }, name)) = + parser::find_decl(subscope.map(|(_, s)| s).unwrap_or(f.exprs()), &f.file, id) + else { return match id { Ok(_) => { debug_assert_eq!(from_file, file); @@ -5264,10 +5354,22 @@ impl<'a> Codegen<'a> { self.tys .ins .consts - .push(Const { ast: ExprRef::new(expr), name, file }) + .push(Const { + ast: ExprRef::new(expr), + name, + file, + parent: subscope.map(|(p, _)| p).unwrap_or(file.into()), + }) .into() } else { - self.parse_ty(file, right, Some(name)) + self.parse_ty( + TyScope { + file, + parent: subscope.map(|(p, _)| p).unwrap_or(file.into()), + name: Some(name), + }, + right, + ) }, ) }) @@ -5309,37 +5411,38 @@ impl<'a> Codegen<'a> { } /// returns none if comptime eval is required - fn parse_ty(&mut self, file: Module, expr: &Expr, name: Option) -> ty::Id { + fn parse_ty(&mut self, sc: TyScope, expr: &Expr) -> ty::Id { match *expr { + Expr::Slf { .. } => sc.parent, Expr::Mod { id, .. } => id.into(), Expr::UnOp { op: TokenKind::Xor, val, .. } => { - let base = self.parse_ty(file, val, None); + let base = self.parse_ty(sc.anon(), val); self.tys.make_ptr(base) } Expr::UnOp { op: TokenKind::Que, val, .. } => { - let base = self.parse_ty(file, val, None); + let base = self.parse_ty(sc.anon(), val); self.tys.make_opt(base) } Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(), - Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id)), + Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.file, Ok(id)), Expr::Field { target, pos, name } - if let ty::Kind::Module(inside) = self.parse_ty(file, target, None).expand() => + if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() => { - self.find_type(pos, file, inside, Err(name)) + self.find_type(pos, sc.file, inside, Err(name)) } Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr), Expr::Slice { size: None, item, .. } => { - let ty = self.parse_ty(file, item, None); + let ty = self.parse_ty(sc.anon(), item); self.tys.make_array(ty, ArrayLen::MAX) } Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => { - let ty = self.parse_ty(file, item, None); + let ty = self.parse_ty(sc.anon(), item); self.tys.make_array(ty, value as _) } Expr::Slice { size, item, .. } => { - let ty = self.parse_ty(file, item, None); + let ty = self.parse_ty(sc.anon(), item); let len = size - .map_or(ArrayLen::MAX, |expr| self.eval_const(file, expr, ty::Id::U32) as _); + .map_or(ArrayLen::MAX, |expr| self.eval_const(sc.file, expr, ty::Id::U32) as _); self.tys.make_array(ty, len) } Expr::Struct { pos, fields, packed, captured, .. } => { @@ -5350,14 +5453,14 @@ impl<'a> Codegen<'a> { } let captured = self.tys.pack_args(captures_start).expect("TODO"); - let sym = SymKey::Struct(file, pos, captured); + let sym = SymKey::Struct(sc.file, pos, captured); if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) { return ty; } let prev_tmp = self.tys.tmp.struct_fields.len(); - for field in fields.iter().filter_map(CommentOr::or) { - let ty = self.parse_ty(file, &field.ty, None); + for field in fields.iter().filter_map(CommentOr::or).filter_map(Result::ok) { + let ty = self.parse_ty(sc.anon(), &field.ty); let field = StructField { name: self.tys.names.intern(field.name), ty }; self.tys.tmp.struct_fields.push(field); } @@ -5367,11 +5470,12 @@ impl<'a> Codegen<'a> { .ins .structs .push(Struct { - file, + file: sc.file, pos, - name: name.unwrap_or_default(), + name: sc.name.unwrap_or_default(), field_start: self.tys.ins.struct_fields.len() as _, explicit_alignment: packed.then_some(1), + ast: ExprRef::new(expr), ..Default::default() }) .into(); @@ -5382,7 +5486,7 @@ impl<'a> Codegen<'a> { ty } Expr::Enum { pos, variants, .. } => { - let sym = SymKey::Enum(file, pos); + let sym = SymKey::Enum(sc.file, pos); if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) { return ty; } @@ -5398,9 +5502,9 @@ impl<'a> Codegen<'a> { .ins .enums .push(Enum { - file, + file: sc.file, pos, - name: name.unwrap_or_default(), + name: sc.name.unwrap_or_default(), field_start: self.tys.ins.enum_fields.len() as _, }) .into(); @@ -5410,27 +5514,28 @@ impl<'a> Codegen<'a> { self.tys.syms.insert(sym, ty, &self.tys.ins); ty } - Expr::Closure { pos, args, ret, .. } if let Some(name) = name => { + Expr::Closure { pos, args, ret, .. } if let Some(name) = sc.name => { let func = Func { - file, + file: sc.file, + parent: sc.parent, name, sig: 'b: { let arg_base = self.tys.tmp.args.len(); for arg in args { let sym = - parser::find_symbol(&self.files[file.index()].symbols, arg.id); + parser::find_symbol(&self.files[sc.file.index()].symbols, arg.id); if sym.flags & idfl::COMPTIME != 0 { self.tys.tmp.args.truncate(arg_base); break 'b None; } - let ty = self.parse_ty(file, &arg.ty, None); + let ty = self.parse_ty(sc.anon(), &arg.ty); self.tys.tmp.args.push(ty); } let Some(args) = self.tys.pack_args(arg_base) else { - return self.error_low(file, pos, "function has too many argumnets"); + return self.error_low(sc.file, pos, "function has too many argumnets"); }; - let ret = self.parse_ty(file, ret, None); + let ret = self.parse_ty(sc.anon(), ret); Some(Sig { args, ret }) }, @@ -5441,12 +5546,25 @@ impl<'a> Codegen<'a> { self.tys.ins.funcs.push(func).into() } - _ if let Some(name) = name => self.eval_global(file, name, expr), - _ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)), + _ if let Some(name) = sc.name => self.eval_global(sc.file, name, expr), + _ => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)), } } } +#[derive(Clone, Copy)] +struct TyScope { + file: Module, + parent: ty::Id, + name: Option, +} + +impl TyScope { + fn anon(self) -> Self { + Self { name: None, ..self } + } +} + #[cfg(test)] mod tests { use { @@ -5503,6 +5621,7 @@ mod tests { loops; pointers; structs; + struct_scopes; enums; nullable_types; struct_operators; diff --git a/lang/tests/son_tests_different_function_destinations.txt b/lang/tests/son_tests_different_function_destinations.txt index 5919ee1..1fdcb83 100644 --- a/lang/tests/son_tests_different_function_destinations.txt +++ b/lang/tests/son_tests_different_function_destinations.txt @@ -1,6 +1,6 @@ main: - ADDI64 r254, r254, -136d - ST r31, r254, 80a, 56h + ADDI64 r254, r254, -104d + ST r31, r254, 48a, 56h LRA r32, r0, :glob_stru JAL r31, r0, :new_stru ST r1, r32, 0a, 16h @@ -19,33 +19,29 @@ main: 2: LI64 r34, 1d ST r34, r32, 0a, 8h ST r34, r32, 8a, 8h - ADDI64 r35, r254, 32d + ADDI64 r35, r254, 0d + ST r34, r254, 0a, 8h + ST r34, r254, 8a, 8h + ST r34, r254, 16a, 8h + ST r34, r254, 24a, 8h ST r34, r254, 32a, 8h ST r34, r254, 40a, 8h - ST r34, r254, 48a, 8h - ST r34, r254, 56a, 8h - ST r34, r254, 64a, 8h - ST r34, r254, 72a, 8h LI64 r36, 3d CP r32, r33 8: JNE r32, r36, :3 - LD r32, r254, 64a, 8h + LD r32, r254, 32a, 8h JEQ r32, r33, :4 LI64 r32, 100d CP r1, r32 JMP :1 - 4: ST r34, r254, 32a, 8h + 4: ST r34, r254, 0a, 8h + ST r34, r254, 8a, 8h + ST r34, r254, 16a, 8h + ST r34, r254, 24a, 8h + ST r34, r254, 32a, 8h ST r34, r254, 40a, 8h - ST r34, r254, 48a, 8h - ST r34, r254, 56a, 8h - ST r34, r254, 64a, 8h - ST r34, r254, 72a, 8h - ST r33, r254, 0a, 8h - ST r33, r254, 8a, 8h - ST r33, r254, 16a, 8h - ST r33, r254, 24a, 8h CP r32, r33 - 7: LD r37, r254, 64a, 8h + 7: LD r37, r254, 32a, 8h JNE r32, r36, :5 JEQ r37, r33, :6 LI64 r32, 10d @@ -65,8 +61,8 @@ main: ST r1, r37, 0a, 16h ADD64 r32, r32, r34 JMP :8 - 1: LD r31, r254, 80a, 56h - ADDI64 r254, r254, 136d + 1: LD r31, r254, 48a, 56h + ADDI64 r254, r254, 104d JALA r0, r31, 0a new_stru: ADDI64 r254, r254, -16d @@ -76,6 +72,6 @@ new_stru: LD r1, r13, 0a, 16h ADDI64 r254, r254, 16d JALA r0, r31, 0a -code size: 736 +code size: 684 ret: 0 status: Ok(()) diff --git a/lang/tests/son_tests_struct_scopes.txt b/lang/tests/son_tests_struct_scopes.txt new file mode 100644 index 0000000..e69de29