forked from AbleOS/holey-bytes
arrays work i guess
This commit is contained in:
parent
25bbe247e9
commit
4f9d4f2e71
|
@ -312,6 +312,18 @@ fib_iter := fn(n: int): int {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### arrays
|
||||||
|
```hb
|
||||||
|
main := fn(): int {
|
||||||
|
arr := [int].(1, 2, 4);
|
||||||
|
return pass(&arr);
|
||||||
|
}
|
||||||
|
|
||||||
|
pass := fn(arr: ^[int; 3]): int {
|
||||||
|
return arr[0] + arr[1] + arr[arr[1]];
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Incomplete Examples
|
### Incomplete Examples
|
||||||
|
|
||||||
#### generic_types
|
#### generic_types
|
||||||
|
|
|
@ -13,6 +13,7 @@ use {
|
||||||
|
|
||||||
type Offset = u32;
|
type Offset = u32;
|
||||||
type Size = u32;
|
type Size = u32;
|
||||||
|
type ArrayLen = u32;
|
||||||
|
|
||||||
mod stack {
|
mod stack {
|
||||||
use {
|
use {
|
||||||
|
@ -192,6 +193,7 @@ mod reg {
|
||||||
pub mod ty {
|
pub mod ty {
|
||||||
use {
|
use {
|
||||||
crate::{
|
crate::{
|
||||||
|
codegen::ArrayLen,
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser::{self, Expr},
|
parser::{self, Expr},
|
||||||
},
|
},
|
||||||
|
@ -205,6 +207,7 @@ pub mod ty {
|
||||||
pub type Global = u32;
|
pub type Global = u32;
|
||||||
pub type Module = u32;
|
pub type Module = u32;
|
||||||
pub type Param = u32;
|
pub type Param = u32;
|
||||||
|
pub type Slice = u32;
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct Tuple(pub u32);
|
pub struct Tuple(pub u32);
|
||||||
|
@ -416,6 +419,7 @@ pub mod ty {
|
||||||
Func,
|
Func,
|
||||||
Global,
|
Global,
|
||||||
Module,
|
Module,
|
||||||
|
Slice,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -454,7 +458,7 @@ pub mod ty {
|
||||||
.tys
|
.tys
|
||||||
.syms
|
.syms
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(sym, &ty)| sym.file != u32::MAX && ty == self.ty)
|
.find(|(sym, &ty)| sym.file < self.files.len() as u32 && ty == self.ty)
|
||||||
&& let Some(name) = self.files[key.file as usize].exprs().iter().find_map(
|
&& let Some(name) = self.files[key.file as usize].exprs().iter().find_map(
|
||||||
|expr| match expr {
|
|expr| match expr {
|
||||||
Expr::BinOp {
|
Expr::BinOp {
|
||||||
|
@ -481,6 +485,13 @@ pub mod ty {
|
||||||
}
|
}
|
||||||
TK::Func(idx) => write!(f, "fn{idx}"),
|
TK::Func(idx) => write!(f, "fn{idx}"),
|
||||||
TK::Global(idx) => write!(f, "global{idx}"),
|
TK::Global(idx) => write!(f, "global{idx}"),
|
||||||
|
TK::Slice(idx) => {
|
||||||
|
let array = self.tys.arrays[idx as usize];
|
||||||
|
match array.len {
|
||||||
|
ArrayLen::MAX => write!(f, "[{}]", self.rety(array.ty)),
|
||||||
|
len => write!(f, "[{}; {len}]", self.rety(array.ty)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -852,6 +863,12 @@ impl ParamAlloc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy)]
|
||||||
|
struct Array {
|
||||||
|
ty: ty::Id,
|
||||||
|
len: ArrayLen,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct Types {
|
struct Types {
|
||||||
syms: HashMap<SymKey, ty::Id>,
|
syms: HashMap<SymKey, ty::Id>,
|
||||||
|
@ -861,6 +878,7 @@ struct Types {
|
||||||
globals: Vec<Global>,
|
globals: Vec<Global>,
|
||||||
structs: Vec<Struct>,
|
structs: Vec<Struct>,
|
||||||
ptrs: Vec<Ptr>,
|
ptrs: Vec<Ptr>,
|
||||||
|
arrays: Vec<Array>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Types {
|
impl Types {
|
||||||
|
@ -896,6 +914,29 @@ impl Types {
|
||||||
.inner()
|
.inner()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn make_array(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Id {
|
||||||
|
ty::Kind::Slice(self.make_array_low(ty, len)).compress()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice {
|
||||||
|
let id = SymKey {
|
||||||
|
file: match len {
|
||||||
|
ArrayLen::MAX => ArrayLen::MAX - 1,
|
||||||
|
len => ArrayLen::MAX - len - 2,
|
||||||
|
},
|
||||||
|
ident: ty.repr(),
|
||||||
|
};
|
||||||
|
|
||||||
|
self.syms
|
||||||
|
.entry(id)
|
||||||
|
.or_insert_with(|| {
|
||||||
|
self.arrays.push(Array { ty, len });
|
||||||
|
ty::Kind::Slice(self.arrays.len() as u32 - 1).compress()
|
||||||
|
})
|
||||||
|
.expand()
|
||||||
|
.inner()
|
||||||
|
}
|
||||||
|
|
||||||
fn align_up(value: Size, align: Size) -> Size {
|
fn align_up(value: Size, align: Size) -> Size {
|
||||||
(value + align - 1) & !(align - 1)
|
(value + align - 1) & !(align - 1)
|
||||||
}
|
}
|
||||||
|
@ -909,9 +950,17 @@ impl Types {
|
||||||
ty::Kind::Builtin(ty::I32 | ty::U32 | ty::TYPE) => 4,
|
ty::Kind::Builtin(ty::I32 | ty::U32 | ty::TYPE) => 4,
|
||||||
ty::Kind::Builtin(ty::I16 | ty::U16) => 2,
|
ty::Kind::Builtin(ty::I16 | ty::U16) => 2,
|
||||||
ty::Kind::Builtin(ty::I8 | ty::U8 | ty::BOOL) => 1,
|
ty::Kind::Builtin(ty::I8 | ty::U8 | ty::BOOL) => 1,
|
||||||
ty::Kind::Struct(ty) => {
|
ty::Kind::Slice(arr) => {
|
||||||
|
let arr = &self.arrays[arr as usize];
|
||||||
|
match arr.len {
|
||||||
|
0 => 0,
|
||||||
|
ArrayLen::MAX => 16,
|
||||||
|
len => self.size_of(arr.ty) * len,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Kind::Struct(stru) => {
|
||||||
let mut offset = 0u32;
|
let mut offset = 0u32;
|
||||||
let record = &self.structs[ty as usize];
|
let record = &self.structs[stru as usize];
|
||||||
for &Field { ty, .. } in record.fields.iter() {
|
for &Field { ty, .. } in record.fields.iter() {
|
||||||
let align = self.align_of(ty);
|
let align = self.align_of(ty);
|
||||||
offset = Self::align_up(offset, align);
|
offset = Self::align_up(offset, align);
|
||||||
|
@ -925,12 +974,19 @@ impl Types {
|
||||||
|
|
||||||
fn align_of(&self, ty: ty::Id) -> Size {
|
fn align_of(&self, ty: ty::Id) -> Size {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
ty::Kind::Struct(t) => self.structs[t as usize]
|
ty::Kind::Struct(stru) => self.structs[stru as usize]
|
||||||
.fields
|
.fields
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&Field { ty, .. }| self.align_of(ty))
|
.map(|&Field { ty, .. }| self.align_of(ty))
|
||||||
.max()
|
.max()
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
|
ty::Kind::Slice(arr) => {
|
||||||
|
let arr = &self.arrays[arr as usize];
|
||||||
|
match arr.len {
|
||||||
|
ArrayLen::MAX => 8,
|
||||||
|
_ => self.align_of(arr.ty),
|
||||||
|
}
|
||||||
|
}
|
||||||
_ => self.size_of(ty).max(1),
|
_ => self.size_of(ty).max(1),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1275,6 +1331,60 @@ impl Codegen {
|
||||||
Some(val)
|
Some(val)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
E::Slice { size, item, .. } => {
|
||||||
|
let ty = self.ty(item);
|
||||||
|
let len = size.map_or(ArrayLen::MAX, |expr| self.eval_const(expr, ty::U32) as _);
|
||||||
|
Some(Value::ty(self.tys.make_array(ty, len)))
|
||||||
|
}
|
||||||
|
E::Index { base, index } => {
|
||||||
|
// TODO: we need to check if index is in bounds on debug builds
|
||||||
|
|
||||||
|
let mut base_val = self.expr(base)?;
|
||||||
|
base_val.loc = self.make_loc_owned(base_val.loc, base_val.ty);
|
||||||
|
let index_val = self.expr(index)?;
|
||||||
|
_ = self.assert_ty(index.pos(), index_val.ty, ty::INT.into());
|
||||||
|
|
||||||
|
if let ty::Kind::Ptr(ty) = base_val.ty.expand() {
|
||||||
|
base_val.ty = self.tys.ptrs[ty as usize].base;
|
||||||
|
base_val.loc = base_val.loc.into_derefed();
|
||||||
|
}
|
||||||
|
|
||||||
|
match base_val.ty.expand() {
|
||||||
|
ty::Kind::Slice(arr) => {
|
||||||
|
let ty = self.tys.arrays[arr as usize].ty;
|
||||||
|
let item_size = self.tys.size_of(ty);
|
||||||
|
|
||||||
|
let Loc::Rt { derefed: true, ref mut reg, ref stack, offset } =
|
||||||
|
base_val.loc
|
||||||
|
else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
if reg.is_ref() {
|
||||||
|
let new_reg = self.ci.regs.allocate();
|
||||||
|
self.stack_offset(new_reg.get(), reg.get(), stack.as_ref(), offset);
|
||||||
|
*reg = new_reg;
|
||||||
|
} else {
|
||||||
|
self.stack_offset(reg.get(), reg.get(), stack.as_ref(), offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
let idx = self.loc_to_reg(index_val.loc, 8);
|
||||||
|
|
||||||
|
self.output.emit(muli64(idx.get(), idx.get(), item_size as _));
|
||||||
|
self.output.emit(add64(reg.get(), reg.get(), idx.get()));
|
||||||
|
self.ci.regs.free(idx);
|
||||||
|
|
||||||
|
Some(Value::new(ty, base_val.loc))
|
||||||
|
}
|
||||||
|
_ => self.report(
|
||||||
|
base.pos(),
|
||||||
|
format_args!(
|
||||||
|
"compiler did not (yet) learn how to index into '{}'",
|
||||||
|
self.ty_display(base_val.ty)
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
E::UnOp { op: T::Xor, val, .. } => {
|
E::UnOp { op: T::Xor, val, .. } => {
|
||||||
let val = self.ty(val);
|
let val = self.ty(val);
|
||||||
Some(Value::ty(self.tys.make_ptr(val)))
|
Some(Value::ty(self.tys.make_ptr(val)))
|
||||||
|
@ -1448,33 +1558,61 @@ impl Codegen {
|
||||||
Some(Value::new(self.tys.make_ptr(ty::U8.into()), reg))
|
Some(Value::new(self.tys.make_ptr(ty::U8.into()), reg))
|
||||||
}
|
}
|
||||||
E::Ctor { pos, ty, fields, .. } => {
|
E::Ctor { pos, ty, fields, .. } => {
|
||||||
let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
|
let (ty, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
|
||||||
|
|
||||||
|
let ty::Kind::Struct(stru) = ty.expand() else {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
"our current technology does not (yet) allow\
|
||||||
|
us to construct '{}' with struct constructor",
|
||||||
|
);
|
||||||
|
};
|
||||||
for &CtorField { pos, name, ref value, .. } in fields {
|
for &CtorField { pos, name, ref value, .. } in fields {
|
||||||
let Some((offset, ty)) = self.tys.offset_of(stuct, name) else {
|
let Some((offset, ty)) = self.tys.offset_of(stru, name) else {
|
||||||
self.report(pos, format_args!("field not found: {name:?}"));
|
self.report(pos, format_args!("field not found: {name:?}"));
|
||||||
};
|
};
|
||||||
let loc = loc.as_ref().offset(offset);
|
let loc = loc.as_ref().offset(offset);
|
||||||
let value = self.expr_ctx(value, Ctx::default().with_loc(loc).with_ty(ty))?;
|
let value = self.expr_ctx(value, Ctx::default().with_loc(loc).with_ty(ty))?;
|
||||||
self.ci.free_loc(value.loc);
|
self.ci.free_loc(value.loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = ty::Kind::Struct(stuct).compress();
|
|
||||||
return Some(Value { ty, loc });
|
return Some(Value { ty, loc });
|
||||||
}
|
}
|
||||||
E::Tupl { pos, ty, fields, .. } => {
|
E::Tupl { pos, ty, fields, .. } => {
|
||||||
let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
|
let (ty, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
|
||||||
let mut offset = 0;
|
|
||||||
let sfields = self.tys.structs[stuct as usize].fields.clone();
|
match ty.expand() {
|
||||||
for (sfield, field) in sfields.iter().zip(fields) {
|
ty::Kind::Struct(stru) => {
|
||||||
let loc = loc.as_ref().offset(offset);
|
let mut offset = 0;
|
||||||
let ctx = Ctx::default().with_loc(loc).with_ty(sfield.ty);
|
let sfields = self.tys.structs[stru as usize].fields.clone();
|
||||||
let value = self.expr_ctx(field, ctx)?;
|
for (sfield, field) in sfields.iter().zip(fields) {
|
||||||
self.ci.free_loc(value.loc);
|
let loc = loc.as_ref().offset(offset);
|
||||||
offset += self.tys.size_of(sfield.ty);
|
let ctx = Ctx::default().with_loc(loc).with_ty(sfield.ty);
|
||||||
offset = Types::align_up(offset, self.tys.align_of(sfield.ty));
|
let value = self.expr_ctx(field, ctx)?;
|
||||||
|
self.ci.free_loc(value.loc);
|
||||||
|
offset += self.tys.size_of(sfield.ty);
|
||||||
|
offset = Types::align_up(offset, self.tys.align_of(sfield.ty));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ty::Kind::Slice(arr) => {
|
||||||
|
let arr = &self.tys.arrays[arr as usize];
|
||||||
|
let item_size = self.tys.size_of(arr.ty);
|
||||||
|
for (i, value) in fields.iter().enumerate() {
|
||||||
|
let loc = loc.as_ref().offset(i as u32 * item_size);
|
||||||
|
let value =
|
||||||
|
self.expr_ctx(value, Ctx::default().with_loc(loc).with_ty(ty))?;
|
||||||
|
self.ci.free_loc(value.loc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.report(
|
||||||
|
pos,
|
||||||
|
format_args!(
|
||||||
|
"compiler does not (yet) know how to initialize\
|
||||||
|
'{}' with tuple constructor",
|
||||||
|
self.ty_display(ty)
|
||||||
|
),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
let ty = ty::Kind::Struct(stuct).compress();
|
|
||||||
return Some(Value { ty, loc });
|
return Some(Value { ty, loc });
|
||||||
}
|
}
|
||||||
E::Field { target, name: field } => {
|
E::Field { target, name: field } => {
|
||||||
|
@ -1932,6 +2070,45 @@ impl Codegen {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn eval_const(&mut self, expr: &Expr, ty: impl Into<ty::Id>) -> u64 {
|
||||||
|
let mut ci = ItemCtx {
|
||||||
|
file: self.ci.file,
|
||||||
|
id: self.ci.id,
|
||||||
|
ret: ty.into(),
|
||||||
|
..self.pool.cis.pop().unwrap_or_default()
|
||||||
|
};
|
||||||
|
ci.vars.append(&mut self.ci.vars);
|
||||||
|
|
||||||
|
let loc = self.ct_eval(ci, |s, prev| {
|
||||||
|
s.output.emit_prelude();
|
||||||
|
|
||||||
|
if s.expr_ctx(
|
||||||
|
&Expr::Return { pos: 0, val: Some(expr) },
|
||||||
|
Ctx::default().with_ty(s.ci.ret),
|
||||||
|
)
|
||||||
|
.is_some()
|
||||||
|
{
|
||||||
|
s.report(expr.pos(), "we fucked up");
|
||||||
|
};
|
||||||
|
|
||||||
|
let stash = s.complete_call_graph();
|
||||||
|
|
||||||
|
s.push_stash(stash);
|
||||||
|
|
||||||
|
s.dunp_imported_fns();
|
||||||
|
|
||||||
|
prev.vars.append(&mut s.ci.vars);
|
||||||
|
s.ci.finalize(&mut s.output);
|
||||||
|
s.output.emit(tx());
|
||||||
|
|
||||||
|
Ok(1)
|
||||||
|
});
|
||||||
|
|
||||||
|
match loc {
|
||||||
|
Ok(i) | Err(i) => self.ct.vm.read_reg(i).cast::<u64>(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn assign_pattern(&mut self, pat: &Expr, right: Value) -> Option<Value> {
|
fn assign_pattern(&mut self, pat: &Expr, right: Value) -> Option<Value> {
|
||||||
match *pat {
|
match *pat {
|
||||||
Expr::Ident { id, .. } => {
|
Expr::Ident { id, .. } => {
|
||||||
|
@ -1977,23 +2154,41 @@ impl Codegen {
|
||||||
ctx: Ctx,
|
ctx: Ctx,
|
||||||
ty: Option<&Expr>,
|
ty: Option<&Expr>,
|
||||||
field_len: usize,
|
field_len: usize,
|
||||||
) -> (ty::Struct, Loc) {
|
) -> (ty::Id, Loc) {
|
||||||
let Some(ty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
let Some(mut ty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
||||||
self.report(pos, "expected type, (it cannot be inferred)");
|
self.report(pos, "expected type, (it cannot be inferred)");
|
||||||
};
|
};
|
||||||
|
|
||||||
let size = self.tys.size_of(ty);
|
match ty.expand() {
|
||||||
let loc = ctx.loc.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size)));
|
ty::Kind::Struct(stru) => {
|
||||||
let ty::Kind::Struct(stuct) = ty.expand() else {
|
let field_count = self.tys.structs[stru as usize].fields.len();
|
||||||
self.report(pos, "expected expression to evaluate to struct")
|
if field_count != field_len {
|
||||||
};
|
self.report(
|
||||||
|
pos,
|
||||||
let field_count = self.tys.structs[stuct as usize].fields.len();
|
format_args!("expected {field_count} fields, got {field_len}"),
|
||||||
if field_count != field_len {
|
);
|
||||||
self.report(pos, format_args!("expected {field_count} fields, got {field_len}"));
|
}
|
||||||
|
}
|
||||||
|
ty::Kind::Slice(arr) => {
|
||||||
|
let arr = &self.tys.arrays[arr as usize];
|
||||||
|
if arr.len == ArrayLen::MAX {
|
||||||
|
ty = self.tys.make_array(arr.ty, field_len as _);
|
||||||
|
} else if arr.len != field_len as u32 {
|
||||||
|
self.report(
|
||||||
|
pos,
|
||||||
|
format_args!(
|
||||||
|
"literal has {} elements, but explicit array type has {} elements",
|
||||||
|
arr.len, field_len
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => self.report(pos, "expected expression to evaluate to struct (or array maybe)"),
|
||||||
}
|
}
|
||||||
|
|
||||||
(stuct, loc)
|
let size = self.tys.size_of(ty);
|
||||||
|
let loc = ctx.loc.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size)));
|
||||||
|
(ty, loc)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_op(
|
fn struct_op(
|
||||||
|
@ -2505,42 +2700,7 @@ impl Codegen {
|
||||||
|
|
||||||
// TODO: sometimes its better to do this in bulk
|
// TODO: sometimes its better to do this in bulk
|
||||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||||
let mut ci = ItemCtx {
|
ty::Id::from(self.eval_const(expr, ty::TYPE).to_ne_bytes())
|
||||||
file: self.ci.file,
|
|
||||||
id: self.ci.id,
|
|
||||||
ret: ty::TYPE.into(),
|
|
||||||
..self.pool.cis.pop().unwrap_or_default()
|
|
||||||
};
|
|
||||||
ci.vars.append(&mut self.ci.vars);
|
|
||||||
|
|
||||||
let loc = self.ct_eval(ci, |s, prev| {
|
|
||||||
s.output.emit_prelude();
|
|
||||||
|
|
||||||
if s.expr_ctx(
|
|
||||||
&Expr::Return { pos: 0, val: Some(expr) },
|
|
||||||
Ctx::default().with_ty(ty::TYPE),
|
|
||||||
)
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
s.report(expr.pos(), "we fucked up");
|
|
||||||
};
|
|
||||||
|
|
||||||
let stash = s.complete_call_graph();
|
|
||||||
|
|
||||||
s.push_stash(stash);
|
|
||||||
|
|
||||||
s.dunp_imported_fns();
|
|
||||||
|
|
||||||
prev.vars.append(&mut s.ci.vars);
|
|
||||||
s.ci.finalize(&mut s.output);
|
|
||||||
s.output.emit(tx());
|
|
||||||
|
|
||||||
Ok(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
ty::Id::from(match loc {
|
|
||||||
Ok(reg) | Err(reg) => self.ct.vm.read_reg(reg).cast::<u64>().to_ne_bytes(),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_ecall(&mut self) {
|
fn handle_ecall(&mut self) {
|
||||||
|
@ -2970,5 +3130,6 @@ mod tests {
|
||||||
generic_functions => README;
|
generic_functions => README;
|
||||||
c_strings => README;
|
c_strings => README;
|
||||||
struct_patterns => README;
|
struct_patterns => README;
|
||||||
|
arrays => README;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -354,16 +354,19 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
},
|
},
|
||||||
T::Ctor => self.ctor(token.start, None),
|
T::Ctor => self.ctor(token.start, None),
|
||||||
T::Tupl => self.tupl(token.start, None),
|
T::Tupl => self.tupl(token.start, None),
|
||||||
|
T::LBrack => E::Slice {
|
||||||
|
item: self.ptr_unit_expr(),
|
||||||
|
size: self.advance_if(T::Semi).then(|| self.ptr_expr()),
|
||||||
|
pos: {
|
||||||
|
self.expect_advance(T::RBrack);
|
||||||
|
token.start
|
||||||
|
},
|
||||||
|
},
|
||||||
T::Band | T::Mul | T::Xor => E::UnOp {
|
T::Band | T::Mul | T::Xor => E::UnOp {
|
||||||
pos: token.start,
|
pos: token.start,
|
||||||
op: token.kind,
|
op: token.kind,
|
||||||
val: {
|
val: {
|
||||||
let expr = if token.kind == T::Xor {
|
let expr = self.ptr_unit_expr();
|
||||||
let expr = self.expr();
|
|
||||||
self.arena.alloc(expr)
|
|
||||||
} else {
|
|
||||||
self.ptr_unit_expr()
|
|
||||||
};
|
|
||||||
if token.kind == T::Band {
|
if token.kind == T::Band {
|
||||||
self.flag_idents(*expr, idfl::REFERENCED);
|
self.flag_idents(*expr, idfl::REFERENCED);
|
||||||
}
|
}
|
||||||
|
@ -392,7 +395,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let token = self.token;
|
let token = self.token;
|
||||||
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl) {
|
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::LBrack) {
|
||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -404,6 +407,14 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
},
|
},
|
||||||
T::Ctor => self.ctor(token.start, Some(expr)),
|
T::Ctor => self.ctor(token.start, Some(expr)),
|
||||||
T::Tupl => self.tupl(token.start, Some(expr)),
|
T::Tupl => self.tupl(token.start, Some(expr)),
|
||||||
|
T::LBrack => E::Index {
|
||||||
|
base: self.arena.alloc(expr),
|
||||||
|
index: {
|
||||||
|
let index = self.expr();
|
||||||
|
self.expect_advance(T::RBrack);
|
||||||
|
self.arena.alloc(index)
|
||||||
|
},
|
||||||
|
},
|
||||||
T::Dot => E::Field {
|
T::Dot => E::Field {
|
||||||
target: self.arena.alloc(expr),
|
target: self.arena.alloc(expr),
|
||||||
name: {
|
name: {
|
||||||
|
@ -682,6 +693,15 @@ generate_expr! {
|
||||||
fields: &'a [Self],
|
fields: &'a [Self],
|
||||||
trailing_comma: bool,
|
trailing_comma: bool,
|
||||||
},
|
},
|
||||||
|
Slice {
|
||||||
|
pos: Pos,
|
||||||
|
size: Option<&'a Self>,
|
||||||
|
item: &'a Self,
|
||||||
|
},
|
||||||
|
Index {
|
||||||
|
base: &'a Self,
|
||||||
|
index: &'a Self,
|
||||||
|
},
|
||||||
Field {
|
Field {
|
||||||
target: &'a Self,
|
target: &'a Self,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
|
@ -888,6 +908,11 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
write!(f, ".(")?;
|
write!(f, ".(")?;
|
||||||
fmt_list(f, trailing_comma, ")", fields, std::fmt::Display::fmt)
|
fmt_list(f, trailing_comma, ")", fields, std::fmt::Display::fmt)
|
||||||
}
|
}
|
||||||
|
Self::Slice { item, size, .. } => match size {
|
||||||
|
Some(size) => write!(f, "[{size}]{item}"),
|
||||||
|
None => write!(f, "[]{item}"),
|
||||||
|
},
|
||||||
|
Self::Index { base, index } => write!(f, "{base}[{index}]"),
|
||||||
Self::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)),
|
Self::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)),
|
||||||
Self::Break { .. } => write!(f, "break"),
|
Self::Break { .. } => write!(f, "break"),
|
||||||
Self::Continue { .. } => write!(f, "continue"),
|
Self::Continue { .. } => write!(f, "continue"),
|
||||||
|
|
3
hblang/tests/codegen_tests_arrays.txt
Normal file
3
hblang/tests/codegen_tests_arrays.txt
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
code size: 418
|
||||||
|
ret: 7
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue