forked from AbleOS/holey-bytes
on the journey twards struct destruct
This commit is contained in:
parent
fa41c56cb3
commit
880cd66c66
|
@ -173,7 +173,8 @@ main := fn(): int {
|
|||
}
|
||||
|
||||
pass := fn(t: ^Ty): int {
|
||||
return t.a - t.b;
|
||||
.{ a, b } := *t;
|
||||
return a - b;
|
||||
}
|
||||
|
||||
odher_pass := fn(t: Ty2): Ty2 {
|
||||
|
|
|
@ -1584,34 +1584,38 @@ impl Codegen {
|
|||
E::Ctor {
|
||||
pos, ty, fields, ..
|
||||
} => {
|
||||
let Some(ty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
||||
self.report(pos, "expected type, (it cannot be inferred)");
|
||||
};
|
||||
let size = self.tys.size_of(ty);
|
||||
|
||||
let loc = ctx
|
||||
.loc
|
||||
.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size)));
|
||||
let ty::Kind::Struct(stuct) = ty.expand() else {
|
||||
self.report(pos, "expected expression to evaluate to struct")
|
||||
};
|
||||
let field_count = self.tys.structs[stuct as usize].fields.len();
|
||||
if field_count != fields.len() {
|
||||
self.report(
|
||||
pos,
|
||||
format_args!("expected {} fields, got {}", field_count, fields.len()),
|
||||
);
|
||||
}
|
||||
|
||||
for (i, (name, field)) in fields.iter().enumerate() {
|
||||
let Some((offset, ty)) = self.tys.offset_of(stuct, name.ok_or(i)) else {
|
||||
let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
|
||||
for (name, field) in fields {
|
||||
let Some((offset, ty)) = self.tys.offset_of(stuct, Ok(name)) else {
|
||||
self.report(pos, format_args!("field not found: {name:?}"));
|
||||
};
|
||||
let loc = loc.as_ref().offset(offset);
|
||||
let value = self.expr_ctx(field, Ctx::default().with_loc(loc).with_ty(ty))?;
|
||||
let value = self.expr_ctx(
|
||||
field.as_ref().expect("TODO"),
|
||||
Ctx::default().with_loc(loc).with_ty(ty),
|
||||
)?;
|
||||
self.ci.free_loc(value.loc);
|
||||
}
|
||||
|
||||
let ty = ty::Kind::Struct(stuct).compress();
|
||||
return Some(Value { ty, loc });
|
||||
}
|
||||
E::Tupl {
|
||||
pos, ty, fields, ..
|
||||
} => {
|
||||
let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
|
||||
let mut offset = 0;
|
||||
let sfields = self.tys.structs[stuct as usize].fields.clone();
|
||||
for (sfield, field) in sfields.iter().zip(fields) {
|
||||
let loc = loc.as_ref().offset(offset);
|
||||
let ctx = Ctx::default().with_loc(loc).with_ty(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));
|
||||
}
|
||||
|
||||
let ty = ty::Kind::Struct(stuct).compress();
|
||||
return Some(Value { ty, loc });
|
||||
}
|
||||
E::Field { target, field } => {
|
||||
|
@ -2138,6 +2142,36 @@ impl Codegen {
|
|||
})
|
||||
}
|
||||
|
||||
fn prepare_struct_ctor(
|
||||
&mut self,
|
||||
pos: Pos,
|
||||
ctx: Ctx,
|
||||
ty: Option<&Expr>,
|
||||
field_len: usize,
|
||||
) -> (ty::Struct, Loc) {
|
||||
let Some(ty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else {
|
||||
self.report(pos, "expected type, (it cannot be inferred)");
|
||||
};
|
||||
|
||||
let size = self.tys.size_of(ty);
|
||||
let loc = ctx
|
||||
.loc
|
||||
.unwrap_or_else(|| Loc::stack(self.ci.stack.allocate(size)));
|
||||
let ty::Kind::Struct(stuct) = ty.expand() else {
|
||||
self.report(pos, "expected expression to evaluate to struct")
|
||||
};
|
||||
|
||||
let field_count = self.tys.structs[stuct as usize].fields.len();
|
||||
if field_count != field_len {
|
||||
self.report(
|
||||
pos,
|
||||
format_args!("expected {field_count} fields, got {field_len}"),
|
||||
);
|
||||
}
|
||||
|
||||
(stuct, loc)
|
||||
}
|
||||
|
||||
fn struct_op(
|
||||
&mut self,
|
||||
op: TokenKind,
|
||||
|
@ -2743,13 +2777,13 @@ impl Codegen {
|
|||
}
|
||||
|
||||
fn handle_ecall(&mut self) {
|
||||
let local_pc = (self.ct.vm.pc.get() as usize - self.output.code.as_ptr() as usize)
|
||||
.checked_sub(self.ci.snap.code);
|
||||
|
||||
let arr = self.ct.vm.pc.get() as *const Trap;
|
||||
let trap = unsafe { std::ptr::read_unaligned(arr) };
|
||||
self.ct.vm.pc = self.ct.vm.pc.wrapping_add(std::mem::size_of::<Trap>());
|
||||
|
||||
let local_pc = (self.ct.vm.pc.get() as usize - self.output.code.as_ptr() as usize)
|
||||
.checked_sub(self.ci.snap.code);
|
||||
|
||||
match trap {
|
||||
Trap::MakeStruct { file, struct_expr } => {
|
||||
let cfile = self.files[file as usize].clone();
|
||||
|
@ -2783,10 +2817,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
if let Some(lpc) = local_pc {
|
||||
let offset = std::mem::size_of::<Trap>()
|
||||
+ lpc
|
||||
+ self.ci.snap.code
|
||||
+ self.output.code.as_ptr() as usize;
|
||||
let offset = lpc + self.ci.snap.code + self.output.code.as_ptr() as usize;
|
||||
self.ct.vm.pc = hbvm::mem::Address::new(offset as _);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -341,6 +341,8 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
},
|
||||
body: self.ptr_expr(),
|
||||
},
|
||||
T::Ctor => self.ctor(token.start, None),
|
||||
T::Tupl => self.tupl(token.start, None),
|
||||
T::Band | T::Mul | T::Xor => E::UnOp {
|
||||
pos: token.start,
|
||||
op: token.kind,
|
||||
|
@ -392,23 +394,8 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
args: self.collect_list(T::Comma, T::RParen, Self::expr),
|
||||
trailing_comma: std::mem::take(&mut self.trailing_sep),
|
||||
},
|
||||
T::Ctor => E::Ctor {
|
||||
pos: token.start,
|
||||
ty: Some(self.arena.alloc(expr)),
|
||||
fields: self.collect_list(T::Comma, T::RBrace, |s| {
|
||||
let name = s.expect_advance(T::Ident);
|
||||
s.expect_advance(T::Colon);
|
||||
let val = s.expr();
|
||||
(Some(s.move_str(name)), val)
|
||||
}),
|
||||
trailing_comma: std::mem::take(&mut self.trailing_sep),
|
||||
},
|
||||
T::Tupl => E::Ctor {
|
||||
pos: token.start,
|
||||
ty: Some(self.arena.alloc(expr)),
|
||||
fields: self.collect_list(T::Comma, T::RParen, |s| (None, s.expr())),
|
||||
trailing_comma: std::mem::take(&mut self.trailing_sep),
|
||||
},
|
||||
T::Ctor => self.ctor(token.start, Some(expr)),
|
||||
T::Tupl => self.tupl(token.start, Some(expr)),
|
||||
T::Dot => E::Field {
|
||||
target: self.arena.alloc(expr),
|
||||
field: {
|
||||
|
@ -431,6 +418,28 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
expr
|
||||
}
|
||||
|
||||
fn tupl(&mut self, pos: Pos, ty: Option<Expr<'a>>) -> Expr<'a> {
|
||||
Expr::Tupl {
|
||||
pos,
|
||||
ty: ty.map(|ty| self.arena.alloc(ty)),
|
||||
fields: self.collect_list(TokenKind::Comma, TokenKind::RParen, Self::expr),
|
||||
trailing_comma: std::mem::take(&mut self.trailing_sep),
|
||||
}
|
||||
}
|
||||
|
||||
fn ctor(&mut self, pos: Pos, ty: Option<Expr<'a>>) -> Expr<'a> {
|
||||
Expr::Ctor {
|
||||
pos,
|
||||
ty: ty.map(|ty| self.arena.alloc(ty)),
|
||||
fields: self.collect_list(TokenKind::Comma, TokenKind::RBrace, |s| {
|
||||
let name = s.advance_ident();
|
||||
let value = s.advance_if(TokenKind::Colon).then(|| s.expr());
|
||||
(s.move_str(name), value)
|
||||
}),
|
||||
trailing_comma: std::mem::take(&mut self.trailing_sep),
|
||||
}
|
||||
}
|
||||
|
||||
fn advance_ident(&mut self) -> Token {
|
||||
if matches!(self.token.kind, TokenKind::Ident | TokenKind::CtIdent) {
|
||||
self.next()
|
||||
|
@ -661,7 +670,13 @@ generate_expr! {
|
|||
Ctor {
|
||||
pos: Pos,
|
||||
ty: Option<&'a Self>,
|
||||
fields: &'a [(Option<&'a str>, Self)],
|
||||
fields: &'a [(&'a str, Option<Self>)],
|
||||
trailing_comma: bool,
|
||||
},
|
||||
Tupl {
|
||||
pos: Pos,
|
||||
ty: Option<&'a Self>,
|
||||
fields: &'a [Self],
|
||||
trailing_comma: bool,
|
||||
},
|
||||
Field {
|
||||
|
@ -720,26 +735,22 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
|
||||
fn fmt_list<T>(
|
||||
f: &mut std::fmt::Formatter,
|
||||
trailing: bool,
|
||||
end: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result,
|
||||
) -> std::fmt::Result {
|
||||
let first = &mut true;
|
||||
for expr in list {
|
||||
if !std::mem::take(first) {
|
||||
write!(f, ", ")?;
|
||||
if !trailing {
|
||||
let first = &mut true;
|
||||
for expr in list {
|
||||
if !std::mem::take(first) {
|
||||
write!(f, ", ")?;
|
||||
}
|
||||
fmt(expr, f)?;
|
||||
}
|
||||
fmt(expr, f)?;
|
||||
return write!(f, "{end}");
|
||||
}
|
||||
write!(f, "{end}")
|
||||
}
|
||||
|
||||
fn fmt_trailing_list<T>(
|
||||
f: &mut std::fmt::Formatter,
|
||||
end: &str,
|
||||
list: &[T],
|
||||
fmt: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result,
|
||||
) -> std::fmt::Result {
|
||||
writeln!(f)?;
|
||||
INDENT.with(|i| i.set(i.get() + 1));
|
||||
let res = (|| {
|
||||
|
@ -805,11 +816,13 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
Self::Field { target, field } => write!(f, "{}.{field}", Postfix(target)),
|
||||
Self::Directive { name, args, .. } => {
|
||||
write!(f, "@{name}(")?;
|
||||
fmt_list(f, ")", args, std::fmt::Display::fmt)
|
||||
fmt_list(f, false, ")", args, std::fmt::Display::fmt)
|
||||
}
|
||||
Self::Struct { fields, .. } => {
|
||||
write!(f, "struct {{")?;
|
||||
fmt_list(f, "}", fields, |(name, val), f| write!(f, "{name}: {val}",))
|
||||
fmt_list(f, true, "}", fields, |(name, val), f| {
|
||||
write!(f, "{name}: {val}",)
|
||||
})
|
||||
}
|
||||
Self::Ctor {
|
||||
ty,
|
||||
|
@ -817,27 +830,30 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
trailing_comma,
|
||||
..
|
||||
} => {
|
||||
let (left, rith) = if fields.iter().any(|(name, _)| name.is_some()) {
|
||||
('{', "}")
|
||||
} else {
|
||||
('(', ")")
|
||||
};
|
||||
|
||||
if let Some(ty) = ty {
|
||||
write!(f, "{}", Unary(ty))?;
|
||||
}
|
||||
write!(f, ".{left}")?;
|
||||
write!(f, ".{{")?;
|
||||
let fmt_field = |(name, val): &_, f: &mut std::fmt::Formatter| {
|
||||
if let Some(name) = name {
|
||||
write!(f, "{name}: ")?;
|
||||
if let Some(val) = val {
|
||||
write!(f, "{name}: {val}")
|
||||
} else {
|
||||
write!(f, "{name}")
|
||||
}
|
||||
write!(f, "{val}")
|
||||
};
|
||||
if trailing_comma {
|
||||
fmt_trailing_list(f, rith, fields, fmt_field)
|
||||
} else {
|
||||
fmt_list(f, rith, fields, fmt_field)
|
||||
fmt_list(f, trailing_comma, "}", fields, fmt_field)
|
||||
}
|
||||
Self::Tupl {
|
||||
ty,
|
||||
fields,
|
||||
trailing_comma,
|
||||
..
|
||||
} => {
|
||||
if let Some(ty) = ty {
|
||||
write!(f, "{}", Unary(ty))?;
|
||||
}
|
||||
write!(f, ".(")?;
|
||||
fmt_list(f, trailing_comma, ")", fields, std::fmt::Display::fmt)
|
||||
}
|
||||
Self::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)),
|
||||
Self::Break { .. } => write!(f, "break"),
|
||||
|
@ -856,7 +872,9 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
ret, body, args, ..
|
||||
} => {
|
||||
write!(f, "fn(")?;
|
||||
fmt_list(f, "", args, |arg, f| write!(f, "{}: {}", arg.name, arg.ty))?;
|
||||
fmt_list(f, false, "", args, |arg, f| {
|
||||
write!(f, "{}: {}", arg.name, arg.ty)
|
||||
})?;
|
||||
write!(f, "): {ret} {body}")?;
|
||||
if !matches!(body, Self::Block { .. }) {
|
||||
write!(f, ";")?;
|
||||
|
@ -869,11 +887,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
|||
trailing_comma,
|
||||
} => {
|
||||
write!(f, "{}(", Postfix(func))?;
|
||||
if trailing_comma {
|
||||
fmt_trailing_list(f, ")", args, std::fmt::Display::fmt)
|
||||
} else {
|
||||
fmt_list(f, ")", args, std::fmt::Display::fmt)
|
||||
}
|
||||
fmt_list(f, trailing_comma, ")", args, std::fmt::Display::fmt)
|
||||
}
|
||||
Self::Return { val: Some(val), .. } => write!(f, "return {val}"),
|
||||
Self::Return { val: None, .. } => write!(f, "return"),
|
||||
|
|
Loading…
Reference in a new issue