From 86f7d707474df2d1afc2169829299a83a3c4f6f6 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Tue, 17 Dec 2024 17:51:14 +0100 Subject: [PATCH] adding default values to struct fields and @kindof directive Signed-off-by: Jakub Doka --- lang/README.md | 8 +++-- lang/src/fmt.rs | 12 ++++++-- lang/src/parser.rs | 45 ++++++++++++++++++++-------- lang/src/son.rs | 75 ++++++++++++++++++++++++++++++++++++---------- lang/src/ty.rs | 34 ++++++++++++++++----- 5 files changed, 132 insertions(+), 42 deletions(-) diff --git a/lang/README.md b/lang/README.md index 9720bff9..95aaf42e 100644 --- a/lang/README.md +++ b/lang/README.md @@ -186,7 +186,7 @@ Ty := struct { Ty2 := struct { ty: Ty, - c: uint, + c: uint = 3, } useless := struct {} @@ -197,7 +197,7 @@ main := fn(): uint { return 9001 } - finst := Ty2.{ty: .{a: 4}, c: 3} + finst := Ty2.{ty: .{a: 4}} inst := odher_pass(finst) if inst.c == 3 { return pass(&inst.ty) @@ -439,6 +439,8 @@ main := fn(): uint { hardcoded_pointer := @as(^u8, @bitcast(10)) ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6)) embedded_array := @as([u8; 15], @embed("text.txt")) + two_fields := @len(foo.Type) + the_struct_kind := @kindof(foo.Type) return @inline(foo.foo) } @@ -464,6 +466,8 @@ arbitrary text - `@eca(...)`: invoke `eca` instruction, where return type is inferred and `...` are arguments passed to the call in the standard call convention - `@embed()`: include relative file as an array of bytes - `@inline(, ...)`: equivalent to `(...)` but function is guaranteed to inline, compiler will otherwise never inline +- `@len()`: reports a length of the type of indexing purposes +- `@kindof()`: gives an u8 integer describing the kind of type as an index to array `[Builtin, Struct, Enum, Union, Ptr, Slice, Opt, Func, Template, Global, Const, Module]` #### c_strings ```hb diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index 9ca9c45f..99cd5c38 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -3,6 +3,7 @@ use { lexer::{self, Lexer, TokenKind}, parser::{ self, CommentOr, CtorField, EnumField, Expr, FieldList, Poser, Radix, StructField, + UnionField, }, }, core::{ @@ -339,10 +340,15 @@ impl<'a> Formatter<'a> { "struct", trailing_comma, fields, - |s, StructField { name, ty, .. }, f| { + |s, StructField { name, ty, default_value, .. }, f| { f.write_str(name)?; f.write_str(": ")?; - s.fmt(ty, f) + s.fmt(ty, f)?; + if let Some(deva) = default_value { + f.write_str(" = ")?; + s.fmt(deva, f)?; + } + Ok(()) }, ) } @@ -351,7 +357,7 @@ impl<'a> Formatter<'a> { "union", trailing_comma, fields, - |s, StructField { name, ty, .. }, f| { + |s, UnionField { name, ty, .. }, f| { f.write_str(name)?; f.write_str(": ")?; s.fmt(ty, f) diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 091f414a..afa898f3 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -378,10 +378,15 @@ impl<'a, 'b> Parser<'a, 'b> { } let name = s.expect_advance(T::Ident)?; s.expect_advance(T::Colon)?; + let (ty, default_value) = match s.expr()? { + Expr::BinOp { left, op: T::Assign, right, .. } => (*left, Some(*right)), + ty => (ty, None), + }; Some(Some(StructField { pos: name.start, name: s.tok_str(name), - ty: s.expr()?, + ty, + default_value, })) })?, captured: self.collect_captures(prev_boundary, prev_captured), @@ -395,11 +400,7 @@ impl<'a, 'b> Parser<'a, 'b> { } let name = s.expect_advance(T::Ident)?; s.expect_advance(T::Colon)?; - Some(Some(StructField { - pos: name.start, - name: s.tok_str(name), - ty: s.expr()?, - })) + Some(Some(UnionField { pos: name.start, name: s.tok_str(name), ty: s.expr()? })) })?, captured: self.collect_captures(prev_boundary, prev_captured), trailing_comma: core::mem::take(&mut self.trailing_sep) || must_trail, @@ -790,15 +791,19 @@ impl<'a, 'b> Parser<'a, 'b> { fn flag_idents(&mut self, e: Expr<'a>, flags: IdentFlags) { match e { - Expr::Ident { id, .. } => find_ident(&mut self.ctx.idents, id).flags |= flags, + Expr::Ident { id, .. } => { + if let Some(f) = find_ident(&mut self.ctx.idents, id) { + f.flags |= flags; + } + } Expr::Field { target, .. } => self.flag_idents(*target, flags), _ => {} } } } -fn find_ident(idents: &mut [ScopeIdent], id: Ident) -> &mut ScopeIdent { - idents.binary_search_by_key(&id, |si| si.ident).map(|i| &mut idents[i]).unwrap() +fn find_ident(idents: &mut [ScopeIdent], id: Ident) -> Option<&mut ScopeIdent> { + idents.binary_search_by_key(&id, |si| si.ident).map(|i| &mut idents[i]).ok() } pub fn find_symbol(symbols: &[Symbol], id: Ident) -> &Symbol { @@ -1005,7 +1010,7 @@ generate_expr! { /// `'union' LIST('{', ',', '}', Ident ':' Expr)` Union { pos: Pos, - fields: FieldList<'a, StructField<'a>>, + fields: FieldList<'a, UnionField<'a>>, captured: &'a [Ident], trailing_comma: bool, }, @@ -1158,11 +1163,25 @@ impl Poser for EnumField<'_> { } } +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub struct UnionField<'a> { + pub pos: Pos, + pub name: &'a str, + pub ty: Expr<'a>, +} + +impl Poser for UnionField<'_> { + fn posi(&self) -> Pos { + self.pos + } +} + #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub struct StructField<'a> { pub pos: Pos, pub name: &'a str, pub ty: Expr<'a>, + pub default_value: Option>, } impl Poser for StructField<'_> { @@ -1227,9 +1246,9 @@ pub enum CommentOr<'a, T> { Comment { literal: &'a str, pos: Pos }, } -impl CommentOr<'_, T> { - pub fn or(&self) -> Option { - match *self { +impl CommentOr<'_, T> { + pub fn or(&self) -> Option<&T> { + match self { CommentOr::Or(v) => Some(v), CommentOr::Comment { .. } => None, } diff --git a/lang/src/son.rs b/lang/src/son.rs index 1ab088ae..9ff816f2 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -17,6 +17,7 @@ use { self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData, GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData, StructField, SymKey, TemplateData, Tuple, TypeBase, TypeIns, Types, UnionData, + UnionField, }, utils::{BitSet, EntSlice, Vc}, Ident, @@ -1281,6 +1282,10 @@ impl<'a> Codegen<'a> { self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID], self.tys); Some(Value::ptr(g).ty(glob.ty)) } + Expr::Directive { name: "kindof", args: [ty], .. } => { + let ty = self.ty(ty); + self.gen_inferred_const(ctx, ty::Id::U8, ty.kind()) + } Expr::Directive { name: "nameof", args: [ty], .. } => { let ty = self.ty(ty); let mut data = core::mem::take(&mut self.pool.lit_buf); @@ -1672,6 +1677,22 @@ impl<'a> Codegen<'a> { self.store_mem(mem, ty, value.id); } + for (i, &mut (ref mut ty, offset)) in + self.tys.struct_field_range(s).zip(&mut offs) + { + if *ty == ty::Id::UNDECLARED { + continue; + } + + let field = &self.tys.ins.struct_fields[i]; + let Some(deva) = field.default_value else { continue }; + let value = self.gen_const(deva, Ctx::default().with_ty(*ty))?; + let mem = self.offset(mem, offset); + self.store_mem(mem, *ty, value.id); + + *ty = ty::Id::UNDECLARED; + } + let field_list = self .tys .struct_fields(s) @@ -2616,14 +2637,16 @@ impl<'a> Codegen<'a> { 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]; - let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() }; + let value = match c.ast.get(f) { + Expr::BinOp { left, op: TokenKind::Decl, right, .. } => left + .find_pattern_path(c.name, right, |expr, is_ct| { + debug_assert!(is_ct); + self.ptr_expr_ctx(expr, ctx) + }) + .unwrap_or_else(|_| unreachable!()), + v => self.ptr_expr_ctx(v, ctx), + }?; - let value = left - .find_pattern_path(c.name, right, |expr, is_ct| { - debug_assert!(is_ct); - self.ptr_expr_ctx(expr, ctx) - }) - .unwrap_or_else(|_| unreachable!())?; self.ci.file = prev_file; self.ci.parent = prev_parent; Some(value) @@ -3731,14 +3754,32 @@ impl<'a> Codegen<'a> { |s| [&mut s.ins.struct_fields, &mut s.tmp.struct_fields], |s, field| { let ty = s.parse_ty(sc.anon(), &field.ty); - StructField { name: s.tys.names.intern(field.name), ty } + StructField { + name: s.tys.names.intern(field.name), + ty, + default_value: field.default_value.as_ref().map(|expr| { + s.tys.ins.consts.push(ConstData { + ast: ExprRef::new(expr), + name: Default::default(), + file: sc.file, + parent: Default::default(), + }) + }), + } }, |s, base| { - s.ins.structs.push(StructData { + let str = s.ins.structs.push(StructData { base, explicit_alignment: packed.then_some(1), ..Default::default() - }) + }); + + s.ins.struct_fields[s.struct_field_range(str)] + .iter() + .filter_map(|f| f.default_value) + .for_each(|c| s.ins.consts[c].parent = str.into()); + + str }, ), Expr::Enum { pos, variants, captured, .. } => self.parse_base_ty( @@ -3757,10 +3798,10 @@ impl<'a> Codegen<'a> { captured, fields, sc, - |s| [&mut s.ins.struct_fields, &mut s.tmp.struct_fields], + |s| [&mut s.ins.union_fields, &mut s.tmp.union_fields], |s, field| { let ty = s.parse_ty(sc.anon(), &field.ty); - StructField { name: s.tys.names.intern(field.name), ty } + UnionField { name: s.tys.names.intern(field.name), ty } }, |s, base| s.ins.unions.push(UnionData { base, ..Default::default() }), ), @@ -3829,7 +3870,7 @@ impl<'a> Codegen<'a> { } #[expect(clippy::too_many_arguments)] - fn parse_base_ty>( + fn parse_base_ty>( &mut self, pos: Pos, expr: &Expr, @@ -3837,7 +3878,7 @@ impl<'a> Codegen<'a> { fields: FieldList, sc: TyScope, get_fields: impl Fn(&mut Types) -> [&mut Vec; 2], - check_field: impl Fn(&mut Self, A) -> F, + check_field: impl Fn(&mut Self, &A) -> F, check: impl Fn(&mut Types, TypeBase) -> T, ) -> ty::Id { let captures_start = self.tys.tmp.args.len(); @@ -3853,7 +3894,9 @@ impl<'a> Codegen<'a> { } let prev_tmp = get_fields(self.tys)[1].len(); - for field in fields.iter().filter_map(CommentOr::or).filter_map(Result::ok) { + for field in + fields.iter().filter_map(CommentOr::or).map(Result::as_ref).filter_map(Result::ok) + { let field = check_field(self, field); get_fields(self.tys)[1].push(field); } @@ -3864,7 +3907,7 @@ impl<'a> Codegen<'a> { pos, captured, name: sc.name.unwrap_or_default(), - field_start: self.tys.ins.struct_fields.len() as _, + field_start: get_fields(self.tys)[0].len() as _, ast: ExprRef::new(expr), }; diff --git a/lang/src/ty.rs b/lang/src/ty.rs index 81e5c872..0cf1e8ba 100644 --- a/lang/src/ty.rs +++ b/lang/src/ty.rs @@ -414,6 +414,12 @@ macro_rules! type_kind { } } + impl Id { + pub fn kind(self) -> u8 { + (self.repr() >> $name::FLAG_OFFSET) as _ + } + } + $( impl From<$variant> for $name { fn from(value: $variant) -> Self { @@ -449,8 +455,8 @@ type_kind! { Func, Template, Global, - Module, Const, + Module, } } @@ -529,7 +535,7 @@ impl core::fmt::Display for Display<'_> { f.write_str("[")?; idx.fmt(f)?; f.write_str("]{")?; - for (i, &StructField { name, ty }) in + for (i, &StructField { name, ty, .. }) in self.tys.struct_fields(idx).iter().enumerate() { if i != 0 { @@ -551,7 +557,7 @@ impl core::fmt::Display for Display<'_> { f.write_str("[")?; idx.fmt(f)?; f.write_str("]{")?; - for (i, &StructField { name, ty }) in + for (i, &UnionField { name, ty }) in self.tys.union_fields(idx).iter().enumerate() { if i != 0 { @@ -724,6 +730,11 @@ pub struct EnumData { impl_deref!(EnumData { base: TypeBase }); +pub struct UnionField { + pub name: Ident, + pub ty: Id, +} + #[derive(Default)] pub struct UnionData { pub base: TypeBase, @@ -736,6 +747,7 @@ impl_deref!(UnionData { base: TypeBase }); pub struct StructField { pub name: Ident, pub ty: Id, + pub default_value: Option, } #[derive(Default)] @@ -818,6 +830,7 @@ impl IdentInterner { #[derive(Default)] pub struct TypesTmp { pub struct_fields: Vec, + pub union_fields: Vec, pub enum_fields: Vec, pub args: Vec, } @@ -826,6 +839,7 @@ pub struct TypesTmp { pub struct TypeIns { pub args: Vec, pub struct_fields: Vec, + pub union_fields: Vec, pub enum_fields: Vec, pub funcs: EntVec, pub templates: EntVec, @@ -917,8 +931,8 @@ impl Types { Tuple::new(sp, len) } - pub fn union_fields(&self, union: Union) -> &[StructField] { - &self.ins.struct_fields[self.union_field_range(union)] + pub fn union_fields(&self, union: Union) -> &[UnionField] { + &self.ins.union_fields[self.union_field_range(union)] } fn union_field_range(&self, union: Union) -> Range { @@ -927,7 +941,7 @@ impl Types { .ins .unions .next(union) - .map_or(self.ins.struct_fields.len(), |s| s.field_start as usize); + .map_or(self.ins.union_fields.len(), |s| s.field_start as usize); start..end } @@ -935,7 +949,7 @@ impl Types { &self.ins.struct_fields[self.struct_field_range(strct)] } - fn struct_field_range(&self, strct: Struct) -> Range { + pub fn struct_field_range(&self, strct: Struct) -> Range { let start = self.ins.structs[strct].field_start as usize; let end = self .ins @@ -1103,7 +1117,7 @@ impl Types { self.struct_fields(s).iter().position(|f| f.name == name) } - pub fn find_union_field(&self, u: Union, name: &str) -> Option<(usize, &StructField)> { + pub fn find_union_field(&self, u: Union, name: &str) -> Option<(usize, &UnionField)> { let name = self.names.project(name)?; self.union_fields(u).iter().enumerate().find(|(_, f)| f.name == name) } @@ -1118,10 +1132,14 @@ impl Types { self.ins.globals.clear(); self.ins.structs.clear(); self.ins.struct_fields.clear(); + self.ins.union_fields.clear(); + self.ins.enum_fields.clear(); self.ins.ptrs.clear(); self.ins.slices.clear(); debug_assert_eq!(self.tmp.struct_fields.len(), 0); + debug_assert_eq!(self.tmp.union_fields.len(), 0); + debug_assert_eq!(self.tmp.enum_fields.len(), 0); debug_assert_eq!(self.tmp.args.len(), 0); debug_assert_eq!(self.tasks.len(), 0);