unifiing the type resolution into a trait
This commit is contained in:
parent
c3a6e62bf2
commit
44c4b71bb3
|
@ -9,7 +9,7 @@ use {
|
||||||
reg,
|
reg,
|
||||||
ty::{self, TyCheck},
|
ty::{self, TyCheck},
|
||||||
Comptime, Field, Func, Global, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
Comptime, Field, Func, Global, OffsetIter, ParamAlloc, Reloc, Sig, Struct, SymKey,
|
||||||
TypedReloc, Types,
|
TypeParser, TypedReloc, Types,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{assert_matches::debug_assert_matches, fmt::Display},
|
core::{assert_matches::debug_assert_matches, fmt::Display},
|
||||||
|
@ -443,7 +443,6 @@ struct ItemCtxSnap {
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ItemCtx {
|
struct ItemCtx {
|
||||||
file: FileId,
|
file: FileId,
|
||||||
id: ty::Kind,
|
|
||||||
ret: Option<ty::Id>,
|
ret: Option<ty::Id>,
|
||||||
ret_reg: rall::Id,
|
ret_reg: rall::Id,
|
||||||
inline_ret_loc: Loc,
|
inline_ret_loc: Loc,
|
||||||
|
@ -704,6 +703,72 @@ pub struct Codegen {
|
||||||
ct: Comptime,
|
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 {
|
impl Codegen {
|
||||||
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
|
pub fn push_embeds(&mut self, embeds: Vec<Vec<u8>>) {
|
||||||
self.tys.ins.globals = embeds
|
self.tys.ins.globals = embeds
|
||||||
|
@ -719,7 +784,7 @@ impl Codegen {
|
||||||
pub fn generate(&mut self, root: FileId) {
|
pub fn generate(&mut self, root: FileId) {
|
||||||
self.ci.emit_entry_prelude();
|
self.ci.emit_entry_prelude();
|
||||||
self.ci.file = root;
|
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.make_func_reachable(0);
|
||||||
self.complete_call_graph();
|
self.complete_call_graph();
|
||||||
}
|
}
|
||||||
|
@ -816,7 +881,9 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
E::Slice { size, item, .. } => {
|
E::Slice { size, item, .. } => {
|
||||||
let ty = self.ty(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)))
|
Some(Value::ty(self.tys.make_array(ty, len)))
|
||||||
}
|
}
|
||||||
E::Index { base, index } => {
|
E::Index { base, index } => {
|
||||||
|
@ -879,15 +946,20 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
E::Directive { name: "inline", args: [func_ast, args @ ..], .. } => {
|
E::Directive { name: "inline", args: [func_ast, args @ ..], .. } => {
|
||||||
let ty::Kind::Func(mut func) = self.ty(func_ast).expand() else {
|
let ty = self.ty(func_ast);
|
||||||
self.report(func_ast.pos(), "first argument of inline needs to be a function");
|
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 fuc = &self.tys.ins.funcs[func as usize];
|
||||||
let ast = self.files[fuc.file as usize].clone();
|
let ast = self.files[fuc.file as usize].clone();
|
||||||
let E::BinOp { right: &E::Closure { args: cargs, body, .. }, .. } =
|
let &E::Closure { args: cargs, body, .. } = fuc.expr.get(&ast).unwrap() else {
|
||||||
fuc.expr.get(&ast).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1183,7 +1255,10 @@ impl Codegen {
|
||||||
self.ci.revert(checkpoint);
|
self.ci.revert(checkpoint);
|
||||||
match self.ty(target).expand() {
|
match self.ty(target).expand() {
|
||||||
ty::Kind::Module(idx) => {
|
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),
|
ty::Kind::Global(idx) => self.handle_global(idx),
|
||||||
e => Some(Value::ty(e.compress())),
|
e => Some(Value::ty(e.compress())),
|
||||||
}
|
}
|
||||||
|
@ -1282,7 +1357,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
E::BinOp { left, op: T::Decl, right } if self.has_ct(left) => {
|
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 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 _) {
|
if self.assign_ct_pattern(left, ty, cnt as _) {
|
||||||
self.ct.vm.write_reg(reg::STACK_PTR, slot_base);
|
self.ct.vm.write_reg(reg::STACK_PTR, slot_base);
|
||||||
}
|
}
|
||||||
|
@ -1296,7 +1371,13 @@ impl Codegen {
|
||||||
log::trace!("call {}", self.ast_display(fast));
|
log::trace!("call {}", self.ast_display(fast));
|
||||||
let func_ty = self.ty(fast);
|
let func_ty = self.ty(fast);
|
||||||
let ty::Kind::Func(mut func) = func_ty.expand() else {
|
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
|
// TODO: this will be usefull but not now
|
||||||
|
@ -1306,9 +1387,7 @@ impl Codegen {
|
||||||
|
|
||||||
let fuc = &self.tys.ins.funcs[func as usize];
|
let fuc = &self.tys.ins.funcs[func as usize];
|
||||||
let ast = self.files[fuc.file as usize].clone();
|
let ast = self.files[fuc.file as usize].clone();
|
||||||
let E::BinOp { right: &E::Closure { args: cargs, .. }, .. } =
|
let &E::Closure { args: cargs, .. } = fuc.expr.get(&ast).unwrap() else {
|
||||||
fuc.expr.get(&ast).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1371,14 +1450,8 @@ impl Codegen {
|
||||||
let loc = var.value.loc.as_ref();
|
let loc = var.value.loc.as_ref();
|
||||||
Some(Value { ty: self.ci.vars[var_index].value.ty, loc })
|
Some(Value { ty: self.ci.vars[var_index].value.ty, loc })
|
||||||
}
|
}
|
||||||
E::Ident { id, .. } => {
|
E::Ident { id, pos, .. } => {
|
||||||
let cfile = self.cfile().clone();
|
match self.find_type(pos, self.ci.file, Ok(id), &self.files.clone()).expand() {
|
||||||
match self.find_or_declare(
|
|
||||||
ident::pos(id),
|
|
||||||
self.ci.file,
|
|
||||||
Ok(id),
|
|
||||||
cfile.ident_str(id),
|
|
||||||
) {
|
|
||||||
ty::Kind::Global(id) => self.handle_global(id),
|
ty::Kind::Global(id) => self.handle_global(id),
|
||||||
tk => Some(Value::ty(tk.compress())),
|
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> {
|
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 fuc = &self.tys.ins.funcs[*func as usize];
|
||||||
let fast = self.files[fuc.file as usize].clone();
|
let fast = self.files[fuc.file as usize].clone();
|
||||||
let Expr::BinOp { right: &Expr::Closure { args: cargs, ret, .. }, .. } =
|
let &Expr::Closure { args: cargs, ret, .. } = fuc.expr.get(&fast).unwrap() else {
|
||||||
fuc.expr.get(&fast).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!();
|
unreachable!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1786,7 +1857,6 @@ impl Codegen {
|
||||||
// FIXME: very inneficient
|
// FIXME: very inneficient
|
||||||
let mut ci = ItemCtx {
|
let mut ci = ItemCtx {
|
||||||
file: self.ci.file,
|
file: self.ci.file,
|
||||||
id: self.ci.id,
|
|
||||||
ret: self.ci.ret,
|
ret: self.ci.ret,
|
||||||
task_base: self.ci.task_base,
|
task_base: self.ci.task_base,
|
||||||
..self.pool.cis.pop().unwrap_or_default()
|
..self.pool.cis.pop().unwrap_or_default()
|
||||||
|
@ -1818,17 +1888,17 @@ impl Codegen {
|
||||||
value.ty
|
value.ty
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eval_const(&mut self, expr: &Expr, ty: impl Into<ty::Id>) -> u64 {
|
fn eval_const(&mut self, file: FileId, expr: &Expr, ty: impl Into<ty::Id>) -> u64 {
|
||||||
self.eval_const_low(expr, Some(ty.into())).0
|
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) {
|
fn eval_const_low(
|
||||||
let mut ci = ItemCtx {
|
&mut self,
|
||||||
file: self.ci.file,
|
file: FileId,
|
||||||
id: ty::Kind::Builtin(u32::MAX),
|
expr: &Expr,
|
||||||
ret: ty,
|
mut ty: Option<ty::Id>,
|
||||||
..self.pool.cis.pop().unwrap_or_default()
|
) -> (u64, ty::Id) {
|
||||||
};
|
let mut ci = ItemCtx { file, ret: ty, ..self.pool.cis.pop().unwrap_or_default() };
|
||||||
ci.vars.append(&mut self.ci.vars);
|
ci.vars.append(&mut self.ci.vars);
|
||||||
|
|
||||||
let loc = self.ct_eval(ci, |s, prev| {
|
let loc = self.ct_eval(ci, |s, prev| {
|
||||||
|
@ -2083,21 +2153,11 @@ impl Codegen {
|
||||||
let expr = func.expr.get(&ast).unwrap();
|
let expr = func.expr.get(&ast).unwrap();
|
||||||
let ct_stack_base = self.ct.vm.read_reg(reg::STACK_PTR).0;
|
let ct_stack_base = self.ct.vm.read_reg(reg::STACK_PTR).0;
|
||||||
|
|
||||||
let repl = ItemCtx {
|
let repl = ItemCtx { file, ret: Some(sig.ret), ..self.pool.cis.pop().unwrap_or_default() };
|
||||||
file,
|
|
||||||
id: ty::Kind::Func(id),
|
|
||||||
ret: Some(sig.ret),
|
|
||||||
..self.pool.cis.pop().unwrap_or_default()
|
|
||||||
};
|
|
||||||
let prev_ci = core::mem::replace(&mut self.ci, repl);
|
let prev_ci = core::mem::replace(&mut self.ci, repl);
|
||||||
self.ci.regs.init();
|
self.ci.regs.init();
|
||||||
|
|
||||||
let Expr::BinOp {
|
let Expr::Closure { body, args, .. } = expr else {
|
||||||
left: Expr::Ident { .. },
|
|
||||||
op: TokenKind::Decl,
|
|
||||||
right: &Expr::Closure { body, args, .. },
|
|
||||||
} = expr
|
|
||||||
else {
|
|
||||||
unreachable!("{}", self.ast_display(expr))
|
unreachable!("{}", self.ast_display(expr))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2375,18 +2435,7 @@ impl Codegen {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||||
let ty = self.tys.ty(self.ci.file, expr, &self.files);
|
self.parse_ty(self.ci.file, expr, None, &self.files.clone())
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_trap(addr: u64) -> Option<&'static trap::Trap> {
|
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 _);
|
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) {
|
fn make_func_reachable(&mut self, func: ty::Func) {
|
||||||
let fuc = &mut self.tys.ins.funcs[func as usize];
|
let fuc = &mut self.tys.ins.funcs[func as usize];
|
||||||
if fuc.offset == u32::MAX {
|
if fuc.offset == u32::MAX {
|
||||||
|
@ -2598,7 +2535,7 @@ impl Codegen {
|
||||||
|
|
||||||
self.ci.free_loc(ret.loc);
|
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>(
|
fn ct_eval<T, E>(
|
||||||
|
|
291
lang/src/lib.rs
291
lang/src/lib.rs
|
@ -34,11 +34,11 @@ use {
|
||||||
self::{
|
self::{
|
||||||
ident::Ident,
|
ident::Ident,
|
||||||
lexer::TokenKind,
|
lexer::TokenKind,
|
||||||
parser::{CommentOr, Expr, ExprRef, FileId, Pos},
|
parser::{idfl, CommentOr, Expr, ExprRef, FileId, Pos},
|
||||||
ty::ArrayLen,
|
ty::ArrayLen,
|
||||||
},
|
},
|
||||||
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
|
||||||
core::{cell::Cell, ops::Range},
|
core::{cell::Cell, fmt::Display, ops::Range},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
hbbytecode as instrs,
|
hbbytecode as instrs,
|
||||||
};
|
};
|
||||||
|
@ -683,7 +683,7 @@ impl Default for Global {
|
||||||
offset: u32::MAX,
|
offset: u32::MAX,
|
||||||
data: Default::default(),
|
data: Default::default(),
|
||||||
file: u32::MAX,
|
file: u32::MAX,
|
||||||
name: u32::MAX,
|
name: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -840,6 +840,192 @@ struct Types {
|
||||||
|
|
||||||
const HEADER_SIZE: usize = core::mem::size_of::<AbleOsExecutableHeader>();
|
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 {
|
impl Types {
|
||||||
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
|
fn struct_field_range(&self, strct: ty::Struct) -> Range<usize> {
|
||||||
let start = self.ins.structs[strct as usize].field_start as 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)]
|
&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>) {
|
fn reassemble(&mut self, buf: &mut Vec<u8>) {
|
||||||
self.ins.funcs.iter_mut().for_each(|f| f.offset = u32::MAX);
|
self.ins.funcs.iter_mut().for_each(|f| f.offset = u32::MAX);
|
||||||
self.ins.globals.iter_mut().for_each(|g| g.offset = u32::MAX);
|
self.ins.globals.iter_mut().for_each(|g| g.offset = u32::MAX);
|
||||||
|
@ -1063,12 +1157,7 @@ impl Types {
|
||||||
.map(|f| {
|
.map(|f| {
|
||||||
let name = if f.file != u32::MAX {
|
let name = if f.file != u32::MAX {
|
||||||
let file = &files[f.file as usize];
|
let file = &files[f.file as usize];
|
||||||
let Expr::BinOp { left: &Expr::Ident { id, .. }, .. } =
|
file.ident_str(f.name)
|
||||||
f.expr.get(file).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
file.ident_str(id)
|
|
||||||
} else {
|
} else {
|
||||||
"target_fn"
|
"target_fn"
|
||||||
};
|
};
|
||||||
|
|
327
lang/src/son.rs
327
lang/src/son.rs
|
@ -12,7 +12,8 @@ use {
|
||||||
reg, task,
|
reg, task,
|
||||||
ty::{self, ArrayLen, Tuple},
|
ty::{self, ArrayLen, Tuple},
|
||||||
vc::{BitSet, Vc},
|
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},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
|
@ -1416,6 +1417,123 @@ pub struct Codegen<'a> {
|
||||||
errors: RefCell<String>,
|
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> {
|
impl<'a> Codegen<'a> {
|
||||||
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
fn store_mem(&mut self, region: Nid, value: Nid) -> Nid {
|
||||||
if value == NEVER {
|
if value == NEVER {
|
||||||
|
@ -1457,7 +1575,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(&mut self) {
|
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.make_func_reachable(0);
|
||||||
self.complete_call_graph();
|
self.complete_call_graph();
|
||||||
}
|
}
|
||||||
|
@ -1491,8 +1609,8 @@ impl<'a> Codegen<'a> {
|
||||||
Some(Value::var(index).ty(var.ty))
|
Some(Value::var(index).ty(var.ty))
|
||||||
}
|
}
|
||||||
Expr::Ident { id, pos, .. } => {
|
Expr::Ident { id, pos, .. } => {
|
||||||
let decl = self.find_or_declare(pos, self.ci.file, Ok(id));
|
let decl = self.find_type(pos, self.ci.file, Ok(id), self.files);
|
||||||
match decl {
|
match decl.expand() {
|
||||||
ty::Kind::Global(global) => {
|
ty::Kind::Global(global) => {
|
||||||
let gl = &self.tys.ins.globals[global as usize];
|
let gl = &self.tys.ins.globals[global as usize];
|
||||||
let value = self.ci.nodes.new_node(gl.ty, Kind::Global { global }, [VOID]);
|
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));
|
let ctx = Ctx::default().with_ty(self.ty(ty));
|
||||||
self.expr_ctx(expr, ctx)
|
self.expr_ctx(expr, ctx)
|
||||||
}
|
}
|
||||||
Expr::Call { func: &Expr::Ident { pos, id, .. }, args, .. } => {
|
Expr::Call { func, args, .. } => {
|
||||||
self.ci.call_count += 1;
|
self.ci.call_count += 1;
|
||||||
let func = self.find_or_declare(pos, self.ci.file, Ok(id));
|
let ty = self.ty(func);
|
||||||
let ty::Kind::Func(func) = func else {
|
let ty::Kind::Func(fnc) = ty.expand() else {
|
||||||
self.report(
|
self.report(
|
||||||
pos,
|
func.pos(),
|
||||||
fa!("compiler cant (yet) call '{}'", self.ty_display(func.compress())),
|
fa!("compiler cant (yet) call '{}'", self.ty_display(ty)),
|
||||||
);
|
);
|
||||||
return Value::NEVER;
|
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 sig = fuc.sig.expect("TODO: generic functions");
|
||||||
let ast = &self.files[fuc.file as usize];
|
let ast = &self.files[fuc.file as usize];
|
||||||
let Expr::BinOp { right: &Expr::Closure { args: cargs, .. }, .. } =
|
let &Expr::Closure { args: cargs, .. } = fuc.expr.get(ast).unwrap() else {
|
||||||
fuc.expr.get(ast).unwrap()
|
|
||||||
else {
|
|
||||||
unreachable!()
|
unreachable!()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.assert_report(
|
self.assert_report(
|
||||||
args.len() == cargs.len(),
|
args.len() == cargs.len(),
|
||||||
pos,
|
func.pos(),
|
||||||
fa!(
|
fa!(
|
||||||
"expected {} function argumenr{}, got {}",
|
"expected {} function argumenr{}, got {}",
|
||||||
cargs.len(),
|
cargs.len(),
|
||||||
|
@ -1805,7 +1921,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
false
|
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);
|
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);
|
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))
|
unreachable!("{}", self.ast_display(expr))
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2335,182 +2451,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
fn ty(&mut self, expr: &Expr) -> ty::Id {
|
||||||
if let Some(ty) = self.tys.ty(self.ci.file, expr, self.files) {
|
self.parse_ty(self.ci.file, expr, None, 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_display(&self, ty: ty::Id) -> ty::Display {
|
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