From 116f045a5f1487514cac41392512855ac6eca6f9 Mon Sep 17 00:00:00 2001 From: Jakub Doka Date: Sun, 24 Nov 2024 18:50:55 +0100 Subject: [PATCH] adding defer --- formatter_only_break_loop.actual | 3 + formatter_only_break_loop.expected | 3 + lang/README.md | 17 ++++ lang/src/fmt.rs | 8 +- lang/src/lexer.rs | 2 + lang/src/parser.rs | 6 ++ lang/src/son.rs | 102 ++++++++++++++++--- lang/tests/son_tests_defer.txt | 19 ++++ lang/tests/son_tests_inline_return_stack.txt | 17 +++- 9 files changed, 160 insertions(+), 17 deletions(-) create mode 100644 formatter_only_break_loop.actual create mode 100644 formatter_only_break_loop.expected create mode 100644 lang/tests/son_tests_defer.txt diff --git a/formatter_only_break_loop.actual b/formatter_only_break_loop.actual new file mode 100644 index 00000000..becc4375 --- /dev/null +++ b/formatter_only_break_loop.actual @@ -0,0 +1,3 @@ +inb := fn(f: int): int return f +outb := fn(f: int, g: int): void { +} \ No newline at end of file diff --git a/formatter_only_break_loop.expected b/formatter_only_break_loop.expected new file mode 100644 index 00000000..becc4375 --- /dev/null +++ b/formatter_only_break_loop.expected @@ -0,0 +1,3 @@ +inb := fn(f: int): int return f +outb := fn(f: int, g: int): void { +} \ No newline at end of file diff --git a/lang/README.md b/lang/README.md index 7caa85db..13bcf80a 100644 --- a/lang/README.md +++ b/lang/README.md @@ -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 #### comptime_pointers diff --git a/lang/src/fmt.rs b/lang/src/fmt.rs index 3d8a43df..cc84c972 100644 --- a/lang/src/fmt.rs +++ b/lang/src/fmt.rs @@ -67,8 +67,8 @@ fn token_group(kind: TokenKind) -> TokenGroup { Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss | ShrAss | ShlAss => TG::Assign, DQuote | Quote => TG::String, - Slf | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed - | True | False | Null | Match | Enum => TG::Keyword, + Slf | Defer | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct + | Packed | True | False | Null | Match | Enum => TG::Keyword, } } @@ -280,6 +280,10 @@ impl<'a> Formatter<'a> { f.write_str("$: ")?; self.fmt(value, f) } + Expr::Defer { value, .. } => { + f.write_str("defer ")?; + self.fmt(value, f) + } Expr::Slf { .. } => f.write_str("Self"), Expr::String { literal, .. } => f.write_str(literal), Expr::Comment { literal, .. } => f.write_str(literal), diff --git a/lang/src/lexer.rs b/lang/src/lexer.rs index b11e56ec..c41d442c 100644 --- a/lang/src/lexer.rs +++ b/lang/src/lexer.rs @@ -153,6 +153,7 @@ pub enum TokenKind { Null, Idk, Die, + Defer, // Unused = a-z LBrace = b'{', @@ -320,6 +321,7 @@ gen_token_kind! { Null = b"null", Idk = b"idk", Die = b"die", + Defer = b"defer", Under = b"_", #[punkt] Ctor = ".{", diff --git a/lang/src/parser.rs b/lang/src/parser.rs index 9ca19226..c4ca472c 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -303,6 +303,7 @@ impl<'a, 'b> Parser<'a, 'b> { let mut must_trail = false; let mut expr = match token.kind { T::Ct => E::Ct { pos, value: self.ptr_expr()? }, + T::Defer => E::Defer { pos, value: self.ptr_expr()? }, T::Slf => E::Slf { pos }, T::Directive if self.lexer.slice(token.range()) == "use" => { self.expect_advance(TokenKind::LParen)?; @@ -850,6 +851,11 @@ generate_expr! { pos: Pos, value: &'a Self, }, + /// `'defer' Expr` + Defer { + pos: Pos, + value: &'a Self, + }, /// `'Self'` Slf { pos: Pos, diff --git a/lang/src/son.rs b/lang/src/son.rs index df8e6023..e9a6d3e3 100644 --- a/lang/src/son.rs +++ b/lang/src/son.rs @@ -27,7 +27,6 @@ use { }, hashbrown::hash_map, hbbytecode::DisasmError, - std::panic, }; const VOID: Nid = 0; @@ -2165,6 +2164,7 @@ struct Loop { ctrl: [StrongRef; 2], ctrl_scope: [Scope; 2], scope: Scope, + defer_base: usize, } mod strong_ref { @@ -2350,22 +2350,26 @@ pub struct ItemCtx { inline_var_base: usize, inline_aclass_base: usize, inline_depth: u16, + inline_defer_base: usize, inline_ret: Option<(Value, StrongRef, Scope, Option)>, nodes: Nodes, ctrl: StrongRef, loops: Vec, + defers: Vec<(Pos, ExprRef)>, scope: Scope, } impl ItemCtx { fn init(&mut self, file: Module, parent: ty::Id, ret: Option, task_base: usize) { 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.aclasses.len(), 0); debug_assert!(self.inline_ret.is_none()); debug_assert_eq!(self.inline_depth, 0); debug_assert_eq!(self.inline_var_base, 0); debug_assert_eq!(self.inline_aclass_base, 0); + debug_assert_eq!(self.inline_defer_base, 0); self.file = file; self.parent = parent; @@ -2858,6 +2862,10 @@ impl<'a> Codegen<'a> { self.ci.nodes[global].aclass = GLOBAL_ACLASS as _; 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 } => { let mut value = if let Some(val) = val { 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); 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 { - self.strip_ptr(&mut value); debug_assert_ne!(self.ci.ctrl.get(), VOID); let mut inps = Vc::from([self.ci.ctrl.get(), value.id]); 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.nodes[ret].pos = pos; 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!( aclass.is_none(), "TODO: oh no, we cant return structs from divergent branches" @@ -2904,8 +2922,8 @@ impl<'a> Codegen<'a> { ); self.ci.nodes.merge_scopes( &mut self.ci.loops, - ctrl, - scope, + &ctrl, + &mut scope, &mut self.ci.scope, self.tys, ); @@ -2918,7 +2936,15 @@ impl<'a> Codegen<'a> { ); self.ci.nodes.lock(pv.id); self.ci.ctrl.set(NEVER, &mut self.ci.nodes); + self.ci.inline_ret = Some((pv, ctrl, scope, aclass)); } 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() { self.ci.nodes.load_loop_aclass(i, aclass, &mut self.ci.loops); } @@ -3632,6 +3658,7 @@ impl<'a> Codegen<'a> { Expr::Block { stmts, .. } => { let base = self.ci.scope.vars.len(); let aclass_base = self.ci.scope.aclasses.len(); + let defer_base = self.ci.defers.len(); let mut ret = Some(Value::VOID); for stmt in stmts { @@ -3662,6 +3689,9 @@ impl<'a> Codegen<'a> { aclass.remove(&mut self.ci.nodes); } + self.gen_defers(defer_base); + self.ci.defers.truncate(defer_base); + ret } Expr::Loop { body, .. } => { @@ -3680,6 +3710,7 @@ impl<'a> Codegen<'a> { ctrl: [StrongRef::DEFAULT; 2], ctrl_scope: core::array::from_fn(|_| Default::default()), 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) { @@ -3721,8 +3752,16 @@ impl<'a> Codegen<'a> { cons.clear(&mut self.ci.nodes); } - let Loop { node, ctrl: [.., bre], ctrl_scope: [.., mut bres], mut scope } = - self.ci.loops.pop().unwrap(); + let Loop { + 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()); @@ -4038,7 +4077,15 @@ impl<'a> Codegen<'a> { Some(Value::VOID) } 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)) } } @@ -4326,6 +4373,8 @@ impl<'a> Codegen<'a> { 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_defer_base = + mem::replace(&mut self.ci.inline_defer_base, self.ci.defers.len()); let prev_inline_ret = self.ci.inline_ret.take(); self.ci.inline_depth += 1; 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_var_base = prev_var_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..) { 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 { - 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"); return None; }; + self.gen_defers(defer_base)?; + + let mut loob = self.ci.loops.last_mut().unwrap(); + if loob.ctrl[id].is_live() { loob.ctrl[id].set( 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 { - 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 { @@ -5422,7 +5485,10 @@ impl<'a> Codegen<'a> { .push(Const { ast: ExprRef::new(expr), name, file, parent }) .into() } 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() } - _ if let Some(name) = sc.name => self.eval_global(sc.file, name, expr), - _ => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)), + _ if sc.alloc_const + && 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, parent: ty::Id, name: Option, + alloc_const: bool, } impl TyScope { @@ -5688,6 +5763,7 @@ mod tests { idk; generic_functions; die; + defer; // Incomplete Examples; //comptime_pointers; diff --git a/lang/tests/son_tests_defer.txt b/lang/tests/son_tests_defer.txt new file mode 100644 index 00000000..c57f52f2 --- /dev/null +++ b/lang/tests/son_tests_defer.txt @@ -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(()) diff --git a/lang/tests/son_tests_inline_return_stack.txt b/lang/tests/son_tests_inline_return_stack.txt index 5aa16aa1..bc49a4b3 100644 --- a/lang/tests/son_tests_inline_return_stack.txt +++ b/lang/tests/son_tests_inline_return_stack.txt @@ -1,6 +1,19 @@ 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 -code size: 22 +code size: 159 ret: 0 status: Ok(())