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 {
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(...<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
- `@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
```hb

View file

@ -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)

View file

@ -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<Expr<'a>>,
}
impl Poser for StructField<'_> {
@ -1227,9 +1246,9 @@ pub enum CommentOr<'a, T> {
Comment { literal: &'a str, pos: Pos },
}
impl<T: Copy> CommentOr<'_, T> {
pub fn or(&self) -> Option<T> {
match *self {
impl<T> CommentOr<'_, T> {
pub fn or(&self) -> Option<&T> {
match self {
CommentOr::Or(v) => Some(v),
CommentOr::Comment { .. } => None,
}

View file

@ -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<A: Copy, F, T: Into<ty::Id>>(
fn parse_base_ty<A, F, T: Into<ty::Id>>(
&mut self,
pos: Pos,
expr: &Expr,
@ -3837,7 +3878,7 @@ impl<'a> Codegen<'a> {
fields: FieldList<A>,
sc: TyScope,
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,
) -> 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),
};

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 {
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<Const>,
}
#[derive(Default)]
@ -818,6 +830,7 @@ impl IdentInterner {
#[derive(Default)]
pub struct TypesTmp {
pub struct_fields: Vec<StructField>,
pub union_fields: Vec<UnionField>,
pub enum_fields: Vec<EnumField>,
pub args: Vec<Id>,
}
@ -826,6 +839,7 @@ pub struct TypesTmp {
pub struct TypeIns {
pub args: Vec<Id>,
pub struct_fields: Vec<StructField>,
pub union_fields: Vec<UnionField>,
pub enum_fields: Vec<EnumField>,
pub funcs: EntVec<Func, FuncData>,
pub templates: EntVec<Template, TemplateData>,
@ -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<usize> {
@ -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<usize> {
pub fn struct_field_range(&self, strct: Struct) -> Range<usize> {
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);