better error recovery
This commit is contained in:
parent
73e13bd93c
commit
b4f64656fe
|
@ -116,16 +116,11 @@ main := fn(): int {
|
||||||
fib := fn(n: int): int {
|
fib := fn(n: int): int {
|
||||||
a := 0
|
a := 0
|
||||||
b := 1
|
b := 1
|
||||||
loop {
|
loop if n == 0 break else {
|
||||||
if n == 0 break
|
|
||||||
c := a + b
|
c := a + b
|
||||||
a = b
|
a = b
|
||||||
b = c
|
b = c
|
||||||
n -= 1
|
n -= 1
|
||||||
|
|
||||||
stack_reclamation_edge_case := 0
|
|
||||||
|
|
||||||
//continue
|
|
||||||
}
|
}
|
||||||
return a
|
return a
|
||||||
}
|
}
|
||||||
|
@ -765,3 +760,69 @@ integer_range := fn(min: uint, max: int): uint {
|
||||||
return @eca(uint, 3, 4) % (@bitcast(max) - min + 1) + min
|
return @eca(uint, 3, 4) % (@bitcast(max) - min + 1) + min
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### exhaustive_loop_testing
|
||||||
|
```hb
|
||||||
|
main := fn(): void {
|
||||||
|
if {
|
||||||
|
} != 3 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
if multiple_breaks(4) != 10 {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
|
||||||
|
if state_change_in_break(0) != 0 {
|
||||||
|
return 3
|
||||||
|
}
|
||||||
|
|
||||||
|
if state_change_in_break(4) != 10 {
|
||||||
|
return 4
|
||||||
|
}
|
||||||
|
|
||||||
|
if continue_and_state_change(0) != 10 {
|
||||||
|
return 5
|
||||||
|
}
|
||||||
|
|
||||||
|
if continue_and_state_change(3) != 0 {
|
||||||
|
return 6
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
multiple_breaks := fn(arg: int): int {
|
||||||
|
loop if arg < 10 {
|
||||||
|
arg += 1
|
||||||
|
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
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
|
@ -3429,7 +3429,6 @@ mod tests {
|
||||||
use {
|
use {
|
||||||
super::parser,
|
super::parser,
|
||||||
crate::{codegen::LoggedMem, log, parser::FileId},
|
crate::{codegen::LoggedMem, log, parser::FileId},
|
||||||
core::panic,
|
|
||||||
std::io,
|
std::io,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -182,6 +182,8 @@ impl TokenKind {
|
||||||
TokenKind::Mul => a.wrapping_mul(b),
|
TokenKind::Mul => a.wrapping_mul(b),
|
||||||
TokenKind::Div => a.wrapping_div(b),
|
TokenKind::Div => a.wrapping_div(b),
|
||||||
TokenKind::Shl => a.wrapping_shl(b as _),
|
TokenKind::Shl => a.wrapping_shl(b as _),
|
||||||
|
TokenKind::Eq => (a == b) as i64,
|
||||||
|
TokenKind::Band => a & b,
|
||||||
s => todo!("{s}"),
|
s => todo!("{s}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,9 @@ use {
|
||||||
},
|
},
|
||||||
core::fmt,
|
core::fmt,
|
||||||
std::{
|
std::{
|
||||||
|
cell::RefCell,
|
||||||
collections::BTreeMap,
|
collections::BTreeMap,
|
||||||
|
fmt::Display,
|
||||||
mem,
|
mem,
|
||||||
ops::{self, Range},
|
ops::{self, Range},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
|
@ -28,7 +30,6 @@ macro_rules! node_loc {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Nid = u32;
|
type Nid = u32;
|
||||||
const NILL: u32 = u32::MAX;
|
|
||||||
|
|
||||||
mod reg {
|
mod reg {
|
||||||
|
|
||||||
|
@ -165,7 +166,7 @@ mod ty {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
|
||||||
pub struct Id(NonZeroU32);
|
pub struct Id(NonZeroU32);
|
||||||
|
|
||||||
impl Default for Id {
|
impl Default for Id {
|
||||||
|
@ -425,7 +426,7 @@ mod ty {
|
||||||
struct Nodes {
|
struct Nodes {
|
||||||
values: Vec<PoolSlot>,
|
values: Vec<PoolSlot>,
|
||||||
free: u32,
|
free: u32,
|
||||||
lookup: HashMap<(Kind, [Nid; MAX_INPUTS]), Nid>,
|
lookup: HashMap<(Kind, [Nid; MAX_INPUTS], ty::Id), Nid>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Nodes {
|
impl Default for Nodes {
|
||||||
|
@ -464,16 +465,17 @@ impl Nodes {
|
||||||
self.free = u32::MAX;
|
self.free = u32::MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new_node<const SIZE: usize>(
|
fn new_node_nop<const SIZE: usize>(
|
||||||
&mut self,
|
&mut self,
|
||||||
ty: impl Into<ty::Id>,
|
ty: impl Into<ty::Id>,
|
||||||
kind: Kind,
|
kind: Kind,
|
||||||
inps: [Nid; SIZE],
|
inps: [Nid; SIZE],
|
||||||
) -> Nid {
|
) -> Nid {
|
||||||
let mut inputs = [NILL; MAX_INPUTS];
|
let mut inputs = [Nid::MAX; MAX_INPUTS];
|
||||||
inputs[..inps.len()].copy_from_slice(&inps);
|
inputs[..inps.len()].copy_from_slice(&inps);
|
||||||
|
let ty = ty.into();
|
||||||
|
|
||||||
if let Some(&id) = self.lookup.get(&(kind.clone(), inputs)) {
|
if let Some(&id) = self.lookup.get(&(kind.clone(), inputs, ty)) {
|
||||||
debug_assert_eq!(&self[id].kind, &kind);
|
debug_assert_eq!(&self[id].kind, &kind);
|
||||||
debug_assert_eq!(self[id].inputs, inputs);
|
debug_assert_eq!(self[id].inputs, inputs);
|
||||||
return id;
|
return id;
|
||||||
|
@ -485,14 +487,24 @@ impl Nodes {
|
||||||
color: 0,
|
color: 0,
|
||||||
depth: u32::MAX,
|
depth: u32::MAX,
|
||||||
lock_rc: 0,
|
lock_rc: 0,
|
||||||
ty: ty.into(),
|
ty,
|
||||||
outputs: vec![],
|
outputs: vec![],
|
||||||
});
|
});
|
||||||
|
|
||||||
let prev = self.lookup.insert((kind, inputs), id);
|
let prev = self.lookup.insert((kind, inputs, ty), id);
|
||||||
debug_assert_eq!(prev, None);
|
debug_assert_eq!(prev, None);
|
||||||
|
|
||||||
self.add_deps(id, &inps);
|
self.add_deps(id, &inps);
|
||||||
|
id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_node<const SIZE: usize>(
|
||||||
|
&mut self,
|
||||||
|
ty: impl Into<ty::Id>,
|
||||||
|
kind: Kind,
|
||||||
|
inps: [Nid; SIZE],
|
||||||
|
) -> Nid {
|
||||||
|
let id = self.new_node_nop(ty, kind, inps);
|
||||||
if let Some(opt) = self.peephole(id) {
|
if let Some(opt) = self.peephole(id) {
|
||||||
debug_assert_ne!(opt, id);
|
debug_assert_ne!(opt, id);
|
||||||
self.lock(opt);
|
self.lock(opt);
|
||||||
|
@ -505,17 +517,11 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lock(&mut self, target: Nid) {
|
fn lock(&mut self, target: Nid) {
|
||||||
if target == NILL {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self[target].lock_rc += 1;
|
self[target].lock_rc += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn unlock(&mut self, target: Nid) {
|
fn unlock(&mut self, target: Nid) {
|
||||||
if target == NILL {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
self[target].lock_rc -= 1;
|
self[target].lock_rc -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -530,7 +536,9 @@ impl Nodes {
|
||||||
self[inp].outputs.swap_remove(index);
|
self[inp].outputs.swap_remove(index);
|
||||||
self.remove(inp);
|
self.remove(inp);
|
||||||
}
|
}
|
||||||
let res = self.lookup.remove(&(self[target].kind.clone(), self[target].inputs));
|
let res =
|
||||||
|
self.lookup.remove(&(self[target].kind.clone(), self[target].inputs, self[target].ty));
|
||||||
|
|
||||||
debug_assert_eq!(res, Some(target));
|
debug_assert_eq!(res, Some(target));
|
||||||
self.remove_low(target);
|
self.remove_low(target);
|
||||||
true
|
true
|
||||||
|
@ -545,7 +553,7 @@ impl Nodes {
|
||||||
Kind::Tuple { .. } => {}
|
Kind::Tuple { .. } => {}
|
||||||
Kind::ConstInt { .. } => {}
|
Kind::ConstInt { .. } => {}
|
||||||
Kind::Call { .. } => {}
|
Kind::Call { .. } => {}
|
||||||
Kind::If => {}
|
Kind::If => return self.peephole_if(target),
|
||||||
Kind::Region => {}
|
Kind::Region => {}
|
||||||
Kind::Phi => {}
|
Kind::Phi => {}
|
||||||
Kind::Loop => {}
|
Kind::Loop => {}
|
||||||
|
@ -553,6 +561,16 @@ impl Nodes {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn peephole_if(&mut self, target: Nid) -> Option<Nid> {
|
||||||
|
let cond = self[target].inputs[1];
|
||||||
|
if let Kind::ConstInt { value } = self[cond].kind {
|
||||||
|
let ty = if value == 0 { ty::LEFT_UNREACHABLE } else { ty::RIGHT_UNREACHABLE };
|
||||||
|
return Some(self.new_node_nop(ty, Kind::If, [self[target].inputs[0], cond]));
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn peephole_binop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> {
|
fn peephole_binop(&mut self, target: Nid, op: TokenKind) -> Option<Nid> {
|
||||||
use TokenKind as T;
|
use TokenKind as T;
|
||||||
let [mut lhs, mut rhs, ..] = self[target].inputs;
|
let [mut lhs, mut rhs, ..] = self[target].inputs;
|
||||||
|
@ -660,14 +678,16 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn modify_input(&mut self, target: Nid, inp_index: usize, with: Nid) -> Nid {
|
fn modify_input(&mut self, target: Nid, inp_index: usize, with: Nid) -> Nid {
|
||||||
let out = self.lookup.remove(&(self[target].kind.clone(), self[target].inputs));
|
let out =
|
||||||
|
self.lookup.remove(&(self[target].kind.clone(), self[target].inputs, self[target].ty));
|
||||||
debug_assert!(out == Some(target));
|
debug_assert!(out == Some(target));
|
||||||
debug_assert_ne!(self[target].inputs[inp_index], with);
|
debug_assert_ne!(self[target].inputs[inp_index], with);
|
||||||
|
|
||||||
let prev = self[target].inputs[inp_index];
|
let prev = self[target].inputs[inp_index];
|
||||||
self[target].inputs[inp_index] = with;
|
self[target].inputs[inp_index] = with;
|
||||||
if let Err(other) =
|
if let Err(other) = self
|
||||||
self.lookup.try_insert((self[target].kind.clone(), self[target].inputs), target)
|
.lookup
|
||||||
|
.try_insert((self[target].kind.clone(), self[target].inputs, self[target].ty), target)
|
||||||
{
|
{
|
||||||
let rpl = *other.entry.get();
|
let rpl = *other.entry.get();
|
||||||
self[target].inputs[inp_index] = prev;
|
self[target].inputs[inp_index] = prev;
|
||||||
|
@ -691,9 +711,6 @@ impl Nodes {
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn unlock_remove(&mut self, id: Nid) -> bool {
|
fn unlock_remove(&mut self, id: Nid) -> bool {
|
||||||
if id == NILL {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
self[id].lock_rc -= 1;
|
self[id].lock_rc -= 1;
|
||||||
self.remove(id)
|
self.remove(id)
|
||||||
}
|
}
|
||||||
|
@ -717,7 +734,7 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
Kind::Return => {
|
Kind::Return => {
|
||||||
write!(f, "{}: return [{:?}] ", node, self[node].inputs[0])?;
|
write!(f, "{}: return [{:?}] ", node, self[node].inputs[0])?;
|
||||||
if self[node].inputs[2] != NILL {
|
if self[node].inputs[2] != 0 {
|
||||||
self.fmt(f, self[node].inputs[2], rcs)?;
|
self.fmt(f, self[node].inputs[2], rcs)?;
|
||||||
}
|
}
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
|
@ -788,6 +805,7 @@ impl Nodes {
|
||||||
| Kind::Return
|
| Kind::Return
|
||||||
| Kind::Tuple { .. }
|
| Kind::Tuple { .. }
|
||||||
| Kind::Call { .. }
|
| Kind::Call { .. }
|
||||||
|
| Kind::If
|
||||||
| Kind::Region
|
| Kind::Region
|
||||||
| Kind::Loop
|
| Kind::Loop
|
||||||
)
|
)
|
||||||
|
@ -907,14 +925,9 @@ impl Node {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inputs(&self) -> &[Nid] {
|
fn inputs(&self) -> &[Nid] {
|
||||||
let len = self.inputs.iter().position(|&n| n == NILL).unwrap_or(MAX_INPUTS);
|
let len = self.inputs.iter().position(|&n| n == Nid::MAX).unwrap_or(MAX_INPUTS);
|
||||||
&self.inputs[..len]
|
&self.inputs[..len]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inputs_mut(&mut self) -> &mut [Nid] {
|
|
||||||
let len = self.inputs.iter().position(|&n| n == NILL).unwrap_or(MAX_INPUTS);
|
|
||||||
&mut self.inputs[..len]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for Nodes {
|
impl fmt::Display for Nodes {
|
||||||
|
@ -1377,6 +1390,7 @@ pub struct Codegen {
|
||||||
tys: Types,
|
tys: Types,
|
||||||
ci: ItemCtx,
|
ci: ItemCtx,
|
||||||
pool: Pool,
|
pool: Pool,
|
||||||
|
errors: RefCell<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Codegen {
|
impl Codegen {
|
||||||
|
@ -1488,16 +1502,15 @@ impl Codegen {
|
||||||
let msg = "i know nothing about this name gal which is vired \
|
let msg = "i know nothing about this name gal which is vired \
|
||||||
because we parsed succesfully";
|
because we parsed succesfully";
|
||||||
match *expr {
|
match *expr {
|
||||||
Expr::Comment { .. } => Some(NILL),
|
Expr::Comment { .. } => Some(0),
|
||||||
Expr::Ident { pos, id, .. } => {
|
Expr::Ident { pos, id, .. } => {
|
||||||
let index = self
|
let Some(index) = self.ci.vars.iter().position(|v| v.id == id) else {
|
||||||
.ci
|
self.report(pos, msg);
|
||||||
.vars
|
return Some(self.ci.end);
|
||||||
.iter()
|
};
|
||||||
.position(|v| v.id == id)
|
|
||||||
.unwrap_or_else(|| self.report(pos, msg));
|
|
||||||
|
|
||||||
if self.ci.vars[index].value == NILL {
|
if self.ci.vars[index].value == 0 {
|
||||||
|
self.ci.nodes.unlock(self.ci.vars[index].value);
|
||||||
let loob = self.ci.loops.last_mut().unwrap();
|
let loob = self.ci.loops.last_mut().unwrap();
|
||||||
let inps = [loob.node, loob.scope[index].value, loob.scope[index].value];
|
let inps = [loob.node, loob.scope[index].value, loob.scope[index].value];
|
||||||
self.ci.nodes.unlock(inps[1]);
|
self.ci.nodes.unlock(inps[1]);
|
||||||
|
@ -1515,7 +1528,7 @@ impl Codegen {
|
||||||
let value = self.expr(right)?;
|
let value = self.expr(right)?;
|
||||||
self.ci.nodes.lock(value);
|
self.ci.nodes.lock(value);
|
||||||
self.ci.vars.push(Variable { id, value });
|
self.ci.vars.push(Variable { id, value });
|
||||||
Some(NILL)
|
Some(0)
|
||||||
}
|
}
|
||||||
Expr::BinOp { left: &Expr::Ident { id, pos, .. }, op: TokenKind::Assign, right } => {
|
Expr::BinOp { left: &Expr::Ident { id, pos, .. }, op: TokenKind::Assign, right } => {
|
||||||
let value = self.expr(right)?;
|
let value = self.expr(right)?;
|
||||||
|
@ -1523,11 +1536,12 @@ impl Codegen {
|
||||||
|
|
||||||
let Some(var) = self.ci.vars.iter_mut().find(|v| v.id == id) else {
|
let Some(var) = self.ci.vars.iter_mut().find(|v| v.id == id) else {
|
||||||
self.report(pos, msg);
|
self.report(pos, msg);
|
||||||
|
return Some(self.ci.end);
|
||||||
};
|
};
|
||||||
|
|
||||||
let prev = std::mem::replace(&mut var.value, value);
|
let prev = std::mem::replace(&mut var.value, value);
|
||||||
self.ci.nodes.unlock_remove(prev);
|
self.ci.nodes.unlock_remove(prev);
|
||||||
Some(NILL)
|
Some(0)
|
||||||
}
|
}
|
||||||
Expr::BinOp { left, op, right } => {
|
Expr::BinOp { left, op, right } => {
|
||||||
let lhs = self.expr_ctx(left, ctx)?;
|
let lhs = self.expr_ctx(left, ctx)?;
|
||||||
|
@ -1535,7 +1549,14 @@ impl Codegen {
|
||||||
let rhs = self.expr_ctx(right, Ctx::default().with_ty(self.tof(lhs)));
|
let rhs = self.expr_ctx(right, Ctx::default().with_ty(self.tof(lhs)));
|
||||||
self.ci.nodes.unlock(lhs);
|
self.ci.nodes.unlock(lhs);
|
||||||
let rhs = rhs?;
|
let rhs = rhs?;
|
||||||
let ty = self.assert_ty(left.pos(), self.tof(rhs), self.tof(lhs), false);
|
log::dbg!("{} {}", self.ty_display(self.tof(rhs)), self.ty_display(self.tof(lhs)));
|
||||||
|
let ty = self.assert_ty(
|
||||||
|
left.pos(),
|
||||||
|
self.tof(rhs),
|
||||||
|
self.tof(lhs),
|
||||||
|
false,
|
||||||
|
"right operand",
|
||||||
|
);
|
||||||
let id =
|
let id =
|
||||||
self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, [lhs, rhs]);
|
self.ci.nodes.new_node(ty::bin_ret(ty, op), Kind::BinOp { op }, [lhs, rhs]);
|
||||||
Some(id)
|
Some(id)
|
||||||
|
@ -1559,7 +1580,7 @@ impl Codegen {
|
||||||
if let Some(branch) = branch {
|
if let Some(branch) = branch {
|
||||||
return self.expr(branch);
|
return self.expr(branch);
|
||||||
} else {
|
} else {
|
||||||
return Some(NILL);
|
return Some(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1570,33 +1591,33 @@ impl Codegen {
|
||||||
|
|
||||||
self.ci.ctrl =
|
self.ci.ctrl =
|
||||||
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [if_node]);
|
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [if_node]);
|
||||||
let lcntrl = self.expr(then).map_or(NILL, |_| self.ci.ctrl);
|
let lcntrl = self.expr(then).map_or(Nid::MAX, |_| self.ci.ctrl);
|
||||||
|
|
||||||
let then_scope = std::mem::replace(&mut self.ci.vars, else_scope);
|
let then_scope = std::mem::replace(&mut self.ci.vars, else_scope);
|
||||||
self.ci.ctrl =
|
self.ci.ctrl =
|
||||||
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 1 }, [if_node]);
|
self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 1 }, [if_node]);
|
||||||
let rcntrl = if let Some(else_) = else_ {
|
let rcntrl = if let Some(else_) = else_ {
|
||||||
self.expr(else_).map_or(NILL, |_| self.ci.ctrl)
|
self.expr(else_).map_or(Nid::MAX, |_| self.ci.ctrl)
|
||||||
} else {
|
} else {
|
||||||
self.ci.ctrl
|
self.ci.ctrl
|
||||||
};
|
};
|
||||||
|
|
||||||
if lcntrl == NILL && rcntrl == NILL {
|
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
||||||
for then_var in then_scope {
|
for then_var in then_scope {
|
||||||
self.ci.nodes.unlock_remove(then_var.value);
|
self.ci.nodes.unlock_remove(then_var.value);
|
||||||
}
|
}
|
||||||
return None;
|
return None;
|
||||||
} else if lcntrl == NILL {
|
} else if lcntrl == Nid::MAX {
|
||||||
for then_var in then_scope {
|
for then_var in then_scope {
|
||||||
self.ci.nodes.unlock_remove(then_var.value);
|
self.ci.nodes.unlock_remove(then_var.value);
|
||||||
}
|
}
|
||||||
return Some(NILL);
|
return Some(0);
|
||||||
} else if rcntrl == NILL {
|
} else if rcntrl == Nid::MAX {
|
||||||
for else_var in &self.ci.vars {
|
for else_var in &self.ci.vars {
|
||||||
self.ci.nodes.unlock_remove(else_var.value);
|
self.ci.nodes.unlock_remove(else_var.value);
|
||||||
}
|
}
|
||||||
self.ci.vars = then_scope;
|
self.ci.vars = then_scope;
|
||||||
return Some(NILL);
|
return Some(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Region, [lcntrl, rcntrl]);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Region, [lcntrl, rcntrl]);
|
||||||
|
@ -1620,39 +1641,41 @@ impl Codegen {
|
||||||
self.ci.nodes.lock(else_var.value);
|
self.ci.nodes.lock(else_var.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(NILL)
|
Some(0)
|
||||||
}
|
}
|
||||||
Expr::Loop { body, .. } => {
|
Expr::Loop { body, .. } => {
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Loop, [self.ci.ctrl; 2]);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Loop, [self.ci.ctrl; 2]);
|
||||||
self.ci.loops.push(Loop {
|
self.ci.loops.push(Loop {
|
||||||
node: self.ci.ctrl,
|
node: self.ci.ctrl,
|
||||||
continue_: NILL,
|
continue_: Nid::MAX,
|
||||||
continue_scope: vec![],
|
continue_scope: vec![],
|
||||||
break_: NILL,
|
break_: Nid::MAX,
|
||||||
break_scope: vec![],
|
break_scope: vec![],
|
||||||
scope: self.ci.vars.clone(),
|
scope: self.ci.vars.clone(),
|
||||||
});
|
});
|
||||||
|
|
||||||
for var in &mut self.ci.vars {
|
for var in &mut self.ci.vars {
|
||||||
var.value = NILL;
|
var.value = 0;
|
||||||
}
|
}
|
||||||
|
self.ci.nodes[0].lock_rc += self.ci.vars.len() as u32;
|
||||||
|
|
||||||
self.expr(body);
|
self.expr(body);
|
||||||
|
|
||||||
let Loop { node, continue_, continue_scope: _, break_, break_scope: _, scope } =
|
let Loop { node, continue_, continue_scope: _, break_, break_scope: _, scope } =
|
||||||
self.ci.loops.pop().unwrap();
|
self.ci.loops.pop().unwrap();
|
||||||
|
|
||||||
assert!(continue_ == NILL, "TODO: handle continue");
|
assert!(continue_ == Nid::MAX, "TODO: handle continue");
|
||||||
|
|
||||||
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
self.ci.nodes.modify_input(node, 1, self.ci.ctrl);
|
||||||
|
|
||||||
self.ci.ctrl = break_;
|
self.ci.ctrl = break_;
|
||||||
if break_ == NILL {
|
if break_ == Nid::MAX {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (loop_var, scope_var) in self.ci.vars.iter_mut().zip(scope) {
|
for (loop_var, scope_var) in self.ci.vars.iter_mut().zip(scope) {
|
||||||
if loop_var.value == NILL {
|
if loop_var.value == 0 {
|
||||||
|
self.ci.nodes.unlock(loop_var.value);
|
||||||
loop_var.value = scope_var.value;
|
loop_var.value = scope_var.value;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1674,14 +1697,14 @@ impl Codegen {
|
||||||
self.ci.nodes.lock(loop_var.value);
|
self.ci.nodes.lock(loop_var.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(NILL)
|
Some(0)
|
||||||
}
|
}
|
||||||
Expr::Break { .. } => {
|
Expr::Break { .. } => {
|
||||||
let loob = self.ci.loops.last_mut().unwrap();
|
let loob = self.ci.loops.last_mut().unwrap();
|
||||||
|
|
||||||
debug_assert_eq!(loob.break_, NILL, "TODO: multile breaks");
|
debug_assert_eq!(loob.break_, Nid::MAX, "TODO: multile breaks");
|
||||||
loob.break_ = self.ci.ctrl;
|
loob.break_ = self.ci.ctrl;
|
||||||
self.ci.ctrl = NILL;
|
self.ci.ctrl = self.ci.end;
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Expr::Call { func: &Expr::Ident { pos, id, name, .. }, args, .. } => {
|
Expr::Call { func: &Expr::Ident { pos, id, name, .. }, args, .. } => {
|
||||||
|
@ -1695,6 +1718,7 @@ impl Codegen {
|
||||||
self.ty_display(func.compress())
|
self.ty_display(func.compress())
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
return Some(self.ci.end);
|
||||||
};
|
};
|
||||||
|
|
||||||
let fuc = &self.tys.funcs[func as usize];
|
let fuc = &self.tys.funcs[func as usize];
|
||||||
|
@ -1706,26 +1730,31 @@ impl Codegen {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
if args.len() != cargs.len() {
|
self.assert_report(
|
||||||
let s = if cargs.len() == 1 { "" } else { "s" };
|
args.len() == cargs.len(),
|
||||||
self.report(
|
|
||||||
pos,
|
pos,
|
||||||
format_args!(
|
format_args!(
|
||||||
"expected {} function argumenr{s}, got {}",
|
"expected {} function argumenr{}, got {}",
|
||||||
cargs.len(),
|
cargs.len(),
|
||||||
|
if cargs.len() == 1 { "" } else { "s" },
|
||||||
args.len()
|
args.len()
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
|
||||||
|
|
||||||
let mut inps = vec![];
|
let mut inps = vec![];
|
||||||
for ((arg, _carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) {
|
for ((arg, carg), tyx) in args.iter().zip(cargs).zip(sig.args.range()) {
|
||||||
let ty = self.tys.args[tyx];
|
let ty = self.tys.args[tyx];
|
||||||
if self.tys.size_of(ty) == 0 {
|
if self.tys.size_of(ty) == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
let value = self.expr_ctx(arg, Ctx::default().with_ty(ty))?;
|
||||||
_ = self.assert_ty(arg.pos(), self.tof(value), ty, true);
|
_ = self.assert_ty(
|
||||||
|
arg.pos(),
|
||||||
|
self.tof(value),
|
||||||
|
ty,
|
||||||
|
true,
|
||||||
|
format_args!("argument {}", carg.name),
|
||||||
|
);
|
||||||
inps.push(value);
|
inps.push(value);
|
||||||
}
|
}
|
||||||
self.ci.ctrl =
|
self.ci.ctrl =
|
||||||
|
@ -1742,30 +1771,31 @@ impl Codegen {
|
||||||
|
|
||||||
(self.tof(value), value)
|
(self.tof(value), value)
|
||||||
} else {
|
} else {
|
||||||
(ty::VOID.into(), NILL)
|
(ty::VOID.into(), 0)
|
||||||
};
|
};
|
||||||
|
|
||||||
if value == NILL {
|
|
||||||
let inps = [self.ci.ctrl, self.ci.end];
|
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
|
||||||
} else {
|
|
||||||
let inps = [self.ci.ctrl, self.ci.end, value];
|
let inps = [self.ci.ctrl, self.ci.end, value];
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Return, inps);
|
||||||
}
|
|
||||||
|
|
||||||
let expected = *self.ci.ret.get_or_insert(ty);
|
let expected = *self.ci.ret.get_or_insert(ty);
|
||||||
_ = self.assert_ty(pos, ty, expected, true);
|
_ = self.assert_ty(pos, ty, expected, true, "return value");
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
Expr::Block { stmts, .. } => {
|
Expr::Block { stmts, .. } => {
|
||||||
let base = self.ci.vars.len();
|
let base = self.ci.vars.len();
|
||||||
|
|
||||||
let mut ret = Some(NILL);
|
let mut ret = Some(0);
|
||||||
for stmt in stmts {
|
for stmt in stmts {
|
||||||
ret = ret.and(self.expr(stmt));
|
ret = ret.and(self.expr(stmt));
|
||||||
if let Some(id) = ret {
|
if let Some(id) = ret {
|
||||||
_ = self.assert_ty(stmt.pos(), self.tof(id), ty::VOID.into(), true);
|
_ = self.assert_ty(
|
||||||
|
stmt.pos(),
|
||||||
|
self.tof(id),
|
||||||
|
ty::VOID.into(),
|
||||||
|
true,
|
||||||
|
"statement",
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1780,23 +1810,22 @@ impl Codegen {
|
||||||
ret
|
ret
|
||||||
}
|
}
|
||||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node(
|
Expr::Number { value, .. } => Some(self.ci.nodes.new_node(
|
||||||
ctx.ty.unwrap_or(ty::INT.into()),
|
ctx.ty.filter(|ty| ty.is_integer() || ty.is_pointer()).unwrap_or(ty::INT.into()),
|
||||||
Kind::ConstInt { value },
|
Kind::ConstInt { value },
|
||||||
[],
|
[],
|
||||||
)),
|
)),
|
||||||
ref e => self.report_unhandled_ast(e, "bruh"),
|
ref e => {
|
||||||
|
self.report_unhandled_ast(e, "bruh");
|
||||||
|
Some(self.ci.end)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
fn tof(&self, id: Nid) -> ty::Id {
|
fn tof(&self, id: Nid) -> ty::Id {
|
||||||
if id == NILL {
|
|
||||||
return ty::VOID.into();
|
|
||||||
}
|
|
||||||
self.ci.nodes[id].ty
|
self.ci.nodes[id].ty
|
||||||
}
|
}
|
||||||
|
|
||||||
//#[must_use]
|
|
||||||
fn complete_call_graph(&mut self) {
|
fn complete_call_graph(&mut self) {
|
||||||
self.complete_call_graph_low();
|
self.complete_call_graph_low();
|
||||||
}
|
}
|
||||||
|
@ -1827,7 +1856,7 @@ impl Codegen {
|
||||||
let prev_ci = std::mem::replace(&mut self.ci, repl);
|
let prev_ci = std::mem::replace(&mut self.ci, repl);
|
||||||
|
|
||||||
self.ci.start = self.ci.nodes.new_node(ty::VOID, Kind::Start, []);
|
self.ci.start = self.ci.nodes.new_node(ty::VOID, Kind::Start, []);
|
||||||
self.ci.end = self.ci.nodes.new_node(ty::VOID, Kind::End, []);
|
self.ci.end = self.ci.nodes.new_node(ty::NEVER, Kind::End, []);
|
||||||
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [self.ci.start]);
|
self.ci.ctrl = self.ci.nodes.new_node(ty::VOID, Kind::Tuple { index: 0 }, [self.ci.start]);
|
||||||
|
|
||||||
let Expr::BinOp {
|
let Expr::BinOp {
|
||||||
|
@ -1864,6 +1893,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if self.errors.borrow().is_empty() {
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
{
|
{
|
||||||
self.ci.nodes.check_final_integrity();
|
self.ci.nodes.check_final_integrity();
|
||||||
|
@ -1919,6 +1949,7 @@ impl Codegen {
|
||||||
self.ci.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, (pushed + stack) as _));
|
self.ci.emit(instrs::addi64(reg::STACK_PTR, reg::STACK_PTR, (pushed + stack) as _));
|
||||||
self.ci.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
|
self.ci.emit(instrs::jala(reg::ZERO, reg::RET_ADDR, 0));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.tys.funcs[id as usize].code.append(&mut self.ci.code);
|
self.tys.funcs[id as usize].code.append(&mut self.ci.code);
|
||||||
self.tys.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
self.tys.funcs[id as usize].relocs.append(&mut self.ci.relocs);
|
||||||
|
@ -1934,7 +1965,8 @@ impl Codegen {
|
||||||
Kind::Start => unreachable!(),
|
Kind::Start => unreachable!(),
|
||||||
Kind::End => unreachable!(),
|
Kind::End => unreachable!(),
|
||||||
Kind::Return => {
|
Kind::Return => {
|
||||||
if let Some(&ret) = self.ci.nodes[ctrl].inputs().get(2) {
|
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||||
|
if ret != 0 {
|
||||||
_ = self.color_expr_consume(ret);
|
_ = self.color_expr_consume(ret);
|
||||||
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
node_loc!(self, ret) = match self.tys.size_of(self.ci.ret.expect("TODO")) {
|
||||||
0 => Loc::default(),
|
0 => Loc::default(),
|
||||||
|
@ -1961,6 +1993,7 @@ impl Codegen {
|
||||||
ctrl = *self.ci.nodes[ctrl]
|
ctrl = *self.ci.nodes[ctrl]
|
||||||
.outputs
|
.outputs
|
||||||
.iter()
|
.iter()
|
||||||
|
.inspect(|&&o| log::dbg!(self.ci.nodes[o].kind))
|
||||||
.find(|&&o| self.ci.nodes.is_cfg(o))
|
.find(|&&o| self.ci.nodes.is_cfg(o))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
@ -2114,7 +2147,8 @@ impl Codegen {
|
||||||
Kind::Start => unreachable!(),
|
Kind::Start => unreachable!(),
|
||||||
Kind::End => unreachable!(),
|
Kind::End => unreachable!(),
|
||||||
Kind::Return => {
|
Kind::Return => {
|
||||||
if let Some(&ret) = self.ci.nodes[ctrl].inputs().get(2) {
|
let ret = self.ci.nodes[ctrl].inputs[2];
|
||||||
|
if ret != 0 {
|
||||||
self.emit_expr_consume(ret);
|
self.emit_expr_consume(ret);
|
||||||
}
|
}
|
||||||
self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4));
|
self.ci.ret_relocs.push(Reloc::new(self.ci.code.len(), 1, 4));
|
||||||
|
@ -2157,6 +2191,7 @@ impl Codegen {
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.ci.nodes[ctrl].outputs.len() == 1 {
|
if self.ci.nodes[ctrl].outputs.len() == 1 {
|
||||||
|
log::dbg!("whata");
|
||||||
break 'b;
|
break 'b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2527,7 +2562,10 @@ impl Codegen {
|
||||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||||
match *expr {
|
match *expr {
|
||||||
Expr::Ident { id, .. } if ident::is_null(id) => id.into(),
|
Expr::Ident { id, .. } if ident::is_null(id) => id.into(),
|
||||||
ref e => self.report_unhandled_ast(e, "type"),
|
ref e => {
|
||||||
|
self.report_unhandled_ast(e, "type");
|
||||||
|
ty::NEVER.into()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2557,6 +2595,7 @@ impl Codegen {
|
||||||
),
|
),
|
||||||
Err(name) => self.report(pos, format_args!("undefined indentifier: {name}")),
|
Err(name) => self.report(pos, format_args!("undefined indentifier: {name}")),
|
||||||
}
|
}
|
||||||
|
return ty::Kind::Builtin(ty::NEVER);
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(existing) = self.tys.syms.get(&SymKey { file, ident }) {
|
if let Some(existing) = self.tys.syms.get(&SymKey { file, ident }) {
|
||||||
|
@ -2590,7 +2629,12 @@ impl Codegen {
|
||||||
self.tys.args.push(ty);
|
self.tys.args.push(ty);
|
||||||
}
|
}
|
||||||
|
|
||||||
let args = self.pack_args(pos, arg_base);
|
let Some(args) = self.pack_args(arg_base) else {
|
||||||
|
self.fatal_report(
|
||||||
|
pos,
|
||||||
|
"you cant be serious, using more the 31 arguments in a function",
|
||||||
|
);
|
||||||
|
};
|
||||||
let ret = self.ty(ret);
|
let ret = self.ty(ret);
|
||||||
|
|
||||||
Some(Sig { args, ret })
|
Some(Sig { args, ret })
|
||||||
|
@ -2629,7 +2673,14 @@ impl Codegen {
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn assert_ty(&self, pos: Pos, ty: ty::Id, expected: ty::Id, preserve_expected: bool) -> ty::Id {
|
fn assert_ty(
|
||||||
|
&self,
|
||||||
|
pos: Pos,
|
||||||
|
ty: ty::Id,
|
||||||
|
expected: ty::Id,
|
||||||
|
preserve_expected: bool,
|
||||||
|
hint: impl fmt::Display,
|
||||||
|
) -> ty::Id {
|
||||||
if let Some(res) = ty.try_upcast(expected)
|
if let Some(res) = ty.try_upcast(expected)
|
||||||
&& (!preserve_expected || res == expected)
|
&& (!preserve_expected || res == expected)
|
||||||
{
|
{
|
||||||
|
@ -2637,31 +2688,40 @@ impl Codegen {
|
||||||
} else {
|
} else {
|
||||||
let ty = self.ty_display(ty);
|
let ty = self.ty_display(ty);
|
||||||
let expected = self.ty_display(expected);
|
let expected = self.ty_display(expected);
|
||||||
self.report(pos, format_args!("expected {expected}, got {ty}"));
|
self.report(pos, format_args!("expected {hint} to be of type {expected}, got {ty}"));
|
||||||
|
ty::NEVER.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn report_log(&self, pos: Pos, msg: impl std::fmt::Display) {
|
fn report_log(&self, pos: Pos, msg: impl std::fmt::Display) {
|
||||||
|
use std::fmt::Write;
|
||||||
|
let mut buf = self.errors.borrow_mut();
|
||||||
let str = &self.cfile().file;
|
let str = &self.cfile().file;
|
||||||
let (line, mut col) = lexer::line_col(str.as_bytes(), pos);
|
let (line, mut col) = lexer::line_col(str.as_bytes(), pos);
|
||||||
println!("{}:{}:{}: {}", self.cfile().path, line, col, msg);
|
_ = writeln!(buf, "{}:{}:{}: {}", self.cfile().path, line, col, msg);
|
||||||
|
|
||||||
let line = &str[str[..pos as usize].rfind('\n').map_or(0, |i| i + 1)
|
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];
|
..str[pos as usize..].find('\n').unwrap_or(str.len()) + pos as usize];
|
||||||
col += line.matches('\t').count() * 3;
|
col += line.matches('\t').count() * 3;
|
||||||
|
|
||||||
println!("{}", line.replace("\t", " "));
|
_ = writeln!(buf, "{}", line.replace("\t", " "));
|
||||||
println!("{}^", " ".repeat(col - 1))
|
_ = writeln!(buf, "{}^", " ".repeat(col - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report(&self, pos: Pos, msg: impl std::fmt::Display) -> ! {
|
fn assert_report(&self, cond: bool, pos: Pos, msg: impl std::fmt::Display) {
|
||||||
|
if !cond {
|
||||||
|
self.report(pos, msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[track_caller]
|
||||||
|
fn report(&self, pos: Pos, msg: impl std::fmt::Display) {
|
||||||
self.report_log(pos, msg);
|
self.report_log(pos, msg);
|
||||||
unreachable!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[track_caller]
|
#[track_caller]
|
||||||
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) -> ! {
|
fn report_unhandled_ast(&self, ast: &Expr, hint: &str) {
|
||||||
self.report(
|
self.report(
|
||||||
ast.pos(),
|
ast.pos(),
|
||||||
format_args!(
|
format_args!(
|
||||||
|
@ -2670,17 +2730,17 @@ impl Codegen {
|
||||||
info for weak people:\n\
|
info for weak people:\n\
|
||||||
{ast:#?}"
|
{ast:#?}"
|
||||||
),
|
),
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cfile(&self) -> &parser::Ast {
|
fn cfile(&self) -> &parser::Ast {
|
||||||
&self.files[self.ci.file as usize]
|
&self.files[self.ci.file as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pack_args(&mut self, pos: Pos, arg_base: usize) -> ty::Tuple {
|
fn pack_args(&mut self, arg_base: usize) -> Option<ty::Tuple> {
|
||||||
let needle = &self.tys.args[arg_base..];
|
let needle = &self.tys.args[arg_base..];
|
||||||
if needle.is_empty() {
|
if needle.is_empty() {
|
||||||
return ty::Tuple::empty();
|
return Some(ty::Tuple::empty());
|
||||||
}
|
}
|
||||||
let len = needle.len();
|
let len = needle.len();
|
||||||
// FIXME: maybe later when this becomes a bottleneck we use more
|
// FIXME: maybe later when this becomes a bottleneck we use more
|
||||||
|
@ -2688,7 +2748,6 @@ impl Codegen {
|
||||||
let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap();
|
let sp = self.tys.args.windows(needle.len()).position(|val| val == needle).unwrap();
|
||||||
self.tys.args.truncate((sp + needle.len()).max(arg_base));
|
self.tys.args.truncate((sp + needle.len()).max(arg_base));
|
||||||
ty::Tuple::new(sp, len)
|
ty::Tuple::new(sp, len)
|
||||||
.unwrap_or_else(|| self.report(pos, "amount of arguments not supported"))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn emit_pass(&mut self, src: Nid, dst: Nid) {
|
fn emit_pass(&mut self, src: Nid, dst: Nid) {
|
||||||
|
@ -2720,6 +2779,12 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn fatal_report(&self, pos: Pos, msg: impl Display) -> ! {
|
||||||
|
self.report(pos, msg);
|
||||||
|
eprintln!("{}", self.errors.borrow());
|
||||||
|
std::process::exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
|
@ -2854,6 +2919,14 @@ mod tests {
|
||||||
|
|
||||||
codegen.generate();
|
codegen.generate();
|
||||||
|
|
||||||
|
{
|
||||||
|
let errors = codegen.errors.borrow();
|
||||||
|
if !errors.is_empty() {
|
||||||
|
output.push_str(&errors);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut out = Vec::new();
|
let mut out = Vec::new();
|
||||||
codegen.assemble(&mut out);
|
codegen.assemble(&mut out);
|
||||||
|
|
||||||
|
@ -2946,5 +3019,6 @@ mod tests {
|
||||||
const_folding_with_arg => README;
|
const_folding_with_arg => README;
|
||||||
// FIXME: contains redundant copies
|
// FIXME: contains redundant copies
|
||||||
branch_assignments => README;
|
branch_assignments => README;
|
||||||
|
exhaustive_loop_testing => README;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
0
hblang/tests/son_tests_exhaustive_loop_testing.txt
Normal file
0
hblang/tests/son_tests_exhaustive_loop_testing.txt
Normal file
10
hblang/tests/son_tests_hex_octal_binary_literals.txt
Normal file
10
hblang/tests/son_tests_hex_octal_binary_literals.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
main:
|
||||||
|
ADDI64 r254, r254, -8d
|
||||||
|
ST r31, r254, 0a, 8h
|
||||||
|
LI64 r1, 0d
|
||||||
|
LD r31, r254, 0a, 8h
|
||||||
|
ADDI64 r254, r254, 8d
|
||||||
|
JALA r0, r31, 0a
|
||||||
|
code size: 77
|
||||||
|
ret: 0
|
||||||
|
status: Ok(())
|
Loading…
Reference in a new issue