adding defer
This commit is contained in:
parent
784d552c1d
commit
116f045a5f
3
formatter_only_break_loop.actual
Normal file
3
formatter_only_break_loop.actual
Normal file
|
@ -0,0 +1,3 @@
|
|||
inb := fn(f: int): int return f
|
||||
outb := fn(f: int, g: int): void {
|
||||
}
|
3
formatter_only_break_loop.expected
Normal file
3
formatter_only_break_loop.expected
Normal file
|
@ -0,0 +1,3 @@
|
|||
inb := fn(f: int): int return f
|
||||
outb := fn(f: int, g: int): void {
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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 = ".{",
|
||||
|
|
|
@ -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,
|
||||
|
|
102
lang/src/son.rs
102
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<AClass>)>,
|
||||
nodes: Nodes,
|
||||
ctrl: StrongRef,
|
||||
loops: Vec<Loop>,
|
||||
defers: Vec<(Pos, ExprRef)>,
|
||||
scope: Scope,
|
||||
}
|
||||
|
||||
impl ItemCtx {
|
||||
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.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<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");
|
||||
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<Ident>,
|
||||
alloc_const: bool,
|
||||
}
|
||||
|
||||
impl TyScope {
|
||||
|
@ -5688,6 +5763,7 @@ mod tests {
|
|||
idk;
|
||||
generic_functions;
|
||||
die;
|
||||
defer;
|
||||
|
||||
// Incomplete Examples;
|
||||
//comptime_pointers;
|
||||
|
|
19
lang/tests/son_tests_defer.txt
Normal file
19
lang/tests/son_tests_defer.txt
Normal 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(())
|
|
@ -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(())
|
||||
|
|
Loading…
Reference in a new issue