in progress of adding methods

This commit is contained in:
Jakub Doka 2024-11-24 14:47:38 +01:00
parent 9dfb2eb606
commit 58ee5c0a56
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
8 changed files with 319 additions and 108 deletions

View file

@ -212,6 +212,35 @@ odher_pass := fn(t: Ty2): Ty2 {
} }
``` ```
#### struct_scopes
```hb
$zr := 0
Struct := struct {
a: uint,
b: uint,
$zero := Self.(zr, zr)
$new := fn(a: uint, b: uint): Self return .(a, b)
$swap := fn(s: ^Self): void {
t := s.a
s.a = s.b
s.b = t
}
$diff := fn(s: Self): uint return s.a - s.b
}
main := fn(): uint {
z := Struct.zero
z += Struct.new(1, 2)
z.swap()
return z.diff()
}
```
#### enums #### enums
```hb ```hb
Enum := enum {A, B, C} Enum := enum {A, B, C}

View file

@ -3,7 +3,10 @@ use {
lexer::{self, Lexer, TokenKind}, lexer::{self, Lexer, TokenKind},
parser::{self, CommentOr, CtorField, EnumField, Expr, Poser, Radix, StructField}, parser::{self, CommentOr, CtorField, EnumField, Expr, Poser, Radix, StructField},
}, },
core::fmt::{self}, core::{
fmt::{self},
mem,
},
}; };
pub fn display_radix(radix: Radix, mut value: u64, buf: &mut [u8; 64]) -> &str { pub fn display_radix(radix: Radix, mut value: u64, buf: &mut [u8; 64]) -> &str {
@ -64,8 +67,8 @@ fn token_group(kind: TokenKind) -> TokenGroup {
Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss
| ShrAss | ShlAss => TG::Assign, | ShrAss | ShlAss => TG::Assign,
DQuote | Quote => TG::String, DQuote | Quote => TG::String,
Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed | True Slf | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed
| False | Null | Match | Enum => TG::Keyword, | True | False | Null | Match | Enum => TG::Keyword,
} }
} }
@ -198,12 +201,18 @@ impl<'a> Formatter<'a> {
return f.write_str(end); return f.write_str(end);
} }
writeln!(f)?; if !end.is_empty() {
self.depth += 1; writeln!(f)?;
}
self.depth += !end.is_empty() as usize;
let mut already_indented = end.is_empty();
let res = (|| { let res = (|| {
for (i, stmt) in list.iter().enumerate() { for (i, stmt) in list.iter().enumerate() {
for _ in 0..self.depth { if !mem::take(&mut already_indented) {
f.write_str("\t")?; for _ in 0..self.depth {
f.write_str("\t")?;
}
} }
let add_sep = fmt(self, stmt, f)?; let add_sep = fmt(self, stmt, f)?;
if add_sep { if add_sep {
@ -225,12 +234,14 @@ impl<'a> Formatter<'a> {
} }
Ok(()) Ok(())
})(); })();
self.depth -= 1; self.depth -= !end.is_empty() as usize;
for _ in 0..self.depth { if !end.is_empty() {
f.write_str("\t")?; for _ in 0..self.depth {
f.write_str("\t")?;
}
f.write_str(end)?;
} }
f.write_str(end)?;
res res
} }
@ -269,6 +280,7 @@ impl<'a> Formatter<'a> {
f.write_str("$: ")?; f.write_str("$: ")?;
self.fmt(value, f) self.fmt(value, f)
} }
Expr::Slf { .. } => f.write_str("Self"),
Expr::String { literal, .. } => f.write_str(literal), Expr::String { literal, .. } => f.write_str(literal),
Expr::Comment { literal, .. } => f.write_str(literal), Expr::Comment { literal, .. } => f.write_str(literal),
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"), Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
@ -292,11 +304,15 @@ impl<'a> Formatter<'a> {
f.write_str("struct {")?; f.write_str("struct {")?;
self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| { self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| {
match field { match field {
CommentOr::Or(StructField { name, ty, .. }) => { CommentOr::Or(Ok(StructField { name, ty, .. })) => {
f.write_str(name)?; f.write_str(name)?;
f.write_str(": ")?; f.write_str(": ")?;
s.fmt(ty, f)? s.fmt(ty, f)?
} }
CommentOr::Or(Err(scope)) => {
s.fmt_list(f, true, "", "", scope, Self::fmt)?;
return Ok(false);
}
CommentOr::Comment { literal, .. } => { CommentOr::Comment { literal, .. } => {
f.write_str(literal)?; f.write_str(literal)?;
f.write_str("\n")?; f.write_str("\n")?;
@ -570,6 +586,7 @@ pub mod test {
let mut ctx = Ctx::default(); let mut ctx = Ctx::default();
let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader); let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader);
log::info!("{}", ctx.errors.borrow());
let mut output = String::new(); let mut output = String::new();
write!(output, "{ast}").unwrap(); write!(output, "{ast}").unwrap();

View file

@ -136,6 +136,7 @@ pub enum TokenKind {
Under = b'_', Under = b'_',
Tick = b'`', Tick = b'`',
Slf,
Return, Return,
If, If,
Match, Match,
@ -302,6 +303,7 @@ gen_token_kind! {
Eof, Eof,
Directive, Directive,
#[keywords] #[keywords]
Slf = b"Self",
Return = b"return", Return = b"return",
If = b"if", If = b"if",
Match = b"match", Match = b"match",
@ -401,6 +403,10 @@ impl<'a> Lexer<'a> {
unsafe { core::str::from_utf8_unchecked(&self.source[tok]) } unsafe { core::str::from_utf8_unchecked(&self.source[tok]) }
} }
pub fn taste(&self) -> Token {
Lexer { pos: self.pos, source: self.source }.eat()
}
fn peek(&self) -> Option<u8> { fn peek(&self) -> Option<u8> {
if core::intrinsics::unlikely(self.pos >= self.source.len() as u32) { if core::intrinsics::unlikely(self.pos >= self.source.len() as u32) {
None None

View file

@ -503,8 +503,8 @@ pub mod ty {
Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg, Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg,
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg, Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack, Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_) => { c @ (Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_)) => {
unreachable!() unreachable!("{c:?}")
} }
} }
} }
@ -823,6 +823,7 @@ pub struct Sig {
#[derive(Default, Clone, Copy)] #[derive(Default, Clone, Copy)]
struct Func { struct Func {
file: Module, file: Module,
parent: ty::Id,
name: Ident, name: Ident,
base: Option<ty::Func>, base: Option<ty::Func>,
expr: ExprRef, expr: ExprRef,
@ -859,6 +860,7 @@ pub struct Const {
ast: ExprRef, ast: ExprRef,
name: Ident, name: Ident,
file: Module, file: Module,
parent: ty::Id,
} }
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27) // TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
@ -915,6 +917,7 @@ struct Struct {
captures: ty::Tuple, captures: ty::Tuple,
explicit_alignment: Option<u8>, explicit_alignment: Option<u8>,
field_start: u32, field_start: u32,
ast: ExprRef,
} }
#[derive(PartialEq, Eq, Hash, Clone, Copy)] #[derive(PartialEq, Eq, Hash, Clone, Copy)]

View file

@ -300,8 +300,10 @@ impl<'a, 'b> Parser<'a, 'b> {
let token @ Token { start: pos, .. } = self.next(); let token @ Token { start: pos, .. } = self.next();
let prev_boundary = self.ns_bound; let prev_boundary = self.ns_bound;
let prev_captured = self.ctx.captured.len(); let prev_captured = self.ctx.captured.len();
let mut must_trail = false;
let mut expr = match token.kind { let mut expr = match token.kind {
T::Ct => E::Ct { pos, value: self.ptr_expr()? }, T::Ct => E::Ct { pos, value: self.ptr_expr()? },
T::Slf => E::Slf { pos },
T::Directive if self.lexer.slice(token.range()) == "use" => { T::Directive if self.lexer.slice(token.range()) == "use" => {
self.expect_advance(TokenKind::LParen)?; self.expect_advance(TokenKind::LParen)?;
let str = self.expect_advance(TokenKind::DQuote)?; let str = self.expect_advance(TokenKind::DQuote)?;
@ -374,14 +376,19 @@ impl<'a, 'b> Parser<'a, 'b> {
let tok = s.token; let tok = s.token;
Some(if s.advance_if(T::Comment) { Some(if s.advance_if(T::Comment) {
CommentOr::Comment { literal: s.tok_str(tok), pos: tok.start } CommentOr::Comment { literal: s.tok_str(tok), pos: tok.start }
} else { } else if s.lexer.taste().kind == T::Colon {
let name = s.expect_advance(T::Ident)?; let name = s.expect_advance(T::Ident)?;
s.expect_advance(T::Colon)?; s.expect_advance(T::Colon)?;
CommentOr::Or(StructField { CommentOr::Or(Ok(StructField {
pos: name.start, pos: name.start,
name: s.tok_str(name), name: s.tok_str(name),
ty: s.expr()?, ty: s.expr()?,
}) }))
} else {
must_trail = true;
CommentOr::Or(Err(
s.collect_list_low(T::Semi, T::RBrace, true, |s| s.expr_low(true))
))
}) })
}) })
}, },
@ -400,7 +407,7 @@ impl<'a, 'b> Parser<'a, 'b> {
} }
pos pos
}, },
trailing_comma: core::mem::take(&mut self.trailing_sep), trailing_comma: core::mem::take(&mut self.trailing_sep) || must_trail,
}, },
T::Enum => E::Enum { T::Enum => E::Enum {
pos, pos,
@ -578,7 +585,7 @@ impl<'a, 'b> Parser<'a, 'b> {
} }
} }
if matches!(token.kind, T::Loop | T::LBrace | T::Fn) { if matches!(token.kind, T::Loop | T::LBrace | T::Fn | T::Struct) {
self.pop_scope(frame); self.pop_scope(frame);
} }
@ -651,11 +658,21 @@ impl<'a, 'b> Parser<'a, 'b> {
&mut self, &mut self,
delim: TokenKind, delim: TokenKind,
end: TokenKind, end: TokenKind,
f: impl FnMut(&mut Self) -> Option<T>,
) -> &'a [T] {
self.collect_list_low(delim, end, false, f)
}
fn collect_list_low<T: Copy>(
&mut self,
delim: TokenKind,
end: TokenKind,
keep_end: bool,
mut f: impl FnMut(&mut Self) -> Option<T>, mut f: impl FnMut(&mut Self) -> Option<T>,
) -> &'a [T] { ) -> &'a [T] {
let mut trailing_sep = false; let mut trailing_sep = false;
let mut view = self.ctx.stack.view(); let mut view = self.ctx.stack.view();
'o: while !self.advance_if(end) { 'o: while (keep_end && self.token.kind != end) || (!keep_end && !self.advance_if(end)) {
let val = match f(self) { let val = match f(self) {
Some(val) => val, Some(val) => val,
None => { None => {
@ -833,6 +850,10 @@ generate_expr! {
pos: Pos, pos: Pos,
value: &'a Self, value: &'a Self,
}, },
/// `'Self'`
Slf {
pos: Pos,
},
/// `'"([^"]|\\")"'` /// `'"([^"]|\\")"'`
String { String {
pos: Pos, pos: Pos,
@ -931,7 +952,7 @@ generate_expr! {
/// `'struct' LIST('{', ',', '}', Ident ':' Expr)` /// `'struct' LIST('{', ',', '}', Ident ':' Expr)`
Struct { Struct {
pos: Pos, pos: Pos,
fields: &'a [CommentOr<'a, StructField<'a>>], fields: &'a [CommentOr<'a, Result<StructField<'a>, &'a[Self]>>],
captured: &'a [Ident], captured: &'a [Ident],
trailing_comma: bool, trailing_comma: bool,
packed: bool, packed: bool,
@ -1112,6 +1133,18 @@ pub trait Poser {
fn posi(&self) -> Pos; fn posi(&self) -> Pos;
} }
impl<O: Poser, E: Poser> Poser for Result<O, E> {
fn posi(&self) -> Pos {
self.as_ref().map_or_else(Poser::posi, Poser::posi)
}
}
impl<T: Poser> Poser for &[T] {
fn posi(&self) -> Pos {
self[0].posi()
}
}
impl Poser for Pos { impl Poser for Pos {
fn posi(&self) -> Pos { fn posi(&self) -> Pos {
*self *self
@ -1312,12 +1345,7 @@ impl Ast {
} }
pub fn find_decl(&self, id: Result<Ident, &str>) -> Option<(&Expr, Ident)> { pub fn find_decl(&self, id: Result<Ident, &str>) -> Option<(&Expr, Ident)> {
self.exprs().iter().find_map(|expr| match expr { find_decl(self.exprs(), &self.file, id)
Expr::BinOp { left, op: TokenKind::Decl, .. } => {
left.declares(id, &self.file).map(|id| (expr, id))
}
_ => None,
})
} }
pub fn ident_str(&self, ident: Ident) -> &str { pub fn ident_str(&self, ident: Ident) -> &str {
@ -1325,6 +1353,19 @@ impl Ast {
} }
} }
pub fn find_decl<'a>(
exprs: &'a [Expr<'a>],
file: &str,
id: Result<Ident, &str>,
) -> Option<(&'a Expr<'a>, Ident)> {
exprs.iter().find_map(|expr| match expr {
Expr::BinOp { left, op: TokenKind::Decl, .. } => {
left.declares(id, file).map(|id| (expr, id))
}
_ => None,
})
}
impl Default for Ast { impl Default for Ast {
fn default() -> Self { fn default() -> Self {
Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader)) Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader))

View file

@ -2342,6 +2342,7 @@ impl Scope {
#[derive(Default, Clone)] #[derive(Default, Clone)]
pub struct ItemCtx { pub struct ItemCtx {
file: Module, file: Module,
parent: ty::Id,
pos: Vec<Pos>, pos: Vec<Pos>,
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
@ -2356,7 +2357,7 @@ pub struct ItemCtx {
} }
impl ItemCtx { impl ItemCtx {
fn init(&mut self, file: Module, ret: Option<ty::Id>, task_base: usize) { fn init(&mut self, file: Module, parent: ty::Id, ret: Option<ty::Id>, task_base: usize) {
debug_assert_eq!(self.loops.len(), 0); debug_assert_eq!(self.loops.len(), 0);
debug_assert_eq!(self.scope.vars.len(), 0); debug_assert_eq!(self.scope.vars.len(), 0);
debug_assert_eq!(self.scope.aclasses.len(), 0); debug_assert_eq!(self.scope.aclasses.len(), 0);
@ -2366,6 +2367,7 @@ impl ItemCtx {
debug_assert_eq!(self.inline_aclass_base, 0); debug_assert_eq!(self.inline_aclass_base, 0);
self.file = file; self.file = file;
self.parent = parent;
self.ret = ret; self.ret = ret;
self.task_base = task_base; self.task_base = task_base;
@ -2433,6 +2435,7 @@ impl Pool {
fn push_ci( fn push_ci(
&mut self, &mut self,
file: Module, file: Module,
parent: ty::Id,
ret: Option<ty::Id>, ret: Option<ty::Id>,
task_base: usize, task_base: usize,
target: &mut ItemCtx, target: &mut ItemCtx,
@ -2443,7 +2446,7 @@ impl Pool {
self.cis.push(ItemCtx::default()); self.cis.push(ItemCtx::default());
mem::swap(self.cis.last_mut().unwrap(), target); mem::swap(self.cis.last_mut().unwrap(), target);
} }
target.init(file, ret, task_base); target.init(file, parent, ret, task_base);
self.used_cis += 1; self.used_cis += 1;
} }
@ -2718,10 +2721,11 @@ impl<'a> Codegen<'a> {
self.ci.nodes[region].kind != Kind::Load self.ci.nodes[region].kind != Kind::Load
|| self.ci.nodes[region].kind == Kind::Stck || self.ci.nodes[region].kind == Kind::Stck
|| self.ci.nodes[region].ty.is_pointer(), || self.ci.nodes[region].ty.is_pointer(),
"{:?} {} {}", "{:?} {} {} {:?}",
self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID)), self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID)),
self.file().path, self.file().path,
self.ty_display(self.ci.nodes[region].ty) self.ty_display(self.ci.nodes[region].ty),
self.ci.nodes[region],
); );
debug_assert!(self.ci.nodes[region].kind != Kind::Stre); debug_assert!(self.ci.nodes[region].kind != Kind::Stre);
let (index, _) = self.ci.nodes.aclass_index(region); let (index, _) = self.ci.nodes.aclass_index(region);
@ -2820,7 +2824,7 @@ impl<'a> Codegen<'a> {
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),
_ => Some(Value::new(Nid::MAX).ty(decl)), _ => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, decl)),
} }
} }
Expr::Comment { .. } => Some(Value::VOID), Expr::Comment { .. } => Some(Value::VOID),
@ -2863,9 +2867,9 @@ impl<'a> Codegen<'a> {
let expected = *self.ci.ret.get_or_insert(value.ty); let expected = *self.ci.ret.get_or_insert(value.ty);
self.assert_ty(pos, &mut value, expected, "return value"); self.assert_ty(pos, &mut value, expected, "return value");
self.strip_ptr(&mut value);
if self.ci.inline_depth == 0 { if self.ci.inline_depth == 0 {
self.strip_ptr(&mut value);
debug_assert_ne!(self.ci.ctrl.get(), VOID); debug_assert_ne!(self.ci.ctrl.get(), VOID);
let mut inps = Vc::from([self.ci.ctrl.get(), value.id]); let mut inps = Vc::from([self.ci.ctrl.get(), value.id]);
for (i, aclass) in self.ci.scope.aclasses.iter_mut().enumerate() { for (i, aclass) in self.ci.scope.aclasses.iter_mut().enumerate() {
@ -2930,10 +2934,7 @@ impl<'a> Codegen<'a> {
.for_each(|v| v.remove(&mut self.ci.nodes)); .for_each(|v| v.remove(&mut self.ci.nodes));
let repl = StrongRef::new(NEVER, &mut self.ci.nodes); let repl = StrongRef::new(NEVER, &mut self.ci.nodes);
let (index, _) = self let (index, _) = self.ci.nodes.aclass_index(value.id);
.ci
.nodes
.aclass_index(*self.ci.nodes[value.id].inputs.get(1).unwrap_or(&VOID));
let aclass = (self.ci.inline_aclass_base <= index) let aclass = (self.ci.inline_aclass_base <= index)
.then(|| self.ci.scope.aclasses[index].dup(&mut self.ci.nodes)); .then(|| self.ci.scope.aclasses[index].dup(&mut self.ci.nodes));
self.ci.inline_ret = self.ci.inline_ret =
@ -2964,7 +2965,7 @@ impl<'a> Codegen<'a> {
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),
v => Some(Value::new(Nid::MAX).ty(v.compress())), v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
} }
} }
ty::Kind::Enum(e) => { ty::Kind::Enum(e) => {
@ -2972,7 +2973,23 @@ impl<'a> Codegen<'a> {
self.gen_enum_variant(pos, e, intrnd) self.gen_enum_variant(pos, e, intrnd)
} }
ty::Kind::Struct(s) => { ty::Kind::Struct(s) => {
let Some((offset, ty)) = OffsetIter::offset_of(self.tys, s, name) else { let Struct { 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(scope))], ..
} = ast.get(&self.files[file.index()])
&& let ty = self.find_type_low(
pos,
self.ci.file,
file,
Some((s.into(), scope)),
Err(name),
)
&& ty != ty::Id::NEVER
{
todo!()
} else {
let field_list = self let field_list = self
.tys .tys
.struct_fields(s) .struct_fields(s)
@ -2984,15 +3001,66 @@ impl<'a> Codegen<'a> {
pos, pos,
fa!( fa!(
"the '{}' does not have this field, \ "the '{}' does not have this field, \
but it does have '{field_list}'", but it does have '{field_list}'",
self.ty_display(tty) self.ty_display(tty)
), ),
); );
return Value::NEVER; Value::NEVER
}; }
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
} }
ty::Kind::TYPE => match ty::Id::from(match self.ci.nodes[vtarget.id].kind {
Kind::CInt { value } => value as u64,
_ => unreachable!(),
})
.expand()
{
ty::Kind::Struct(s) => {
let Struct { ast, file, .. } = self.tys.ins.structs[s];
let Expr::Struct { fields: &[.., CommentOr::Or(Err(scope))], .. } =
ast.get(&self.files[file.index()])
else {
self.error(
pos,
fa!("'{}' has not declarations", self.ty_display(s.into())),
);
return Value::NEVER;
};
match self
.find_type_low(
pos,
self.ci.file,
file,
Some((s.into(), scope)),
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),
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
}
}
ty::Kind::Module(m) => {
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),
v => Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, v.compress())),
}
}
ty => {
self.error(
pos,
fa!(
"accesing scope on '{}' is not supported yet",
self.ty_display(ty.compress())
),
);
Value::NEVER
}
},
_ => { _ => {
self.error( self.error(
pos, pos,
@ -3203,11 +3271,13 @@ impl<'a> Codegen<'a> {
Some(bop) Some(bop)
} }
ty::Kind::Struct(s) if op.is_homogenous() => { ty::Kind::Struct(s) if op.is_homogenous() => {
debug_assert!(lhs.ptr);
self.ci.nodes.lock(lhs.id); self.ci.nodes.lock(lhs.id);
let rhs = self.raw_expr_ctx(right, Ctx::default().with_ty(lhs.ty)); let rhs = self.raw_expr_ctx(right, Ctx::default().with_ty(lhs.ty));
self.ci.nodes.unlock(lhs.id); self.ci.nodes.unlock(lhs.id);
let mut rhs = rhs?; let mut rhs = rhs?;
self.strip_var(&mut rhs); self.strip_var(&mut rhs);
debug_assert!(rhs.ptr);
self.assert_ty(pos, &mut rhs, lhs.ty, "struct operand"); self.assert_ty(pos, &mut rhs, lhs.ty, "struct operand");
let dst = self.new_stack(pos, lhs.ty); let dst = self.new_stack(pos, lhs.ty);
self.struct_op(left.pos(), op, s, dst, lhs.id, rhs.id); self.struct_op(left.pos(), op, s, dst, lhs.id, rhs.id);
@ -4082,8 +4152,8 @@ impl<'a> Codegen<'a> {
Some(Value::VOID) Some(Value::VOID)
} }
ref e => { ref e => {
self.error_unhandled_ast(e, "bruh"); let ty = self.ty(e);
Value::NEVER Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, ty))
} }
} }
} }
@ -4161,7 +4231,12 @@ impl<'a> Codegen<'a> {
} }
fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> { fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> {
let ty = self.ty(func); let mut ty = self.expr(func)?;
self.assert_ty(func.pos(), &mut ty, ty::Id::TYPE, "function");
let ty = ty::Id::from(match self.ci.nodes[ty.id].kind {
Kind::CInt { value } => value as u64,
_ => unreachable!(),
});
let ty::Kind::Func(mut fu) = ty.expand() else { let ty::Kind::Func(mut fu) = ty.expand() else {
self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty))); self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
return Value::NEVER; return Value::NEVER;
@ -4333,7 +4408,8 @@ impl<'a> Codegen<'a> {
fn gen_const(&mut self, cnst: ty::Const, ctx: Ctx) -> Option<Value> { fn gen_const(&mut self, cnst: ty::Const, ctx: Ctx) -> Option<Value> {
let c = &self.tys.ins.consts[cnst]; let c = &self.tys.ins.consts[cnst];
let prev = mem::replace(&mut self.ci.file, c.file); 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.index()];
let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() }; let Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() };
@ -4344,7 +4420,8 @@ impl<'a> Codegen<'a> {
}) })
.unwrap_or_else(|_| unreachable!())?; .unwrap_or_else(|_| unreachable!())?;
self.strip_var(&mut value); self.strip_var(&mut value);
self.ci.file = prev; self.ci.file = prev_file;
self.ci.parent = prev_parent;
Some(value) Some(value)
} }
@ -4475,7 +4552,7 @@ impl<'a> Codegen<'a> {
} }
fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> { fn compute_signature(&mut self, func: &mut ty::Func, pos: Pos, args: &[Expr]) -> Option<Sig> {
let Func { file, expr, sig, .. } = self.tys.ins.funcs[*func]; let Func { file, expr, sig, parent, .. } = self.tys.ins.funcs[*func];
let fast = &self.files[file.index()]; let fast = &self.files[file.index()];
let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else { let &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else {
unreachable!(); unreachable!();
@ -4488,7 +4565,7 @@ impl<'a> Codegen<'a> {
let base = self.ci.scope.vars.len(); let base = self.ci.scope.vars.len();
for (arg, carg) in args.iter().zip(cargs) { for (arg, carg) in args.iter().zip(cargs) {
let ty = self.ty_in(file, &carg.ty); let ty = self.ty_in(file, parent, &carg.ty);
self.tys.tmp.args.push(ty); self.tys.tmp.args.push(ty);
let sym = parser::find_symbol(&fast.symbols, carg.id); let sym = parser::find_symbol(&fast.symbols, carg.id);
@ -4526,7 +4603,7 @@ impl<'a> Codegen<'a> {
self.error(pos, "function instance has too many arguments"); self.error(pos, "function instance has too many arguments");
return None; return None;
}; };
let ret = self.ty_in(file, ret); let ret = self.ty_in(file, parent, ret);
self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes)); self.ci.scope.vars.drain(base..).for_each(|v| v.remove(&mut self.ci.nodes));
@ -4695,7 +4772,7 @@ impl<'a> Codegen<'a> {
let ast = &self.files[file.index()]; let ast = &self.files[file.index()];
let expr = func.expr.get(ast); let expr = func.expr.get(ast);
self.pool.push_ci(file, Some(sig.ret), 0, &mut self.ci); self.pool.push_ci(file, func.parent, Some(sig.ret), 0, &mut self.ci);
let prev_err_len = self.errors.borrow().len(); let prev_err_len = self.errors.borrow().len();
log::info!("{}", self.ast_display(expr)); log::info!("{}", self.ast_display(expr));
@ -4852,11 +4929,11 @@ impl<'a> Codegen<'a> {
} }
fn ty(&mut self, expr: &Expr) -> ty::Id { fn ty(&mut self, expr: &Expr) -> ty::Id {
self.ty_in(self.ci.file, expr) self.ty_in(self.ci.file, self.ci.parent, expr)
} }
fn ty_in(&mut self, file: Module, expr: &Expr) -> ty::Id { fn ty_in(&mut self, file: Module, parent: ty::Id, expr: &Expr) -> ty::Id {
self.parse_ty(file, expr, None) self.parse_ty(TyScope { file, parent, name: None }, expr)
} }
fn ty_display(&self, ty: ty::Id) -> ty::Display { fn ty_display(&self, ty: ty::Id) -> ty::Display {
@ -5117,7 +5194,7 @@ impl<'a> Codegen<'a> {
_ => unreachable!(), _ => unreachable!(),
}) })
.collect::<Vec<_>>(); .collect::<Vec<_>>();
self.pool.push_ci(file, Some(ret), self.tys.tasks.len(), &mut self.ci); self.pool.push_ci(file, self.ci.parent, Some(ret), self.tys.tasks.len(), &mut self.ci);
self.ci.scope.vars = scope self.ci.scope.vars = scope
.into_iter() .into_iter()
.map(|(v, id)| { .map(|(v, id)| {
@ -5170,7 +5247,7 @@ impl<'a> Codegen<'a> {
let gid = self.tys.ins.globals.push(Global { file, name, ..Default::default() }); let gid = self.tys.ins.globals.push(Global { file, name, ..Default::default() });
self.pool.push_ci(file, None, self.tys.tasks.len(), &mut self.ci); self.pool.push_ci(file, self.ci.parent, None, self.tys.tasks.len(), &mut self.ci);
let prev_err_len = self.errors.borrow().len(); let prev_err_len = self.errors.borrow().len();
self.expr(&(Expr::Return { pos: expr.pos(), val: Some(expr) })); self.expr(&(Expr::Return { pos: expr.pos(), val: Some(expr) }));
@ -5216,6 +5293,17 @@ impl<'a> Codegen<'a> {
from_file: Module, from_file: Module,
file: Module, file: Module,
id: Result<Ident, &str>, id: Result<Ident, &str>,
) -> ty::Id {
self.find_type_low(pos, from_file, file, None, id)
}
fn find_type_low(
&mut self,
pos: Pos,
from_file: Module,
file: Module,
subscope: Option<(ty::Id, &[Expr])>,
id: Result<Ident, &str>,
) -> ty::Id { ) -> ty::Id {
let ty = if let Ok(id) = id let ty = if let Ok(id) = id
&& let Some(ty) = self.find_local_ty(id) && let Some(ty) = self.find_local_ty(id)
@ -5229,7 +5317,9 @@ impl<'a> Codegen<'a> {
} else { } else {
let f = &self.files[file.index()]; let f = &self.files[file.index()];
let Some((expr @ Expr::BinOp { left, right, .. }, name)) = f.find_decl(id) else { let Some((expr @ Expr::BinOp { left, right, .. }, name)) =
parser::find_decl(subscope.map(|(_, s)| s).unwrap_or(f.exprs()), &f.file, id)
else {
return match id { return match id {
Ok(_) => { Ok(_) => {
debug_assert_eq!(from_file, file); debug_assert_eq!(from_file, file);
@ -5264,10 +5354,22 @@ impl<'a> Codegen<'a> {
self.tys self.tys
.ins .ins
.consts .consts
.push(Const { ast: ExprRef::new(expr), name, file }) .push(Const {
ast: ExprRef::new(expr),
name,
file,
parent: subscope.map(|(p, _)| p).unwrap_or(file.into()),
})
.into() .into()
} else { } else {
self.parse_ty(file, right, Some(name)) self.parse_ty(
TyScope {
file,
parent: subscope.map(|(p, _)| p).unwrap_or(file.into()),
name: Some(name),
},
right,
)
}, },
) )
}) })
@ -5309,37 +5411,38 @@ impl<'a> Codegen<'a> {
} }
/// returns none if comptime eval is required /// returns none if comptime eval is required
fn parse_ty(&mut self, file: Module, expr: &Expr, name: Option<Ident>) -> ty::Id { fn parse_ty(&mut self, sc: TyScope, expr: &Expr) -> ty::Id {
match *expr { match *expr {
Expr::Slf { .. } => sc.parent,
Expr::Mod { id, .. } => id.into(), Expr::Mod { id, .. } => id.into(),
Expr::UnOp { op: TokenKind::Xor, val, .. } => { Expr::UnOp { op: TokenKind::Xor, val, .. } => {
let base = self.parse_ty(file, val, None); let base = self.parse_ty(sc.anon(), val);
self.tys.make_ptr(base) self.tys.make_ptr(base)
} }
Expr::UnOp { op: TokenKind::Que, val, .. } => { Expr::UnOp { op: TokenKind::Que, val, .. } => {
let base = self.parse_ty(file, val, None); let base = self.parse_ty(sc.anon(), val);
self.tys.make_opt(base) self.tys.make_opt(base)
} }
Expr::Ident { id, .. } if let Ok(bt) = ty::Builtin::try_from(id) => bt.into(), 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::Ident { id, pos, .. } => self.find_type(pos, sc.file, sc.file, Ok(id)),
Expr::Field { target, pos, name } Expr::Field { target, pos, name }
if let ty::Kind::Module(inside) = self.parse_ty(file, target, None).expand() => if let ty::Kind::Module(inside) = self.parse_ty(sc.anon(), target).expand() =>
{ {
self.find_type(pos, file, inside, Err(name)) self.find_type(pos, sc.file, inside, Err(name))
} }
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr), Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
Expr::Slice { size: None, item, .. } => { Expr::Slice { size: None, item, .. } => {
let ty = self.parse_ty(file, item, None); let ty = self.parse_ty(sc.anon(), item);
self.tys.make_array(ty, ArrayLen::MAX) self.tys.make_array(ty, ArrayLen::MAX)
} }
Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => { Expr::Slice { size: Some(&Expr::Number { value, .. }), item, .. } => {
let ty = self.parse_ty(file, item, None); let ty = self.parse_ty(sc.anon(), item);
self.tys.make_array(ty, value as _) self.tys.make_array(ty, value as _)
} }
Expr::Slice { size, item, .. } => { Expr::Slice { size, item, .. } => {
let ty = self.parse_ty(file, item, None); let ty = self.parse_ty(sc.anon(), item);
let len = size let len = size
.map_or(ArrayLen::MAX, |expr| self.eval_const(file, expr, ty::Id::U32) as _); .map_or(ArrayLen::MAX, |expr| self.eval_const(sc.file, expr, ty::Id::U32) as _);
self.tys.make_array(ty, len) self.tys.make_array(ty, len)
} }
Expr::Struct { pos, fields, packed, captured, .. } => { Expr::Struct { pos, fields, packed, captured, .. } => {
@ -5350,14 +5453,14 @@ impl<'a> Codegen<'a> {
} }
let captured = self.tys.pack_args(captures_start).expect("TODO"); let captured = self.tys.pack_args(captures_start).expect("TODO");
let sym = SymKey::Struct(file, pos, captured); let sym = SymKey::Struct(sc.file, pos, captured);
if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) { if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) {
return ty; return ty;
} }
let prev_tmp = self.tys.tmp.struct_fields.len(); let prev_tmp = self.tys.tmp.struct_fields.len();
for field in fields.iter().filter_map(CommentOr::or) { for field in fields.iter().filter_map(CommentOr::or).filter_map(Result::ok) {
let ty = self.parse_ty(file, &field.ty, None); let ty = self.parse_ty(sc.anon(), &field.ty);
let field = StructField { name: self.tys.names.intern(field.name), ty }; let field = StructField { name: self.tys.names.intern(field.name), ty };
self.tys.tmp.struct_fields.push(field); self.tys.tmp.struct_fields.push(field);
} }
@ -5367,11 +5470,12 @@ impl<'a> Codegen<'a> {
.ins .ins
.structs .structs
.push(Struct { .push(Struct {
file, file: sc.file,
pos, pos,
name: name.unwrap_or_default(), name: sc.name.unwrap_or_default(),
field_start: self.tys.ins.struct_fields.len() as _, field_start: self.tys.ins.struct_fields.len() as _,
explicit_alignment: packed.then_some(1), explicit_alignment: packed.then_some(1),
ast: ExprRef::new(expr),
..Default::default() ..Default::default()
}) })
.into(); .into();
@ -5382,7 +5486,7 @@ impl<'a> Codegen<'a> {
ty ty
} }
Expr::Enum { pos, variants, .. } => { Expr::Enum { pos, variants, .. } => {
let sym = SymKey::Enum(file, pos); let sym = SymKey::Enum(sc.file, pos);
if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) { if let Some(&ty) = self.tys.syms.get(sym, &self.tys.ins) {
return ty; return ty;
} }
@ -5398,9 +5502,9 @@ impl<'a> Codegen<'a> {
.ins .ins
.enums .enums
.push(Enum { .push(Enum {
file, file: sc.file,
pos, pos,
name: name.unwrap_or_default(), name: sc.name.unwrap_or_default(),
field_start: self.tys.ins.enum_fields.len() as _, field_start: self.tys.ins.enum_fields.len() as _,
}) })
.into(); .into();
@ -5410,27 +5514,28 @@ impl<'a> Codegen<'a> {
self.tys.syms.insert(sym, ty, &self.tys.ins); self.tys.syms.insert(sym, ty, &self.tys.ins);
ty ty
} }
Expr::Closure { pos, args, ret, .. } if let Some(name) = name => { Expr::Closure { pos, args, ret, .. } if let Some(name) = sc.name => {
let func = Func { let func = Func {
file, file: sc.file,
parent: sc.parent,
name, name,
sig: 'b: { sig: 'b: {
let arg_base = self.tys.tmp.args.len(); let arg_base = self.tys.tmp.args.len();
for arg in args { for arg in args {
let sym = let sym =
parser::find_symbol(&self.files[file.index()].symbols, arg.id); parser::find_symbol(&self.files[sc.file.index()].symbols, arg.id);
if sym.flags & idfl::COMPTIME != 0 { if sym.flags & idfl::COMPTIME != 0 {
self.tys.tmp.args.truncate(arg_base); self.tys.tmp.args.truncate(arg_base);
break 'b None; break 'b None;
} }
let ty = self.parse_ty(file, &arg.ty, None); let ty = self.parse_ty(sc.anon(), &arg.ty);
self.tys.tmp.args.push(ty); self.tys.tmp.args.push(ty);
} }
let Some(args) = self.tys.pack_args(arg_base) else { let Some(args) = self.tys.pack_args(arg_base) else {
return self.error_low(file, pos, "function has too many argumnets"); return self.error_low(sc.file, pos, "function has too many argumnets");
}; };
let ret = self.parse_ty(file, ret, None); let ret = self.parse_ty(sc.anon(), ret);
Some(Sig { args, ret }) Some(Sig { args, ret })
}, },
@ -5441,12 +5546,25 @@ impl<'a> Codegen<'a> {
self.tys.ins.funcs.push(func).into() self.tys.ins.funcs.push(func).into()
} }
_ if let Some(name) = name => self.eval_global(file, name, expr), _ if let Some(name) = sc.name => self.eval_global(sc.file, name, expr),
_ => ty::Id::from(self.eval_const(file, expr, ty::Id::TYPE)), _ => ty::Id::from(self.eval_const(sc.file, expr, ty::Id::TYPE)),
} }
} }
} }
#[derive(Clone, Copy)]
struct TyScope {
file: Module,
parent: ty::Id,
name: Option<Ident>,
}
impl TyScope {
fn anon(self) -> Self {
Self { name: None, ..self }
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use { use {
@ -5503,6 +5621,7 @@ mod tests {
loops; loops;
pointers; pointers;
structs; structs;
struct_scopes;
enums; enums;
nullable_types; nullable_types;
struct_operators; struct_operators;

View file

@ -1,6 +1,6 @@
main: main:
ADDI64 r254, r254, -136d ADDI64 r254, r254, -104d
ST r31, r254, 80a, 56h ST r31, r254, 48a, 56h
LRA r32, r0, :glob_stru LRA r32, r0, :glob_stru
JAL r31, r0, :new_stru JAL r31, r0, :new_stru
ST r1, r32, 0a, 16h ST r1, r32, 0a, 16h
@ -19,33 +19,29 @@ main:
2: LI64 r34, 1d 2: LI64 r34, 1d
ST r34, r32, 0a, 8h ST r34, r32, 0a, 8h
ST r34, r32, 8a, 8h ST r34, r32, 8a, 8h
ADDI64 r35, r254, 32d ADDI64 r35, r254, 0d
ST r34, r254, 0a, 8h
ST r34, r254, 8a, 8h
ST r34, r254, 16a, 8h
ST r34, r254, 24a, 8h
ST r34, r254, 32a, 8h ST r34, r254, 32a, 8h
ST r34, r254, 40a, 8h ST r34, r254, 40a, 8h
ST r34, r254, 48a, 8h
ST r34, r254, 56a, 8h
ST r34, r254, 64a, 8h
ST r34, r254, 72a, 8h
LI64 r36, 3d LI64 r36, 3d
CP r32, r33 CP r32, r33
8: JNE r32, r36, :3 8: JNE r32, r36, :3
LD r32, r254, 64a, 8h LD r32, r254, 32a, 8h
JEQ r32, r33, :4 JEQ r32, r33, :4
LI64 r32, 100d LI64 r32, 100d
CP r1, r32 CP r1, r32
JMP :1 JMP :1
4: ST r34, r254, 32a, 8h 4: ST r34, r254, 0a, 8h
ST r34, r254, 8a, 8h
ST r34, r254, 16a, 8h
ST r34, r254, 24a, 8h
ST r34, r254, 32a, 8h
ST r34, r254, 40a, 8h ST r34, r254, 40a, 8h
ST r34, r254, 48a, 8h
ST r34, r254, 56a, 8h
ST r34, r254, 64a, 8h
ST r34, r254, 72a, 8h
ST r33, r254, 0a, 8h
ST r33, r254, 8a, 8h
ST r33, r254, 16a, 8h
ST r33, r254, 24a, 8h
CP r32, r33 CP r32, r33
7: LD r37, r254, 64a, 8h 7: LD r37, r254, 32a, 8h
JNE r32, r36, :5 JNE r32, r36, :5
JEQ r37, r33, :6 JEQ r37, r33, :6
LI64 r32, 10d LI64 r32, 10d
@ -65,8 +61,8 @@ main:
ST r1, r37, 0a, 16h ST r1, r37, 0a, 16h
ADD64 r32, r32, r34 ADD64 r32, r32, r34
JMP :8 JMP :8
1: LD r31, r254, 80a, 56h 1: LD r31, r254, 48a, 56h
ADDI64 r254, r254, 136d ADDI64 r254, r254, 104d
JALA r0, r31, 0a JALA r0, r31, 0a
new_stru: new_stru:
ADDI64 r254, r254, -16d ADDI64 r254, r254, -16d
@ -76,6 +72,6 @@ new_stru:
LD r1, r13, 0a, 16h LD r1, r13, 0a, 16h
ADDI64 r254, r254, 16d ADDI64 r254, r254, 16d
JALA r0, r31, 0a JALA r0, r31, 0a
code size: 736 code size: 684
ret: 0 ret: 0
status: Ok(()) status: Ok(())

View file