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;
|
||||
use {
|
||||
self::{
|
||||
lexer::TokenKind,
|
||||
parser::{idfl, CommentOr, Expr, ExprRef, Pos},
|
||||
parser::{ExprRef, Pos},
|
||||
ty::{ArrayLen, Builtin, Module},
|
||||
utils::EntVec,
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{cell::Cell, fmt::Display, ops::Range},
|
||||
core::{cell::Cell, ops::Range},
|
||||
hashbrown::hash_map,
|
||||
};
|
||||
|
||||
|
@ -1034,266 +1033,6 @@ pub struct Types {
|
|||
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 {
|
||||
pub fn case(&self, ty: ty::Id) -> fn(&str) -> Result<(), &'static str> {
|
||||
match ty.expand() {
|
||||
|
|
279
lang/src/son.rs
279
lang/src/son.rs
|
@ -10,12 +10,12 @@ use {
|
|||
parser::{
|
||||
self,
|
||||
idfl::{self},
|
||||
CtorField, Expr, MatchBranch, Pos,
|
||||
CommentOr, CtorField, Expr, ExprRef, MatchBranch, Pos,
|
||||
},
|
||||
ty::{self, Arg, ArrayLen, Loc, Module, Tuple},
|
||||
utils::{BitSet, Ent, Vc},
|
||||
CompState, FTask, Func, Global, Ident, Offset, OffsetIter, OptLayout, Sig, StringRef,
|
||||
SymKey, TypeParser, Types,
|
||||
CompState, Const, Enum, EnumField, FTask, Func, Global, Ident, Offset, OffsetIter,
|
||||
OptLayout, Sig, StringRef, Struct, StructField, SymKey, Types,
|
||||
},
|
||||
alloc::{string::String, vec::Vec},
|
||||
core::{
|
||||
|
@ -2488,7 +2488,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
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() {
|
||||
return;
|
||||
}
|
||||
|
@ -2732,7 +2732,7 @@ impl<'a> Codegen<'a> {
|
|||
Some(Value::var(index).ty(var.ty))
|
||||
}
|
||||
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() {
|
||||
ty::Kind::NEVER => Value::NEVER,
|
||||
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() {
|
||||
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::Global(global) => self.gen_global(global),
|
||||
ty::Kind::Const(cnst) => self.gen_const(cnst, ctx),
|
||||
|
@ -3894,7 +3894,8 @@ impl<'a> Codegen<'a> {
|
|||
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 } => {
|
||||
let value = self.expr(value)?;
|
||||
|
@ -3983,9 +3984,9 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
for (lcntrl, then_scope) in scopes.into_iter().rev() {
|
||||
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 {
|
||||
then_scope.clear(&mut self.ci.nodes);
|
||||
return None;
|
||||
} else if lcntrl == Nid::MAX {
|
||||
then_scope.clear(&mut self.ci.nodes);
|
||||
return Some(Value::VOID);
|
||||
return Some(VOID);
|
||||
} else if rcntrl == Nid::MAX {
|
||||
self.ci.scope.clear(&mut self.ci.nodes);
|
||||
self.ci.scope = then_scope;
|
||||
self.ci.ctrl.set(lcntrl, &mut self.ci.nodes);
|
||||
return Some(Value::VOID);
|
||||
return Some(VOID);
|
||||
}
|
||||
|
||||
self.ci.ctrl.set(
|
||||
|
@ -4029,7 +4030,7 @@ impl<'a> Codegen<'a> {
|
|||
self.tys,
|
||||
);
|
||||
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> {
|
||||
|
@ -4741,7 +4742,7 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
@ -4988,16 +4989,6 @@ impl<'a> Codegen<'a> {
|
|||
fn file(&self) -> &'a parser::Ast {
|
||||
&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 {
|
||||
self.ct.activate();
|
||||
|
@ -5066,13 +5057,13 @@ impl TypeParser for Codegen<'_> {
|
|||
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();
|
||||
write!(buf, "{}", self.files[file.index()].report(pos, msg)).unwrap();
|
||||
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();
|
||||
write!(buf, "(W) {}", self.files[file.index()].report(pos, msg)).unwrap();
|
||||
ty::Id::NEVER
|
||||
|
@ -5081,6 +5072,242 @@ impl TypeParser for Codegen<'_> {
|
|||
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)
|
||||
}
|
||||
|
||||
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)]
|
||||
|
|
Loading…
Reference in a new issue