Compare commits
2 commits
542c69fd60
...
bc2dd82eb7
Author | SHA1 | Date | |
---|---|---|---|
bc2dd82eb7 | |||
aa2de502cc |
265
lang/src/lib.rs
265
lang/src/lib.rs
|
@ -34,13 +34,12 @@ pub use fs::*;
|
||||||
pub use utils::Ent;
|
pub use utils::Ent;
|
||||||
use {
|
use {
|
||||||
self::{
|
self::{
|
||||||
lexer::TokenKind,
|
parser::{ExprRef, Pos},
|
||||||
parser::{idfl, CommentOr, Expr, ExprRef, Pos},
|
|
||||||
ty::{ArrayLen, Builtin, Module},
|
ty::{ArrayLen, Builtin, Module},
|
||||||
utils::EntVec,
|
utils::EntVec,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{cell::Cell, fmt::Display, ops::Range},
|
core::{cell::Cell, ops::Range},
|
||||||
hashbrown::hash_map,
|
hashbrown::hash_map,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1034,266 +1033,6 @@ pub struct Types {
|
||||||
tasks: Vec<Option<FTask>>,
|
tasks: Vec<Option<FTask>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove this
|
|
||||||
trait TypeParser {
|
|
||||||
fn tys(&mut self) -> &mut Types;
|
|
||||||
fn ty_display(&self, of: ty::Id) -> ty::Display;
|
|
||||||
fn on_reuse(&mut self, existing: ty::Id);
|
|
||||||
fn find_local_ty(&mut self, name: Ident) -> Option<ty::Id>;
|
|
||||||
fn eval_const(&mut self, file: Module, expr: &Expr, ty: ty::Id) -> u64;
|
|
||||||
fn eval_global(&mut self, file: Module, name: Ident, expr: &Expr) -> ty::Id;
|
|
||||||
fn infer_type(&mut self, expr: &Expr) -> ty::Id;
|
|
||||||
fn error(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id;
|
|
||||||
fn warn(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id;
|
|
||||||
|
|
||||||
fn find_type(
|
|
||||||
&mut self,
|
|
||||||
pos: Pos,
|
|
||||||
from_file: Module,
|
|
||||||
file: Module,
|
|
||||||
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.index()];
|
|
||||||
|
|
||||||
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else {
|
|
||||||
return match id {
|
|
||||||
Ok(_) => {
|
|
||||||
debug_assert_eq!(from_file, file);
|
|
||||||
self.error(file, pos, "somehow this was not found")
|
|
||||||
}
|
|
||||||
Err("main") => self.error(
|
|
||||||
from_file,
|
|
||||||
pos,
|
|
||||||
format_args!(
|
|
||||||
"missing main function in '{}', compiler can't \
|
|
||||||
emmit libraries since such concept is not defined \
|
|
||||||
(minimal main function: `main := fn(): void {{}}`)",
|
|
||||||
f.path
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Err(name) => {
|
|
||||||
self.error(from_file, pos, format_args!("undefined indentifier: {name}"))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
let tys = self.tys();
|
|
||||||
let ty = if let Some(&ty) = tys.syms.get(SymKey::Decl(file, name), &tys.ins) {
|
|
||||||
ty
|
|
||||||
} 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(Const { ast: ExprRef::new(expr), name, file })
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
self.parse_ty(file, right, Some(name), files)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.unwrap_or_else(|_| unreachable!());
|
|
||||||
let tys = self.tys();
|
|
||||||
if let ty::Kind::Func(f) = ty.expand()
|
|
||||||
&& is_ct
|
|
||||||
{
|
|
||||||
tys.ins.funcs[f].is_inline = true;
|
|
||||||
}
|
|
||||||
tys.syms.insert(SymKey::Decl(file, name), ty, &tys.ins);
|
|
||||||
ty
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Err(proper_case) = self.tys().case(ty)(f.ident_str(name)) {
|
|
||||||
self.warn(
|
|
||||||
from_file,
|
|
||||||
pos,
|
|
||||||
format_args!(
|
|
||||||
"the declaration does not have conventional \
|
|
||||||
casing, expected '{proper_case}', \
|
|
||||||
because the declared type is '{}'",
|
|
||||||
self.ty_display(ty),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
ty
|
|
||||||
};
|
|
||||||
|
|
||||||
let tys = self.tys();
|
|
||||||
if let ty::Kind::Global(g) = ty.expand() {
|
|
||||||
let g = &tys.ins.globals[g];
|
|
||||||
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: Module,
|
|
||||||
expr: &Expr,
|
|
||||||
name: Option<Ident>,
|
|
||||||
files: &[parser::Ast],
|
|
||||||
) -> ty::Id {
|
|
||||||
match *expr {
|
|
||||||
Expr::Mod { id, .. } => id.into(),
|
|
||||||
Expr::UnOp { op: TokenKind::Xor, val, .. } => {
|
|
||||||
let base = self.parse_ty(file, val, None, files);
|
|
||||||
self.tys().make_ptr(base)
|
|
||||||
}
|
|
||||||
Expr::UnOp { op: TokenKind::Que, val, .. } => {
|
|
||||||
let base = self.parse_ty(file, val, None, files);
|
|
||||||
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, file, file, Ok(id), files),
|
|
||||||
Expr::Field { target, pos, name }
|
|
||||||
if let ty::Kind::Module(inside) =
|
|
||||||
self.parse_ty(file, target, None, files).expand() =>
|
|
||||||
{
|
|
||||||
self.find_type(pos, file, inside, Err(name), files)
|
|
||||||
}
|
|
||||||
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
|
|
||||||
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::Slice { size, item, .. } => {
|
|
||||||
let ty = self.parse_ty(file, item, None, files);
|
|
||||||
let len = size
|
|
||||||
.map_or(ArrayLen::MAX, |expr| self.eval_const(file, expr, ty::Id::U32) as _);
|
|
||||||
self.tys().make_array(ty, len)
|
|
||||||
}
|
|
||||||
Expr::Struct { pos, fields, packed, captured, .. } => {
|
|
||||||
let captures_start = self.tys().tmp.args.len();
|
|
||||||
for &cp in captured {
|
|
||||||
let ty = self.find_local_ty(cp).expect("TODO");
|
|
||||||
self.tys().tmp.args.push(ty);
|
|
||||||
}
|
|
||||||
let captured = self.tys().pack_args(captures_start).expect("TODO");
|
|
||||||
|
|
||||||
let sym = SymKey::Struct(file, pos, captured);
|
|
||||||
let tys = self.tys();
|
|
||||||
if let Some(&ty) = tys.syms.get(sym, &tys.ins) {
|
|
||||||
return ty;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prev_tmp = self.tys().tmp.struct_fields.len();
|
|
||||||
for field in fields.iter().filter_map(CommentOr::or) {
|
|
||||||
let ty = self.parse_ty(file, &field.ty, None, files);
|
|
||||||
let field = StructField { name: self.tys().names.intern(field.name), ty };
|
|
||||||
self.tys().tmp.struct_fields.push(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tys = self.tys();
|
|
||||||
let ty = tys
|
|
||||||
.ins
|
|
||||||
.structs
|
|
||||||
.push(Struct {
|
|
||||||
file,
|
|
||||||
pos,
|
|
||||||
name: name.unwrap_or_default(),
|
|
||||||
field_start: tys.ins.struct_fields.len() as _,
|
|
||||||
explicit_alignment: packed.then_some(1),
|
|
||||||
..Default::default()
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
|
|
||||||
tys.ins.struct_fields.extend(tys.tmp.struct_fields.drain(prev_tmp..));
|
|
||||||
|
|
||||||
tys.syms.insert(sym, ty, &tys.ins);
|
|
||||||
ty
|
|
||||||
}
|
|
||||||
Expr::Enum { pos, variants, .. } => {
|
|
||||||
let sym = SymKey::Enum(file, pos);
|
|
||||||
let tys = self.tys();
|
|
||||||
if let Some(&ty) = tys.syms.get(sym, &tys.ins) {
|
|
||||||
return ty;
|
|
||||||
}
|
|
||||||
|
|
||||||
let prev_tmp = self.tys().tmp.enum_fields.len();
|
|
||||||
for field in variants.iter().filter_map(CommentOr::or) {
|
|
||||||
let field = EnumField { name: self.tys().names.intern(field.name) };
|
|
||||||
self.tys().tmp.enum_fields.push(field);
|
|
||||||
}
|
|
||||||
|
|
||||||
let tys = self.tys();
|
|
||||||
let ty = tys
|
|
||||||
.ins
|
|
||||||
.enums
|
|
||||||
.push(Enum {
|
|
||||||
file,
|
|
||||||
pos,
|
|
||||||
name: name.unwrap_or_default(),
|
|
||||||
field_start: tys.ins.enum_fields.len() as _,
|
|
||||||
})
|
|
||||||
.into();
|
|
||||||
|
|
||||||
tys.ins.enum_fields.extend(tys.tmp.enum_fields.drain(prev_tmp..));
|
|
||||||
|
|
||||||
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.index()].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.error(file, pos, "function has too many argumnets");
|
|
||||||
};
|
|
||||||
let ret = self.parse_ty(file, ret, None, files);
|
|
||||||
|
|
||||||
Some(Sig { args, ret })
|
|
||||||
},
|
|
||||||
expr: ExprRef::new(expr),
|
|
||||||
returns_type: matches!(ret, &Expr::Ident { id, .. } if ty::Builtin::try_from(id) == Ok(ty::Builtin::TYPE)),
|
|
||||||
..Default::default()
|
|
||||||
};
|
|
||||||
|
|
||||||
self.tys().ins.funcs.push(func).into()
|
|
||||||
}
|
|
||||||
_ if let Some(name) = name => self.eval_global(file, name, expr),
|
|
||||||
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Types {
|
impl Types {
|
||||||
pub fn case(&self, ty: ty::Id) -> fn(&str) -> Result<(), &'static str> {
|
pub fn case(&self, ty: ty::Id) -> fn(&str) -> Result<(), &'static str> {
|
||||||
match ty.expand() {
|
match ty.expand() {
|
||||||
|
|
279
lang/src/son.rs
279
lang/src/son.rs
|
@ -10,12 +10,12 @@ use {
|
||||||
parser::{
|
parser::{
|
||||||
self,
|
self,
|
||||||
idfl::{self},
|
idfl::{self},
|
||||||
CtorField, Expr, MatchBranch, Pos,
|
CommentOr, CtorField, Expr, ExprRef, MatchBranch, Pos,
|
||||||
},
|
},
|
||||||
ty::{self, Arg, ArrayLen, Loc, Module, Tuple},
|
ty::{self, Arg, ArrayLen, Loc, Module, Tuple},
|
||||||
utils::{BitSet, Ent, Vc},
|
utils::{BitSet, Ent, Vc},
|
||||||
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
|
CompState, Const, Enum, EnumField, FTask, Func, Global, Ident, Offset, OffsetIter,
|
||||||
SymKey, TypeParser, Types,
|
OptLayout, Sig, StringRef, Struct, StructField, SymKey, Types,
|
||||||
},
|
},
|
||||||
alloc::{string::String, vec::Vec},
|
alloc::{string::String, vec::Vec},
|
||||||
core::{
|
core::{
|
||||||
|
@ -2488,7 +2488,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate(&mut self, entry: Module) {
|
pub fn generate(&mut self, entry: Module) {
|
||||||
self.find_type(0, entry, entry, Err("main"), self.files);
|
self.find_type(0, entry, entry, Err("main"));
|
||||||
if self.tys.ins.funcs.is_empty() {
|
if self.tys.ins.funcs.is_empty() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2732,7 +2732,7 @@ 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_type(pos, self.ci.file, self.ci.file, Ok(id), self.files);
|
let decl = self.find_type(pos, self.ci.file, self.ci.file, Ok(id));
|
||||||
match decl.expand() {
|
match decl.expand() {
|
||||||
ty::Kind::NEVER => Value::NEVER,
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
ty::Kind::Global(global) => self.gen_global(global),
|
ty::Kind::Global(global) => self.gen_global(global),
|
||||||
|
@ -2877,7 +2877,7 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
match self.tys.base_of(tty).unwrap_or(tty).expand() {
|
match self.tys.base_of(tty).unwrap_or(tty).expand() {
|
||||||
ty::Kind::Module(m) => {
|
ty::Kind::Module(m) => {
|
||||||
match self.find_type(pos, self.ci.file, m, Err(name), self.files).expand() {
|
match self.find_type(pos, self.ci.file, m, Err(name)).expand() {
|
||||||
ty::Kind::NEVER => Value::NEVER,
|
ty::Kind::NEVER => Value::NEVER,
|
||||||
ty::Kind::Global(global) => self.gen_global(global),
|
ty::Kind::Global(global) => self.gen_global(global),
|
||||||
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
||||||
|
@ -3894,7 +3894,8 @@ impl<'a> Codegen<'a> {
|
||||||
self.ci.ctrl.get()
|
self.ci.ctrl.get()
|
||||||
};
|
};
|
||||||
|
|
||||||
self.close_if(lcntrl, rcntrl, then_scope)
|
self.close_if(lcntrl, rcntrl, then_scope)?;
|
||||||
|
Some(Value::VOID)
|
||||||
}
|
}
|
||||||
Expr::Match { pos, value, branches } => {
|
Expr::Match { pos, value, branches } => {
|
||||||
let value = self.expr(value)?;
|
let value = self.expr(value)?;
|
||||||
|
@ -3983,9 +3984,9 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
for (lcntrl, then_scope) in scopes.into_iter().rev() {
|
for (lcntrl, then_scope) in scopes.into_iter().rev() {
|
||||||
if let Some(v) = self.close_if(lcntrl, rcntrl, then_scope)
|
if let Some(v) = self.close_if(lcntrl, rcntrl, then_scope)
|
||||||
&& v.id != VOID
|
&& v != VOID
|
||||||
{
|
{
|
||||||
rcntrl = v.id;
|
rcntrl = v;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4002,18 +4003,18 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn close_if(&mut self, lcntrl: Nid, rcntrl: Nid, mut then_scope: Scope) -> Option<Value> {
|
fn close_if(&mut self, lcntrl: Nid, rcntrl: Nid, mut then_scope: Scope) -> Option<Nid> {
|
||||||
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
if lcntrl == Nid::MAX && rcntrl == Nid::MAX {
|
||||||
then_scope.clear(&mut self.ci.nodes);
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
return None;
|
return None;
|
||||||
} else if lcntrl == Nid::MAX {
|
} else if lcntrl == Nid::MAX {
|
||||||
then_scope.clear(&mut self.ci.nodes);
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
return Some(Value::VOID);
|
return Some(VOID);
|
||||||
} else if rcntrl == Nid::MAX {
|
} else if rcntrl == Nid::MAX {
|
||||||
self.ci.scope.clear(&mut self.ci.nodes);
|
self.ci.scope.clear(&mut self.ci.nodes);
|
||||||
self.ci.scope = then_scope;
|
self.ci.scope = then_scope;
|
||||||
self.ci.ctrl.set(lcntrl, &mut self.ci.nodes);
|
self.ci.ctrl.set(lcntrl, &mut self.ci.nodes);
|
||||||
return Some(Value::VOID);
|
return Some(VOID);
|
||||||
}
|
}
|
||||||
|
|
||||||
self.ci.ctrl.set(
|
self.ci.ctrl.set(
|
||||||
|
@ -4029,7 +4030,7 @@ impl<'a> Codegen<'a> {
|
||||||
self.tys,
|
self.tys,
|
||||||
);
|
);
|
||||||
then_scope.clear(&mut self.ci.nodes);
|
then_scope.clear(&mut self.ci.nodes);
|
||||||
Some(Value::new(self.ci.ctrl.get()).ty(ty::Id::VOID))
|
Some(self.ci.ctrl.get())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_enum_variant(&mut self, pos: Pos, e: ty::Enum, intrnd: Option<Ident>) -> Option<Value> {
|
fn gen_enum_variant(&mut self, pos: Pos, e: ty::Enum, intrnd: Option<Ident>) -> Option<Value> {
|
||||||
|
@ -4741,7 +4742,7 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_in(&mut self, file: Module, expr: &Expr) -> ty::Id {
|
fn ty_in(&mut self, file: Module, expr: &Expr) -> ty::Id {
|
||||||
self.parse_ty(file, expr, None, self.files)
|
self.parse_ty(file, expr, None)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ty_display(&self, ty: ty::Id) -> ty::Display {
|
fn ty_display(&self, ty: ty::Id) -> ty::Display {
|
||||||
|
@ -4988,16 +4989,6 @@ impl<'a> Codegen<'a> {
|
||||||
fn file(&self) -> &'a parser::Ast {
|
fn file(&self) -> &'a parser::Ast {
|
||||||
&self.files[self.ci.file.index()]
|
&self.files[self.ci.file.index()]
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TypeParser for Codegen<'_> {
|
|
||||||
fn tys(&mut self) -> &mut Types {
|
|
||||||
self.tys
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ty_display(&self, of: ty::Id) -> ty::Display {
|
|
||||||
self.ty_display(of)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn eval_const(&mut self, file: Module, expr: &Expr, ret: ty::Id) -> u64 {
|
fn eval_const(&mut self, file: Module, expr: &Expr, ret: ty::Id) -> u64 {
|
||||||
self.ct.activate();
|
self.ct.activate();
|
||||||
|
@ -5066,13 +5057,13 @@ impl TypeParser for Codegen<'_> {
|
||||||
gid.into()
|
gid.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
|
fn error_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
|
||||||
let mut buf = self.errors.borrow_mut();
|
let mut buf = self.errors.borrow_mut();
|
||||||
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
|
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
|
||||||
ty::Id::NEVER
|
ty::Id::NEVER
|
||||||
}
|
}
|
||||||
|
|
||||||
fn warn(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
|
fn warn_low(&self, file: Module, pos: Pos, msg: impl Display) -> ty::Id {
|
||||||
let mut buf = self.warnings.borrow_mut();
|
let mut buf = self.warnings.borrow_mut();
|
||||||
write!(buf, "(W) {}", self.files[file.index()].report(pos, msg)).unwrap();
|
write!(buf, "(W) {}", self.files[file.index()].report(pos, msg)).unwrap();
|
||||||
ty::Id::NEVER
|
ty::Id::NEVER
|
||||||
|
@ -5081,6 +5072,242 @@ impl TypeParser for Codegen<'_> {
|
||||||
fn find_local_ty(&mut self, ident: Ident) -> Option<ty::Id> {
|
fn find_local_ty(&mut self, ident: Ident) -> Option<ty::Id> {
|
||||||
self.ci.scope.vars.iter().rfind(|v| (v.id == ident && v.value() == NEVER)).map(|v| v.ty)
|
self.ci.scope.vars.iter().rfind(|v| (v.id == ident && v.value() == NEVER)).map(|v| v.ty)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_type(
|
||||||
|
&mut self,
|
||||||
|
pos: Pos,
|
||||||
|
from_file: Module,
|
||||||
|
file: Module,
|
||||||
|
id: Result<Ident, &str>,
|
||||||
|
) -> 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 Some(&ty) = self.tys.syms.get(SymKey::Decl(file, id), &self.tys.ins)
|
||||||
|
{
|
||||||
|
self.on_reuse(ty);
|
||||||
|
ty
|
||||||
|
} else {
|
||||||
|
let f = &self.files[file.index()];
|
||||||
|
|
||||||
|
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else {
|
||||||
|
return match id {
|
||||||
|
Ok(_) => {
|
||||||
|
debug_assert_eq!(from_file, file);
|
||||||
|
self.error_low(file, pos, "somehow this was not found")
|
||||||
|
}
|
||||||
|
Err("main") => self.error_low(
|
||||||
|
from_file,
|
||||||
|
pos,
|
||||||
|
format_args!(
|
||||||
|
"missing main function in '{}', compiler can't \
|
||||||
|
emmit libraries since such concept is not defined \
|
||||||
|
(minimal main function: `main := fn(): void {{}}`)",
|
||||||
|
f.path
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Err(name) => self.error_low(
|
||||||
|
from_file,
|
||||||
|
pos,
|
||||||
|
format_args!("undefined indentifier: {name}"),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
let ty = if let Some(&ty) = self.tys.syms.get(SymKey::Decl(file, name), &self.tys.ins) {
|
||||||
|
ty
|
||||||
|
} 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(Const { ast: ExprRef::new(expr), name, file })
|
||||||
|
.into()
|
||||||
|
} else {
|
||||||
|
self.parse_ty(file, right, Some(name))
|
||||||
|
},
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.unwrap_or_else(|_| unreachable!());
|
||||||
|
if let ty::Kind::Func(f) = ty.expand()
|
||||||
|
&& is_ct
|
||||||
|
{
|
||||||
|
self.tys.ins.funcs[f].is_inline = true;
|
||||||
|
}
|
||||||
|
self.tys.syms.insert(SymKey::Decl(file, name), ty, &self.tys.ins);
|
||||||
|
ty
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(proper_case) = self.tys.case(ty)(f.ident_str(name)) {
|
||||||
|
self.warn_low(
|
||||||
|
from_file,
|
||||||
|
pos,
|
||||||
|
format_args!(
|
||||||
|
"the declaration does not have conventional \
|
||||||
|
casing, expected '{proper_case}', \
|
||||||
|
because the declared type is '{}'",
|
||||||
|
self.ty_display(ty),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
ty
|
||||||
|
};
|
||||||
|
|
||||||
|
if let ty::Kind::Global(g) = ty.expand() {
|
||||||
|
let g = &self.tys.ins.globals[g];
|
||||||
|
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: Module, expr: &Expr, name: Option<Ident>) -> ty::Id {
|
||||||
|
match *expr {
|
||||||
|
Expr::Mod { id, .. } => id.into(),
|
||||||
|
Expr::UnOp { op: TokenKind::Xor, val, .. } => {
|
||||||
|
let base = self.parse_ty(file, val, None);
|
||||||
|
self.tys.make_ptr(base)
|
||||||
|
}
|
||||||
|
Expr::UnOp { op: TokenKind::Que, val, .. } => {
|
||||||
|
let base = self.parse_ty(file, val, None);
|
||||||
|
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, file, file, Ok(id)),
|
||||||
|
Expr::Field { target, pos, name }
|
||||||
|
if let ty::Kind::Module(inside) = self.parse_ty(file, target, None).expand() =>
|
||||||
|
{
|
||||||
|
self.find_type(pos, file, inside, Err(name))
|
||||||
|
}
|
||||||
|
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
|
||||||
|
Expr::Slice { size: None, item, .. } => {
|
||||||
|
let ty = self.parse_ty(file, item, None);
|
||||||
|
self.tys.make_array(ty, ArrayLen::MAX)
|
||||||
|
}
|
||||||
|
Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => {
|
||||||
|
let ty = self.parse_ty(file, item, None);
|
||||||
|
self.tys.make_array(ty, value as _)
|
||||||
|
}
|
||||||
|
Expr::Slice { size, item, .. } => {
|
||||||
|
let ty = self.parse_ty(file, item, None);
|
||||||
|
let len = size
|
||||||
|
.map_or(ArrayLen::MAX, |expr| self.eval_const(file, expr, ty::Id::U32) as _);
|
||||||
|
self.tys.make_array(ty, len)
|
||||||
|
}
|
||||||
|
Expr::Struct { pos, fields, packed, captured, .. } => {
|
||||||
|
let captures_start = self.tys.tmp.args.len();
|
||||||
|
for &cp in captured {
|
||||||
|
let ty = self.find_local_ty(cp).expect("TODO");
|
||||||
|
self.tys.tmp.args.push(ty);
|
||||||
|
}
|
||||||
|
let captured = self.tys.pack_args(captures_start).expect("TODO");
|
||||||
|
|
||||||
|
let sym = SymKey::Struct(file, pos, captured);
|
||||||
|
if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) {
|
||||||
|
return ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_tmp = self.tys.tmp.struct_fields.len();
|
||||||
|
for field in fields.iter().filter_map(CommentOr::or) {
|
||||||
|
let ty = self.parse_ty(file, &field.ty, None);
|
||||||
|
let field = StructField { name: self.tys.names.intern(field.name), ty };
|
||||||
|
self.tys.tmp.struct_fields.push(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = self
|
||||||
|
.tys
|
||||||
|
.ins
|
||||||
|
.structs
|
||||||
|
.push(Struct {
|
||||||
|
file,
|
||||||
|
pos,
|
||||||
|
name: name.unwrap_or_default(),
|
||||||
|
field_start: self.tys.ins.struct_fields.len() as _,
|
||||||
|
explicit_alignment: packed.then_some(1),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
self.tys.ins.struct_fields.extend(self.tys.tmp.struct_fields.drain(prev_tmp..));
|
||||||
|
|
||||||
|
self.tys.syms.insert(sym, ty, &self.tys.ins);
|
||||||
|
ty
|
||||||
|
}
|
||||||
|
Expr::Enum { pos, variants, .. } => {
|
||||||
|
let sym = SymKey::Enum(file, pos);
|
||||||
|
if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) {
|
||||||
|
return ty;
|
||||||
|
}
|
||||||
|
|
||||||
|
let prev_tmp = self.tys.tmp.enum_fields.len();
|
||||||
|
for field in variants.iter().filter_map(CommentOr::or) {
|
||||||
|
let field = EnumField { name: self.tys.names.intern(field.name) };
|
||||||
|
self.tys.tmp.enum_fields.push(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
let ty = self
|
||||||
|
.tys
|
||||||
|
.ins
|
||||||
|
.enums
|
||||||
|
.push(Enum {
|
||||||
|
file,
|
||||||
|
pos,
|
||||||
|
name: name.unwrap_or_default(),
|
||||||
|
field_start: self.tys.ins.enum_fields.len() as _,
|
||||||
|
})
|
||||||
|
.into();
|
||||||
|
|
||||||
|
self.tys.ins.enum_fields.extend(self.tys.tmp.enum_fields.drain(prev_tmp..));
|
||||||
|
|
||||||
|
self.tys.syms.insert(sym, ty, &self.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(&self.files[file.index()].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);
|
||||||
|
self.tys.tmp.args.push(ty);
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(args) = self.tys.pack_args(arg_base) else {
|
||||||
|
return self.error_low(file, pos, "function has too many argumnets");
|
||||||
|
};
|
||||||
|
let ret = self.parse_ty(file, ret, None);
|
||||||
|
|
||||||
|
Some(Sig { args, ret })
|
||||||
|
},
|
||||||
|
expr: ExprRef::new(expr),
|
||||||
|
returns_type: matches!(ret, &Expr::Ident { id, .. } if ty::Builtin::try_from(id) == Ok(ty::Builtin::TYPE)),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
self.tys.ins.funcs.push(func).into()
|
||||||
|
}
|
||||||
|
_ if let Some(name) = name => self.eval_global(file, name, expr),
|
||||||
|
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
Loading…
Reference in a new issue