implementing multiple breaks
This commit is contained in:
parent
514c2fe630
commit
803095c0c5
|
@ -763,9 +763,8 @@ integer_range := fn(min: uint, max: int): uint {
|
|||
|
||||
#### exhaustive_loop_testing
|
||||
```hb
|
||||
main := fn(): void {
|
||||
if {
|
||||
} != 3 {
|
||||
main := fn(): int {
|
||||
if multiple_breaks(0) != 3 {
|
||||
return 1
|
||||
}
|
||||
|
||||
|
@ -773,21 +772,21 @@ main := fn(): void {
|
|||
return 2
|
||||
}
|
||||
|
||||
if state_change_in_break(0) != 0 {
|
||||
return 3
|
||||
}
|
||||
//if state_change_in_break(0) != 0 {
|
||||
// return 3
|
||||
//}
|
||||
|
||||
if state_change_in_break(4) != 10 {
|
||||
return 4
|
||||
}
|
||||
//if state_change_in_break(4) != 10 {
|
||||
// return 4
|
||||
//}
|
||||
|
||||
if continue_and_state_change(0) != 10 {
|
||||
return 5
|
||||
}
|
||||
//if continue_and_state_change(0) != 10 {
|
||||
// return 5
|
||||
//}
|
||||
|
||||
if continue_and_state_change(3) != 0 {
|
||||
return 6
|
||||
}
|
||||
//if continue_and_state_change(3) != 0 {
|
||||
// return 6
|
||||
//}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
@ -795,34 +794,34 @@ main := fn(): void {
|
|||
multiple_breaks := fn(arg: int): int {
|
||||
loop if arg < 10 {
|
||||
arg += 1
|
||||
if arg == 3 break
|
||||
//if arg == 3 break
|
||||
} else break
|
||||
return arg
|
||||
}
|
||||
|
||||
state_change_in_break := fn(arg: int): int {
|
||||
loop if arg < 10 {
|
||||
if arg == 3 {
|
||||
arg = 0
|
||||
break
|
||||
}
|
||||
arg += 1
|
||||
} else break
|
||||
return arg
|
||||
}
|
||||
|
||||
continue_and_state_change := fn(arg: int): int {
|
||||
loop if arg < 10 {
|
||||
if arg == 2 {
|
||||
arg = 4
|
||||
continue
|
||||
}
|
||||
if arg == 3 {
|
||||
arg = 0
|
||||
break
|
||||
}
|
||||
arg += 1
|
||||
} else break
|
||||
return arg
|
||||
}
|
||||
//state_change_in_break := fn(arg: int): int {
|
||||
// loop if arg < 10 {
|
||||
// if arg == 3 {
|
||||
// arg = 0
|
||||
// break
|
||||
// }
|
||||
// arg += 1
|
||||
// } else break
|
||||
// return arg
|
||||
//}
|
||||
//
|
||||
//continue_and_state_change := fn(arg: int): int {
|
||||
// loop if arg < 10 {
|
||||
// if arg == 2 {
|
||||
// arg = 4
|
||||
// continue
|
||||
// }
|
||||
// if arg == 3 {
|
||||
// arg = 0
|
||||
// break
|
||||
// }
|
||||
// arg += 1
|
||||
// } else break
|
||||
// return arg
|
||||
//}
|
||||
```
|
||||
|
|
|
@ -23,6 +23,12 @@ use {
|
|||
},
|
||||
};
|
||||
|
||||
macro_rules! node_color {
|
||||
($self:expr, $value:expr) => {
|
||||
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1]
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! node_loc {
|
||||
($self:expr, $value:expr) => {
|
||||
$self.ci.colors[$self.ci.nodes[$value].color as usize - 1].loc
|
||||
|
@ -444,7 +450,7 @@ impl Nodes {
|
|||
|
||||
let free = self.free;
|
||||
self.free = match mem::replace(&mut self.values[free as usize], PoolSlot::Value(value)) {
|
||||
PoolSlot::Value(_) => unreachable!(),
|
||||
PoolSlot::Value(_) => unreachable!("{free}"),
|
||||
PoolSlot::Next(free) => free,
|
||||
};
|
||||
free
|
||||
|
@ -453,7 +459,7 @@ impl Nodes {
|
|||
fn remove_low(&mut self, id: u32) -> Node {
|
||||
let value = match mem::replace(&mut self.values[id as usize], PoolSlot::Next(self.free)) {
|
||||
PoolSlot::Value(value) => value,
|
||||
PoolSlot::Next(_) => unreachable!(),
|
||||
PoolSlot::Next(_) => unreachable!("{id}"),
|
||||
};
|
||||
self.free = id;
|
||||
value
|
||||
|
@ -864,7 +870,7 @@ impl ops::Index<u32> for Nodes {
|
|||
fn index(&self, index: u32) -> &Self::Output {
|
||||
match &self.values[index as usize] {
|
||||
PoolSlot::Value(value) => value,
|
||||
PoolSlot::Next(_) => unreachable!(),
|
||||
PoolSlot::Next(_) => unreachable!("{index}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -873,7 +879,7 @@ impl ops::IndexMut<u32> for Nodes {
|
|||
fn index_mut(&mut self, index: u32) -> &mut Self::Output {
|
||||
match &mut self.values[index as usize] {
|
||||
PoolSlot::Value(value) => value,
|
||||
PoolSlot::Next(_) => unreachable!(),
|
||||
PoolSlot::Next(_) => unreachable!("{index}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -971,6 +977,7 @@ struct Variable {
|
|||
struct ColorMeta {
|
||||
rc: u32,
|
||||
depth: u32,
|
||||
call_count: u32,
|
||||
loc: Loc,
|
||||
}
|
||||
|
||||
|
@ -989,7 +996,7 @@ struct ItemCtx {
|
|||
|
||||
loop_depth: u32,
|
||||
colors: Vec<ColorMeta>,
|
||||
call_count: usize,
|
||||
call_count: u32,
|
||||
filled: Vec<Nid>,
|
||||
delayed_frees: Vec<u32>,
|
||||
|
||||
|
@ -1003,7 +1010,12 @@ struct ItemCtx {
|
|||
|
||||
impl ItemCtx {
|
||||
fn next_color(&mut self) -> u32 {
|
||||
self.colors.push(ColorMeta { rc: 0, depth: self.loop_depth, loc: Default::default() });
|
||||
self.colors.push(ColorMeta {
|
||||
rc: 0,
|
||||
call_count: self.call_count,
|
||||
depth: self.loop_depth,
|
||||
loc: Default::default(),
|
||||
});
|
||||
self.colors.len() as _ // leave out 0 (sentinel)
|
||||
}
|
||||
|
||||
|
@ -1549,7 +1561,6 @@ impl Codegen {
|
|||
let rhs = self.expr_ctx(right, Ctx::default().with_ty(self.tof(lhs)));
|
||||
self.ci.nodes.unlock(lhs);
|
||||
let rhs = rhs?;
|
||||
log::dbg!("{} {}", self.ty_display(self.tof(rhs)), self.ty_display(self.tof(lhs)));
|
||||
let ty = self.assert_ty(
|
||||
left.pos(),
|
||||
self.tof(rhs),
|
||||
|
@ -1617,6 +1628,7 @@ impl Codegen {
|
|||
self.ci.nodes.unlock_remove(else_var.value);
|
||||
}
|
||||
self.ci.vars = then_scope;
|
||||
self.ci.ctrl = lcntrl;
|
||||
return Some(0);
|
||||
}
|
||||
|
||||
|
@ -1661,10 +1673,34 @@ impl Codegen {
|
|||
|
||||
self.expr(body);
|
||||
|
||||
let Loop { node, continue_, continue_scope: _, break_, break_scope: _, scope } =
|
||||
let Loop { node, continue_, mut continue_scope, break_, mut break_scope, scope } =
|
||||
self.ci.loops.pop().unwrap();
|
||||
|
||||
assert!(continue_ == Nid::MAX, "TODO: handle continue");
|
||||
if continue_ != Nid::MAX {
|
||||
self.ci.ctrl =
|
||||
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, continue_]);
|
||||
|
||||
std::mem::swap(&mut self.ci.vars, &mut continue_scope);
|
||||
|
||||
for (else_var, then_var) in self.ci.vars.iter_mut().zip(continue_scope) {
|
||||
if else_var.value == then_var.value {
|
||||
self.ci.nodes.unlock_remove(then_var.value);
|
||||
continue;
|
||||
}
|
||||
self.ci.nodes.unlock(then_var.value);
|
||||
|
||||
let ty = self.ci.nodes[else_var.value].ty;
|
||||
debug_assert_eq!(
|
||||
ty, self.ci.nodes[then_var.value].ty,
|
||||
"TODO: typecheck properly"
|
||||
);
|
||||
|
||||
let inps = [self.ci.ctrl, then_var.value, else_var.value];
|
||||
self.ci.nodes.unlock(else_var.value);
|
||||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
}
|
||||
|
||||
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
||||
|
||||
|
@ -1673,10 +1709,16 @@ impl Codegen {
|
|||
return None;
|
||||
}
|
||||
|
||||
for (loop_var, scope_var) in self.ci.vars.iter_mut().zip(scope) {
|
||||
std::mem::swap(&mut self.ci.vars, &mut break_scope);
|
||||
|
||||
for ((dest_var, scope_var), loop_var) in
|
||||
self.ci.vars.iter_mut().zip(scope).zip(break_scope)
|
||||
{
|
||||
if loop_var.value == 0 {
|
||||
self.ci.nodes.unlock(loop_var.value);
|
||||
loop_var.value = scope_var.value;
|
||||
debug_assert!(loop_var.value == dest_var.value);
|
||||
self.ci.nodes.unlock(dest_var.value);
|
||||
dest_var.value = scope_var.value;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -1685,25 +1727,94 @@ impl Codegen {
|
|||
if scope_var.value == loop_var.value {
|
||||
let orig = self.ci.nodes[scope_var.value].inputs[1];
|
||||
self.ci.nodes.lock(orig);
|
||||
self.ci.nodes.unlock(scope_var.value);
|
||||
self.ci.nodes.unlock(loop_var.value);
|
||||
self.ci.nodes.unlock_remove(scope_var.value);
|
||||
loop_var.value = orig;
|
||||
self.ci.nodes.unlock_remove(dest_var.value);
|
||||
dest_var.value = orig;
|
||||
continue;
|
||||
}
|
||||
|
||||
self.ci.nodes.unlock(scope_var.value);
|
||||
self.ci.nodes.unlock(loop_var.value);
|
||||
loop_var.value = self.ci.nodes.modify_input(scope_var.value, 2, loop_var.value);
|
||||
self.ci.nodes.lock(loop_var.value);
|
||||
let phy = self.ci.nodes.modify_input(scope_var.value, 2, loop_var.value);
|
||||
self.ci.nodes.unlock_remove(dest_var.value);
|
||||
dest_var.value = phy;
|
||||
}
|
||||
|
||||
Some(0)
|
||||
}
|
||||
Expr::Break { .. } => {
|
||||
let loob = self.ci.loops.last_mut().unwrap();
|
||||
Expr::Break { pos } => {
|
||||
let Some(loob) = self.ci.loops.last_mut() else {
|
||||
self.report(pos, "break outside a loop");
|
||||
return None;
|
||||
};
|
||||
|
||||
debug_assert_eq!(loob.break_, Nid::MAX, "TODO: multile breaks");
|
||||
if loob.break_ == Nid::MAX {
|
||||
loob.break_ = self.ci.ctrl;
|
||||
loob.break_scope = self.ci.vars[..loob.scope.len()].to_owned();
|
||||
for v in &loob.break_scope {
|
||||
self.ci.nodes.lock(v.value)
|
||||
}
|
||||
} else {
|
||||
loob.break_ =
|
||||
self.ci.nodes.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.break_]);
|
||||
|
||||
for (else_var, then_var) in loob.break_scope.iter_mut().zip(&self.ci.vars) {
|
||||
if else_var.value == then_var.value {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ty = self.ci.nodes[else_var.value].ty;
|
||||
debug_assert_eq!(
|
||||
ty, self.ci.nodes[then_var.value].ty,
|
||||
"TODO: typecheck properly"
|
||||
);
|
||||
|
||||
let inps = [loob.break_, then_var.value, else_var.value];
|
||||
self.ci.nodes.unlock(else_var.value);
|
||||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.end;
|
||||
None
|
||||
}
|
||||
Expr::Continue { pos } => {
|
||||
let Some(loob) = self.ci.loops.last_mut() else {
|
||||
self.report(pos, "break outside a loop");
|
||||
return None;
|
||||
};
|
||||
|
||||
if loob.continue_ == Nid::MAX {
|
||||
loob.continue_ = self.ci.ctrl;
|
||||
loob.continue_scope = self.ci.vars[..loob.scope.len()].to_owned();
|
||||
for v in &loob.continue_scope {
|
||||
self.ci.nodes.lock(v.value)
|
||||
}
|
||||
} else {
|
||||
loob.continue_ = self
|
||||
.ci
|
||||
.nodes
|
||||
.new_node(ty::VOID, Kind::Region, [self.ci.ctrl, loob.continue_]);
|
||||
|
||||
for (else_var, then_var) in loob.continue_scope.iter_mut().zip(&self.ci.vars) {
|
||||
if else_var.value == then_var.value {
|
||||
continue;
|
||||
}
|
||||
|
||||
let ty = self.ci.nodes[else_var.value].ty;
|
||||
debug_assert_eq!(
|
||||
ty, self.ci.nodes[then_var.value].ty,
|
||||
"TODO: typecheck properly"
|
||||
);
|
||||
|
||||
let inps = [loob.continue_, then_var.value, else_var.value];
|
||||
self.ci.nodes.unlock(else_var.value);
|
||||
else_var.value = self.ci.nodes.new_node(ty, Kind::Phi, inps);
|
||||
self.ci.nodes.lock(else_var.value);
|
||||
}
|
||||
}
|
||||
|
||||
self.ci.ctrl = self.ci.end;
|
||||
None
|
||||
}
|
||||
|
@ -1766,19 +1877,20 @@ impl Codegen {
|
|||
Some(self.ci.ctrl)
|
||||
}
|
||||
Expr::Return { pos, val } => {
|
||||
let (ty, value) = if let Some(val) = val {
|
||||
let value = self.expr_ctx(val, Ctx { ty: self.ci.ret })?;
|
||||
|
||||
(self.tof(value), value)
|
||||
let value = if let Some(val) = val {
|
||||
self.expr_ctx(val, Ctx { ty: self.ci.ret })?
|
||||
} else {
|
||||
(ty::VOID.into(), 0)
|
||||
0
|
||||
};
|
||||
|
||||
let inps = [self.ci.ctrl, self.ci.end, value];
|
||||
let out = &mut String::new();
|
||||
self.report_log_to(pos, "returning here", out);
|
||||
log::dbg!("{out}");
|
||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
||||
|
||||
let expected = *self.ci.ret.get_or_insert(ty);
|
||||
_ = self.assert_ty(pos, ty, expected, true, "return value");
|
||||
let expected = *self.ci.ret.get_or_insert(self.tof(value));
|
||||
_ = self.assert_ty(pos, self.tof(value), expected, true, "return value");
|
||||
|
||||
None
|
||||
}
|
||||
|
@ -1908,6 +2020,7 @@ impl Codegen {
|
|||
|
||||
self.ci.regs.init();
|
||||
|
||||
let call_count = self.ci.call_count;
|
||||
'_color_args: {
|
||||
for var in &orig_vars {
|
||||
if var.id != u32::MAX {
|
||||
|
@ -1922,6 +2035,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
self.ci.vars = orig_vars;
|
||||
self.ci.call_count = call_count;
|
||||
self.emit_control(self.ci.nodes[self.ci.start].outputs[0]);
|
||||
self.ci.vars.clear();
|
||||
|
||||
|
@ -1968,11 +2082,14 @@ impl Codegen {
|
|||
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||
if ret != 0 {
|
||||
_ = self.color_expr_consume(ret);
|
||||
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
||||
if node_color!(self, ret).call_count == self.ci.call_count {
|
||||
node_loc!(self, ret) =
|
||||
match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
||||
0 => Loc::default(),
|
||||
1..=8 => Loc { reg: 1 },
|
||||
s => todo!("{s}"),
|
||||
};
|
||||
}
|
||||
self.ci.regs.mark_leaked(1);
|
||||
}
|
||||
return None;
|
||||
|
@ -1988,12 +2105,13 @@ impl Codegen {
|
|||
self.ci.set_next_color(arg);
|
||||
}
|
||||
|
||||
self.ci.call_count -= 1;
|
||||
|
||||
self.ci.set_next_color(ctrl);
|
||||
|
||||
ctrl = *self.ci.nodes[ctrl]
|
||||
.outputs
|
||||
.iter()
|
||||
.inspect(|&&o| log::dbg!(self.ci.nodes[o].kind))
|
||||
.find(|&&o| self.ci.nodes.is_cfg(o))
|
||||
.unwrap();
|
||||
}
|
||||
|
@ -2149,6 +2267,26 @@ impl Codegen {
|
|||
Kind::Return => {
|
||||
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||
if ret != 0 {
|
||||
// NOTE: this is safer less efficient way, maybe it will be needed
|
||||
//self.emit_expr_consume(ret);
|
||||
//if node_color!(self, ret).call_count != self.ci.call_count {
|
||||
// let src = node_loc!(self, ret);
|
||||
// let loc = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
||||
// 0 => Loc::default(),
|
||||
// 1..=8 => Loc { reg: 1 },
|
||||
// s => todo!("{s}"),
|
||||
// };
|
||||
// if src != loc {
|
||||
// let inst = instrs::cp(loc.reg, src.reg);
|
||||
// self.ci.emit(inst);
|
||||
// }
|
||||
//}
|
||||
|
||||
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
||||
0 => Loc::default(),
|
||||
1..=8 => Loc { reg: 1 },
|
||||
s => todo!("{s}"),
|
||||
};
|
||||
self.emit_expr_consume(ret);
|
||||
}
|
||||
self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4));
|
||||
|
@ -2172,6 +2310,7 @@ impl Codegen {
|
|||
};
|
||||
self.ci.regs.mark_leaked(node_loc!(self, arg).reg);
|
||||
self.emit_expr_consume(arg);
|
||||
self.ci.nodes[arg].depth = 0;
|
||||
}
|
||||
|
||||
let reloc = Reloc::new(self.ci.code.len(), 3, 4);
|
||||
|
@ -2191,7 +2330,6 @@ impl Codegen {
|
|||
};
|
||||
|
||||
if self.ci.nodes[ctrl].outputs.len() == 1 {
|
||||
log::dbg!("whata");
|
||||
break 'b;
|
||||
}
|
||||
|
||||
|
@ -2212,35 +2350,48 @@ impl Codegen {
|
|||
let cond = self.ci.nodes[ctrl].inputs[1];
|
||||
|
||||
let jump_offset: i64;
|
||||
match self.ci.nodes[cond].kind {
|
||||
Kind::BinOp { op: op @ (TokenKind::Le | TokenKind::Eq) } => {
|
||||
let mut swapped = false;
|
||||
'resolve_cond: {
|
||||
'optimize_cond: {
|
||||
let Kind::BinOp { op } = self.ci.nodes[cond].kind else {
|
||||
break 'optimize_cond;
|
||||
};
|
||||
|
||||
let [left, right, ..] = self.ci.nodes[cond].inputs;
|
||||
swapped = matches!(op, TokenKind::Lt | TokenKind::Gt);
|
||||
let signed = self.ci.nodes[left].ty.is_signed();
|
||||
let op = match op {
|
||||
TokenKind::Le if signed => instrs::jgts,
|
||||
TokenKind::Le => instrs::jgtu,
|
||||
TokenKind::Lt if signed => instrs::jlts,
|
||||
TokenKind::Lt => instrs::jltu,
|
||||
TokenKind::Eq => instrs::jne,
|
||||
TokenKind::Ne => instrs::jeq,
|
||||
_ => break 'optimize_cond,
|
||||
};
|
||||
|
||||
self.emit_expr_consume(left);
|
||||
self.emit_expr_consume(right);
|
||||
|
||||
let op = match op {
|
||||
TokenKind::Le if self.ci.nodes[left].ty.is_signed() => instrs::jgts,
|
||||
TokenKind::Le => instrs::jgtu,
|
||||
TokenKind::Eq => instrs::jne,
|
||||
op => unreachable!("{op}"),
|
||||
};
|
||||
|
||||
jump_offset = self.ci.code.len() as _;
|
||||
self.ci.emit(op(
|
||||
node_loc!(self, left).reg,
|
||||
node_loc!(self, right).reg,
|
||||
0,
|
||||
));
|
||||
|
||||
break 'resolve_cond;
|
||||
}
|
||||
_ => {
|
||||
|
||||
self.emit_expr_consume(cond);
|
||||
jump_offset = self.ci.code.len() as _;
|
||||
self.ci.emit(instrs::jeq(node_loc!(self, cond).reg, reg::ZERO, 0));
|
||||
}
|
||||
}
|
||||
|
||||
let [loff, roff] = [swapped as usize, !swapped as usize];
|
||||
|
||||
let filled_base = self.ci.filled.len();
|
||||
let left_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[0]);
|
||||
let left_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[loff]);
|
||||
for fld in self.ci.filled.drain(filled_base..) {
|
||||
self.ci.nodes[fld].depth = 0;
|
||||
}
|
||||
|
@ -2251,7 +2402,7 @@ impl Codegen {
|
|||
if self.ci.nodes[o].kind != Kind::Phi {
|
||||
continue;
|
||||
}
|
||||
let out = self.ci.nodes[o].inputs[1];
|
||||
let out = self.ci.nodes[o].inputs[1 + loff];
|
||||
self.emit_expr_consume(out);
|
||||
self.emit_pass(out, o);
|
||||
}
|
||||
|
@ -2262,7 +2413,7 @@ impl Codegen {
|
|||
|
||||
let right_base = self.ci.code.len();
|
||||
let filled_base = self.ci.filled.len();
|
||||
let right_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[1]);
|
||||
let right_unreachable = self.emit_control(self.ci.nodes[ctrl].outputs[roff]);
|
||||
|
||||
for fld in self.ci.filled.drain(filled_base..) {
|
||||
self.ci.nodes[fld].depth = 0;
|
||||
|
@ -2273,7 +2424,7 @@ impl Codegen {
|
|||
if self.ci.nodes[o].kind != Kind::Phi {
|
||||
continue;
|
||||
}
|
||||
let out = self.ci.nodes[o].inputs[2];
|
||||
let out = self.ci.nodes[o].inputs[1 + roff];
|
||||
self.emit_expr_consume(out);
|
||||
self.emit_pass(out, o);
|
||||
}
|
||||
|
@ -2694,18 +2845,21 @@ impl Codegen {
|
|||
}
|
||||
|
||||
fn report_log(&self, pos: Pos, msg: impl std::fmt::Display) {
|
||||
use std::fmt::Write;
|
||||
let mut buf = self.errors.borrow_mut();
|
||||
self.report_log_to(pos, msg, &mut *buf);
|
||||
}
|
||||
|
||||
fn report_log_to(&self, pos: Pos, msg: impl std::fmt::Display, out: &mut impl std::fmt::Write) {
|
||||
let str = &self.cfile().file;
|
||||
let (line, mut col) = lexer::line_col(str.as_bytes(), pos);
|
||||
_ = writeln!(buf, "{}:{}:{}: {}", self.cfile().path, line, col, msg);
|
||||
_ = writeln!(out, "{}:{}:{}: {}", self.cfile().path, line, col, msg);
|
||||
|
||||
let line = &str[str[..pos as usize].rfind('\n').map_or(0, |i| i + 1)
|
||||
..str[pos as usize..].find('\n').unwrap_or(str.len()) + pos as usize];
|
||||
col += line.matches('\t').count() * 3;
|
||||
|
||||
_ = writeln!(buf, "{}", line.replace("\t", " "));
|
||||
_ = writeln!(buf, "{}^", " ".repeat(col - 1));
|
||||
_ = writeln!(out, "{}", line.replace("\t", " "));
|
||||
_ = writeln!(out, "{}^", " ".repeat(col - 1));
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
main:
|
||||
ADDI64 r254, r254, -24d
|
||||
ST r31, r254, 0a, 24h
|
||||
LI64 r2, 0d
|
||||
JAL r31, r0, :multiple_breaks
|
||||
CP r32, r1
|
||||
LI64 r32, 3d
|
||||
JEQ r32, r32, :0
|
||||
LI64 r1, 1d
|
||||
JMP :1
|
||||
0: LI64 r2, 4d
|
||||
JAL r31, r0, :multiple_breaks
|
||||
LI64 r33, 10d
|
||||
JEQ r1, r33, :2
|
||||
LI64 r1, 2d
|
||||
JMP :1
|
||||
2: LI64 r1, 0d
|
||||
1: LD r31, r254, 0a, 24h
|
||||
ADDI64 r254, r254, 24d
|
||||
JALA r0, r31, 0a
|
||||
multiple_breaks:
|
||||
ADDI64 r254, r254, -32d
|
||||
ST r31, r254, 0a, 32h
|
||||
CP r32, r2
|
||||
CP r1, r32
|
||||
2: LI64 r33, 10d
|
||||
JLTS r1, r33, :0
|
||||
JMP :1
|
||||
0: ADDI64 r34, r1, 1d
|
||||
CP r1, r34
|
||||
JMP :2
|
||||
1: LD r31, r254, 0a, 32h
|
||||
ADDI64 r254, r254, 32d
|
||||
JALA r0, r31, 0a
|
||||
code size: 278
|
||||
ret: 0
|
||||
status: Ok(())
|
|
@ -1,36 +1,36 @@
|
|||
main:
|
||||
ADDI64 r254, r254, -96d
|
||||
ST r31, r254, 0a, 96h
|
||||
ADDI64 r254, r254, -104d
|
||||
ST r31, r254, 0a, 104h
|
||||
JAL r31, r0, :check_platform
|
||||
LI64 r1, 0d
|
||||
CP r32, r1
|
||||
LI64 r33, 30d
|
||||
CP r34, r33
|
||||
LI64 r35, 100d
|
||||
CP r36, r35
|
||||
CP r37, r32
|
||||
CP r38, r36
|
||||
4: ADDI64 r39, r34, 1d
|
||||
JGTS r32, r39, :0
|
||||
LI64 r32, 0d
|
||||
CP r33, r32
|
||||
LI64 r34, 30d
|
||||
CP r35, r34
|
||||
LI64 r36, 100d
|
||||
CP r37, r36
|
||||
CP r38, r33
|
||||
CP r39, r37
|
||||
4: ADDI64 r40, r35, 1d
|
||||
JGTS r33, r40, :0
|
||||
JAL r31, r0, :set_pixel
|
||||
CP r40, r4
|
||||
ADDI64 r41, r3, 1d
|
||||
CP r42, r3
|
||||
CP r41, r4
|
||||
ADDI64 r42, r3, 1d
|
||||
CP r43, r3
|
||||
JMP :1
|
||||
0: JAL r31, r0, :set_pixel
|
||||
CP r40, r4
|
||||
CP r41, r1
|
||||
ADDI64 r42, r3, 1d
|
||||
1: JNE r42, r40, :2
|
||||
CP r41, r4
|
||||
CP r42, r32
|
||||
ADDI64 r43, r3, 1d
|
||||
1: JNE r43, r41, :2
|
||||
JMP :3
|
||||
2: CP r2, r41
|
||||
CP r34, r33
|
||||
CP r4, r35
|
||||
CP r3, r42
|
||||
CP r4, r40
|
||||
2: CP r2, r42
|
||||
CP r35, r34
|
||||
CP r4, r36
|
||||
CP r3, r43
|
||||
CP r4, r41
|
||||
JMP :4
|
||||
3: LD r31, r254, 0a, 96h
|
||||
ADDI64 r254, r254, 96d
|
||||
3: LD r31, r254, 0a, 104h
|
||||
ADDI64 r254, r254, 104d
|
||||
JALA r0, r31, 0a
|
||||
set_pixel:
|
||||
ADDI64 r254, r254, -8d
|
||||
|
|
Loading…
Reference in a new issue