forked from AbleOS/holey-bytes
unifiing the type resolution into a trait
This commit is contained in:
parent
c3a6e62bf2
commit
44c4b71bb3
|
@ -9,7 +9,7 @@ use {
|
|||
reg,
|
||||
ty::{self, TyCheck},
|
||||
Comptime, Field, Func, Global, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
||||
TypedReloc, Types,
|
||||
TypeParser, TypedReloc, Types,
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{assert_matches::debug_assert_matches, fmt::Display},
|
||||
|
@ -443,7 +443,6 @@ struct ItemCtxSnap {
|
|||
#[derive(Default)]
|
||||
struct ItemCtx {
|
||||
file: FileId,
|
||||
id: ty::Kind,
|
||||
ret: Option<ty::Id>,
|
||||
ret_reg: rall::Id,
|
||||
inline_ret_loc: Loc,
|
||||
|
@ -704,6 +703,72 @@ pub struct Codegen {
|
|||
ct: Comptime,
|
||||
}
|
||||
|
||||
impl TypeParser for Codegen {
|
||||
fn tys(&mut self) -> &mut Types {
|
||||
&mut self.tys
|
||||
}
|
||||
|
||||
fn on_reuse(&mut self, existing: ty::Id) {
|
||||
if let ty::Kind::Func(id) = existing.expand()
|
||||
&& let func = &mut self.tys.ins.funcs[id as usize]
|
||||
&& let Err(idx) = task::unpack(func.offset)
|
||||
&& idx < self.tasks.len()
|
||||
{
|
||||
func.offset = task::id(self.tasks.len());
|
||||
let task = self.tasks[idx].take();
|
||||
self.tasks.push(task);
|
||||
}
|
||||
}
|
||||
|
||||
fn eval_ty(
|
||||
&mut self,
|
||||
file: FileId,
|
||||
name: Option<Ident>,
|
||||
expr: &Expr,
|
||||
_: &[parser::Ast],
|
||||
) -> ty::Id {
|
||||
let prev_file = core::mem::replace(&mut self.ci.file, file);
|
||||
let sym = match *expr {
|
||||
Expr::Slice { size, item, .. } => {
|
||||
let ty = self.ty(item);
|
||||
let len = size.map_or(ArrayLen::MAX, |expr| {
|
||||
self.eval_const(self.ci.file, expr, ty::U32) as _
|
||||
});
|
||||
self.tys.make_array(ty, len).expand()
|
||||
}
|
||||
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr).expand(),
|
||||
_ if let Some(name) = name => {
|
||||
let gid = self.tys.ins.globals.len() as ty::Global;
|
||||
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
|
||||
|
||||
let ci = ItemCtx { file, ..self.pool.cis.pop().unwrap_or_default() };
|
||||
|
||||
self.tys.ins.globals[gid as usize] = self
|
||||
.ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr, file, name)))
|
||||
.into_ok();
|
||||
|
||||
ty::Kind::Global(gid)
|
||||
}
|
||||
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)).expand(),
|
||||
};
|
||||
self.ci.file = prev_file;
|
||||
sym.compress()
|
||||
}
|
||||
|
||||
fn report(&self, pos: Pos, msg: impl Display) -> ty::Id {
|
||||
self.report(pos, msg)
|
||||
}
|
||||
|
||||
fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id> {
|
||||
self.ci.vars.iter().rfind(|v| v.id == name && v.value.ty == ty::Id::TYPE).map(|v| {
|
||||
match v.value.loc {
|
||||
Loc::Rt { .. } => unreachable!(),
|
||||
Loc::Ct { derefed, value } => ty::Id::from(ensure_loaded(value, derefed, 4)),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Codegen {
|
||||
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
|
||||
self.tys.ins.globals = embeds
|
||||
|
@ -719,7 +784,7 @@ impl Codegen {
|
|||
pub fn generate(&mut self, root: FileId) {
|
||||
self.ci.emit_entry_prelude();
|
||||
self.ci.file = root;
|
||||
self.find_or_declare(0, root, Err("main"), "");
|
||||
self.find_type(0, root, Err("main"), &self.files.clone());
|
||||
self.make_func_reachable(0);
|
||||
self.complete_call_graph();
|
||||
}
|
||||
|
@ -816,7 +881,9 @@ impl Codegen {
|
|||
}
|
||||
E::Slice { size, item, .. } => {
|
||||
let ty = self.ty(item);
|
||||
let len = size.map_or(ArrayLen::MAX, |expr| self.eval_const(expr, ty::U32) as _);
|
||||
let len = size.map_or(ArrayLen::MAX, |expr| {
|
||||
self.eval_const(self.ci.file, expr, ty::U32) as _
|
||||
});
|
||||
Some(Value::ty(self.tys.make_array(ty, len)))
|
||||
}
|
||||
E::Index { base, index } => {
|
||||
|
@ -879,15 +946,20 @@ impl Codegen {
|
|||
}
|
||||
}
|
||||
E::Directive { name: "inline", args: [func_ast, args @ ..], .. } => {
|
||||
let ty::Kind::Func(mut func) = self.ty(func_ast).expand() else {
|
||||
self.report(func_ast.pos(), "first argument of inline needs to be a function");
|
||||
let ty = self.ty(func_ast);
|
||||
let ty::Kind::Func(mut func) = ty.expand() else {
|
||||
self.report(
|
||||
func_ast.pos(),
|
||||
format_args!(
|
||||
"first argument of inline needs to be a function, but its '{}'",
|
||||
self.ty_display(ty)
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
let fuc = &self.tys.ins.funcs[func as usize];
|
||||
let ast = self.files[fuc.file as usize].clone();
|
||||
let E::BinOp { right: &E::Closure { args: cargs, body, .. }, .. } =
|
||||
fuc.expr.get(&ast).unwrap()
|
||||
else {
|
||||
let &E::Closure { args: cargs, body, .. } = fuc.expr.get(&ast).unwrap() else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
|
@ -1183,7 +1255,10 @@ impl Codegen {
|
|||
self.ci.revert(checkpoint);
|
||||
match self.ty(target).expand() {
|
||||
ty::Kind::Module(idx) => {
|
||||
match self.find_or_declare(pos, idx, Err(field), "") {
|
||||
match self
|
||||
.find_type(pos, idx, Err(field), &self.files.clone())
|
||||
.expand()
|
||||
{
|
||||
ty::Kind::Global(idx) => self.handle_global(idx),
|
||||
e => Some(Value::ty(e.compress())),
|
||||
}
|
||||
|
@ -1282,7 +1357,7 @@ impl Codegen {
|
|||
}
|
||||
E::BinOp { left, op: T::Decl, right } if self.has_ct(left) => {
|
||||
let slot_base = self.ct.vm.read_reg(reg::STACK_PTR).0;
|
||||
let (cnt, ty) = self.eval_const_low(right, None);
|
||||
let (cnt, ty) = self.eval_const_low(self.ci.file, right, None);
|
||||
if self.assign_ct_pattern(left, ty, cnt as _) {
|
||||
self.ct.vm.write_reg(reg::STACK_PTR, slot_base);
|
||||
}
|
||||
|
@ -1296,7 +1371,13 @@ impl Codegen {
|
|||
log::trace!("call {}", self.ast_display(fast));
|
||||
let func_ty = self.ty(fast);
|
||||
let ty::Kind::Func(mut func) = func_ty.expand() else {
|
||||
self.report(fast.pos(), "can't call this, maybe in the future");
|
||||
self.report(
|
||||
fast.pos(),
|
||||
format_args!(
|
||||
"can't '{}' this, maybe in the future",
|
||||
self.ty_display(func_ty)
|
||||
),
|
||||
);
|
||||
};
|
||||
|
||||
// TODO: this will be usefull but not now
|
||||
|
@ -1306,9 +1387,7 @@ impl Codegen {
|
|||
|
||||
let fuc = &self.tys.ins.funcs[func as usize];
|
||||
let ast = self.files[fuc.file as usize].clone();
|
||||
let E::BinOp { right: &E::Closure { args: cargs, .. }, .. } =
|
||||
fuc.expr.get(&ast).unwrap()
|
||||
else {
|
||||
let &E::Closure { args: cargs, .. } = fuc.expr.get(&ast).unwrap() else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
|
@ -1371,14 +1450,8 @@ impl Codegen {
|
|||
let loc = var.value.loc.as_ref();
|
||||
Some(Value { ty: self.ci.vars[var_index].value.ty, loc })
|
||||
}
|
||||
E::Ident { id, .. } => {
|
||||
let cfile = self.cfile().clone();
|
||||
match self.find_or_declare(
|
||||
ident::pos(id),
|
||||
self.ci.file,
|
||||
Ok(id),
|
||||
cfile.ident_str(id),
|
||||
) {
|
||||
E::Ident { id, pos, .. } => {
|
||||
match self.find_type(pos, self.ci.file, Ok(id), &self.files.clone()).expand() {
|
||||
ty::Kind::Global(id) => self.handle_global(id),
|
||||
tk => Some(Value::ty(tk.compress())),
|
||||
}
|
||||
|
@ -1719,9 +1792,7 @@ impl Codegen {
|
|||
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
|
||||
let fuc = &self.tys.ins.funcs[*func as usize];
|
||||
let fast = self.files[fuc.file as usize].clone();
|
||||
let Expr::BinOp { right: &Expr::Closure { args: cargs, ret, .. }, .. } =
|
||||
fuc.expr.get(&fast).unwrap()
|
||||
else {
|
||||
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast).unwrap() else {
|
||||
unreachable!();
|
||||
};
|
||||
|
||||
|
@ -1786,7 +1857,6 @@ impl Codegen {
|
|||
// FIXME: very inneficient
|
||||
let mut ci = ItemCtx {
|
||||
file: self.ci.file,
|
||||
id: self.ci.id,
|
||||
ret: self.ci.ret,
|
||||
task_base: self.ci.task_base,
|
||||
..self.pool.cis.pop().unwrap_or_default()
|
||||
|
@ -1818,17 +1888,17 @@ impl Codegen {
|
|||
value.ty
|
||||
}
|
||||
|
||||
fn eval_const(&mut self, expr: &Expr, ty: impl Into<ty::Id>) -> u64 {
|
||||
self.eval_const_low(expr, Some(ty.into())).0
|
||||
fn eval_const(&mut self, file: FileId, expr: &Expr, ty: impl Into<ty::Id>) -> u64 {
|
||||
self.eval_const_low(file, expr, Some(ty.into())).0
|
||||
}
|
||||
|
||||
fn eval_const_low(&mut self, expr: &Expr, mut ty: Option<ty::Id>) -> (u64, ty::Id) {
|
||||
let mut ci = ItemCtx {
|
||||
file: self.ci.file,
|
||||
id: ty::Kind::Builtin(u32::MAX),
|
||||
ret: ty,
|
||||
..self.pool.cis.pop().unwrap_or_default()
|
||||
};
|
||||
fn eval_const_low(
|
||||
&mut self,
|
||||
file: FileId,
|
||||
expr: &Expr,
|
||||
mut ty: Option<ty::Id>,
|
||||
) -> (u64, ty::Id) {
|
||||
let mut ci = ItemCtx { file, ret: ty, ..self.pool.cis.pop().unwrap_or_default() };
|
||||
ci.vars.append(&mut self.ci.vars);
|
||||
|
||||
let loc = self.ct_eval(ci, |s, prev| {
|
||||
|
@ -2083,21 +2153,11 @@ impl Codegen {
|
|||
let expr = func.expr.get(&ast).unwrap();
|
||||
let ct_stack_base = self.ct.vm.read_reg(reg::STACK_PTR).0;
|
||||
|
||||
let repl = ItemCtx {
|
||||
file,
|
||||
id: ty::Kind::Func(id),
|
||||
ret: Some(sig.ret),
|
||||
..self.pool.cis.pop().unwrap_or_default()
|
||||
};
|
||||
let repl = ItemCtx { file, ret: Some(sig.ret), ..self.pool.cis.pop().unwrap_or_default() };
|
||||
let prev_ci = core::mem::replace(&mut self.ci, repl);
|
||||
self.ci.regs.init();
|
||||
|
||||
let Expr::BinOp {
|
||||
left: Expr::Ident { .. },
|
||||
op: TokenKind::Decl,
|
||||
right: &Expr::Closure { body, args, .. },
|
||||
} = expr
|
||||
else {
|
||||
let Expr::Closure { body, args, .. } = expr else {
|
||||
unreachable!("{}", self.ast_display(expr))
|
||||
};
|
||||
|
||||
|
@ -2375,18 +2435,7 @@ impl Codegen {
|
|||
}
|
||||
|
||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||
let ty = self.tys.ty(self.ci.file, expr, &self.files);
|
||||
let evaled_ty = ty::Id::from(self.eval_const(expr, ty::TYPE));
|
||||
if let Some(ty) = ty {
|
||||
debug_assert_eq!(
|
||||
ty,
|
||||
evaled_ty,
|
||||
"{} {}",
|
||||
self.ty_display(ty),
|
||||
self.ty_display(evaled_ty)
|
||||
);
|
||||
}
|
||||
evaled_ty
|
||||
self.parse_ty(self.ci.file, expr, None, &self.files.clone())
|
||||
}
|
||||
|
||||
fn read_trap(addr: u64) -> Option<&'static trap::Trap> {
|
||||
|
@ -2455,118 +2504,6 @@ impl Codegen {
|
|||
self.ct.vm.pc = hbvm::mem::Address::new(offset as _);
|
||||
}
|
||||
|
||||
fn find_or_declare(
|
||||
&mut self,
|
||||
pos: Pos,
|
||||
file: FileId,
|
||||
name: Result<Ident, &str>,
|
||||
lit_name: &str,
|
||||
) -> ty::Kind {
|
||||
log::trace!("find_or_declare: {lit_name} {file}");
|
||||
if let Some(ty) = self.tys.find_type(file, name, &self.files) {
|
||||
return ty.expand();
|
||||
}
|
||||
|
||||
let f = self.files[file as usize].clone();
|
||||
let Some((expr, ident)) = f.find_decl(name) else {
|
||||
match name {
|
||||
Ok(_) => self.report(pos, format_args!("undefined identifier: {lit_name}")),
|
||||
Err("main") => self.report(pos, format_args!("missing main function")),
|
||||
Err(name) => self.report(pos, format_args!("undefined indentifier: {name}")),
|
||||
}
|
||||
};
|
||||
|
||||
let key = SymKey::Decl(file, ident);
|
||||
if let Some(existing) = self.tys.syms.get(key, &self.tys.ins) {
|
||||
if let ty::Kind::Func(id) = existing.expand()
|
||||
&& let func = &mut self.tys.ins.funcs[id as usize]
|
||||
&& let Err(idx) = task::unpack(func.offset)
|
||||
&& idx < self.tasks.len()
|
||||
{
|
||||
func.offset = task::id(self.tasks.len());
|
||||
let task = self.tasks[idx].take();
|
||||
self.tasks.push(task);
|
||||
}
|
||||
return existing.expand();
|
||||
}
|
||||
|
||||
let prev_file = core::mem::replace(&mut self.ci.file, file);
|
||||
let sym = match expr {
|
||||
Expr::BinOp {
|
||||
left: &Expr::Ident { id, .. },
|
||||
op: TokenKind::Decl,
|
||||
right: &Expr::Closure { pos, args, ret, .. },
|
||||
} => {
|
||||
let func = Func {
|
||||
file,
|
||||
name: id,
|
||||
sig: 'b: {
|
||||
let arg_base = self.tys.tmp.args.len();
|
||||
for arg in args {
|
||||
let sym = find_symbol(&self.files[file as usize].symbols, arg.id);
|
||||
if sym.flags & idfl::COMPTIME != 0 {
|
||||
self.tys.tmp.args.truncate(arg_base);
|
||||
break 'b None;
|
||||
}
|
||||
let ty = self.ty(&arg.ty);
|
||||
self.tys.tmp.args.push(ty);
|
||||
}
|
||||
|
||||
let args = self
|
||||
.tys
|
||||
.pack_args(arg_base)
|
||||
.unwrap_or_else(|| self.report(pos, "function has too many argumnets"));
|
||||
let ret = self.ty(ret);
|
||||
|
||||
Some(Sig { args, ret })
|
||||
},
|
||||
expr: {
|
||||
let refr = ExprRef::new(expr);
|
||||
debug_assert!(refr.get(&f).is_some());
|
||||
refr
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let id = self.tys.ins.funcs.len() as _;
|
||||
self.tys.ins.funcs.push(func);
|
||||
|
||||
ty::Kind::Func(id)
|
||||
}
|
||||
Expr::BinOp {
|
||||
left: &Expr::Ident { id, .. },
|
||||
op: TokenKind::Decl,
|
||||
right: stru @ Expr::Struct { .. },
|
||||
} => {
|
||||
let str = self.ty(stru).expand().inner();
|
||||
self.tys.ins.structs[str as usize].name = id;
|
||||
ty::Kind::Struct(str)
|
||||
}
|
||||
Expr::BinOp { left, op: TokenKind::Decl, right } => {
|
||||
let gid = self.tys.ins.globals.len() as ty::Global;
|
||||
self.tys.ins.globals.push(Global { file, name: ident, ..Default::default() });
|
||||
|
||||
let ci = ItemCtx {
|
||||
file,
|
||||
id: ty::Kind::Builtin(u32::MAX),
|
||||
..self.pool.cis.pop().unwrap_or_default()
|
||||
};
|
||||
|
||||
_ = left.find_pattern_path(ident, right, |expr| {
|
||||
self.tys.ins.globals[gid as usize] = self
|
||||
.ct_eval(ci, |s, _| Ok::<_, !>(s.generate_global(expr, file, ident)))
|
||||
.into_ok();
|
||||
});
|
||||
|
||||
ty::Kind::Global(gid)
|
||||
}
|
||||
e => unimplemented!("{e:#?}"),
|
||||
};
|
||||
self.ci.file = prev_file;
|
||||
self.tys.syms.insert(key, sym.compress(), &self.tys.ins);
|
||||
sym
|
||||
}
|
||||
|
||||
fn make_func_reachable(&mut self, func: ty::Func) {
|
||||
let fuc = &mut self.tys.ins.funcs[func as usize];
|
||||
if fuc.offset == u32::MAX {
|
||||
|
@ -2598,7 +2535,7 @@ impl Codegen {
|
|||
|
||||
self.ci.free_loc(ret.loc);
|
||||
|
||||
Global { ty: ret.ty, file, name, data, ..Default::default() }
|
||||
Global { ty: ret.ty, file, data, name, ..Default::default() }
|
||||
}
|
||||
|
||||
fn ct_eval<T, E>(
|
||||
|
|
291
lang/src/lib.rs
291
lang/src/lib.rs
|
@ -34,11 +34,11 @@ use {
|
|||
self::{
|
||||
ident::Ident,
|
||||
lexer::TokenKind,
|
||||
parser::{CommentOr, Expr, ExprRef, FileId, Pos},
|
||||
parser::{idfl, CommentOr, Expr, ExprRef, FileId, Pos},
|
||||
ty::ArrayLen,
|
||||
},
|
||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||
core::{cell::Cell, ops::Range},
|
||||
core::{cell::Cell, fmt::Display, ops::Range},
|
||||
hashbrown::hash_map,
|
||||
hbbytecode as instrs,
|
||||
};
|
||||
|
@ -683,7 +683,7 @@ impl Default for Global {
|
|||
offset: u32::MAX,
|
||||
data: Default::default(),
|
||||
file: u32::MAX,
|
||||
name: u32::MAX,
|
||||
name: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -840,6 +840,192 @@ struct Types {
|
|||
|
||||
const HEADER_SIZE: usize = core::mem::size_of::<AbleOsExecutableHeader>();
|
||||
|
||||
trait TypeParser {
|
||||
fn tys(&mut self) -> &mut Types;
|
||||
fn on_reuse(&mut self, existing: ty::Id);
|
||||
fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id>;
|
||||
fn report(&self, pos: Pos, msg: impl Display) -> ty::Id;
|
||||
fn eval_ty(
|
||||
&mut self,
|
||||
file: FileId,
|
||||
name: Option<Ident>,
|
||||
expr: &Expr,
|
||||
files: &[parser::Ast],
|
||||
) -> ty::Id;
|
||||
|
||||
fn find_type(
|
||||
&mut self,
|
||||
pos: Pos,
|
||||
file: FileId,
|
||||
id: Result<Ident, &str>,
|
||||
files: &[parser::Ast],
|
||||
) -> ty::Id {
|
||||
let ty = if let Ok(id) = id
|
||||
&& let Some(ty) = self.find_local_ty(id)
|
||||
{
|
||||
ty
|
||||
} else if let Ok(id) = id
|
||||
&& let tys = self.tys()
|
||||
&& let Some(&ty) = tys.syms.get(SymKey::Decl(file, id), &tys.ins)
|
||||
{
|
||||
self.on_reuse(ty);
|
||||
ty
|
||||
} else {
|
||||
let f = &files[file as usize];
|
||||
|
||||
let Some((Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else {
|
||||
return match id {
|
||||
Ok(name) => {
|
||||
let name = f.ident_str(name);
|
||||
self.report(pos, format_args!("undefined indentifier: {name}"))
|
||||
}
|
||||
Err("main") => self.report(
|
||||
pos,
|
||||
format_args!(
|
||||
"missing main function in '{}', compiler can't \
|
||||
emmit libraries since such concept is not defined",
|
||||
f.path
|
||||
),
|
||||
),
|
||||
Err(name) => self.report(pos, format_args!("undefined indentifier: {name}")),
|
||||
};
|
||||
};
|
||||
|
||||
let tys = self.tys();
|
||||
if let Some(&ty) = tys.syms.get(SymKey::Decl(file, name), &tys.ins) {
|
||||
ty
|
||||
} else {
|
||||
let ty = left
|
||||
.find_pattern_path(name, right, |right| {
|
||||
self.parse_ty(file, right, Some(name), files)
|
||||
})
|
||||
.unwrap_or_else(|_| unreachable!());
|
||||
let tys = self.tys();
|
||||
let nm = match ty.expand() {
|
||||
ty::Kind::Struct(s) => &mut tys.ins.structs[s as usize].name,
|
||||
ty::Kind::Func(s) => &mut tys.ins.funcs[s as usize].name,
|
||||
ty::Kind::Global(s) => &mut tys.ins.globals[s as usize].name,
|
||||
_ => &mut 0,
|
||||
};
|
||||
if *nm == 0 {
|
||||
*nm = name;
|
||||
}
|
||||
tys.syms.insert(SymKey::Decl(file, name), ty, &tys.ins);
|
||||
ty
|
||||
}
|
||||
};
|
||||
|
||||
let tys = self.tys();
|
||||
if let ty::Kind::Global(g) = ty.expand() {
|
||||
let g = &tys.ins.globals[g as usize];
|
||||
if g.ty == ty::Id::TYPE {
|
||||
return ty::Id::from(
|
||||
u32::from_ne_bytes(g.data.as_slice().try_into().unwrap()) as u64
|
||||
);
|
||||
}
|
||||
}
|
||||
ty
|
||||
}
|
||||
|
||||
/// returns none if comptime eval is required
|
||||
fn parse_ty(
|
||||
&mut self,
|
||||
file: FileId,
|
||||
expr: &Expr,
|
||||
name: Option<Ident>,
|
||||
files: &[parser::Ast],
|
||||
) -> ty::Id {
|
||||
match *expr {
|
||||
Expr::Mod { id, .. } => ty::Kind::Module(id).compress(),
|
||||
Expr::UnOp { op: TokenKind::Xor, val, .. } => {
|
||||
let base = self.parse_ty(file, val, None, files);
|
||||
self.tys().make_ptr(base)
|
||||
}
|
||||
Expr::Ident { id, .. } if ident::is_null(id) => id.into(),
|
||||
Expr::Ident { id, pos, .. } => self.find_type(pos, file, Ok(id), files),
|
||||
Expr::Field { target, pos, name } => {
|
||||
let ty::Kind::Module(file) = self.parse_ty(file, target, None, files).expand()
|
||||
else {
|
||||
return self.eval_ty(file, None, expr, files);
|
||||
};
|
||||
|
||||
self.find_type(pos, file, Err(name), files)
|
||||
}
|
||||
Expr::Slice { size: None, item, .. } => {
|
||||
let ty = self.parse_ty(file, item, None, files);
|
||||
self.tys().make_array(ty, ArrayLen::MAX)
|
||||
}
|
||||
Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => {
|
||||
let ty = self.parse_ty(file, item, None, files);
|
||||
self.tys().make_array(ty, value as _)
|
||||
}
|
||||
Expr::Struct { pos, fields, packed, .. } => {
|
||||
let sym = SymKey::Struct(file, pos);
|
||||
let tys = self.tys();
|
||||
if let Some(&ty) = tys.syms.get(sym, &tys.ins) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
let prev_tmp = self.tys().tmp.fields.len();
|
||||
for field in fields.iter().filter_map(CommentOr::or) {
|
||||
let ty = self.parse_ty(file, &field.ty, None, files);
|
||||
let field = Field { name: self.tys().names.intern(field.name), ty };
|
||||
self.tys().tmp.fields.push(field);
|
||||
}
|
||||
|
||||
let tys = self.tys();
|
||||
tys.ins.structs.push(Struct {
|
||||
file,
|
||||
pos,
|
||||
name: name.unwrap_or(0),
|
||||
field_start: tys.ins.fields.len() as _,
|
||||
explicit_alignment: packed.then_some(1),
|
||||
..Default::default()
|
||||
});
|
||||
|
||||
tys.ins.fields.extend(tys.tmp.fields.drain(prev_tmp..));
|
||||
|
||||
let ty = ty::Kind::Struct(tys.ins.structs.len() as u32 - 1).compress();
|
||||
tys.syms.insert(sym, ty, &tys.ins);
|
||||
ty
|
||||
}
|
||||
Expr::Closure { pos, args, ret, .. } if let Some(name) = name => {
|
||||
let func = Func {
|
||||
file,
|
||||
name,
|
||||
sig: 'b: {
|
||||
let arg_base = self.tys().tmp.args.len();
|
||||
for arg in args {
|
||||
let sym = parser::find_symbol(&files[file as usize].symbols, arg.id);
|
||||
if sym.flags & idfl::COMPTIME != 0 {
|
||||
self.tys().tmp.args.truncate(arg_base);
|
||||
break 'b None;
|
||||
}
|
||||
let ty = self.parse_ty(file, &arg.ty, None, files);
|
||||
self.tys().tmp.args.push(ty);
|
||||
}
|
||||
|
||||
let Some(args) = self.tys().pack_args(arg_base) else {
|
||||
return self.report(pos, "function has too many argumnets");
|
||||
};
|
||||
let ret = self.parse_ty(file, ret, None, files);
|
||||
|
||||
Some(Sig { args, ret })
|
||||
},
|
||||
expr: ExprRef::new(expr),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let id = self.tys().ins.funcs.len() as _;
|
||||
self.tys().ins.funcs.push(func);
|
||||
|
||||
ty::Kind::Func(id).compress()
|
||||
}
|
||||
_ => self.eval_ty(file, name, expr, files),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Types {
|
||||
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
|
||||
let start = self.ins.structs[strct as usize].field_start as usize;
|
||||
|
@ -870,98 +1056,6 @@ impl Types {
|
|||
&self.ins.fields[self.struct_field_range(strct)]
|
||||
}
|
||||
|
||||
fn find_type(
|
||||
&mut self,
|
||||
file: FileId,
|
||||
id: Result<Ident, &str>,
|
||||
files: &[parser::Ast],
|
||||
) -> Option<ty::Id> {
|
||||
if let Ok(id) = id
|
||||
&& let Some(&ty) = self.syms.get(SymKey::Decl(file, id), &self.ins)
|
||||
{
|
||||
if let ty::Kind::Global(g) = ty.expand() {
|
||||
let g = &self.ins.globals[g as usize];
|
||||
if g.ty == ty::Id::TYPE {
|
||||
return Some(ty::Id::from(
|
||||
u32::from_ne_bytes(*g.data.first_chunk().unwrap()) as u64
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return Some(ty);
|
||||
}
|
||||
|
||||
let f = &files[file as usize];
|
||||
let (Expr::BinOp { left, right, .. }, name) = f.find_decl(id)? else { unreachable!() };
|
||||
|
||||
let ty = left
|
||||
.find_pattern_path(name, right, |right| self.ty(file, right, files))
|
||||
.unwrap_or_else(|_| unreachable!())?;
|
||||
if let ty::Kind::Struct(s) = ty.expand() {
|
||||
self.ins.structs[s as usize].name = name;
|
||||
}
|
||||
|
||||
self.syms.insert(SymKey::Decl(file, name), ty, &self.ins);
|
||||
Some(ty)
|
||||
}
|
||||
|
||||
/// returns none if comptime eval is required
|
||||
fn ty(&mut self, file: FileId, expr: &Expr, files: &[parser::Ast]) -> Option<ty::Id> {
|
||||
Some(match *expr {
|
||||
Expr::Mod { id, .. } => ty::Kind::Module(id).compress(),
|
||||
Expr::UnOp { op: TokenKind::Xor, val, .. } => {
|
||||
let base = self.ty(file, val, files)?;
|
||||
self.make_ptr(base)
|
||||
}
|
||||
Expr::Ident { id, .. } if ident::is_null(id) => id.into(),
|
||||
Expr::Ident { id, .. } => self.find_type(file, Ok(id), files)?,
|
||||
Expr::Field { target, name, .. } => {
|
||||
let ty::Kind::Module(file) = self.ty(file, target, files)?.expand() else {
|
||||
return None;
|
||||
};
|
||||
|
||||
self.find_type(file, Err(name), files)?
|
||||
}
|
||||
Expr::Slice { size: None, item, .. } => {
|
||||
let ty = self.ty(file, item, files)?;
|
||||
self.make_array(ty, ArrayLen::MAX)
|
||||
}
|
||||
Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => {
|
||||
let ty = self.ty(file, item, files)?;
|
||||
self.make_array(ty, value as _)
|
||||
}
|
||||
Expr::Struct { pos, fields, packed, .. } => {
|
||||
let sym = SymKey::Struct(file, pos);
|
||||
if let Some(&ty) = self.syms.get(sym, &self.ins) {
|
||||
return Some(ty);
|
||||
}
|
||||
|
||||
let prev_tmp = self.tmp.fields.len();
|
||||
for field in fields.iter().filter_map(CommentOr::or) {
|
||||
let Some(ty) = self.ty(file, &field.ty, files) else {
|
||||
self.tmp.fields.truncate(prev_tmp);
|
||||
return None;
|
||||
};
|
||||
self.tmp.fields.push(Field { name: self.names.intern(field.name), ty });
|
||||
}
|
||||
|
||||
self.ins.structs.push(Struct {
|
||||
file,
|
||||
pos,
|
||||
field_start: self.ins.fields.len() as _,
|
||||
explicit_alignment: packed.then_some(1),
|
||||
..Default::default()
|
||||
});
|
||||
self.ins.fields.extend(self.tmp.fields.drain(prev_tmp..));
|
||||
|
||||
let ty = ty::Kind::Struct(self.ins.structs.len() as u32 - 1).compress();
|
||||
self.syms.insert(sym, ty, &self.ins);
|
||||
ty
|
||||
}
|
||||
_ => return None,
|
||||
})
|
||||
}
|
||||
|
||||
fn reassemble(&mut self, buf: &mut Vec<u8>) {
|
||||
self.ins.funcs.iter_mut().for_each(|f| f.offset = u32::MAX);
|
||||
self.ins.globals.iter_mut().for_each(|g| g.offset = u32::MAX);
|
||||
|
@ -1063,12 +1157,7 @@ impl Types {
|
|||
.map(|f| {
|
||||
let name = if f.file != u32::MAX {
|
||||
let file = &files[f.file as usize];
|
||||
let Expr::BinOp { left: &Expr::Ident { id, .. }, .. } =
|
||||
f.expr.get(file).unwrap()
|
||||
else {
|
||||
unreachable!()
|
||||
};
|
||||
file.ident_str(id)
|
||||
file.ident_str(f.name)
|
||||
} else {
|
||||
"target_fn"
|
||||
};
|
||||
|
|
327
lang/src/son.rs
327
lang/src/son.rs
|
@ -12,7 +12,8 @@ use {
|
|||
reg, task,
|
||||
ty::{self, ArrayLen, Tuple},
|
||||
vc::{BitSet, Vc},
|
||||
Comptime, Func, Global, HashMap, Offset, OffsetIter, Reloc, Sig, SymKey, TypedReloc, Types,
|
||||
Comptime, Func, Global, HashMap, Offset, OffsetIter, Reloc, Sig, TypeParser, TypedReloc,
|
||||
Types,
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{
|
||||
|
@ -1416,6 +1417,123 @@ pub struct Codegen<'a> {
|
|||
errors: RefCell<String>,
|
||||
}
|
||||
|
||||
impl TypeParser for Codegen<'_> {
|
||||
fn tys(&mut self) -> &mut Types {
|
||||
&mut self.tys
|
||||
}
|
||||
|
||||
fn on_reuse(&mut self, existing: ty::Id) {
|
||||
if let ty::Kind::Func(id) = existing.expand()
|
||||
&& let func = &mut self.tys.ins.funcs[id as usize]
|
||||
&& let Err(idx) = task::unpack(func.offset)
|
||||
&& idx < self.tasks.len()
|
||||
{
|
||||
func.offset = task::id(self.tasks.len());
|
||||
let task = self.tasks[idx].take();
|
||||
self.tasks.push(task);
|
||||
}
|
||||
}
|
||||
|
||||
#[expect(unused)]
|
||||
fn eval_ty(
|
||||
&mut self,
|
||||
file: FileId,
|
||||
name: Option<Ident>,
|
||||
expr: &Expr,
|
||||
files: &[parser::Ast],
|
||||
) -> ty::Id {
|
||||
let sym = match expr {
|
||||
right if let Some(name) = name => {
|
||||
let gid = self.tys.ins.globals.len() as ty::Global;
|
||||
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
|
||||
|
||||
let ty = ty::Kind::Global(gid);
|
||||
self.pool.push_ci(file, None, self.tasks.len(), &mut self.ci);
|
||||
|
||||
let ret = Expr::Return { pos: right.pos(), val: Some(right) };
|
||||
self.expr(&ret);
|
||||
|
||||
self.ci.finalize();
|
||||
|
||||
let ret = self.ci.ret.expect("for return type to be infered");
|
||||
if self.errors.borrow().is_empty() {
|
||||
self.ci.emit_body(&mut self.tys, self.files, Sig { args: Tuple::empty(), ret });
|
||||
self.ci.code.truncate(self.ci.code.len() - instrs::jala(0, 0, 0).0);
|
||||
self.ci.emit(instrs::tx());
|
||||
|
||||
let func = Func {
|
||||
file,
|
||||
name,
|
||||
expr: ExprRef::new(expr),
|
||||
relocs: core::mem::take(&mut self.ci.relocs),
|
||||
code: core::mem::take(&mut self.ci.code),
|
||||
..Default::default()
|
||||
};
|
||||
self.pool.pop_ci(&mut self.ci);
|
||||
self.complete_call_graph();
|
||||
|
||||
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
||||
|
||||
// TODO: return them back
|
||||
let fuc = self.tys.ins.funcs.len() as ty::Func;
|
||||
self.tys.ins.funcs.push(func);
|
||||
|
||||
self.tys.dump_reachable(fuc, &mut self.ct.code);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let mut vc = String::new();
|
||||
if let Err(e) = self.tys.disasm(&self.ct.code, self.files, &mut vc, |_| {})
|
||||
{
|
||||
panic!("{e} {}", vc);
|
||||
} else {
|
||||
log::trace!("{}", vc);
|
||||
}
|
||||
}
|
||||
|
||||
self.ct.vm.write_reg(reg::RET, mem.as_mut_ptr() as u64);
|
||||
let prev_pc = self.ct.push_pc(self.tys.ins.funcs[fuc as usize].offset);
|
||||
loop {
|
||||
match self.ct.vm.run().expect("TODO") {
|
||||
hbvm::VmRunOk::End => break,
|
||||
hbvm::VmRunOk::Timer => todo!(),
|
||||
hbvm::VmRunOk::Ecall => todo!(),
|
||||
hbvm::VmRunOk::Breakpoint => todo!(),
|
||||
}
|
||||
}
|
||||
self.ct.pop_pc(prev_pc);
|
||||
|
||||
match mem.len() {
|
||||
0 => unreachable!(),
|
||||
len @ 1..=8 => mem
|
||||
.copy_from_slice(&self.ct.vm.read_reg(reg::RET).0.to_ne_bytes()[..len]),
|
||||
9..=16 => todo!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.tys.ins.globals[gid as usize].data = mem;
|
||||
} else {
|
||||
self.pool.pop_ci(&mut self.ci);
|
||||
}
|
||||
self.tys.ins.globals[gid as usize].ty = ret;
|
||||
|
||||
ty
|
||||
}
|
||||
e => self.report_unhandled_ast(expr, "type"),
|
||||
};
|
||||
sym.compress()
|
||||
}
|
||||
|
||||
fn report(&self, pos: Pos, msg: impl Display) -> ty::Id {
|
||||
self.report(pos, msg);
|
||||
ty::Id::NEVER
|
||||
}
|
||||
|
||||
fn find_local_ty(&mut self, _: Ident) -> Option<ty::Id> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Codegen<'a> {
|
||||
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
||||
if value == NEVER {
|
||||
|
@ -1457,7 +1575,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
pub fn generate(&mut self) {
|
||||
self.find_or_declare(0, 0, Err("main"));
|
||||
self.find_type(0, 0, Err("main"), self.files);
|
||||
self.make_func_reachable(0);
|
||||
self.complete_call_graph();
|
||||
}
|
||||
|
@ -1491,8 +1609,8 @@ impl<'a> Codegen<'a> {
|
|||
Some(Value::var(index).ty(var.ty))
|
||||
}
|
||||
Expr::Ident { id, pos, .. } => {
|
||||
let decl = self.find_or_declare(pos, self.ci.file, Ok(id));
|
||||
match decl {
|
||||
let decl = self.find_type(pos, self.ci.file, Ok(id), self.files);
|
||||
match decl.expand() {
|
||||
ty::Kind::Global(global) => {
|
||||
let gl = &self.tys.ins.globals[global as usize];
|
||||
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
||||
|
@ -1744,31 +1862,29 @@ impl<'a> Codegen<'a> {
|
|||
let ctx = Ctx::default().with_ty(self.ty(ty));
|
||||
self.expr_ctx(expr, ctx)
|
||||
}
|
||||
Expr::Call { func: &Expr::Ident { pos, id, .. }, args, .. } => {
|
||||
Expr::Call { func, args, .. } => {
|
||||
self.ci.call_count += 1;
|
||||
let func = self.find_or_declare(pos, self.ci.file, Ok(id));
|
||||
let ty::Kind::Func(func) = func else {
|
||||
let ty = self.ty(func);
|
||||
let ty::Kind::Func(fnc) = ty.expand() else {
|
||||
self.report(
|
||||
pos,
|
||||
fa!("compiler cant (yet) call '{}'", self.ty_display(func.compress())),
|
||||
func.pos(),
|
||||
fa!("compiler cant (yet) call '{}'", self.ty_display(ty)),
|
||||
);
|
||||
return Value::NEVER;
|
||||
};
|
||||
|
||||
self.make_func_reachable(func);
|
||||
self.make_func_reachable(fnc);
|
||||
|
||||
let fuc = &self.tys.ins.funcs[func as usize];
|
||||
let fuc = &self.tys.ins.funcs[fnc as usize];
|
||||
let sig = fuc.sig.expect("TODO: generic functions");
|
||||
let ast = &self.files[fuc.file as usize];
|
||||
let Expr::BinOp { right: &Expr::Closure { args: cargs, .. }, .. } =
|
||||
fuc.expr.get(ast).unwrap()
|
||||
else {
|
||||
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast).unwrap() else {
|
||||
unreachable!()
|
||||
};
|
||||
|
||||
self.assert_report(
|
||||
args.len() == cargs.len(),
|
||||
pos,
|
||||
func.pos(),
|
||||
fa!(
|
||||
"expected {} function argumenr{}, got {}",
|
||||
cargs.len(),
|
||||
|
@ -1805,7 +1921,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
false
|
||||
});
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func }, inps);
|
||||
self.ci.ctrl = self.ci.nodes.new_node(sig.ret, Kind::Call { func: fnc }, inps);
|
||||
|
||||
self.store_mem(VOID, VOID);
|
||||
|
||||
|
@ -2301,7 +2417,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci);
|
||||
|
||||
let Expr::BinOp { right: &Expr::Closure { body, args, .. }, .. } = expr else {
|
||||
let &Expr::Closure { body, args, .. } = expr else {
|
||||
unreachable!("{}", self.ast_display(expr))
|
||||
};
|
||||
|
||||
|
@ -2335,182 +2451,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||
if let Some(ty) = self.tys.ty(self.ci.file, expr, self.files) {
|
||||
return ty;
|
||||
}
|
||||
|
||||
self.report_unhandled_ast(expr, "type")
|
||||
}
|
||||
|
||||
fn find_or_declare(&mut self, pos: Pos, file: FileId, name: Result<Ident, &str>) -> ty::Kind {
|
||||
let f = &self.files[file as usize];
|
||||
let lit_name = name.map(|e| f.ident_str(e)).unwrap_or_else(core::convert::identity);
|
||||
log::trace!("find_or_declare: {lit_name} {file}");
|
||||
if let Some(ty) = self.tys.find_type(file, name, self.files) {
|
||||
return ty.expand();
|
||||
}
|
||||
|
||||
let Some((expr, ident)) = f.find_decl(name) else {
|
||||
match name {
|
||||
Ok(name) => {
|
||||
let name = self.cfile().ident_str(name);
|
||||
self.report(pos, fa!("idk indentifier: {name}"))
|
||||
}
|
||||
Err("main") => self.report(
|
||||
pos,
|
||||
fa!(
|
||||
"missing main function in '{}', compiler can't \
|
||||
emmit libraries since such concept is not defined",
|
||||
f.path
|
||||
),
|
||||
),
|
||||
Err(name) => self.report(pos, fa!("idk indentifier: {name}")),
|
||||
}
|
||||
return ty::Id::NEVER.expand();
|
||||
};
|
||||
|
||||
let key = SymKey::Decl(file, ident);
|
||||
if let Some(existing) = self.tys.syms.get(key, &self.tys.ins) {
|
||||
if let ty::Kind::Func(id) = existing.expand()
|
||||
&& let func = &mut self.tys.ins.funcs[id as usize]
|
||||
&& let Err(idx) = task::unpack(func.offset)
|
||||
&& idx < self.tasks.len()
|
||||
{
|
||||
func.offset = task::id(self.tasks.len());
|
||||
let task = self.tasks[idx].take();
|
||||
self.tasks.push(task);
|
||||
}
|
||||
return existing.expand();
|
||||
}
|
||||
|
||||
let prev_file = core::mem::replace(&mut self.ci.file, file);
|
||||
let sym = match expr {
|
||||
Expr::BinOp {
|
||||
left: &Expr::Ident { id, .. },
|
||||
op: TokenKind::Decl,
|
||||
right: &Expr::Closure { pos, args, ret, .. },
|
||||
} => {
|
||||
let func = Func {
|
||||
file,
|
||||
name: id,
|
||||
sig: '_b: {
|
||||
let arg_base = self.tys.tmp.args.len();
|
||||
for arg in args {
|
||||
let sym = parser::find_symbol(&f.symbols, arg.id);
|
||||
assert!(sym.flags & idfl::COMPTIME == 0, "TODO");
|
||||
let ty = self.ty(&arg.ty);
|
||||
self.tys.tmp.args.push(ty);
|
||||
}
|
||||
|
||||
let Some(args) = self.tys.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);
|
||||
|
||||
Some(Sig { args, ret })
|
||||
},
|
||||
expr: {
|
||||
let refr = ExprRef::new(expr);
|
||||
debug_assert!(refr.get(f).is_some());
|
||||
refr
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let id = self.tys.ins.funcs.len() as _;
|
||||
self.tys.ins.funcs.push(func);
|
||||
|
||||
ty::Kind::Func(id)
|
||||
}
|
||||
Expr::BinOp {
|
||||
left: Expr::Ident { .. },
|
||||
op: TokenKind::Decl,
|
||||
right: right @ (Expr::Struct { .. } | Expr::Mod { .. }),
|
||||
} => self.ty(right).expand(),
|
||||
Expr::BinOp { left: &Expr::Ident { id: name, .. }, op: TokenKind::Decl, right } => {
|
||||
let gid = self.tys.ins.globals.len() as ty::Global;
|
||||
self.tys.ins.globals.push(Global { file, name, ..Default::default() });
|
||||
|
||||
let ty = ty::Kind::Global(gid);
|
||||
self.pool.push_ci(file, None, self.tasks.len(), &mut self.ci);
|
||||
|
||||
let ret = Expr::Return { pos: right.pos(), val: Some(right) };
|
||||
self.expr(&ret);
|
||||
|
||||
self.ci.finalize();
|
||||
|
||||
let ret = self.ci.ret.expect("for return type to be infered");
|
||||
if self.errors.borrow().is_empty() {
|
||||
self.ci.emit_body(&mut self.tys, self.files, Sig { args: Tuple::empty(), ret });
|
||||
self.ci.code.truncate(self.ci.code.len() - instrs::jala(0, 0, 0).0);
|
||||
self.ci.emit(instrs::tx());
|
||||
|
||||
let func = Func {
|
||||
file,
|
||||
name,
|
||||
expr: ExprRef::new(expr),
|
||||
relocs: core::mem::take(&mut self.ci.relocs),
|
||||
code: core::mem::take(&mut self.ci.code),
|
||||
..Default::default()
|
||||
};
|
||||
self.pool.pop_ci(&mut self.ci);
|
||||
self.complete_call_graph();
|
||||
|
||||
let mut mem = vec![0u8; self.tys.size_of(ret) as usize];
|
||||
|
||||
// TODO: return them back
|
||||
let fuc = self.tys.ins.funcs.len() as ty::Func;
|
||||
self.tys.ins.funcs.push(func);
|
||||
|
||||
self.tys.dump_reachable(fuc, &mut self.ct.code);
|
||||
|
||||
#[cfg(debug_assertions)]
|
||||
{
|
||||
let mut vc = String::new();
|
||||
if let Err(e) = self.tys.disasm(&self.ct.code, self.files, &mut vc, |_| {})
|
||||
{
|
||||
panic!("{e} {}", vc);
|
||||
} else {
|
||||
log::trace!("{}", vc);
|
||||
}
|
||||
}
|
||||
|
||||
self.ct.vm.write_reg(reg::RET, mem.as_mut_ptr() as u64);
|
||||
let prev_pc = self.ct.push_pc(self.tys.ins.funcs[fuc as usize].offset);
|
||||
loop {
|
||||
match self.ct.vm.run().expect("TODO") {
|
||||
hbvm::VmRunOk::End => break,
|
||||
hbvm::VmRunOk::Timer => todo!(),
|
||||
hbvm::VmRunOk::Ecall => todo!(),
|
||||
hbvm::VmRunOk::Breakpoint => todo!(),
|
||||
}
|
||||
}
|
||||
self.ct.pop_pc(prev_pc);
|
||||
|
||||
match mem.len() {
|
||||
0 => unreachable!(),
|
||||
len @ 1..=8 => mem
|
||||
.copy_from_slice(&self.ct.vm.read_reg(reg::RET).0.to_ne_bytes()[..len]),
|
||||
9..=16 => todo!(),
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.tys.ins.globals[gid as usize].data = mem;
|
||||
} else {
|
||||
self.pool.pop_ci(&mut self.ci);
|
||||
}
|
||||
self.tys.ins.globals[gid as usize].ty = ret;
|
||||
|
||||
ty
|
||||
}
|
||||
e => unimplemented!("{e:#?}"),
|
||||
};
|
||||
self.ci.file = prev_file;
|
||||
self.tys.syms.insert(key, sym.compress(), &self.tys.ins);
|
||||
sym
|
||||
self.parse_ty(self.ci.file, expr, None, self.files)
|
||||
}
|
||||
|
||||
fn ty_display(&self, ty: ty::Id) -> ty::Display {
|
||||
|
|
7
lang/tests/son_tests_comptime_min_reg_leak.txt
Normal file
7
lang/tests/son_tests_comptime_min_reg_leak.txt
Normal file
|
@ -0,0 +1,7 @@
|
|||
main:
|
||||
LRA r1, r0, :a
|
||||
LD r1, r1, 0a, 8h
|
||||
JALA r0, r31, 0a
|
||||
code size: 47
|
||||
ret: 50
|
||||
status: Ok(())
|
Loading…
Reference in a new issue