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
|
|| global_offset > off + len
|
||||||
|| prev
|
|| prev
|
||||||
.get(global_offset as usize)
|
.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;
|
has_oob |= local_has_oob;
|
||||||
let label = labels.get(&global_offset).unwrap();
|
let label = labels.get(&global_offset).unwrap();
|
||||||
if local_has_oob {
|
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
|
#### struct_scopes
|
||||||
```hb
|
```hb
|
||||||
$zr := 0
|
$zr := 0
|
||||||
|
@ -475,7 +483,7 @@ arbitrary text
|
||||||
- `@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 or length ot a string constant
|
- `@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
|
- `@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
|
- `@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`)
|
- `@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},
|
utils::{EntSlice, EntVec},
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
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, *},
|
hbbytecode::{self as instrs, *},
|
||||||
reg::Reg,
|
reg::Reg,
|
||||||
};
|
};
|
||||||
|
@ -314,7 +314,7 @@ impl Backend for HbvmBackend {
|
||||||
&& self
|
&& self
|
||||||
.jump_relocs
|
.jump_relocs
|
||||||
.last()
|
.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.code.truncate(self.code.len() - 5);
|
||||||
self.ret_relocs.pop();
|
self.ret_relocs.pop();
|
||||||
|
@ -653,6 +653,7 @@ enum PLoc {
|
||||||
WideReg(Reg, u16),
|
WideReg(Reg, u16),
|
||||||
Ref(Reg, u32),
|
Ref(Reg, u32),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PLoc {
|
impl PLoc {
|
||||||
fn reg(self) -> u8 {
|
fn reg(self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
|
|
|
@ -804,6 +804,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(unused)]
|
||||||
fn init_loc_of(&self, def: Nid, types: &Types) -> Reg {
|
fn init_loc_of(&self, def: Nid, types: &Types) -> Reg {
|
||||||
if self[def].kind == Kind::Arg {
|
if self[def].kind == Kind::Arg {
|
||||||
let mut parama = ParamAlloc(0..11);
|
let mut parama = ParamAlloc(0..11);
|
||||||
|
@ -821,8 +822,9 @@ impl Nodes {
|
||||||
255
|
255
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(unused)]
|
||||||
fn use_reg_of(&self, def: Nid, usage: Nid) -> Reg {
|
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
|
255
|
||||||
}
|
}
|
||||||
|
@ -852,7 +854,7 @@ impl<'a> Regalloc<'a> {
|
||||||
Self { nodes: ctx, tys, res }.run_low(special_count);
|
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.general_bundles.clear();
|
||||||
self.res.node_to_reg.clear();
|
self.res.node_to_reg.clear();
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
|
|
|
@ -2089,7 +2089,7 @@ pub enum Kind {
|
||||||
Call {
|
Call {
|
||||||
unreachable: bool,
|
unreachable: bool,
|
||||||
func: ty::Func,
|
func: ty::Func,
|
||||||
args: ty::Tuple,
|
args: ty::List,
|
||||||
},
|
},
|
||||||
// [ctrl]
|
// [ctrl]
|
||||||
Die,
|
Die,
|
||||||
|
|
103
lang/src/son.rs
103
lang/src/son.rs
|
@ -15,9 +15,9 @@ use {
|
||||||
},
|
},
|
||||||
ty::{
|
ty::{
|
||||||
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, List, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef,
|
||||||
StructField, SymKey, TemplateData, Tuple, TypeBase, TypeIns, Types, UnionData,
|
StructData, StructField, SymKey, TemplateData, TupleData, TypeBase, TypeIns, Types,
|
||||||
UnionField,
|
UnionData, UnionField,
|
||||||
},
|
},
|
||||||
utils::{BitSet, EntSlice, Vc},
|
utils::{BitSet, EntSlice, Vc},
|
||||||
Ident,
|
Ident,
|
||||||
|
@ -657,7 +657,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
let fuc = self.tys.ins.funcs.push(FuncData {
|
let fuc = self.tys.ins.funcs.push(FuncData {
|
||||||
file,
|
file,
|
||||||
sig: Sig { args: Tuple::empty(), ret },
|
sig: Sig { args: List::empty(), ret },
|
||||||
..Default::default()
|
..Default::default()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -1274,10 +1274,37 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
Some(Value::ptr(self.offset(bs.id, offset)).ty(f))
|
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(
|
_ => self.error(
|
||||||
base.pos(),
|
base.pos(),
|
||||||
fa!(
|
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)
|
self.ty_display(bs.ty)
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -1581,14 +1608,51 @@ impl<'a> Codegen<'a> {
|
||||||
self.gen_call(func, args, true)
|
self.gen_call(func, args, true)
|
||||||
}
|
}
|
||||||
Expr::Tupl { pos, ty, fields, .. } => {
|
Expr::Tupl { pos, ty, fields, .. } => {
|
||||||
ctx.ty = ty
|
let ty = ty
|
||||||
.map(|ty| self.ty(ty))
|
.map(|ty| self.ty(ty))
|
||||||
.or(ctx.ty.map(|ty| self.tys.inner_of(ty).unwrap_or(ty)));
|
.or(ctx.ty.map(|ty| self.tys.inner_of(ty).unwrap_or(ty)))
|
||||||
inference!(sty, ctx, self, pos, "struct or slice", "<struct_ty>.(...)");
|
.map(ty::Id::expand);
|
||||||
|
|
||||||
match sty.expand() {
|
match ty {
|
||||||
ty::Kind::Struct(s) => {
|
None => {
|
||||||
let mem = self.new_stack(pos, sty);
|
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);
|
let mut offs = OffsetIter::new(s, self.tys);
|
||||||
for field in fields {
|
for field in fields {
|
||||||
let Some((ty, offset)) = offs.next_ty(self.tys) else {
|
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)"),
|
(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 slice = &self.tys.ins.slices[s];
|
||||||
let len = slice.len().unwrap_or(fields.len());
|
let len = slice.len().unwrap_or(fields.len());
|
||||||
let elem = slice.elem;
|
let elem = slice.elem;
|
||||||
let elem_size = self.tys.size_of(elem);
|
let elem_size = self.tys.size_of(elem);
|
||||||
let aty = slice
|
let aty = slice.len().map_or_else(
|
||||||
.len()
|
|| self.tys.make_array(elem, len as ArrayLen),
|
||||||
.map_or_else(|| self.tys.make_array(elem, len as ArrayLen), |_| sty);
|
|_| s.into(),
|
||||||
|
);
|
||||||
|
|
||||||
if len != fields.len() {
|
if len != fields.len() {
|
||||||
return self.error(
|
return self.error(
|
||||||
|
@ -1651,13 +1716,13 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
Some(Value::ptr(mem).ty(aty))
|
Some(Value::ptr(mem).ty(aty))
|
||||||
}
|
}
|
||||||
_ => self.error(
|
Some(t) => self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"the {}type of the constructor is `{}`, \
|
"the {}type of the constructor is `{}`, \
|
||||||
but thats not a struct nor slice or array",
|
but thats not a struct nor slice or array",
|
||||||
if ty.is_some() { "" } else { "inferred " },
|
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::Func(_)
|
||||||
| ty::Kind::Template(_)
|
| ty::Kind::Template(_)
|
||||||
| ty::Kind::Global(_)
|
| ty::Kind::Global(_)
|
||||||
|
| ty::Kind::Tuple(_)
|
||||||
| ty::Kind::Const(_)) => self.error(
|
| ty::Kind::Const(_)) => self.error(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
|
@ -4146,6 +4212,7 @@ mod tests {
|
||||||
loops;
|
loops;
|
||||||
pointers;
|
pointers;
|
||||||
structs;
|
structs;
|
||||||
|
tuples;
|
||||||
struct_scopes;
|
struct_scopes;
|
||||||
enums;
|
enums;
|
||||||
unions;
|
unions;
|
||||||
|
|
208
lang/src/ty.rs
208
lang/src/ty.rs
|
@ -38,9 +38,9 @@ pub type Offset = u32;
|
||||||
pub type Size = u32;
|
pub type Size = u32;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, Default, PartialOrd, Ord)]
|
#[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_BITS: u32 = 5;
|
||||||
const LEN_MASK: usize = Self::MAX_LEN - 1;
|
const LEN_MASK: usize = Self::MAX_LEN - 1;
|
||||||
const MAX_LEN: usize = 1 << Self::LEN_BITS;
|
const MAX_LEN: usize = 1 << Self::LEN_BITS;
|
||||||
|
@ -104,6 +104,12 @@ impl ArgIter {
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||||
pub struct Id(NonZeroU32);
|
pub struct Id(NonZeroU32);
|
||||||
|
|
||||||
|
impl AsRef<Id> for Id {
|
||||||
|
fn as_ref(&self) -> &Id {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<Id> for i64 {
|
impl From<Id> for i64 {
|
||||||
fn from(value: Id) -> Self {
|
fn from(value: Id) -> Self {
|
||||||
value.0.get() as _
|
value.0.get() as _
|
||||||
|
@ -150,6 +156,7 @@ impl crate::ctx_map::CtxEntry for Id {
|
||||||
SymKey::Decl(gb.file.into(), gb.name)
|
SymKey::Decl(gb.file.into(), gb.name)
|
||||||
}
|
}
|
||||||
Kind::Slice(s) => SymKey::Array(&ctx.slices[s]),
|
Kind::Slice(s) => SymKey::Array(&ctx.slices[s]),
|
||||||
|
Kind::Tuple(t) => SymKey::Tuple(ctx.tuples[t].fields),
|
||||||
Kind::Module(_) | Kind::Builtin(_) => {
|
Kind::Module(_) | Kind::Builtin(_) => {
|
||||||
SymKey::Decl(Module::default().into(), Ident::INVALID)
|
SymKey::Decl(Module::default().into(), Ident::INVALID)
|
||||||
}
|
}
|
||||||
|
@ -266,22 +273,19 @@ impl Id {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
||||||
|
use Kind as K;
|
||||||
match self.expand() {
|
match self.expand() {
|
||||||
Kind::Opt(o)
|
K::Opt(o)
|
||||||
if let ty = tys.ins.opts[o].base
|
if let ty = tys.ins.opts[o].base
|
||||||
&& ty.loc(tys) == Loc::Reg
|
&& ty.loc(tys) == Loc::Reg
|
||||||
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
||||||
{
|
{
|
||||||
Loc::Reg
|
Loc::Reg
|
||||||
}
|
}
|
||||||
Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg,
|
K::Ptr(_) | K::Enum(_) | K::Builtin(_) => Loc::Reg,
|
||||||
Kind::Struct(_) | Kind::Union(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
K::Struct(_) | K::Tuple(_) | K::Union(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
||||||
Kind::Struct(_) | Kind::Union(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
K::Struct(_) | K::Tuple(_) | K::Union(_) | K::Slice(_) | K::Opt(_) => Loc::Stack,
|
||||||
c @ (Kind::Func(_)
|
c @ (K::Func(_) | K::Global(_) | K::Module(_) | K::Const(_) | K::Template(_)) => {
|
||||||
| Kind::Global(_)
|
|
||||||
| Kind::Module(_)
|
|
||||||
| Kind::Const(_)
|
|
||||||
| Kind::Template(_)) => {
|
|
||||||
unreachable!("{c:?}")
|
unreachable!("{c:?}")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -450,6 +454,7 @@ type_kind! {
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Builtin,
|
Builtin,
|
||||||
Struct,
|
Struct,
|
||||||
|
Tuple,
|
||||||
Enum,
|
Enum,
|
||||||
Union,
|
Union,
|
||||||
Ptr,
|
Ptr,
|
||||||
|
@ -514,25 +519,25 @@ impl<'a> Display<'a> {
|
||||||
|
|
||||||
impl core::fmt::Display for Display<'_> {
|
impl core::fmt::Display for Display<'_> {
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||||
use Kind as TK;
|
use Kind as K;
|
||||||
match TK::from_ty(self.ty) {
|
match K::from_ty(self.ty) {
|
||||||
TK::Module(idx) => {
|
K::Module(idx) => {
|
||||||
f.write_str("@use(\"")?;
|
f.write_str("@use(\"")?;
|
||||||
self.files[idx].path.fmt(f)?;
|
self.files[idx].path.fmt(f)?;
|
||||||
f.write_str(")[")?;
|
f.write_str(")[")?;
|
||||||
idx.fmt(f)?;
|
idx.fmt(f)?;
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
K::Builtin(ty) => f.write_str(to_str(ty)),
|
||||||
TK::Opt(ty) => {
|
K::Opt(ty) => {
|
||||||
f.write_str("?")?;
|
f.write_str("?")?;
|
||||||
self.rety(self.tys.ins.opts[ty].base).fmt(f)
|
self.rety(self.tys.ins.opts[ty].base).fmt(f)
|
||||||
}
|
}
|
||||||
TK::Ptr(ty) => {
|
K::Ptr(ty) => {
|
||||||
f.write_str("^")?;
|
f.write_str("^")?;
|
||||||
self.rety(self.tys.ins.ptrs[ty].base).fmt(f)
|
self.rety(self.tys.ins.ptrs[ty].base).fmt(f)
|
||||||
}
|
}
|
||||||
TK::Struct(idx) => {
|
K::Struct(idx) => {
|
||||||
let record = &self.tys.ins.structs[idx];
|
let record = &self.tys.ins.structs[idx];
|
||||||
if record.name.is_null() {
|
if record.name.is_null() {
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
|
@ -554,7 +559,19 @@ impl core::fmt::Display for Display<'_> {
|
||||||
f.write_str(file.ident_str(record.name))
|
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];
|
let record = &self.tys.ins.unions[idx];
|
||||||
if record.name.is_null() {
|
if record.name.is_null() {
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
|
@ -576,27 +593,27 @@ impl core::fmt::Display for Display<'_> {
|
||||||
f.write_str(file.ident_str(record.name))
|
f.write_str(file.ident_str(record.name))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
TK::Enum(idx) => {
|
K::Enum(idx) => {
|
||||||
let enm = &self.tys.ins.enums[idx];
|
let enm = &self.tys.ins.enums[idx];
|
||||||
debug_assert!(!enm.name.is_null());
|
debug_assert!(!enm.name.is_null());
|
||||||
let file = &self.files[enm.file];
|
let file = &self.files[enm.file];
|
||||||
f.write_str(file.ident_str(enm.name))
|
f.write_str(file.ident_str(enm.name))
|
||||||
}
|
}
|
||||||
TK::Func(idx) => {
|
K::Func(idx) => {
|
||||||
f.write_str("fn")?;
|
f.write_str("fn")?;
|
||||||
idx.fmt(f)
|
idx.fmt(f)
|
||||||
}
|
}
|
||||||
TK::Template(idx) => {
|
K::Template(idx) => {
|
||||||
f.write_str("fn")?;
|
f.write_str("fn")?;
|
||||||
idx.fmt(f)
|
idx.fmt(f)
|
||||||
}
|
}
|
||||||
TK::Global(idx) => {
|
K::Global(idx) => {
|
||||||
let global = &self.tys.ins.globals[idx];
|
let global = &self.tys.ins.globals[idx];
|
||||||
let file = &self.files[global.file];
|
let file = &self.files[global.file];
|
||||||
f.write_str(file.ident_str(global.name))?;
|
f.write_str(file.ident_str(global.name))?;
|
||||||
f.write_str(" (global)")
|
f.write_str(" (global)")
|
||||||
}
|
}
|
||||||
TK::Slice(idx) => {
|
K::Slice(idx) => {
|
||||||
let array = self.tys.ins.slices[idx];
|
let array = self.tys.ins.slices[idx];
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
self.rety(array.elem).fmt(f)?;
|
self.rety(array.elem).fmt(f)?;
|
||||||
|
@ -606,7 +623,7 @@ impl core::fmt::Display for Display<'_> {
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
TK::Const(idx) => {
|
K::Const(idx) => {
|
||||||
let cnst = &self.tys.ins.consts[idx];
|
let cnst = &self.tys.ins.consts[idx];
|
||||||
let file = &self.files[cnst.file];
|
let file = &self.files[cnst.file];
|
||||||
f.write_str(file.ident_str(cnst.name))?;
|
f.write_str(file.ident_str(cnst.name))?;
|
||||||
|
@ -618,9 +635,10 @@ impl core::fmt::Display for Display<'_> {
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub enum SymKey<'a> {
|
pub enum SymKey<'a> {
|
||||||
|
Tuple(List),
|
||||||
Pointer(&'a PtrData),
|
Pointer(&'a PtrData),
|
||||||
Optional(&'a OptData),
|
Optional(&'a OptData),
|
||||||
Type(Id, Pos, Tuple),
|
Type(Id, Pos, List),
|
||||||
Decl(Id, Ident),
|
Decl(Id, Ident),
|
||||||
Array(&'a ArrayData),
|
Array(&'a ArrayData),
|
||||||
Constant(&'a ConstData),
|
Constant(&'a ConstData),
|
||||||
|
@ -628,7 +646,7 @@ pub enum SymKey<'a> {
|
||||||
|
|
||||||
#[derive(Clone, Copy, Default)]
|
#[derive(Clone, Copy, Default)]
|
||||||
pub struct Sig {
|
pub struct Sig {
|
||||||
pub args: Tuple,
|
pub args: List,
|
||||||
pub ret: Id,
|
pub ret: Id,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -722,7 +740,7 @@ pub struct TypeBase {
|
||||||
pub pos: Pos,
|
pub pos: Pos,
|
||||||
pub name: Ident,
|
pub name: Ident,
|
||||||
pub field_start: u32,
|
pub field_start: u32,
|
||||||
pub captured: Tuple,
|
pub captured: List,
|
||||||
pub ast: ExprRef,
|
pub ast: ExprRef,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -764,6 +782,13 @@ pub struct StructData {
|
||||||
|
|
||||||
impl_deref!(StructData { base: TypeBase });
|
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)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub struct OptData {
|
pub struct OptData {
|
||||||
pub base: Id,
|
pub base: Id,
|
||||||
|
@ -854,6 +879,7 @@ pub struct TypeIns {
|
||||||
pub ptrs: EntVec<Ptr, PtrData>,
|
pub ptrs: EntVec<Ptr, PtrData>,
|
||||||
pub opts: EntVec<Opt, OptData>,
|
pub opts: EntVec<Opt, OptData>,
|
||||||
pub slices: EntVec<Slice, ArrayData>,
|
pub slices: EntVec<Slice, ArrayData>,
|
||||||
|
pub tuples: EntVec<Tuple, TupleData>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct FTask {
|
pub struct FTask {
|
||||||
|
@ -897,6 +923,7 @@ impl Types {
|
||||||
| Kind::Builtin(_)
|
| Kind::Builtin(_)
|
||||||
| Kind::Ptr(_)
|
| Kind::Ptr(_)
|
||||||
| Kind::Slice(_)
|
| Kind::Slice(_)
|
||||||
|
| Kind::Tuple(_)
|
||||||
| Kind::Opt(_) => utils::is_pascal_case,
|
| Kind::Opt(_) => utils::is_pascal_case,
|
||||||
Kind::Func(f)
|
Kind::Func(f)
|
||||||
if let &Expr::Closure { ret: &Expr::Ident { id, .. }, .. } =
|
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();
|
let base = self.ins.args.len();
|
||||||
self.ins.args.extend(self.tmp.args.drain(arg_base..));
|
self.ins.args.extend(self.tmp.args.drain(arg_base..));
|
||||||
let needle = &self.ins.args[base..];
|
let needle = &self.ins.args[base..];
|
||||||
if needle.is_empty() {
|
if needle.is_empty() {
|
||||||
return Some(Tuple::empty());
|
return Some(List::empty());
|
||||||
}
|
}
|
||||||
let len = needle.len();
|
let len = needle.len();
|
||||||
// FIXME: maybe later when this becomes a bottleneck we use more
|
// FIXME: maybe later when this becomes a bottleneck we use more
|
||||||
// efficient search (SIMD?, indexing?)
|
// efficient search (SIMD?, indexing?)
|
||||||
let sp = self.ins.args.windows(needle.len()).position(|val| val == needle).unwrap();
|
let sp = self.ins.args.windows(needle.len()).position(|val| val == needle).unwrap();
|
||||||
self.ins.args.truncate((sp + needle.len()).max(base));
|
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] {
|
pub fn union_fields(&self, union: Union) -> &[UnionField] {
|
||||||
|
@ -1014,6 +1041,16 @@ impl Types {
|
||||||
self.ins.structs[stru].size.set(oiter.offset);
|
self.ins.structs[stru].size.set(oiter.offset);
|
||||||
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) => {
|
Kind::Union(union) => {
|
||||||
if self.ins.unions[union].size.get() != 0 {
|
if self.ins.unions[union].size.get() != 0 {
|
||||||
return self.ins.unions[union].size.get();
|
return self.ins.unions[union].size.get();
|
||||||
|
@ -1033,8 +1070,12 @@ impl Types {
|
||||||
self.size_of(base) + self.align_of(base)
|
self.size_of(base) + self.align_of(base)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ if let Some(size) = ty.simple_size() => size,
|
Kind::Ptr(_) | Kind::Builtin(_) => ty.simple_size().unwrap(),
|
||||||
ty => unimplemented!("size_of: {:?}", ty),
|
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());
|
self.ins.structs[stru].align.set(align.try_into().unwrap());
|
||||||
align
|
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) => {
|
Kind::Slice(arr) => {
|
||||||
let arr = &self.ins.slices[arr];
|
let arr = &self.ins.slices[arr];
|
||||||
match arr.len {
|
match arr.len {
|
||||||
|
@ -1073,7 +1123,14 @@ impl Types {
|
||||||
_ => self.align_of(arr.elem),
|
_ => 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::Template(_)
|
||||||
| Kind::Global(_)
|
| Kind::Global(_)
|
||||||
| Kind::Module(_)
|
| Kind::Module(_)
|
||||||
|
| Kind::Tuple(_)
|
||||||
| Kind::Const(_) => return None,
|
| Kind::Const(_) => return None,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1186,7 +1244,7 @@ impl Types {
|
||||||
self.type_base_of(ty).map(|b| b.parent)
|
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 base = self.type_base_of(ty)?;
|
||||||
|
|
||||||
let (Expr::Struct { captured, .. }
|
let (Expr::Struct { captured, .. }
|
||||||
|
@ -1212,6 +1270,10 @@ impl Types {
|
||||||
let str = unsafe { core::mem::transmute::<&mut Vec<u8>, &mut String>(data) };
|
let str = unsafe { core::mem::transmute::<&mut Vec<u8>, &mut String>(data) };
|
||||||
write!(str, "{}", Display::new(self, files, ty)).unwrap();
|
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 {
|
pub struct OptLayout {
|
||||||
|
@ -1220,17 +1282,57 @@ pub struct OptLayout {
|
||||||
pub payload_offset: Offset,
|
pub payload_offset: Offset,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OffsetIter {
|
pub trait Agregate: Copy {
|
||||||
strct: Struct,
|
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,
|
offset: Offset,
|
||||||
fields: Range<usize>,
|
fields: Range<usize>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OffsetIter {
|
impl OffsetIter<Struct> {
|
||||||
pub fn new(strct: Struct, tys: &Types) -> Self {
|
|
||||||
Self { strct, offset: 0, fields: tys.struct_field_range(strct) }
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn offset_of(tys: &Types, idx: Struct, field: &str) -> Option<(Offset, Id)> {
|
pub fn offset_of(tys: &Types, idx: Struct, field: &str) -> Option<(Offset, Id)> {
|
||||||
let field_id = tys.names.project(field)?;
|
let field_id = tys.names.project(field)?;
|
||||||
OffsetIter::new(idx, tys)
|
OffsetIter::new(idx, tys)
|
||||||
|
@ -1238,25 +1340,33 @@ impl OffsetIter {
|
||||||
.find(|(f, _)| f.name == field_id)
|
.find(|(f, _)| f.name == field_id)
|
||||||
.map(|(f, off)| (off, f.ty))
|
.map(|(f, off)| (off, f.ty))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn next<'a>(&mut self, tys: &'a Types) -> Option<(&'a StructField, Offset)> {
|
impl<T: Agregate> OffsetIter<T> {
|
||||||
let stru = &tys.ins.structs[self.strct];
|
pub fn new(strct: T, tys: &Types) -> Self {
|
||||||
let field = &tys.ins.struct_fields[self.fields.next()?];
|
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);
|
self.offset = (self.offset + align - 1) & !(align - 1);
|
||||||
|
|
||||||
let off = self.offset;
|
let off = self.offset;
|
||||||
self.offset += tys.size_of(field.ty);
|
self.offset += tys.size_of(*field.as_ref());
|
||||||
Some((field, off))
|
Some((field, off))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_ty(&mut self, tys: &Types) -> Option<(Id, Offset)> {
|
pub fn next_ty(&mut self, tys: &Types) -> Option<(Id, Offset)> {
|
||||||
let (field, off) = self.next(tys)?;
|
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))
|
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