Removing repetative code, adding ent slice to properly index modules

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-01 19:04:27 +01:00
parent 9ce446b507
commit c553c3d9e9
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
8 changed files with 285 additions and 243 deletions

15
foo.hb Normal file
View file

@ -0,0 +1,15 @@
Res := fn($O: type, $E: type): type return union(enum) {
ok: O,
err: E,
}
main := fn(): uint {
r := do_something()
if r == .err return v.err
return v.ok
}
do_something := fn(): Res(uint, uint) {
return .{ok: 0}
}

View file

@ -5,7 +5,7 @@ use {
parser,
son::{Kind, Nid, Node, Nodes, MEM, VOID},
ty::{self, Arg, Loc, Module, Offset, Sig, Size, Types},
utils::{Ent, EntVec},
utils::{EntSlice, EntVec},
},
alloc::{boxed::Box, collections::BTreeMap, string::String, vec::Vec},
core::{assert_matches::debug_assert_matches, mem, ops::Range},
@ -213,7 +213,7 @@ impl Backend for HbvmBackend {
mut sluce: &[u8],
eca_handler: &mut dyn FnMut(&mut &[u8]),
types: &'a Types,
files: &'a [parser::Ast],
files: &'a EntSlice<Module, parser::Ast>,
output: &mut String,
) -> Result<(), hbbytecode::DisasmError<'a>> {
use hbbytecode::DisasmItem;
@ -225,7 +225,7 @@ impl Backend for HbvmBackend {
.filter(|(_, f)| f.offset != u32::MAX)
.map(|(f, fd)| {
let name = if f.file != Module::default() {
let file = &files[f.file.index()];
let file = &files[f.file];
file.ident_str(f.name)
} else {
"target_fn"
@ -243,7 +243,7 @@ impl Backend for HbvmBackend {
let name = if g.file == Module::default() {
core::str::from_utf8(&g.data).unwrap_or("invalid utf-8")
} else {
let file = &files[g.file.index()];
let file = &files[g.file];
file.ident_str(g.name)
};
(gd.offset, (name, g.data.len() as Size, DisasmItem::Global))
@ -253,14 +253,26 @@ impl Backend for HbvmBackend {
hbbytecode::disasm(&mut sluce, &functions, output, eca_handler)
}
fn emit_ct_body(&mut self, id: ty::Func, nodes: &Nodes, tys: &Types, files: &[parser::Ast]) {
fn emit_ct_body(
&mut self,
id: ty::Func,
nodes: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
self.emit_body(id, nodes, tys, files);
let fd = &mut self.funcs[id];
fd.code.truncate(fd.code.len() - instrs::jala(0, 0, 0).0);
emit(&mut fd.code, instrs::tx());
}
fn emit_body(&mut self, id: ty::Func, nodes: &Nodes, tys: &Types, files: &[parser::Ast]) {
fn emit_body(
&mut self,
id: ty::Func,
nodes: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
let sig = tys.ins.funcs[id].sig.unwrap();
debug_assert!(self.code.is_empty());
@ -432,11 +444,18 @@ struct InstrCtx<'a> {
allocs: &'a [u8],
nodes: &'a Nodes,
tys: &'a Types,
files: &'a [parser::Ast],
files: &'a EntSlice<Module, parser::Ast>,
}
impl HbvmBackend {
fn extend(&mut self, base: ty::Id, dest: ty::Id, reg: Reg, tys: &Types, files: &[parser::Ast]) {
fn extend(
&mut self,
base: ty::Id,
dest: ty::Id,
reg: Reg,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
if reg == 0 {
return;
}

View file

@ -6,8 +6,8 @@ use {
},
parser, quad_sort,
son::{Kind, ARG_START, MEM, VOID},
ty::{self, Arg, Loc, Sig, Types},
utils::BitSet,
ty::{self, Arg, Loc, Module, Sig, Types},
utils::{BitSet, EntSlice},
},
alloc::{borrow::ToOwned, vec::Vec},
core::{assert_matches::debug_assert_matches, mem, ops::Range},
@ -20,7 +20,7 @@ impl HbvmBackend {
nodes: &Nodes,
sig: Sig,
tys: &Types,
files: &[parser::Ast],
files: &EntSlice<Module, parser::Ast>,
) -> (usize, bool) {
let tail = Function::build(nodes, tys, &mut self.ralloc, sig);

View file

@ -69,7 +69,8 @@ pub mod backend {
crate::{
parser,
son::Nodes,
ty::{self, Types},
ty::{self, Module, Types},
utils::EntSlice,
},
alloc::{string::String, vec::Vec},
};
@ -94,12 +95,24 @@ pub mod backend {
sluce: &[u8],
eca_handler: &mut dyn FnMut(&mut &[u8]),
types: &'a Types,
files: &'a [parser::Ast],
files: &'a EntSlice<Module, parser::Ast>,
output: &mut String,
) -> Result<(), hbbytecode::DisasmError<'a>>;
fn emit_body(&mut self, id: ty::Func, ci: &Nodes, tys: &Types, files: &[parser::Ast]);
fn emit_body(
&mut self,
id: ty::Func,
ci: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
);
fn emit_ct_body(&mut self, id: ty::Func, ci: &Nodes, tys: &Types, files: &[parser::Ast]) {
fn emit_ct_body(
&mut self,
id: ty::Func,
ci: &Nodes,
tys: &Types,
files: &EntSlice<Module, parser::Ast>,
) {
self.emit_body(id, ci, tys, files);
}

View file

@ -1079,9 +1079,11 @@ generate_expr! {
}
impl Expr<'_> {
pub fn declares(&self, iden: Result<Ident, &str>, source: &str) -> Option<Ident> {
pub fn declares(&self, iden: DeclId, source: &str) -> Option<Ident> {
match *self {
Self::Ident { id, .. } if iden == Ok(id) || iden == Err(&source[id.range()]) => {
Self::Ident { id, .. }
if iden == DeclId::Ident(id) || iden == DeclId::Name(&source[id.range()]) =>
{
Some(id)
}
Self::Ctor { fields, .. } => fields.iter().find_map(|f| f.value.declares(iden, source)),
@ -1389,7 +1391,7 @@ impl Ast {
unsafe { self.0.as_ref() }
}
pub fn find_decl(&self, id: Result<Ident, &str>) -> Option<(&Expr, Ident)> {
pub fn find_decl(&self, id: DeclId) -> Option<(&Expr, Ident)> {
find_decl(self.exprs(), &self.file, id)
}
@ -1401,7 +1403,7 @@ impl Ast {
pub fn find_decl<'a>(
exprs: &'a [Expr<'a>],
file: &str,
id: Result<Ident, &str>,
id: DeclId,
) -> Option<(&'a Expr<'a>, Ident)> {
exprs.iter().find_map(|expr| match expr {
Expr::BinOp { left, op: TokenKind::Decl, .. } => {
@ -1411,6 +1413,24 @@ pub fn find_decl<'a>(
})
}
#[derive(PartialEq, Eq, Clone, Copy)]
pub enum DeclId<'a> {
Ident(Ident),
Name(&'a str),
}
impl From<Ident> for DeclId<'_> {
fn from(value: Ident) -> Self {
Self::Ident(value)
}
}
impl<'a> From<&'a str> for DeclId<'a> {
fn from(value: &'a str) -> Self {
Self::Name(value)
}
}
impl Default for Ast {
fn default() -> Self {
Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader))

View file

@ -11,14 +11,14 @@ use {
parser::{
self,
idfl::{self},
CommentOr, CtorField, Expr, ExprRef, FieldList, MatchBranch, Pos,
CommentOr, CtorField, DeclId, Expr, ExprRef, FieldList, MatchBranch, Pos,
},
ty::{
self, Arg, ArrayLen, CompState, ConstData, EnumData, EnumField, FTask, FuncData,
GlobalData, Loc, Module, Offset, OffsetIter, OptLayout, Sig, StringRef, StructData,
StructField, SymKey, Tuple, TypeBase, TypeIns, Types, UnionData,
},
utils::{BitSet, Ent, Vc},
utils::{BitSet, EntSlice, Vc},
Ident,
},
alloc::{string::String, vec::Vec},
@ -2506,7 +2506,12 @@ impl ItemCtx {
self.scope.aclasses.push(AClass::new(&mut self.nodes)); // GLOBAL
}
fn finalize(&mut self, stack: &mut Vec<Nid>, tys: &Types, _files: &[parser::Ast]) {
fn finalize(
&mut self,
stack: &mut Vec<Nid>,
tys: &Types,
_files: &EntSlice<Module, parser::Ast>,
) {
self.scope.clear(&mut self.nodes);
mem::take(&mut self.ctrl).soft_remove(&mut self.nodes);
@ -2535,6 +2540,7 @@ pub struct Pool {
used_cis: usize,
scratch1: Vec<Nid>,
scratch2: Vec<Nid>,
lit_buf: Vec<u8>,
nid_set: BitSet,
}
@ -2546,7 +2552,7 @@ impl Pool {
ret: Option<ty::Id>,
task_base: usize,
target: &mut ItemCtx,
) {
) -> &mut ItemCtx {
if let Some(slot) = self.cis.get_mut(self.used_cis) {
mem::swap(slot, target);
} else {
@ -2555,6 +2561,7 @@ impl Pool {
}
target.init(file, parent, ret, task_base);
self.used_cis += 1;
&mut self.cis[self.used_cis - 1]
}
fn pop_ci(&mut self, target: &mut ItemCtx) {
@ -2633,7 +2640,7 @@ impl CodegenCtx {
}
pub struct Codegen<'a> {
pub files: &'a [parser::Ast],
pub files: &'a EntSlice<Module, parser::Ast>,
pub errors: &'a RefCell<String>,
pub warnings: &'a RefCell<String>,
tys: &'a mut Types,
@ -2665,7 +2672,7 @@ impl<'a> Codegen<'a> {
ctx: &'a mut CodegenCtx,
) -> Self {
Self {
files,
files: files.into(),
errors: &ctx.parser.errors,
warnings: &ctx.parser.warnings,
tys: &mut ctx.tys,
@ -2678,7 +2685,7 @@ impl<'a> Codegen<'a> {
}
pub fn generate(&mut self, entry: Module) {
self.find_type_in_file(0, entry, Err("main"));
self.find_type(0, entry, entry, "main");
if self.tys.ins.funcs.is_empty() {
return;
}
@ -2925,46 +2932,37 @@ impl<'a> Codegen<'a> {
Some(Value::var(index).ty(var.ty))
}
Expr::Ident { id, pos, .. } => {
let decl = self.find_type_in_scope(pos, Ok(id));
match decl.expand() {
ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
_ => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, decl)),
}
}
Expr::Ident { id, pos, .. } => self.find_type_as_value(pos, self.ci.parent, id, ctx),
Expr::Comment { .. } => Some(Value::VOID),
Expr::String { pos, literal } => {
let literal = &literal[1..literal.len() - 1];
let mut data = std::mem::take(&mut self.pool.lit_buf);
debug_assert!(data.is_empty());
let report = |bytes: &core::str::Bytes, message: &str| {
self.error(pos + (literal.len() - bytes.len()) as u32 - 1, message);
};
let mut data = Vec::<u8>::with_capacity(literal.len());
crate::endoce_string(literal, &mut data, report).unwrap();
let ty = self.tys.make_ptr(ty::Id::U8);
let global = match self.tys.strings.entry(&data, &self.tys.ins.globals) {
(hash_map::RawEntryMut::Occupied(occupied_entry), _) => {
occupied_entry.get_key_value().0.value.0
}
(hash_map::RawEntryMut::Vacant(vacant_entry), hash) => {
let global = self.tys.ins.globals.push(GlobalData {
data,
let global = self
.tys
.strings
.get_or_insert(&data, &mut self.tys.ins.globals, |globals| {
StringRef(globals.push(GlobalData {
data: data.clone(),
ty,
..Default::default()
});
vacant_entry
.insert(crate::ctx_map::Key { value: StringRef(global), hash }, ())
.0
.value
.0
}
};
}))
})
.0;
let global = self.ci.nodes.new_node_nop(ty, Kind::Global { global }, [VOID]);
self.ci.nodes[global].aclass = GLOBAL_ACLASS as _;
data.clear();
self.pool.lit_buf = data;
Some(Value::new(global).ty(ty))
}
Expr::Defer { pos, value } => {
@ -3080,9 +3078,7 @@ impl<'a> Codegen<'a> {
self.ci.nodes.new_node_nop(ty::Id::VOID, Kind::Die, [self.ci.ctrl.get()]),
&mut self.ci.nodes,
);
self.ci.nodes[NEVER].inputs.push(self.ci.ctrl.get());
self.ci.nodes[self.ci.ctrl.get()].outputs.push(NEVER);
self.ci.nodes.bind(self.ci.ctrl.get(), NEVER);
None
}
Expr::Field { target, name, pos } => {
@ -3115,11 +3111,10 @@ impl<'a> Codegen<'a> {
self.implicit_unwrap(val.pos(), &mut vl);
let Some(base) = self.tys.base_of(vl.ty) else {
self.error(
return self.error(
pos,
fa!("the '{}' can not be dereferneced", self.ty_display(vl.ty)),
);
return Value::NEVER;
};
vl.ptr = true;
vl.ty = base;
@ -3129,11 +3124,10 @@ impl<'a> Codegen<'a> {
inference!(ty, ctx, self, pos, "enum type", "<EnumTy>.Variant");
let ty::Kind::Enum(e) = ty.expand() else {
self.error(
return self.error(
pos,
fa!("expected inferred type to be enum but got '{}'", self.ty_display(ty)),
);
return Value::NEVER;
};
let intrnd = self.tys.names.project(self.file().ident_str(id));
@ -3158,8 +3152,7 @@ impl<'a> Codegen<'a> {
self.tys,
))
} else {
self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty)));
Value::NEVER
self.error(pos, fa!("cant negate '{}'", self.ty_display(val.ty)))
}
}
Expr::UnOp { pos, op: op @ TokenKind::Not, val } => {
@ -3173,8 +3166,7 @@ impl<'a> Codegen<'a> {
self.tys,
))
} else {
self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)));
Value::NEVER
self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)))
}
}
Expr::BinOp { left, op: TokenKind::Decl, right, pos } => {
@ -3218,8 +3210,7 @@ impl<'a> Codegen<'a> {
Some(Value::VOID)
}
Expr::BinOp { left: &Expr::Null { pos }, .. } => {
self.error(pos, "'null' must always be no the right side of an expression");
Value::NEVER
self.error(pos, "'null' must always be no the right side of an expression")
}
Expr::BinOp {
left,
@ -3231,11 +3222,10 @@ impl<'a> Codegen<'a> {
self.strip_var(&mut cmped);
let Some(ty) = self.tys.inner_of(cmped.ty) else {
self.error(
return self.error(
left.pos(),
fa!("'{}' is never null, remove this check", self.ty_display(cmped.ty)),
);
return Value::NEVER;
};
Some(Value::new(self.gen_null_check(cmped, ty, op)).ty(ty::Id::BOOL))
@ -3316,13 +3306,8 @@ impl<'a> Codegen<'a> {
self.struct_fold_op(left.pos(), op, binding_op, s, lhs.id, rhs.id)
.or(Value::NEVER)
}
_ => {
self.error(
pos,
fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty)),
);
Value::NEVER
}
_ => self
.error(pos, fa!("'{} {op} _' is not supported", self.ty_display(lhs.ty))),
}
}
Expr::Index { base, index } => {
@ -3335,14 +3320,13 @@ impl<'a> Codegen<'a> {
}
let ty::Kind::Slice(s) = bs.ty.expand() else {
self.error(
return self.error(
base.pos(),
fa!(
"cant index into '{}' which is not array nor slice",
self.ty_display(bs.ty)
),
);
return Value::NEVER;
};
let elem = self.tys.ins.slices[s].elem;
@ -3421,14 +3405,13 @@ impl<'a> Codegen<'a> {
self.strip_var(&mut val);
if !val.ty.is_optional() {
self.error(
return self.error(
expr.pos(),
fa!(
"only optional types can be unwrapped ('{}' is not optional)",
self.ty_display(val.ty)
),
);
return Value::NEVER;
};
self.explicit_unwrap(expr.pos(), &mut val);
@ -3438,14 +3421,13 @@ impl<'a> Codegen<'a> {
let mut val = self.expr(expr)?;
if !val.ty.is_integer() {
self.error(
return self.error(
expr.pos(),
fa!(
"only integers can be truncated ('{}' is not an integer)",
self.ty_display(val.ty)
),
);
return Value::NEVER;
}
inference!(ty, ctx, self, pos, "integer", "@as(<ty>, @intcast(<expr>))");
@ -3471,14 +3453,13 @@ impl<'a> Codegen<'a> {
let val = self.expr(expr)?;
if !val.ty.is_float() {
self.error(
return self.error(
expr.pos(),
fa!(
"only floats can be truncated ('{}' is not a float)",
self.ty_display(val.ty)
),
);
return Value::NEVER;
}
inference!(ty, ctx, self, pos, "float", "@as(<floaty>, @floatcast(<expr>))");
@ -3510,11 +3491,10 @@ impl<'a> Codegen<'a> {
let ret_ty = match val.ty {
ty::Id::F32 | ty::Id::F64 => ty::Id::INT,
_ => {
self.error(
return self.error(
expr.pos(),
fa!("expected float ('{}' is not a float)", self.ty_display(val.ty)),
);
return Value::NEVER;
)
}
};
@ -3653,7 +3633,7 @@ impl<'a> Codegen<'a> {
.map_or_else(|| self.tys.make_array(elem, len as ArrayLen), |_| sty);
if len != fields.len() {
self.error(
return self.error(
pos,
fa!(
"expected '{}' but constructor has {} elements",
@ -3661,7 +3641,6 @@ impl<'a> Codegen<'a> {
fields.len()
),
);
return Value::NEVER;
}
let mem = self.new_stack(pos, aty);
@ -3677,18 +3656,15 @@ impl<'a> Codegen<'a> {
Some(Value::ptr(mem).ty(aty))
}
_ => {
let inferred = if ty.is_some() { "" } else { "inferred " };
self.error(
pos,
fa!(
"the {inferred}type of the constructor is `{}`, \
_ => self.error(
pos,
fa!(
"the {}type of the constructor is `{}`, \
but thats not a struct nor slice or array",
self.ty_display(sty)
),
);
Value::NEVER
}
if ty.is_some() { "" } else { "inferred " },
self.ty_display(sty),
),
),
}
}
Expr::Struct { .. } => {
@ -3712,15 +3688,14 @@ impl<'a> Codegen<'a> {
let mem = self.new_stack(pos, sty);
let Some(index) = self.tys.find_union_field(u, name) else {
self.error(
let Some((_, field)) = self.tys.find_union_field(u, name) else {
return self.error(
fpos,
fa!("union '{}' does not have this field", self.ty_display(sty)),
);
return Value::NEVER;
};
let (ty, offset) = (self.tys.union_fields(u)[index].ty, 0);
let (ty, offset) = (field.ty, 0);
let mut value = self.expr_ctx(&value, Ctx::default().with_ty(ty))?;
self.assert_ty(fpos, &mut value, ty, fa!("field {}", name));
@ -4118,14 +4093,13 @@ impl<'a> Codegen<'a> {
let value = self.expr(value)?;
let ty::Kind::Enum(e) = value.ty.expand() else {
self.error(
return self.error(
pos,
fa!(
"match operates on enums (for now), '{}' is not an enum",
self.ty_display(value.ty)
),
);
return Value::NEVER;
};
let mut covered_values = vec![Pos::MAX; self.tys.enum_field_range(e).len()];
@ -4142,7 +4116,7 @@ impl<'a> Codegen<'a> {
continue;
}
let pat_val = self.eval_const(self.ci.file, &pat, value.ty);
let pat_val = self.eval_const(self.ci.file, self.ci.parent, &pat, value.ty);
if covered_values[pat_val as usize] != Pos::MAX {
self.error(bp, "duplicate branch");
self.error(
@ -4241,93 +4215,78 @@ impl<'a> Codegen<'a> {
let tty = vtarget.ty;
match self.tys.base_of(tty).unwrap_or(tty).expand() {
ty::Kind::Module(m) => self.find_type_as_value(pos, m, m, Err(name), ctx),
ty::Kind::Module(m) => self.find_type_as_value(pos, m, name, ctx),
ty::Kind::Enum(e) => {
let intrnd = self.tys.names.project(name);
self.gen_enum_variant(pos, e, intrnd)
}
ty::Kind::Union(u) => {
let TypeBase { ast, file, .. } = *self.tys.ins.unions[u];
if let Some(f) =
self.tys.find_union_field(u, name).map(|i| &self.tys.union_fields(u)[i])
{
if let Some((_, f)) = self.tys.find_union_field(u, name) {
Some(Value::ptr(vtarget.id).ty(f.ty))
} else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } =
ast.get(&self.files[file.index()])
&& let ty = self.find_type(pos, self.ci.file, file, u.into(), Err(name))
} else if let ty = self.find_type(pos, self.ci.file, u, name)
&& let ty::Kind::Func(_) = ty.expand()
{
return Some(Err((ty, vtarget)));
} else {
let field_list = self
.tys
.union_fields(u)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
self.error(
pos,
fa!(
"the '{}' does not have this field, \
but it does have '{field_list}'",
self.ty_display(tty)
but it does have '{}'",
self.ty_display(tty),
self.tys
.union_fields(u)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>()
),
);
Value::NEVER
)
}
}
ty::Kind::Struct(s) => {
let TypeBase { ast, file, .. } = *self.tys.ins.structs[s];
if let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) {
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
} else if let Expr::Struct { fields: [.., CommentOr::Or(Err(_))], .. } =
ast.get(&self.files[file.index()])
&& let ty = self.find_type(pos, self.ci.file, file, s.into(), Err(name))
} else if let ty = self.find_type(pos, self.ci.file, s, name)
&& let ty::Kind::Func(_) = ty.expand()
{
return Some(Err((ty, vtarget)));
} else {
let field_list = self
.tys
.struct_fields(s)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
self.error(
pos,
fa!(
"the '{}' does not have this field, \
but it does have '{field_list}'",
self.ty_display(tty)
but it does have '{}'",
self.ty_display(tty),
self.tys
.struct_fields(s)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>()
),
);
Value::NEVER
)
}
}
ty::Kind::TYPE => match self.ci.nodes.as_ty(vtarget.id).expand() {
ty::Kind::Struct(s) => {
let TypeBase { file, .. } = *self.tys.ins.structs[s];
self.find_type_as_value(pos, file, s, Err(name), ctx)
ty::Kind::Module(m) => self.find_type_as_value(pos, m, name, ctx),
ty::Kind::Enum(e)
if let intrnd = self.tys.names.project(name)
&& let Some(index) =
self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd) =>
{
Some(self.ci.nodes.new_const_lit(e.into(), index as i64))
}
ty::Kind::Union(u) => {
let TypeBase { file, .. } = *self.tys.ins.unions[u];
self.find_type_as_value(pos, file, u, Err(name), ctx)
ty @ (ty::Kind::Struct(_) | ty::Kind::Enum(_) | ty::Kind::Union(_)) => {
self.find_type_as_value(pos, ty.compress(), name, ctx)
}
ty::Kind::Module(m) => self.find_type_as_value(pos, m, m, Err(name), ctx),
ty::Kind::Enum(e) => {
let intrnd = self.tys.names.project(name);
if let Some(index) =
self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd)
{
Some(self.ci.nodes.new_const_lit(e.into(), index as i64))
} else {
let TypeBase { file, .. } = *self.tys.ins.enums[e];
self.find_type_as_value(pos, file, e, Err(name), ctx)
}
}
ty => self.error(
ty @ (ty::Kind::Builtin(_)
| ty::Kind::Ptr(_)
| ty::Kind::Slice(_)
| ty::Kind::Opt(_)
| ty::Kind::Func(_)
| ty::Kind::Global(_)
| ty::Kind::Const(_)) => self.error(
pos,
fa!(
"accesing scope on '{}' is not supported yet",
@ -4380,22 +4339,20 @@ impl<'a> Codegen<'a> {
fn gen_enum_variant(&mut self, pos: Pos, e: ty::Enum, intrnd: Option<Ident>) -> Option<Value> {
let Some(index) = self.tys.enum_fields(e).iter().position(|f| Some(f.name) == intrnd)
else {
let field_list = self
.tys
.enum_fields(e)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>();
self.error(
return self.error(
pos,
fa!(
"the '{}' does not have this variant, \
but it does have '{field_list}'",
self.ty_display(e.into())
but it does have '{}'",
self.ty_display(e.into()),
self.tys
.enum_fields(e)
.iter()
.map(|f| self.tys.names.ident_str(f.name))
.intersperse("', '")
.collect::<String>()
),
);
return Value::NEVER;
};
Some(self.ci.nodes.new_const_lit(e.into(), index as i64))
@ -4445,7 +4402,7 @@ impl<'a> Codegen<'a> {
inline |= sig.ret == ty::Id::TYPE;
let FuncData { expr, file, is_inline, parent, .. } = self.tys.ins.funcs[fu];
let ast = &self.files[file.index()];
let ast = &self.files[file];
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
let arg_count = args.len() + caller.is_some() as usize;
@ -4661,7 +4618,7 @@ impl<'a> Codegen<'a> {
let c = &self.tys.ins.consts[cnst];
let prev_file = mem::replace(&mut self.ci.file, c.file);
let prev_parent = mem::replace(&mut self.ci.parent, c.parent);
let f = &self.files[c.file.index()];
let f = &self.files[c.file];
let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() };
let mut value = left
@ -4806,7 +4763,7 @@ impl<'a> Codegen<'a> {
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
let FuncData { file, expr, sig, parent, .. } = self.tys.ins.funcs[*func];
let fast = &self.files[file.index()];
let fast = &self.files[file];
let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else {
unreachable!();
};
@ -5035,7 +4992,7 @@ impl<'a> Codegen<'a> {
debug_assert_eq!(cct, ct);
func.comp_state[cct as usize] = CompState::Compiled;
let sig = func.sig.expect("to emmit only concrete functions");
let ast = &self.files[file.index()];
let ast = &self.files[file];
let expr = func.expr.get(ast);
self.pool.push_ci(file, func.parent, Some(sig.ret), 0, &mut self.ci);
@ -5445,22 +5402,18 @@ impl<'a> Codegen<'a> {
}
fn file(&self) -> &'a parser::Ast {
&self.files[self.ci.file.index()]
&self.files[self.ci.file]
}
fn eval_const(&mut self, file: Module, expr: &Expr, ret: ty::Id) -> u64 {
fn eval_const(&mut self, file: Module, parent: ty::Id, expr: &Expr, ret: ty::Id) -> u64 {
self.ct.activate();
let scope = self
.ci
.scope
let prev = self.pool.push_ci(file, parent, Some(ret), self.tys.tasks.len(), &mut self.ci);
prev.scope
.vars
.iter()
.filter(|v| v.ty == ty::Id::TYPE)
.map(|v| (self.ci.nodes.as_ty(v.value()), v.id))
.collect::<Vec<_>>();
self.pool.push_ci(file, self.ci.parent, Some(ret), self.tys.tasks.len(), &mut self.ci);
self.ci.scope.vars = scope
.into_iter()
.map(|v| (prev.nodes.as_ty(v.value()), v.id))
.map(|(v, id)| {
Variable::new(
id,
@ -5470,14 +5423,17 @@ impl<'a> Codegen<'a> {
&mut self.ci.nodes,
)
})
.collect();
.collect_into(&mut self.ci.scope.vars);
let prev_err_len = self.errors.borrow().len();
self.expr(&Expr::Return { pos: expr.pos(), val: Some(expr) });
let res =
if self.finalize(prev_err_len) { self.emit_and_eval(file, ret, &mut []) } else { 1 };
let res = if self.finalize(prev_err_len) {
self.emit_and_eval(file, ret, &mut [])
} else {
i64::from(ty::Id::UNDECLARED) as _
};
self.pool.pop_ci(&mut self.ci);
@ -5532,13 +5488,13 @@ impl<'a> Codegen<'a> {
fn error_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
let mut buf = self.errors.borrow_mut();
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
write!(buf, "{}", self.files[file].report(pos, msg)).unwrap();
ty::Id::NEVER
}
fn warn_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
let mut buf = self.warnings.borrow_mut();
write!(buf, "(W) {}", self.files[file.index()].report(pos, msg)).unwrap();
write!(buf, "(W) {}", self.files[file].report(pos, msg)).unwrap();
ty::Id::NEVER
}
@ -5551,23 +5507,14 @@ impl<'a> Codegen<'a> {
.map(|v| self.ci.nodes.as_ty(v.value()))
}
fn find_type_in_file(&mut self, pos: Pos, file: Module, id: Result<Ident, &str>) -> ty::Id {
self.find_type(pos, file, file, file.into(), id)
}
fn find_type_in_scope(&mut self, pos: Pos, id: Result<Ident, &str>) -> ty::Id {
self.find_type(pos, self.ci.file, self.ci.file, self.ci.parent, id)
}
fn find_type_as_value(
&mut self,
pos: Pos,
file: Module,
parent: impl Into<ty::Id>,
id: Result<Ident, &str>,
id: impl Into<DeclId>,
ctx: Ctx,
) -> Option<Value> {
match self.find_type(pos, self.ci.file, file, parent.into(), id).expand() {
match self.find_type(pos, self.ci.file, parent, id).expand() {
ty::Kind::NEVER => Value::NEVER,
ty::Kind::Global(global) => self.gen_global(global),
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
@ -5579,21 +5526,29 @@ impl<'a> Codegen<'a> {
&mut self,
pos: Pos,
from_file: Module,
file: Module,
parent: ty::Id,
id: Result<Ident, &str>,
parent: impl Into<ty::Id>,
id: impl Into<DeclId>,
) -> ty::Id {
let ty = if let Ok(id) = id
self.find_type_low(pos, from_file, parent.into(), id.into())
}
fn find_type_low(&mut self, pos: Pos, from_file: Module, parent: ty::Id, id: DeclId) -> ty::Id {
let file = match parent.expand() {
ty::Kind::Module(m) => m,
_ => self.tys.type_base_of(parent).unwrap().file,
};
let ty = if let DeclId::Ident(id) = id
&& let Some(ty) = self.find_local_ty(id)
{
ty
} else if let Ok(id) = id
} else if let DeclId::Ident(id) = id
&& let Some(&ty) = self.tys.syms.get(SymKey::Decl(parent, id), &self.tys.ins)
{
self.on_reuse(ty);
ty
} else {
let f = &self.files[file.index()];
let f = &self.files[file];
let mut piter = parent;
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = (loop {
@ -5604,7 +5559,7 @@ impl<'a> Codegen<'a> {
}
if let Some((captures, capture_tuple)) = self.tys.captures_of(piter, f)
&& let Some(idx) = captures.iter().position(|&cid| Ok(cid) == id)
&& let Some(idx) = captures.iter().position(|&cid| DeclId::Ident(cid) == id)
{
return self.tys.ins.args[capture_tuple.range().start + idx];
}
@ -5620,11 +5575,11 @@ impl<'a> Codegen<'a> {
};
}) else {
return match id {
Ok(_) => {
debug_assert_eq!(from_file, file);
DeclId::Ident(id) => {
debug_assert_eq!(from_file, file, "{}", f.ident_str(id));
self.error_low(file, pos, "somehow this was not found")
}
Err("main") => self.error_low(
DeclId::Name("main") => self.error_low(
from_file,
pos,
format_args!(
@ -5634,7 +5589,7 @@ impl<'a> Codegen<'a> {
f.path
),
),
Err(name) => self.error_low(
DeclId::Name(name) => self.error_low(
from_file,
pos,
format_args!("undefined indentifier: {name}"),
@ -5648,21 +5603,19 @@ impl<'a> Codegen<'a> {
} else {
let (is_ct, ty) = left
.find_pattern_path(name, right, |right, is_ct| {
(
is_ct,
if is_ct && !matches!(right, Expr::Closure { .. }) {
self.tys
.ins
.consts
.push(ConstData { ast: ExprRef::new(expr), name, file, parent })
.into()
} else {
self.parse_ty(
TyScope { file, parent, name: Some(name), alloc_const: true },
right,
)
},
)
let ty = if is_ct && !matches!(right, Expr::Closure { .. }) {
self.tys
.ins
.consts
.push(ConstData { ast: ExprRef::new(expr), name, file, parent })
.into()
} else {
self.parse_ty(
TyScope { file, parent, name: Some(name), alloc_const: true },
right,
)
};
(is_ct, ty)
})
.unwrap_or_else(|_| unreachable!());
if let ty::Kind::Func(f) = ty.expand()
@ -5715,11 +5668,11 @@ impl<'a> Codegen<'a> {
self.tys.make_opt(base)
}
Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(),
Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.file, sc.parent, Ok(id)),
Expr::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.parent, id),
Expr::Field { target, pos, name }
if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() =>
{
self.find_type(pos, sc.file, inside, inside.into(), Err(name))
self.find_type(pos, sc.file, inside, name)
}
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
Expr::Slice { size: None, item, .. } => {
@ -5732,8 +5685,9 @@ impl<'a> Codegen<'a> {
}
Expr::Slice { size, item, .. } => {
let ty = self.parse_ty(sc.anon(), item);
let len = size
.map_or(ArrayLen::MAX, |expr| self.eval_const(sc.file, expr, ty::Id::U32) as _);
let len = size.map_or(ArrayLen::MAX, |expr| {
self.eval_const(sc.file, sc.parent, expr, ty::Id::U32) as _
});
self.tys.make_array(ty, len)
}
Expr::Struct { pos, fields, packed, captured, .. } => self.parse_base_ty(
@ -5786,8 +5740,7 @@ impl<'a> Codegen<'a> {
sig: 'b: {
let arg_base = self.tys.tmp.args.len();
for arg in args {
let sym =
parser::find_symbol(&self.files[sc.file.index()].symbols, arg.id);
let sym = parser::find_symbol(&self.files[sc.file].symbols, arg.id);
if sym.flags & idfl::COMPTIME != 0 {
self.tys.tmp.args.truncate(arg_base);
break 'b None;
@ -5815,7 +5768,9 @@ impl<'a> Codegen<'a> {
{
self.eval_global(sc.file, name, expr)
}
_ if sc.alloc_const => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)),
_ if sc.alloc_const => {
ty::Id::from(self.eval_const(sc.file, sc.parent, expr, ty::Id::TYPE))
}
ref e => {
self.error_unhandled_ast(e, "bruh");
ty::Id::NEVER

View file

@ -3,7 +3,7 @@ use {
ctx_map,
lexer::TokenKind,
parser::{self, CommentOr, Expr, ExprRef, Pos},
utils::{self, Ent, EntVec},
utils::{self, Ent, EntSlice, EntVec},
Ident,
},
alloc::{string::String, vec::Vec},
@ -480,12 +480,12 @@ impl Default for Kind {
pub struct Display<'a> {
tys: &'a Types,
files: &'a [parser::Ast],
files: &'a EntSlice<Module, parser::Ast>,
ty: Id,
}
impl<'a> Display<'a> {
pub fn new(tys: &'a Types, files: &'a [parser::Ast], ty: Id) -> Self {
pub fn new(tys: &'a Types, files: &'a EntSlice<Module, parser::Ast>, ty: Id) -> Self {
Self { tys, files, ty }
}
@ -500,7 +500,7 @@ impl core::fmt::Display for Display<'_> {
match TK::from_ty(self.ty) {
TK::Module(idx) => {
f.write_str("@use(\"")?;
self.files[idx.index()].path.fmt(f)?;
self.files[idx].path.fmt(f)?;
f.write_str(")[")?;
idx.fmt(f)?;
f.write_str("]")
@ -532,7 +532,7 @@ impl core::fmt::Display for Display<'_> {
}
f.write_str("}")
} else {
let file = &self.files[record.file.index()];
let file = &self.files[record.file];
f.write_str(file.ident_str(record.name))
}
}
@ -554,14 +554,14 @@ impl core::fmt::Display for Display<'_> {
}
f.write_str("}")
} else {
let file = &self.files[record.file.index()];
let file = &self.files[record.file];
f.write_str(file.ident_str(record.name))
}
}
TK::Enum(idx) => {
let enm = &self.tys.ins.enums[idx];
debug_assert!(!enm.name.is_null());
let file = &self.files[enm.file.index()];
let file = &self.files[enm.file];
f.write_str(file.ident_str(enm.name))
}
TK::Func(idx) => {
@ -570,7 +570,7 @@ impl core::fmt::Display for Display<'_> {
}
TK::Global(idx) => {
let global = &self.tys.ins.globals[idx];
let file = &self.files[global.file.index()];
let file = &self.files[global.file];
f.write_str(file.ident_str(global.name))?;
f.write_str(" (global)")
}
@ -586,7 +586,7 @@ impl core::fmt::Display for Display<'_> {
}
TK::Const(idx) => {
let cnst = &self.tys.ins.consts[idx];
let file = &self.files[cnst.file.index()];
let file = &self.files[cnst.file];
f.write_str(file.ident_str(cnst.name))?;
f.write_str(" (const)")
}
@ -1029,9 +1029,9 @@ impl Types {
self.struct_fields(s).iter().position(|f| f.name == name)
}
pub fn find_union_field(&self, u: Union, name: &str) -> Option<usize> {
pub fn find_union_field(&self, u: Union, name: &str) -> Option<(usize, &StructField)> {
let name = self.names.project(name)?;
self.union_fields(u).iter().position(|f| f.name == name)
self.union_fields(u).iter().enumerate().find(|(_, f)| f.name == name)
}
pub fn clear(&mut self) {
@ -1053,7 +1053,7 @@ impl Types {
debug_assert_eq!(self.tasks.len(), 0);
}
fn type_base_of(&self, id: Id) -> Option<&TypeBase> {
pub fn type_base_of(&self, id: Id) -> Option<&TypeBase> {
Some(match id.expand() {
Kind::Struct(s) => &*self.ins.structs[s],
Kind::Enum(e) => &*self.ins.enums[e],

View file

@ -559,6 +559,26 @@ pub trait Ent: Copy {
fn index(self) -> usize;
}
#[repr(transparent)]
pub struct EntSlice<K: Ent, T> {
k: PhantomData<fn(K)>,
data: [T],
}
impl<'a, K: Ent, T> From<&'a [T]> for &'a EntSlice<K, T> {
fn from(value: &'a [T]) -> Self {
unsafe { core::mem::transmute(value) }
}
}
impl<K: Ent, T> core::ops::Index<K> for EntSlice<K, T> {
type Output = T;
fn index(&self, index: K) -> &Self::Output {
&self.data[index.index()]
}
}
pub struct EntVec<K: Ent, T> {
data: ::alloc::vec::Vec<T>,
k: PhantomData<fn(K)>,