adding default values to struct fields and @kindof directive

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-17 17:51:14 +01:00
parent 0516ce68f4
commit 86f7d70747
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 132 additions and 42 deletions

View file

@ -186,7 +186,7 @@ Ty := struct {
Ty2 := struct { Ty2 := struct {
ty: Ty, ty: Ty,
c: uint, c: uint = 3,
} }
useless := struct {} useless := struct {}
@ -197,7 +197,7 @@ main := fn(): uint {
return 9001 return 9001
} }
finst := Ty2.{ty: .{a: 4}, c: 3} finst := Ty2.{ty: .{a: 4}}
inst := odher_pass(finst) inst := odher_pass(finst)
if inst.c == 3 { if inst.c == 3 {
return pass(&inst.ty) return pass(&inst.ty)
@ -439,6 +439,8 @@ main := fn(): uint {
hardcoded_pointer := @as(^u8, @bitcast(10)) hardcoded_pointer := @as(^u8, @bitcast(10))
ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6)) ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6))
embedded_array := @as([u8; 15], @embed("text.txt")) embedded_array := @as([u8; 15], @embed("text.txt"))
two_fields := @len(foo.Type)
the_struct_kind := @kindof(foo.Type)
return @inline(foo.foo) return @inline(foo.foo)
} }
@ -464,6 +466,8 @@ arbitrary text
- `@eca(...<expr>)`: invoke `eca` instruction, where return type is inferred and `<expr>...` are arguments passed to the call in the standard call convention - `@eca(...<expr>)`: invoke `eca` instruction, where return type is inferred and `<expr>...` are arguments passed to the call in the standard call convention
- `@embed(<string>)`: include relative file as an array of bytes - `@embed(<string>)`: include relative file as an array of bytes
- `@inline(<func>, ...<args>)`: equivalent to `<func>(...<args>)` but function is guaranteed to inline, compiler will otherwise never inline - `@inline(<func>, ...<args>)`: equivalent to `<func>(...<args>)` but function is guaranteed to inline, compiler will otherwise never inline
- `@len(<ty>)`: reports a length of the type of indexing purposes
- `@kindof(<ty>)`: 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 #### c_strings
```hb ```hb

View file

