forked from AbleOS/holey-bytes
adding default values to struct fields and @kindof directive
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
0516ce68f4
commit
86f7d70747
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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,
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in a new issue