diff --git a/lang/src/lib.rs b/lang/src/lib.rs index b959bb0..be6f58a 100644 --- a/lang/src/lib.rs +++ b/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>, } -// 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; - 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, - 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, - 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() { diff --git a/lang/src/son.rs b/lang/src/son.rs index 87fa11c..faafea4 100644 --- a/lang/src/son.rs +++ b/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), @@ -4741,7 +4741,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 +4988,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 +5056,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 +5071,242 @@ impl TypeParser for Codegen<'_> { fn find_local_ty(&mut self, ident: Ident) -> Option { 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, + ) -> 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) -> 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)]