adding defer

This commit is contained in:
Jakub Doka 2024-11-24 18:50:55 +01:00
parent 784d552c1d
commit 116f045a5f
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
9 changed files with 160 additions and 17 deletions

View file

@ -0,0 +1,3 @@
inb := fn(f: int): int return f
outb := fn(f: int, g: int): void {
}

View file

@ -0,0 +1,3 @@
inb := fn(f: int): int return f
outb := fn(f: int, g: int): void {
}

View file

@ -567,6 +567,23 @@ main := fn(): never {
} }
``` ```
#### defer
```hb
main := fn(): uint {
i := 0
loop {
defer i += 1
if i == 10 break
if i % 3 == 0 {
continue
}
}
return i - 11
}
```
### Incomplete Examples ### Incomplete Examples
#### comptime_pointers #### comptime_pointers

View file

@ -67,8 +67,8 @@ fn token_group(kind: TokenKind) -> TokenGroup {
Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss
| ShrAss | ShlAss => TG::Assign, | ShrAss | ShlAss => TG::Assign,
DQuote | Quote => TG::String, DQuote | Quote => TG::String,
Slf | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed Slf | Defer | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct
| True | False | Null | Match | Enum => TG::Keyword, | Packed | True | False | Null | Match | Enum => TG::Keyword,
} }
} }
@ -280,6 +280,10 @@ impl<'a> Formatter<'a> {
f.write_str("$: ")?; f.write_str("$: ")?;
self.fmt(value, f) self.fmt(value, f)
} }
Expr::Defer { value, .. } => {
f.write_str("defer ")?;
self.fmt(value, f)
}
Expr::Slf { .. } => f.write_str("Self"), Expr::Slf { .. } => f.write_str("Self"),
Expr::String { literal, .. } => f.write_str(literal), Expr::String { literal, .. } => f.write_str(literal),
Expr::Comment { literal, .. } => f.write_str(literal), Expr::Comment { literal, .. } => f.write_str(literal),

View file