@ -3,6 +3,7 @@ use {
lexer::{self, Lexer, TokenKind}, lexer::{self, Lexer, TokenKind},
parser::{ parser::{
self, CommentOr, CtorField, EnumField, Expr, FieldList, Poser, Radix, StructField, self, CommentOr, CtorField, EnumField, Expr, FieldList, Poser, Radix, StructField,
UnionField,
}, },
}, },
core::{ core::{
@ -339,10 +340,15 @@ impl<'a> Formatter<'a> {
"struct", "struct",
trailing_comma, trailing_comma,
fields, fields,
|s, StructField { name, ty, .. }, f| { |s, StructField { name, ty, default_value, .. }, f| {
f.write_str(name)?; f.write_str(name)?;
f.write_str(": ")?; 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", "union",
trailing_comma, trailing_comma,
fields, fields,
|s, StructField { name, ty, .. }, f| { |s, UnionField { name, ty, .. }, f| {
f.write_str(name)?; f.write_str(name)?;
f.write_str(": ")?; f.write_str(": ")?;
s.fmt(ty, f) s.fmt(ty, f)

View file

@ -378,10 +378,15 @@ impl<'a, 'b> Parser<'a, 'b> {
} }
let name = s.expect_advance(T::Ident)?; let name = s.expect_advance(T::Ident)?;
s.expect_advance(T::Colon)?; 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 { Some(Some(StructField {
pos: name.start, pos: name.start,
name: s.tok_str(name), name: s.tok_str(name),
ty: s.expr()?, ty,
default_value,
})) }))
})?, })?,
captured: self.collect_captures(prev_boundary, prev_captured), 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)?; let name = s.expect_advance(T::Ident)?;
s.expect_advance(T::Colon)?; s.expect_advance(T::Colon)?;
Some(Some(StructField { Some(Some(UnionField { pos: name.start, name: s.tok_str(name), ty: s.expr()? }))
pos: name.start,
name: s.tok_str(name),
ty: s.expr()?,
}))
})?, })?,
captured: self.collect_captures(prev_boundary, prev_captured), captured: self.collect_captures(prev_boundary, prev_captured),
trailing_comma: core::mem::take(&mut self.trailing_sep) || must_trail, 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) { fn flag_idents(&mut self, e: Expr<'a>, flags: IdentFlags) {
match e { 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), Expr::Field { target, .. } => self.flag_idents(*target, flags),
_ => {} _ => {}
} }
} }
} }
fn find_ident(idents: &mut [ScopeIdent], id: Ident) -> &mut ScopeIdent { 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]).unwrap() idents.binary_search_by_key(&id, |si| si.ident).map(|i| &mut idents[i]).ok()
} }
pub fn find_symbol(symbols: &[Symbol], id: Ident) -> &Symbol { pub fn find_symbol(symbols: &[Symbol], id: Ident) -> &Symbol {
@ -1005,7 +1010,7 @@ generate_expr! {
/// `'union' LIST('{', ',', '}', Ident ':' Expr)` /// `'union' LIST('{', ',', '}', Ident ':' Expr)`
Union { Union {
pos: Pos, pos: Pos,
fields: FieldList<'a, StructField<'a>>, fields: FieldList<'a, UnionField<'a>>,
captured: &'a [Ident], captured: &'a [Ident],
trailing_comma: bool, 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)] #[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct StructField<'a> { pub struct StructField<'a> {
pub pos: Pos, pub pos: Pos,
pub name: &'a str, pub name: &'a str,
pub ty: Expr<'a>, pub ty: Expr<'a>,
pub default_value: Option<Expr<'a>>,
} }
impl Poser for StructField<'_> { impl Poser for StructField<'_> {
@ -1227,9 +1246,9 @@ pub enum CommentOr<'a, T> {
Comment { literal: &'a str, pos: Pos }, Comment { literal: &'a str, pos: Pos },
} }
impl<T: Copy> CommentOr<'_, T> { impl<T> CommentOr<'_, T> {
pub fn or(&self) -> Option<T> { pub fn or(&self) -> Option<&T> {
match *self { match self {
CommentOr::Or(v) => Some(v), CommentOr::Or(v) => Some(v),
CommentOr::Comment { .. } => None, CommentOr::Comment { .. } => None,
} }

View file

@ -17,6 +17,7 @@ use {
self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData, self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData,
GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData, GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData,
StructField, SymKey, TemplateData, Tuple, TypeBase, TypeIns, Types, UnionData, StructField, SymKey, TemplateData, Tuple, TypeBase, TypeIns, Types, UnionData,
UnionField,
}, },
utils::{BitSet, EntSlice, Vc}, utils::{BitSet, EntSlice, Vc},
Ident, Ident,
@ -1281,6 +1282,10 @@ impl<'a> Codegen<'a> {
self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID], self.tys); self.ci.nodes.new_node(glob.ty, Kind::Global { global: id }, [VOID], self.tys);
Some(Value::ptr(g).ty(glob.ty)) 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], .. } => { Expr::Directive { name: "nameof", args: [ty], .. } => {
let ty = self.ty(ty); let ty = self.ty(ty);
let mut data = core::mem::take(&mut self.pool.lit_buf); 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); 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 let field_list = self
.tys .tys
.struct_fields(s) .struct_fields(s)
@ -2616,14 +2637,16 @@ impl<'a> Codegen<'a> {
let prev_file = 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 prev_parent = mem::replace(&mut self.ci.parent, c.parent);
let f = &self.files[c.file]; 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.file = prev_file;
self.ci.parent = prev_parent; self.ci.parent = prev_parent;
Some(value) Some(value)
@ -3731,14 +3754,32 @@ impl<'a> Codegen<'a> {
|s| [&mut s.ins.struct_fields, &mut s.tmp.struct_fields], |s| [&mut s.ins.struct_fields, &mut s.tmp.struct_fields],
|s, field| { |s, field| {
let ty = s.parse_ty(sc.anon(), &field.ty); 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, base| {
s.ins.structs.push(StructData { let str = s.ins.structs.push(StructData {
base, base,
explicit_alignment: packed.then_some(1), explicit_alignment: packed.then_some(1),
..Default::default() ..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( Expr::Enum { pos, variants, captured, .. } => self.parse_base_ty(
@ -3757,10 +3798,10 @@ impl<'a> Codegen<'a> {
captured, captured,
fields, fields,
sc, 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| { |s, field| {
let ty = s.parse_ty(sc.anon(), &field.ty); 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() }), |s, base| s.ins.unions.push(UnionData { base, ..Default::default() }),
), ),
@ -3829,7 +3870,7 @@ impl<'a> Codegen<'a> {
} }
#[expect(clippy::too_many_arguments)] #[expect(clippy::too_many_arguments)]
fn parse_base_ty<A: Copy, F, T: Into<ty::Id>>( fn parse_base_ty<A, F, T: Into<ty::Id>>(
&mut self, &mut self,
pos: Pos, pos: Pos,
expr: &Expr, expr: &Expr,
@ -3837,7 +3878,7 @@ impl<'a> Codegen<'a> {
fields: FieldList<A>, fields: FieldList<A>,
sc: TyScope, sc: TyScope,
get_fields: impl Fn(&mut Types) -> [&mut Vec<F>; 2], get_fields: impl Fn(&mut Types) -> [&mut Vec<F>; 2],
check_field: impl Fn(&mut Self, A) -> F, check_field: impl Fn(&mut Self, &A) -> F,
check: impl Fn(&mut Types, TypeBase) -> T, check: impl Fn(&mut Types, TypeBase) -> T,
) -> ty::Id { ) -> ty::Id {
let captures_start = self.tys.tmp.args.len(); 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(); 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); let field = check_field(self, field);
get_fields(self.tys)[1].push(field); get_fields(self.tys)[1].push(field);
} }
@ -3864,7 +3907,7 @@ impl<'a> Codegen<'a> {
pos, pos,
captured, captured,
name: sc.name.unwrap_or_default(), 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), ast: ExprRef::new(expr),
}; };

View file

@ -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 { impl From<$variant> for $name {
fn from(value: $variant) -> Self { fn from(value: $variant) -> Self {
@ -449,8 +455,8 @@ type_kind! {
Func, Func,
Template, Template,
Global, Global,
Module,
Const, Const,
Module,
} }
} }
@ -529,7 +535,7 @@ impl core::fmt::Display for Display<'_> {
f.write_str("[")?; f.write_str("[")?;
idx.fmt(f)?; idx.fmt(f)?;
f.write_str("]{")?; f.write_str("]{")?;
for (i, &StructField { name, ty }) in for (i, &StructField { name, ty, .. }) in
self.tys.struct_fields(idx).iter().enumerate() self.tys.struct_fields(idx).iter().enumerate()
{ {
if i != 0 { if i != 0 {
@ -551,7 +557,7 @@ impl core::fmt::Display for Display<'_> {
f.write_str("[")?; f.write_str("[")?;
idx.fmt(f)?; idx.fmt(f)?;
f.write_str("]{")?; f.write_str("]{")?;
for (i, &StructField { name, ty }) in for (i, &UnionField { name, ty }) in
self.tys.union_fields(idx).iter().enumerate() self.tys.union_fields(idx).iter().enumerate()
{ {
if i != 0 { if i != 0 {
@ -724,6 +730,11 @@ pub struct EnumData {
impl_deref!(EnumData { base: TypeBase }); impl_deref!(EnumData { base: TypeBase });
pub struct UnionField {
pub name: Ident,
pub ty: Id,
}
#[derive(Default)] #[derive(Default)]
pub struct UnionData { pub struct UnionData {
pub base: TypeBase, pub base: TypeBase,
@ -736,6 +747,7 @@ impl_deref!(UnionData { base: TypeBase });
pub struct StructField { pub struct StructField {
pub name: Ident, pub name: Ident,
pub ty: Id, pub ty: Id,
pub default_value: Option<Const>,
} }
#[derive(Default)] #[derive(Default)]
@ -818,6 +830,7 @@ impl IdentInterner {
#[derive(Default)] #[derive(Default)]
pub struct TypesTmp { pub struct TypesTmp {
pub struct_fields: Vec<StructField>, pub struct_fields: Vec<StructField>,
pub union_fields: Vec<UnionField>,
pub enum_fields: Vec<EnumField>, pub enum_fields: Vec<EnumField>,
pub args: Vec<Id>, pub args: Vec<Id>,
} }
@ -826,6 +839,7 @@ pub struct TypesTmp {
pub struct TypeIns { pub struct TypeIns {
pub args: Vec<Id>, pub args: Vec<Id>,
pub struct_fields: Vec<StructField>, pub struct_fields: Vec<StructField>,
pub union_fields: Vec<UnionField>,
pub enum_fields: Vec<EnumField>, pub enum_fields: Vec<EnumField>,
pub funcs: EntVec<Func, FuncData>, pub funcs: EntVec<Func, FuncData>,
pub templates: EntVec<Template, TemplateData>, pub templates: EntVec<Template, TemplateData>,
@ -917,8 +931,8 @@ impl Types {
Tuple::new(sp, len) Tuple::new(sp, len)
} }
pub fn union_fields(&self, union: Union) -> &[StructField] { pub fn union_fields(&self, union: Union) -> &[UnionField] {
&self.ins.struct_fields[self.union_field_range(union)] &self.ins.union_fields[self.union_field_range(union)]
} }
fn union_field_range(&self, union: Union) -> Range<usize> { fn union_field_range(&self, union: Union) -> Range<usize> {
@ -927,7 +941,7 @@ impl Types {
.ins .ins
.unions .unions
.next(union) .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 start..end
} }
@ -935,7 +949,7 @@ impl Types {
&self.ins.struct_fields[self.struct_field_range(strct)] &self.ins.struct_fields[self.struct_field_range(strct)]
} }
fn struct_field_range(&self, strct: Struct) -> Range<usize> { pub fn struct_field_range(&self, strct: Struct) -> Range<usize> {
let start = self.ins.structs[strct].field_start as usize; let start = self.ins.structs[strct].field_start as usize;
let end = self let end = self
.ins .ins
@ -1103,7 +1117,7 @@ impl Types {
self.struct_fields(s).iter().position(|f| f.name == name) 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)?; let name = self.names.project(name)?;
self.union_fields(u).iter().enumerate().find(|(_, f)| f.name == name) self.union_fields(u).iter().enumerate().find(|(_, f)| f.name == name)
} }
@ -1118,10 +1132,14 @@ impl Types {
self.ins.globals.clear(); self.ins.globals.clear();
self.ins.structs.clear(); self.ins.structs.clear();
self.ins.struct_fields.clear(); self.ins.struct_fields.clear();
self.ins.union_fields.clear();
self.ins.enum_fields.clear();
self.ins.ptrs.clear(); self.ins.ptrs.clear();
self.ins.slices.clear(); self.ins.slices.clear();
debug_assert_eq!(self.tmp.struct_fields.len(), 0); 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.tmp.args.len(), 0);
debug_assert_eq!(self.tasks.len(), 0); debug_assert_eq!(self.tasks.len(), 0);