adding tuples
Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
969ea57e3f
commit
6e8eb059f6
|
@ -254,7 +254,7 @@ pub fn disasm<'a>(
|
|||
|| global_offset > off + len
|
||||
|| prev
|
||||
.get(global_offset as usize)
|
||||
.map_or(true, |&b| instr_from_byte(b).is_err());
|
||||
.is_none_or(|&b| instr_from_byte(b).is_err());
|
||||
has_oob |= local_has_oob;
|
||||
let label = labels.get(&global_offset).unwrap();
|
||||
if local_has_oob {
|
||||
|
|
|
@ -214,6 +214,14 @@ odher_pass := fn(t: Ty2): Ty2 {
|
|||
}
|
||||
```
|
||||
|
||||
#### tuples
|
||||
```hb
|
||||
main := fn(): uint {
|
||||
tupl := .(1, 1)
|
||||
return tupl[0] - tupl[1]
|
||||
}
|
||||
```
|
||||
|
||||
#### struct_scopes
|
||||
```hb
|
||||
$zr := 0
|
||||
|
@ -475,7 +483,7 @@ arbitrary text
|
|||
- `@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 or length ot a string constant
|
||||
- `@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]`
|
||||
- `@kindof(<ty>)`: gives an u8 integer describing the kind of type as an index to array `[Builtin, Struct, Tuple, Enum, Union, Ptr, Slice, Opt, Func, Template, Global, Const, Module]`
|
||||
- `@Any()`: generic parameter based on inference, TBD: this will ake arguments in the future that restrict what is accepted
|
||||
- `@error(...<expr>)`: emit compiler error, if reachable, and use arguments to construct a message, can display strings and types
|
||||
- `@ChildOf(<ty>)`: returns the child type of the `<ty>`, works for pointers and optionals (`@ChildOf(?u8) == u8`)
|
||||
|
|
|
@ -8,7 +8,7 @@ use {
|
|||
utils::{EntSlice, EntVec},
|
||||
},
|
||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||
core::{assert_matches::debug_assert_matches, mem, ops::Range, usize},
|
||||
core::{assert_matches::debug_assert_matches, mem, ops::Range},
|
||||
hbbytecode::{self as instrs, *},
|
||||
reg::Reg,
|
||||
};
|
||||
|
@ -314,7 +314,7 @@ impl Backend for HbvmBackend {
|
|||
&& self
|
||||
.jump_relocs
|
||||
.last()
|
||||
.map_or(true, |&(r, _)| self.offsets[r as usize] as usize != self.code.len())
|
||||
.is_none_or(|&(r, _)| self.offsets[r as usize] as usize != self.code.len())
|
||||
{
|
||||
self.code.truncate(self.code.len() - 5);
|
||||
self.ret_relocs.pop();
|
||||
|
@ -653,6 +653,7 @@ enum PLoc {
|
|||
WideReg(Reg, u16),
|
||||
Ref(Reg, u32),
|
||||
}
|
||||
|
||||
impl PLoc {
|
||||
fn reg(self) -> u8 {
|
||||
match self {
|
||||
|
|
|
@ -804,6 +804,7 @@ impl Nodes {
|
|||
}
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
fn init_loc_of(&self, def: Nid, types: &Types) -> Reg {
|
||||
if self[def].kind == Kind::Arg {
|
||||
let mut parama = ParamAlloc(0..11);
|
||||
|
@ -821,8 +822,9 @@ impl Nodes {
|
|||
255
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
fn use_reg_of(&self, def: Nid, usage: Nid) -> Reg {
|
||||
if matches!(self[usage].kind, Kind::Return { .. }) {}
|
||||
//if matches!(self[usage].kind, Kind::Return { .. }) {}
|
||||
|
||||
255
|
||||
}
|
||||
|
@ -852,7 +854,7 @@ impl<'a> Regalloc<'a> {
|
|||
Self { nodes: ctx, tys, res }.run_low(special_count);
|
||||
}
|
||||
|
||||
fn run_low(&mut self, special_count: usize) {
|
||||
fn run_low(&mut self, #[expect(unused)] special_count: usize) {
|
||||
self.res.general_bundles.clear();
|
||||
self.res.node_to_reg.clear();
|
||||
#[cfg(debug_assertions)]
|
||||
|
|
|
@ -2089,7 +2089,7 @@ pub enum Kind {
|
|||
Call {
|
||||
unreachable: bool,
|
||||
func: ty::Func,
|
||||
args: ty::Tuple,
|
||||
args: ty::List,
|
||||
},
|
||||
// [ctrl]
|
||||
Die,
|
||||
|
|
103
lang/src/son.rs
103
lang/src/son.rs
|
@ -15,9 +15,9 @@ use {
|
|||
},
|
||||
ty::{
|
||||
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,
|
||||
GlobalData, List, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef,
|
||||
StructData, StructField, SymKey, TemplateData, TupleData, TypeBase, TypeIns, Types,
|
||||
UnionData, UnionField,
|
||||
},
|
||||
utils::{BitSet, EntSlice, Vc},
|
||||
Ident,
|
||||
|
@ -657,7 +657,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
let fuc = self.tys.ins.funcs.push(FuncData {
|
||||
file,
|
||||
sig: Sig { args: Tuple::empty(), ret },
|
||||
sig: Sig { args: List::empty(), ret },
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
|
@ -1274,10 +1274,37 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
Some(Value::ptr(self.offset(bs.id, offset)).ty(f))
|
||||
}
|
||||
ty::Kind::Tuple(t) => {
|
||||
let Kind::CInt { value: idx } = self.ci.nodes[idx.id].kind else {
|
||||
return self.error(
|
||||
index.pos(),
|
||||
"field index needs to be known at compile time",
|
||||
);
|
||||
};
|
||||
|
||||
let Some((f, offset)) = OffsetIter::new(t, self.tys)
|
||||
.into_iter(self.tys)
|
||||
.nth(idx as _)
|
||||
.map(|(&f, off)| (f, off))
|
||||
else {
|
||||
return self.error(
|
||||
index.pos(),
|
||||
fa!(
|
||||
"struct '{}' has only `{}' fields, \
|
||||
but index was '{}'",
|
||||
self.ty_display(bs.ty),
|
||||
self.tys.tuple_fields(t).len(),
|
||||
idx
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
Some(Value::ptr(self.offset(bs.id, offset)).ty(f))
|
||||
}
|
||||
_ => self.error(
|
||||
base.pos(),
|
||||
fa!(
|
||||
"cant index into '{}' which is not array nor slice",
|
||||
"cant index into '{}' which is not array nor slice or tuple or struct",
|
||||
self.ty_display(bs.ty)
|
||||
),
|
||||
),
|
||||
|
@ -1581,14 +1608,51 @@ impl<'a> Codegen<'a> {
|
|||
self.gen_call(func, args, true)
|
||||
}
|
||||
Expr::Tupl { pos, ty, fields, .. } => {
|
||||
ctx.ty = ty
|
||||
let ty = ty
|
||||
.map(|ty| self.ty(ty))
|
||||
.or(ctx.ty.map(|ty| self.tys.inner_of(ty).unwrap_or(ty)));
|
||||
inference!(sty, ctx, self, pos, "struct or slice", "<struct_ty>.(...)");
|
||||
.or(ctx.ty.map(|ty| self.tys.inner_of(ty).unwrap_or(ty)))
|
||||
.map(ty::Id::expand);
|
||||
|
||||
match sty.expand() {
|
||||
ty::Kind::Struct(s) => {
|
||||
let mem = self.new_stack(pos, sty);
|
||||
match ty {
|
||||
None => {
|
||||
let arg_base = self.tys.tmp.args.len();
|
||||
let mut values = Vec::with_capacity(fields.len());
|
||||
for field in fields {
|
||||
let val = self.expr(field)?;
|
||||
self.tys.tmp.args.push(val.ty);
|
||||
self.ci.nodes.lock(val.id);
|
||||
values.push(val);
|
||||
}
|
||||
|
||||
let Some(fields) = self.tys.pack_args(arg_base) else {
|
||||
return self.error(pos, "this tuple exceeded the reasonable limit");
|
||||
};
|
||||
|
||||
let key = SymKey::Tuple(fields);
|
||||
let ty::Kind::Tuple(tupl) = self
|
||||
.tys
|
||||
.syms
|
||||
.get_or_insert(key, &mut self.tys.ins, |ins| {
|
||||
ins.tuples.push(TupleData { fields, ..Default::default() }).into()
|
||||
})
|
||||
.expand()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
let mem = self.new_stack(pos, tupl.into());
|
||||
let mut offs = OffsetIter::new(tupl, self.tys);
|
||||
for value in values {
|
||||
let (ty, offset) = offs.next_ty(self.tys).unwrap();
|
||||
let mem = self.offset(mem, offset);
|
||||
self.ci.nodes.unlock(value.id);
|
||||
self.store_mem(mem, ty, value.id);
|
||||
}
|
||||
|
||||
Some(Value::ptr(mem).ty(tupl.into()))
|
||||
}
|
||||
Some(ty::Kind::Struct(s)) => {
|
||||
let mem = self.new_stack(pos, s.into());
|
||||
let mut offs = OffsetIter::new(s, self.tys);
|
||||
for field in fields {
|
||||
let Some((ty, offset)) = offs.next_ty(self.tys) else {
|
||||
|
@ -1617,16 +1681,17 @@ impl<'a> Codegen<'a> {
|
|||
(append them to the end of the constructor)"),
|
||||
);
|
||||
}
|
||||
Some(Value::ptr(mem).ty(sty))
|
||||
Some(Value::ptr(mem).ty(s.into()))
|
||||
}
|
||||
ty::Kind::Slice(s) => {
|
||||
Some(ty::Kind::Slice(s)) => {
|
||||
let slice = &self.tys.ins.slices[s];
|
||||
let len = slice.len().unwrap_or(fields.len());
|
||||
let elem = slice.elem;
|
||||
let elem_size = self.tys.size_of(elem);
|
||||
let aty = slice
|
||||
.len()
|
||||
.map_or_else(|| self.tys.make_array(elem, len as ArrayLen), |_| sty);
|
||||
let aty = slice.len().map_or_else(
|
||||
|| self.tys.make_array(elem, len as ArrayLen),
|
||||
|_| s.into(),
|
||||
);
|
||||
|
||||
if len != fields.len() {
|
||||
return self.error(
|
||||
|
@ -1651,13 +1716,13 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
Some(Value::ptr(mem).ty(aty))
|
||||
}
|
||||
_ => self.error(
|
||||
Some(t) => self.error(
|
||||
pos,
|
||||
fa!(
|
||||
"the {}type of the constructor is `{}`, \
|
||||
but thats not a struct nor slice or array",
|
||||
if ty.is_some() { "" } else { "inferred " },
|
||||
self.ty_display(sty),
|
||||
self.ty_display(t.compress()),
|
||||
),
|
||||
),
|
||||
}
|
||||
|
@ -2393,6 +2458,7 @@ impl<'a> Codegen<'a> {
|
|||
| ty::Kind::Func(_)
|
||||
| ty::Kind::Template(_)
|
||||
| ty::Kind::Global(_)
|
||||
| ty::Kind::Tuple(_)
|
||||
| ty::Kind::Const(_)) => self.error(
|
||||
pos,
|
||||
fa!(
|
||||
|
@ -4146,6 +4212,7 @@ mod tests {
|
|||
loops;
|
||||
pointers;
|
||||
structs;
|
||||
tuples;
|
||||
struct_scopes;
|
||||
enums;
|
||||
unions;
|
||||
|
|
208
lang/src/ty.rs
208
lang/src/ty.rs
|
@ -38,9 +38,9 @@ pub type Offset = u32;
|
|||
pub type Size = u32;
|
||||
|
||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
|
||||
pub struct Tuple(pub u32);
|
||||
pub struct List(pub u32);
|
||||
|
||||
impl Tuple {
|
||||
impl List {
|
||||
const LEN_BITS: u32 = 5;
|
||||
const LEN_MASK: usize = Self::MAX_LEN - 1;
|
||||
const MAX_LEN: usize = 1 << Self::LEN_BITS;
|
||||
|
@ -104,6 +104,12 @@ impl ArgIter {
|
|||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||
pub struct Id(NonZeroU32);
|
||||
|
||||
impl AsRef<Id> for Id {
|
||||
fn as_ref(&self) -> &Id {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Id> for i64 {
|
||||
fn from(value: Id) -> Self {
|
||||
value.0.get() as _
|
||||
|
@ -150,6 +156,7 @@ impl crate::ctx_map::CtxEntry for Id {
|
|||
SymKey::Decl(gb.file.into(), gb.name)
|
||||
}
|
||||
Kind::Slice(s) => SymKey::Array(&ctx.slices[s]),
|
||||
Kind::Tuple(t) => SymKey::Tuple(ctx.tuples[t].fields),
|
||||
Kind::Module(_) | Kind::Builtin(_) => {
|
||||
SymKey::Decl(Module::default().into(), Ident::INVALID)
|
||||
}
|
||||
|
@ -266,22 +273,19 @@ impl Id {
|
|||
}
|
||||
|
||||
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
||||
use Kind as K;
|
||||
match self.expand() {
|
||||
Kind::Opt(o)
|
||||
K::Opt(o)
|
||||
if let ty = tys.ins.opts[o].base
|
||||
&& ty.loc(tys) == Loc::Reg
|
||||
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
||||
{
|
||||
Loc::Reg
|
||||
}
|
||||
Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg,
|
||||
Kind::Struct(_) | Kind::Union(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
||||
Kind::Struct(_) | Kind::Union(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
||||
c @ (Kind::Func(_)
|
||||
| Kind::Global(_)
|
||||
| Kind::Module(_)
|
||||
| Kind::Const(_)
|
||||
| Kind::Template(_)) => {
|
||||
K::Ptr(_) | K::Enum(_) | K::Builtin(_) => Loc::Reg,
|
||||
K::Struct(_) | K::Tuple(_) | K::Union(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
||||
K::Struct(_) | K::Tuple(_) | K::Union(_) | K::Slice(_) | K::Opt(_) => Loc::Stack,
|
||||
c @ (K::Func(_) | K::Global(_) | K::Module(_) | K::Const(_) | K::Template(_)) => {
|
||||
unreachable!("{c:?}")
|
||||
}
|
||||
}
|
||||
|
@ -450,6 +454,7 @@ type_kind! {
|
|||
pub enum Kind {
|
||||
Builtin,
|
||||
Struct,
|
||||
Tuple,
|
||||
Enum,
|
||||
Union,
|
||||
Ptr,
|
||||
|
@ -514,25 +519,25 @@ impl<'a> Display<'a> {
|
|||
|
||||
impl core::fmt::Display for Display<'_> {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
use Kind as TK;
|
||||
match TK::from_ty(self.ty) {
|
||||
TK::Module(idx) => {
|
||||
use Kind as K;
|
||||
match K::from_ty(self.ty) {
|
||||
K::Module(idx) => {
|
||||
f.write_str("@use(\"")?;
|
||||
self.files[idx].path.fmt(f)?;
|
||||
f.write_str(")[")?;
|
||||
idx.fmt(f)?;
|
||||
f.write_str("]")
|
||||
}
|
||||
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
||||
TK::Opt(ty) => {
|
||||
K::Builtin(ty) => f.write_str(to_str(ty)),
|
||||
K::Opt(ty) => {
|
||||
f.write_str("?")?;
|
||||
self.rety(self.tys.ins.opts[ty].base).fmt(f)
|
||||
}
|
||||
TK::Ptr(ty) => {
|
||||
K::Ptr(ty) => {
|
||||
f.write_str("^")?;
|
||||
self.rety(self.tys.ins.ptrs[ty].base).fmt(f)
|
||||
}
|
||||
TK::Struct(idx) => {
|
||||
K::Struct(idx) => {
|
||||
let record = &self.tys.ins.structs[idx];
|
||||
if record.name.is_null() {
|
||||
f.write_str("[")?;
|
||||
|
@ -554,7 +559,19 @@ impl core::fmt::Display for Display<'_> {
|
|||
f.write_str(file.ident_str(record.name))
|
||||
}
|
||||
}
|
||||
TK::Union(idx) => {
|
||||
K::Tuple(idx) => {
|
||||
f.write_str(".(")?;
|
||||
for (i, &ty) in
|
||||
self.tys.ins.args[self.tys.ins.tuples[idx].fields.range()].iter().enumerate()
|
||||
{
|
||||
if i != 0 {
|
||||
f.write_str(", ")?;
|
||||
}
|
||||
self.rety(ty).fmt(f)?;
|
||||
}
|
||||
f.write_str(")")
|
||||
}
|
||||
K::Union(idx) => {
|
||||
let record = &self.tys.ins.unions[idx];
|
||||
if record.name.is_null() {
|
||||
f.write_str("[")?;
|
||||
|
@ -576,27 +593,27 @@ impl core::fmt::Display for Display<'_> {
|
|||
f.write_str(file.ident_str(record.name))
|
||||
}
|
||||
}
|
||||
TK::Enum(idx) => {
|
||||
K::Enum(idx) => {
|
||||
let enm = &self.tys.ins.enums[idx];
|
||||
debug_assert!(!enm.name.is_null());
|
||||
let file = &self.files[enm.file];
|
||||
f.write_str(file.ident_str(enm.name))
|
||||
}
|
||||
TK::Func(idx) => {
|
||||
K::Func(idx) => {
|
||||
f.write_str("fn")?;
|
||||
idx.fmt(f)
|
||||
}
|
||||
TK::Template(idx) => {
|
||||
K::Template(idx) => {
|
||||
f.write_str("fn")?;
|
||||
idx.fmt(f)
|
||||
}
|
||||
TK::Global(idx) => {
|
||||
K::Global(idx) => {
|
||||
let global = &self.tys.ins.globals[idx];
|
||||
let file = &self.files[global.file];
|
||||
f.write_str(file.ident_str(global.name))?;
|
||||
f.write_str(" (global)")
|
||||
}
|
||||
TK::Slice(idx) => {
|
||||
K::Slice(idx) => {
|
||||
let array = self.tys.ins.slices[idx];
|
||||
f.write_str("[")?;
|
||||
self.rety(array.elem).fmt(f)?;
|
||||
|
@ -606,7 +623,7 @@ impl core::fmt::Display for Display<'_> {
|
|||
}
|
||||
f.write_str("]")
|
||||
}
|
||||
TK::Const(idx) => {
|
||||
K::Const(idx) => {
|
||||
let cnst = &self.tys.ins.consts[idx];
|
||||
let file = &self.files[cnst.file];
|
||||
f.write_str(file.ident_str(cnst.name))?;
|
||||
|
@ -618,9 +635,10 @@ impl core::fmt::Display for Display<'_> {
|
|||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub enum SymKey<'a> {
|
||||
Tuple(List),
|
||||
Pointer(&'a PtrData),
|
||||
Optional(&'a OptData),
|
||||
Type(Id, Pos, Tuple),
|
||||
Type(Id, Pos, List),
|
||||
Decl(Id, Ident),
|
||||
Array(&'a ArrayData),
|
||||
Constant(&'a ConstData),
|
||||
|
@ -628,7 +646,7 @@ pub enum SymKey<'a> {
|
|||
|
||||
#[derive(Clone, Copy, Default)]
|
||||
pub struct Sig {
|
||||
pub args: Tuple,
|
||||
pub args: List,
|
||||
pub ret: Id,
|
||||
}
|
||||
|
||||
|
@ -722,7 +740,7 @@ pub struct TypeBase {
|
|||
pub pos: Pos,
|
||||
pub name: Ident,
|
||||
pub field_start: u32,
|
||||
pub captured: Tuple,
|
||||
pub captured: List,
|
||||
pub ast: ExprRef,
|
||||
}
|
||||
|
||||
|
@ -764,6 +782,13 @@ pub struct StructData {
|
|||
|
||||
impl_deref!(StructData { base: TypeBase });
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct TupleData {
|
||||
pub fields: List,
|
||||
pub size: Cell<Size>,
|
||||
pub align: Cell<u8>,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
pub struct OptData {
|
||||
pub base: Id,
|
||||
|
@ -854,6 +879,7 @@ pub struct TypeIns {
|
|||
pub ptrs: EntVec<Ptr, PtrData>,
|
||||
pub opts: EntVec<Opt, OptData>,
|
||||
pub slices: EntVec<Slice, ArrayData>,
|
||||
pub tuples: EntVec<Tuple, TupleData>,
|
||||
}
|
||||
|
||||
pub struct FTask {
|
||||
|
@ -897,6 +923,7 @@ impl Types {
|
|||
| Kind::Builtin(_)
|
||||
| Kind::Ptr(_)
|
||||
| Kind::Slice(_)
|
||||
| Kind::Tuple(_)
|
||||
| Kind::Opt(_) => utils::is_pascal_case,
|
||||
Kind::Func(f)
|
||||
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
|
||||
|
@ -919,19 +946,19 @@ impl Types {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn pack_args(&mut self, arg_base: usize) -> Option<Tuple> {
|
||||
pub fn pack_args(&mut self, arg_base: usize) -> Option<List> {
|
||||
let base = self.ins.args.len();
|
||||
self.ins.args.extend(self.tmp.args.drain(arg_base..));
|
||||
let needle = &self.ins.args[base..];
|
||||
if needle.is_empty() {
|
||||
return Some(Tuple::empty());
|
||||
return Some(List::empty());
|
||||
}
|
||||
let len = needle.len();
|
||||
// FIXME: maybe later when this becomes a bottleneck we use more
|
||||
// efficient search (SIMD?, indexing?)
|
||||
let sp = self.ins.args.windows(needle.len()).position(|val| val == needle).unwrap();
|
||||
self.ins.args.truncate((sp + needle.len()).max(base));
|
||||
Tuple::new(sp, len)
|
||||
List::new(sp, len)
|
||||
}
|
||||
|
||||
pub fn union_fields(&self, union: Union) -> &[UnionField] {
|
||||
|
@ -1014,6 +1041,16 @@ impl Types {
|
|||
self.ins.structs[stru].size.set(oiter.offset);
|
||||
oiter.offset
|
||||
}
|
||||
Kind::Tuple(tuple) => {
|
||||
if self.ins.tuples[tuple].size.get() != 0 {
|
||||
return self.ins.tuples[tuple].size.get();
|
||||
}
|
||||
|
||||
let mut oiter = OffsetIter::new(tuple, self);
|
||||
while oiter.next(self).is_some() {}
|
||||
self.ins.tuples[tuple].size.set(oiter.offset);
|
||||
oiter.offset
|
||||
}
|
||||
Kind::Union(union) => {
|
||||
if self.ins.unions[union].size.get() != 0 {
|
||||
return self.ins.unions[union].size.get();
|
||||
|
@ -1033,8 +1070,12 @@ impl Types {
|
|||
self.size_of(base) + self.align_of(base)
|
||||
}
|
||||
}
|
||||
_ if let Some(size) = ty.simple_size() => size,
|
||||
ty => unimplemented!("size_of: {:?}", ty),
|
||||
Kind::Ptr(_) | Kind::Builtin(_) => ty.simple_size().unwrap(),
|
||||
Kind::Func(_)
|
||||
| Kind::Template(_)
|
||||
| Kind::Global(_)
|
||||
| Kind::Const(_)
|
||||
| Kind::Module(_) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1066,6 +1107,15 @@ impl Types {
|
|||
self.ins.structs[stru].align.set(align.try_into().unwrap());
|
||||
align
|
||||
}
|
||||
Kind::Tuple(tuple) => {
|
||||
if self.ins.tuples[tuple].align.get() != 0 {
|
||||
return self.ins.tuples[tuple].align.get() as _;
|
||||
}
|
||||
let align =
|
||||
self.tuple_fields(tuple).iter().map(|&f| self.align_of(f)).max().unwrap_or(1);
|
||||
self.ins.tuples[tuple].align.set(align.try_into().unwrap());
|
||||
align
|
||||
}
|
||||
Kind::Slice(arr) => {
|
||||
let arr = &self.ins.slices[arr];
|
||||
match arr.len {
|
||||
|
@ -1073,7 +1123,14 @@ impl Types {
|
|||
_ => self.align_of(arr.elem),
|
||||
}
|
||||
}
|
||||
_ => self.size_of(ty).max(1),
|
||||
Kind::Opt(opt) => self.align_of(self.ins.opts[opt].base),
|
||||
Kind::Builtin(_) | Kind::Enum(_) | Kind::Ptr(_) => self.size_of(ty),
|
||||
Kind::Func(_)
|
||||
| Kind::Template(_)
|
||||
| Kind::Global(_)
|
||||
| Kind::Const(_)
|
||||
| Kind::Module(_) => unreachable!(),
|
||||
//_ => self.size_of(ty).max(1),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1161,6 +1218,7 @@ impl Types {
|
|||
| Kind::Template(_)
|
||||
| Kind::Global(_)
|
||||
| Kind::Module(_)
|
||||
| Kind::Tuple(_)
|
||||
| Kind::Const(_) => return None,
|
||||
})
|
||||
}
|
||||
|
@ -1186,7 +1244,7 @@ impl Types {
|
|||
self.type_base_of(ty).map(|b| b.parent)
|
||||
}
|
||||
|
||||
pub fn captures_of<'a>(&self, ty: Id, file: &'a parser::Ast) -> Option<(&'a [Ident], Tuple)> {
|
||||
pub fn captures_of<'a>(&self, ty: Id, file: &'a parser::Ast) -> Option<(&'a [Ident], List)> {
|
||||
let base = self.type_base_of(ty)?;
|
||||
|
||||
let (Expr::Struct { captured, .. }
|
||||
|
@ -1212,6 +1270,10 @@ impl Types {
|
|||
let str = unsafe { core::mem::transmute::<&mut Vec<u8>, &mut String>(data) };
|
||||
write!(str, "{}", Display::new(self, files, ty)).unwrap();
|
||||
}
|
||||
|
||||
pub fn tuple_fields(&self, tuple: Tuple) -> &[Id] {
|
||||
&self.ins.args[self.ins.tuples[tuple].fields.range()]
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OptLayout {
|
||||
|
@ -1220,17 +1282,57 @@ pub struct OptLayout {
|
|||
pub payload_offset: Offset,
|
||||
}
|
||||
|
||||
pub struct OffsetIter {
|
||||
strct: Struct,
|
||||
pub trait Agregate: Copy {
|
||||
type Field: AsRef<Id> + 'static;
|
||||
|
||||
fn fields(self, tys: &Types) -> Range<usize>;
|
||||
fn field_by_idx(tys: &Types, index: usize) -> &Self::Field;
|
||||
fn align_override(self, _: &Types) -> Option<u8> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Agregate for Tuple {
|
||||
type Field = Id;
|
||||
|
||||
fn fields(self, tys: &Types) -> Range<usize> {
|
||||
tys.ins.tuples[self].fields.range()
|
||||
}
|
||||
|
||||
fn field_by_idx(tys: &Types, index: usize) -> &Self::Field {
|
||||
&tys.ins.args[index]
|
||||
}
|
||||
}
|
||||
|
||||
impl Agregate for Struct {
|
||||
type Field = StructField;
|
||||
|
||||
fn fields(self, tys: &Types) -> Range<usize> {
|
||||
tys.struct_field_range(self)
|
||||
}
|
||||
|
||||
fn field_by_idx(tys: &Types, index: usize) -> &Self::Field {
|
||||
&tys.ins.struct_fields[index]
|
||||
}
|
||||
|
||||
fn align_override(self, tys: &Types) -> Option<u8> {
|
||||
tys.ins.structs[self].explicit_alignment
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Id> for StructField {
|
||||
fn as_ref(&self) -> &Id {
|
||||
&self.ty
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OffsetIter<T> {
|
||||
strct: T,
|
||||
offset: Offset,
|
||||
fields: Range<usize>,
|
||||
}
|
||||
|
||||
impl OffsetIter {
|
||||
pub fn new(strct: Struct, tys: &Types) -> Self {
|
||||
Self { strct, offset: 0, fields: tys.struct_field_range(strct) }
|
||||
}
|
||||
|
||||
impl OffsetIter<Struct> {
|
||||
pub fn offset_of(tys: &Types, idx: Struct, field: &str) -> Option<(Offset, Id)> {
|
||||
let field_id = tys.names.project(field)?;
|
||||
OffsetIter::new(idx, tys)
|
||||
|
@ -1238,25 +1340,33 @@ impl OffsetIter {
|
|||
.find(|(f, _)| f.name == field_id)
|
||||
.map(|(f, off)| (off, f.ty))
|
||||
}
|
||||
}
|
||||
|
||||
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a StructField, Offset)> {
|
||||
let stru = &tys.ins.structs[self.strct];
|
||||
let field = &tys.ins.struct_fields[self.fields.next()?];
|
||||
impl<T: Agregate> OffsetIter<T> {
|
||||
pub fn new(strct: T, tys: &Types) -> Self {
|
||||
Self { strct, offset: 0, fields: strct.fields(tys) }
|
||||
}
|
||||
|
||||
let align = stru.explicit_alignment.map_or_else(|| tys.align_of(field.ty), |a| a as u32);
|
||||
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a T::Field, Offset)> {
|
||||
let field = &T::field_by_idx(tys, self.fields.next()?);
|
||||
|
||||
let align = self
|
||||
.strct
|
||||
.align_override(tys)
|
||||
.map_or_else(|| tys.align_of(*field.as_ref()), |a| a as u32);
|
||||
self.offset = (self.offset + align - 1) & !(align - 1);
|
||||
|
||||
let off = self.offset;
|
||||
self.offset += tys.size_of(field.ty);
|
||||
self.offset += tys.size_of(*field.as_ref());
|
||||
Some((field, off))
|
||||
}
|
||||
|
||||
pub fn next_ty(&mut self, tys: &Types) -> Option<(Id, Offset)> {
|
||||
let (field, off) = self.next(tys)?;
|
||||
Some((field.ty, off))
|
||||
Some((*field.as_ref(), off))
|
||||
}
|
||||
|
||||
pub fn into_iter(mut self, tys: &Types) -> impl Iterator<Item = (&StructField, Offset)> {
|
||||
pub fn into_iter(mut self, tys: &Types) -> impl Iterator<Item = (&T::Field, Offset)> {
|
||||
core::iter::from_fn(move || self.next(tys))
|
||||
}
|
||||
}
|
||||
|
|
6
lang/tests/son_tests_tuples.txt
Normal file
6
lang/tests/son_tests_tuples.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
main:
|
||||
CP r1, r0
|
||||
JALA r0, r31, 0a
|
||||
code size: 22
|
||||
ret: 0
|
||||
status: Ok(())
|
Loading…
Reference in a new issue