on the journey twards struct destruct

This commit is contained in:
mlokr 2024-07-07 19:16:15 +02:00
parent b90e72f624
commit f75f6f7481
3 changed files with 129 additions and 83 deletions

View file

@ -173,7 +173,8 @@ main := fn(): int {
} }
pass := fn(t: ^Ty): int { pass := fn(t: ^Ty): int {
return t.a - t.b; .{ a, b } := *t;
return a - b;
} }
odher_pass := fn(t: Ty2): Ty2 { odher_pass := fn(t: Ty2): Ty2 {

View file

@ -1584,34 +1584,38 @@ impl Codegen {
E::Ctor { E::Ctor {
pos, ty, fields, .. pos, ty, fields, ..
} => { } => {
let Some(ty) = ty.map(|ty| self.ty(ty)).or(ctx.ty) else { let (stuct, loc) = self.prepare_struct_ctor(pos, ctx, ty, fields.len());
self.report(pos, "expected type, (it cannot be inferred)"); for (name, field) in fields {
}; let Some((offset, ty)) = self.tys.offset_of(stuct, Ok(name)) else {
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 {
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(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); 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 }); return Some(Value { ty, loc });
} }
E::Field { target, field } => { 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( fn struct_op(
&mut self, &mut self,
op: TokenKind, op: TokenKind,
@ -2743,13 +2777,13 @@ impl Codegen {
} }
fn handle_ecall(&mut self) { 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 arr = self.ct.vm.pc.get() as *const Trap;
let trap = unsafe { std::ptr::read_unaligned(arr) }; let trap = unsafe { std::ptr::read_unaligned(arr) };
self.ct.vm.pc = self.ct.vm.pc.wrapping_add(std::mem::size_of::<Trap>()); 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 { match trap {
Trap::MakeStruct { file, struct_expr } => { Trap::MakeStruct { file, struct_expr } => {
let cfile = self.files[file as usize].clone(); let cfile = self.files[file as usize].clone();
@ -2783,10 +2817,7 @@ impl Codegen {
} }
if let Some(lpc) = local_pc { if let Some(lpc) = local_pc {
let offset = std::mem::size_of::<Trap>() let offset = lpc + self.ci.snap.code + self.output.code.as_ptr() as usize;
+ lpc
+ self.ci.snap.code
+ self.output.code.as_ptr() as usize;
self.ct.vm.pc = hbvm::mem::Address::new(offset as _); self.ct.vm.pc = hbvm::mem::Address::new(offset as _);
} }
} }

View file

@ -341,6 +341,8 @@ impl<'a, 'b> Parser<'a, 'b> {
}, },
body: self.ptr_expr(), 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 { T::Band | T::Mul | T::Xor => E::UnOp {
pos: token.start, pos: token.start,
op: token.kind, op: token.kind,
@ -392,23 +394,8 @@ impl<'a, 'b> Parser<'a, 'b> {
args: self.collect_list(T::Comma, T::RParen, Self::expr), args: self.collect_list(T::Comma, T::RParen, Self::expr),
trailing_comma: std::mem::take(&mut self.trailing_sep), trailing_comma: std::mem::take(&mut self.trailing_sep),
}, },
T::Ctor => E::Ctor { T::Ctor => self.ctor(token.start, Some(expr)),
pos: token.start, T::Tupl => self.tupl(token.start, Some(expr)),
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::Dot => E::Field { T::Dot => E::Field {
target: self.arena.alloc(expr), target: self.arena.alloc(expr),
field: { field: {
@ -431,6 +418,28 @@ impl<'a, 'b> Parser<'a, 'b> {
expr 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 { fn advance_ident(&mut self) -> Token {
if matches!(self.token.kind, TokenKind::Ident | TokenKind::CtIdent) { if matches!(self.token.kind, TokenKind::Ident | TokenKind::CtIdent) {
self.next() self.next()
@ -661,7 +670,13 @@ generate_expr! {
Ctor { Ctor {
pos: Pos, pos: Pos,
ty: Option<&'a Self>, 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, trailing_comma: bool,
}, },
Field { Field {
@ -720,10 +735,12 @@ impl<'a> std::fmt::Display for Expr<'a> {
fn fmt_list<T>( fn fmt_list<T>(
f: &mut std::fmt::Formatter, f: &mut std::fmt::Formatter,
trailing: bool,
end: &str, end: &str,
list: &[T], list: &[T],
fmt: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result, fmt: impl Fn(&T, &mut std::fmt::Formatter) -> std::fmt::Result,
) -> std::fmt::Result { ) -> std::fmt::Result {
if !trailing {
let first = &mut true; let first = &mut true;
for expr in list { for expr in list {
if !std::mem::take(first) { if !std::mem::take(first) {
@ -731,15 +748,9 @@ impl<'a> std::fmt::Display for Expr<'a> {
} }
fmt(expr, f)?; fmt(expr, f)?;
} }
write!(f, "{end}") return 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)?; writeln!(f)?;
INDENT.with(|i| i.set(i.get() + 1)); INDENT.with(|i| i.set(i.get() + 1));
let res = (|| { let res = (|| {
@ -805,11 +816,13 @@ impl<'a> std::fmt::Display for Expr<'a> {
Self::Field { target, field } => write!(f, "{}.{field}", Postfix(target)), Self::Field { target, field } => write!(f, "{}.{field}", Postfix(target)),
Self::Directive { name, args, .. } => { Self::Directive { name, args, .. } => {
write!(f, "@{name}(")?; write!(f, "@{name}(")?;
fmt_list(f, ")", args, std::fmt::Display::fmt) fmt_list(f, false, ")", args, std::fmt::Display::fmt)
} }
Self::Struct { fields, .. } => { Self::Struct { fields, .. } => {
write!(f, "struct {{")?; 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 { Self::Ctor {
ty, ty,
@ -817,27 +830,30 @@ impl<'a> std::fmt::Display for Expr<'a> {
trailing_comma, trailing_comma,
.. ..
} => { } => {
let (left, rith) = if fields.iter().any(|(name, _)| name.is_some()) {
('{', "}")
} else {
('(', ")")
};
if let Some(ty) = ty { if let Some(ty) = ty {
write!(f, "{}", Unary(ty))?; write!(f, "{}", Unary(ty))?;
} }
write!(f, ".{left}")?; write!(f, ".{{")?;
let fmt_field = |(name, val): &_, f: &mut std::fmt::Formatter| { let fmt_field = |(name, val): &_, f: &mut std::fmt::Formatter| {
if let Some(name) = name { if let Some(val) = val {
write!(f, "{name}: ")?; write!(f, "{name}: {val}")
}
write!(f, "{val}")
};
if trailing_comma {
fmt_trailing_list(f, rith, fields, fmt_field)
} else { } else {
fmt_list(f, rith, fields, fmt_field) write!(f, "{name}")
} }
};
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::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)),
Self::Break { .. } => write!(f, "break"), Self::Break { .. } => write!(f, "break"),
@ -856,7 +872,9 @@ impl<'a> std::fmt::Display for Expr<'a> {
ret, body, args, .. ret, body, args, ..
} => { } => {
write!(f, "fn(")?; 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}")?; write!(f, "): {ret} {body}")?;
if !matches!(body, Self::Block { .. }) { if !matches!(body, Self::Block { .. }) {
write!(f, ";")?; write!(f, ";")?;
@ -869,11 +887,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
trailing_comma, trailing_comma,
} => { } => {
write!(f, "{}(", Postfix(func))?; write!(f, "{}(", Postfix(func))?;
if trailing_comma { fmt_list(f, trailing_comma, ")", args, std::fmt::Display::fmt)
fmt_trailing_list(f, ")", args, std::fmt::Display::fmt)
} else {
fmt_list(f, ")", args, std::fmt::Display::fmt)
}
} }
Self::Return { val: Some(val), .. } => write!(f, "return {val}"), Self::Return { val: Some(val), .. } => write!(f, "return {val}"),
Self::Return { val: None, .. } => write!(f, "return"), Self::Return { val: None, .. } => write!(f, "return"),