@ -153,6 +153,7 @@ pub enum TokenKind {
Null, Null,
Idk, Idk,
Die, Die,
Defer,
// Unused = a-z // Unused = a-z
LBrace = b'{', LBrace = b'{',
@ -320,6 +321,7 @@ gen_token_kind! {
Null = b"null", Null = b"null",
Idk = b"idk", Idk = b"idk",
Die = b"die", Die = b"die",
Defer = b"defer",
Under = b"_", Under = b"_",
#[punkt] #[punkt]
Ctor = ".{", Ctor = ".{",

View file

@ -303,6 +303,7 @@ impl<'a, 'b> Parser<'a, 'b> {
let mut must_trail = false; let mut must_trail = false;
let mut expr = match token.kind { let mut expr = match token.kind {
T::Ct => E::Ct { pos, value: self.ptr_expr()? }, T::Ct => E::Ct { pos, value: self.ptr_expr()? },
T::Defer => E::Defer { pos, value: self.ptr_expr()? },
T::Slf => E::Slf { pos }, T::Slf => E::Slf { pos },
T::Directive if self.lexer.slice(token.range()) == "use" => { T::Directive if self.lexer.slice(token.range()) == "use" => {
self.expect_advance(TokenKind::LParen)?; self.expect_advance(TokenKind::LParen)?;
@ -850,6 +851,11 @@ generate_expr! {
pos: Pos, pos: Pos,
value: &'a Self, value: &'a Self,
}, },
/// `'defer' Expr`
Defer {
pos: Pos,
value: &'a Self,
},
/// `'Self'` /// `'Self'`
Slf { Slf {
pos: Pos, pos: Pos,

View file

@ -27,7 +27,6 @@ use {
}, },
hashbrown::hash_map, hashbrown::hash_map,
hbbytecode::DisasmError, hbbytecode::DisasmError,
std::panic,
}; };
const VOID: Nid = 0; const VOID: Nid = 0;
@ -2165,6 +2164,7 @@ struct Loop {
ctrl: [StrongRef; 2], ctrl: [StrongRef; 2],
ctrl_scope: [Scope; 2], ctrl_scope: [Scope; 2],
scope: Scope, scope: Scope,
defer_base: usize,
} }
mod strong_ref { mod strong_ref {
@ -2350,22 +2350,26 @@ pub struct ItemCtx {
inline_var_base: usize, inline_var_base: usize,
inline_aclass_base: usize, inline_aclass_base: usize,
inline_depth: u16, inline_depth: u16,
inline_defer_base: usize,
inline_ret: Option<(Value, StrongRef, Scope, Option<AClass>)>, inline_ret: Option<(Value, StrongRef, Scope, Option<AClass>)>,
nodes: Nodes, nodes: Nodes,
ctrl: StrongRef, ctrl: StrongRef,
loops: Vec<Loop>, loops: Vec<Loop>,
defers: Vec<(Pos, ExprRef)>,
scope: Scope, scope: Scope,
} }
impl ItemCtx { impl ItemCtx {
fn init(&mut self, file: Module, parent: ty::Id, ret: Option<ty::Id>, task_base: usize) { fn init(&mut self, file: Module, parent: ty::Id, ret: Option<ty::Id>, task_base: usize) {
debug_assert_eq!(self.loops.len(), 0); debug_assert_eq!(self.loops.len(), 0);
debug_assert_eq!(self.defers.len(), 0);
debug_assert_eq!(self.scope.vars.len(), 0); debug_assert_eq!(self.scope.vars.len(), 0);
debug_assert_eq!(self.scope.aclasses.len(), 0); debug_assert_eq!(self.scope.aclasses.len(), 0);
debug_assert!(self.inline_ret.is_none()); debug_assert!(self.inline_ret.is_none());
debug_assert_eq!(self.inline_depth, 0); debug_assert_eq!(self.inline_depth, 0);
debug_assert_eq!(self.inline_var_base, 0); debug_assert_eq!(self.inline_var_base, 0);
debug_assert_eq!(self.inline_aclass_base, 0); debug_assert_eq!(self.inline_aclass_base, 0);
debug_assert_eq!(self.inline_defer_base, 0);
self.file = file; self.file = file;
self.parent = parent; self.parent = parent;
@ -2858,6 +2862,10 @@ impl<'a> Codegen<'a> {
self.ci.nodes[global].aclass = GLOBAL_ACLASS as _; self.ci.nodes[global].aclass = GLOBAL_ACLASS as _;
Some(Value::new(global).ty(ty)) Some(Value::new(global).ty(ty))
} }
Expr::Defer { pos, value } => {
self.ci.defers.push((pos, ExprRef::new(value)));
Some(Value::VOID)
}
Expr::Return { pos, val } => { Expr::Return { pos, val } => {
let mut value = if let Some(val) = val { let mut value = if let Some(val) = val {
self.raw_expr_ctx(val, Ctx { ty: self.ci.ret })? self.raw_expr_ctx(val, Ctx { ty: self.ci.ret })?
@ -2868,9 +2876,10 @@ impl<'a> Codegen<'a> {
let expected = *self.ci.ret.get_or_insert(value.ty); let expected = *self.ci.ret.get_or_insert(value.ty);
self.assert_ty(pos, &mut value, expected, "return value"); self.assert_ty(pos, &mut value, expected, "return value");
self.strip_ptr(&mut value);
self.gen_defers(self.ci.inline_defer_base);
if self.ci.inline_depth == 0 { if self.ci.inline_depth == 0 {
self.strip_ptr(&mut value);
debug_assert_ne!(self.ci.ctrl.get(), VOID); debug_assert_ne!(self.ci.ctrl.get(), VOID);
let mut inps = Vc::from([self.ci.ctrl.get(), value.id]); let mut inps = Vc::from([self.ci.ctrl.get(), value.id]);
for (i, aclass) in self.ci.scope.aclasses.iter_mut().enumerate() { for (i, aclass) in self.ci.scope.aclasses.iter_mut().enumerate() {
@ -2888,7 +2897,16 @@ impl<'a> Codegen<'a> {
self.ci.ctrl.set(NEVER, &mut self.ci.nodes); self.ci.ctrl.set(NEVER, &mut self.ci.nodes);
self.ci.nodes[ret].pos = pos; self.ci.nodes[ret].pos = pos;
self.ci.nodes.bind(ret, NEVER); self.ci.nodes.bind(ret, NEVER);
} else if let Some((pv, ctrl, scope, aclass)) = &mut self.ci.inline_ret { } else if let Some((mut pv, mut ctrl, mut scope, aclass)) =
self.ci.inline_ret.take()
{
if value.ty.loc(self.tys) == Loc::Stack {
let stck = self.new_stack(pos, value.ty);
self.store_mem(stck, value.ty, value.id);
value.id = stck;
value.ptr = true;
}
debug_assert!( debug_assert!(
aclass.is_none(), aclass.is_none(),
"TODO: oh no, we cant return structs from divergent branches" "TODO: oh no, we cant return structs from divergent branches"
@ -2904,8 +2922,8 @@ impl<'a> Codegen<'a> {
); );
self.ci.nodes.merge_scopes( self.ci.nodes.merge_scopes(
&mut self.ci.loops, &mut self.ci.loops,
ctrl, &ctrl,
scope, &mut scope,
&mut self.ci.scope, &mut self.ci.scope,
self.tys, self.tys,
); );
@ -2918,7 +2936,15 @@ impl<'a> Codegen<'a> {
); );
self.ci.nodes.lock(pv.id); self.ci.nodes.lock(pv.id);
self.ci.ctrl.set(NEVER, &mut self.ci.nodes); self.ci.ctrl.set(NEVER, &mut self.ci.nodes);
self.ci.inline_ret = Some((pv, ctrl, scope, aclass));
} else { } else {
if value.ty.loc(self.tys) == Loc::Stack {
let stck = self.new_stack(pos, value.ty);
self.store_mem(stck, value.ty, value.id);
value.id = stck;
value.ptr = true;
}
for (i, aclass) in self.ci.scope.aclasses[..2].iter_mut().enumerate() { for (i, aclass) in self.ci.scope.aclasses[..2].iter_mut().enumerate() {
self.ci.nodes.load_loop_aclass(i, aclass, &mut self.ci.loops); self.ci.nodes.load_loop_aclass(i, aclass, &mut self.ci.loops);
} }
@ -3632,6 +3658,7 @@ impl<'a> Codegen<'a> {
Expr::Block { stmts, .. } => { Expr::Block { stmts, .. } => {
let base = self.ci.scope.vars.len(); let base = self.ci.scope.vars.len();
let aclass_base = self.ci.scope.aclasses.len(); let aclass_base = self.ci.scope.aclasses.len();
let defer_base = self.ci.defers.len();
let mut ret = Some(Value::VOID); let mut ret = Some(Value::VOID);
for stmt in stmts { for stmt in stmts {
@ -3662,6 +3689,9 @@ impl<'a> Codegen<'a> {
aclass.remove(&mut self.ci.nodes); aclass.remove(&mut self.ci.nodes);
} }
self.gen_defers(defer_base);
self.ci.defers.truncate(defer_base);
ret ret
} }
Expr::Loop { body, .. } => { Expr::Loop { body, .. } => {
@ -3680,6 +3710,7 @@ impl<'a> Codegen<'a> {
ctrl: [StrongRef::DEFAULT; 2], ctrl: [StrongRef::DEFAULT; 2],
ctrl_scope: core::array::from_fn(|_| Default::default()), ctrl_scope: core::array::from_fn(|_| Default::default()),
scope: self.ci.scope.dup(&mut self.ci.nodes), scope: self.ci.scope.dup(&mut self.ci.nodes),
defer_base: self.ci.defers.len(),
}); });
for var in self.ci.scope.vars.iter_mut().skip(self.ci.inline_var_base) { for var in self.ci.scope.vars.iter_mut().skip(self.ci.inline_var_base) {
@ -3721,8 +3752,16 @@ impl<'a> Codegen<'a> {
cons.clear(&mut self.ci.nodes); cons.clear(&mut self.ci.nodes);
} }
let Loop { node, ctrl: [.., bre], ctrl_scope: [.., mut bres], mut scope } = let Loop {
self.ci.loops.pop().unwrap(); node,
ctrl: [.., bre],
ctrl_scope: [.., mut bres],
mut scope,
defer_base,
} = self.ci.loops.pop().unwrap();
self.gen_defers(defer_base);
self.ci.defers.truncate(defer_base);
self.ci.nodes.modify_input(node, 1, self.ci.ctrl.get()); self.ci.nodes.modify_input(node, 1, self.ci.ctrl.get());
@ -4038,7 +4077,15 @@ impl<'a> Codegen<'a> {
Some(Value::VOID) Some(Value::VOID)
} }
ref e => { ref e => {
let ty = self.ty(e); let ty = self.parse_ty(
TyScope {
file: self.ci.file,
parent: self.ci.parent,
name: None,
alloc_const: false,
},
e,
);
Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, ty)) Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, ty))
} }
} }
@ -4326,6 +4373,8 @@ impl<'a> Codegen<'a> {
let prev_var_base = mem::replace(&mut self.ci.inline_var_base, var_base); let prev_var_base = mem::replace(&mut self.ci.inline_var_base, var_base);
let prev_aclass_base = mem::replace(&mut self.ci.inline_aclass_base, aclass_base); let prev_aclass_base = mem::replace(&mut self.ci.inline_aclass_base, aclass_base);
let prev_defer_base =
mem::replace(&mut self.ci.inline_defer_base, self.ci.defers.len());
let prev_inline_ret = self.ci.inline_ret.take(); let prev_inline_ret = self.ci.inline_ret.take();
self.ci.inline_depth += 1; self.ci.inline_depth += 1;
let prev_ret = self.ci.ret.replace(sig.ret); let prev_ret = self.ci.ret.replace(sig.ret);
@ -4351,6 +4400,7 @@ impl<'a> Codegen<'a> {
self.ci.inline_depth -= 1; self.ci.inline_depth -= 1;
self.ci.inline_var_base = prev_var_base; self.ci.inline_var_base = prev_var_base;
self.ci.inline_aclass_base = prev_aclass_base; self.ci.inline_aclass_base = prev_aclass_base;
self.ci.inline_defer_base = prev_defer_base;
for var in self.ci.scope.vars.drain(var_base..) { for var in self.ci.scope.vars.drain(var_base..) {
var.remove(&mut self.ci.nodes); var.remove(&mut self.ci.nodes);
} }
@ -4755,12 +4805,25 @@ impl<'a> Codegen<'a> {
} }
} }
fn gen_defers(&mut self, base: usize) -> Option<()> {
let defers = mem::take(&mut self.ci.defers);
for &(_, defer) in defers.iter().skip(base).rev() {
self.expr(defer.get(self.file()))?;
}
self.ci.defers = defers;
Some(())
}
fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Value> { fn jump_to(&mut self, pos: Pos, id: usize) -> Option<Value> {
let Some(mut loob) = self.ci.loops.last_mut() else { let Some(&mut Loop { defer_base, .. }) = self.ci.loops.last_mut() else {
self.error(pos, "break outside a loop"); self.error(pos, "break outside a loop");
return None; return None;
}; };
self.gen_defers(defer_base)?;
let mut loob = self.ci.loops.last_mut().unwrap();
if loob.ctrl[id].is_live() { if loob.ctrl[id].is_live() {
loob.ctrl[id].set( loob.ctrl[id].set(
self.ci.nodes.new_node( self.ci.nodes.new_node(
@ -4985,7 +5048,7 @@ impl<'a> Codegen<'a> {
} }
fn ty_in(&mut self, file: Module, parent: ty::Id, expr: &Expr) -> ty::Id { fn ty_in(&mut self, file: Module, parent: ty::Id, expr: &Expr) -> ty::Id {
self.parse_ty(TyScope { file, parent, name: None }, expr) self.parse_ty(TyScope { file, parent, name: None, alloc_const: true }, expr)
} }
fn ty_display(&self, ty: ty::Id) -> ty::Display { fn ty_display(&self, ty: ty::Id) -> ty::Display {
@ -5422,7 +5485,10 @@ impl<'a> Codegen<'a> {
.push(Const { ast: ExprRef::new(expr), name, file, parent }) .push(Const { ast: ExprRef::new(expr), name, file, parent })
.into() .into()
} else { } else {
self.parse_ty(TyScope { file, parent, name: Some(name) }, right) self.parse_ty(
TyScope { file, parent, name: Some(name), alloc_const: true },
right,
)
}, },
) )
}) })
@ -5599,8 +5665,16 @@ impl<'a> Codegen<'a> {
self.tys.ins.funcs.push(func).into() self.tys.ins.funcs.push(func).into()
} }
_ if let Some(name) = sc.name => self.eval_global(sc.file, name, expr), _ if sc.alloc_const
_ => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)), && let Some(name) = sc.name =>
{
self.eval_global(sc.file, name, expr)
}
_ if sc.alloc_const => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)),
ref e => {
self.error_unhandled_ast(e, "bruh");
ty::Id::NEVER
}
} }
} }
} }
@ -5610,6 +5684,7 @@ struct TyScope {
file: Module, file: Module,
parent: ty::Id, parent: ty::Id,
name: Option<Ident>, name: Option<Ident>,
alloc_const: bool,
} }
impl TyScope { impl TyScope {
@ -5688,6 +5763,7 @@ mod tests {
idk; idk;
generic_functions; generic_functions;
die; die;
defer;
// Incomplete Examples; // Incomplete Examples;
//comptime_pointers; //comptime_pointers;

View file

@ -0,0 +1,19 @@
main:
LI64 r15, 3d
LI64 r16, 10d
CP r14, r0
CP r13, r14
3: JNE r13, r16, :0
LI64 r14, -10d
ADD64 r14, r13, r14
CP r1, r14
JMP :1
0: DIRU64 r0, r17, r13, r15
JNE r17, r14, :2
JMP :2
2: ADDI64 r13, r13, 1d
JMP :3
1: JALA r0, r31, 0a
code size: 103
ret: 0
status: Ok(())

View file

@ -1,6 +1,19 @@
main: main:
CP r1, r0 ADDI64 r254, r254, -72d
ADDI64 r13, r254, 24d
ST r0, r254, 24a, 8h
LI64 r14, 1d
ST r14, r254, 32a, 8h
LI64 r14, 2d
ST r14, r254, 40a, 8h
ADDI64 r14, r254, 0d
BMC r13, r14, 24h
ADDI64 r13, r254, 48d
BMC r14, r13, 24h
LD r13, r254, 48a, 8h
CP r1, r13
ADDI64 r254, r254, 72d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 22 code size: 159
ret: 0 ret: 0
status: Ok(()) status: Ok(())