forked from AbleOS/holey-bytes
in progress of adding methods
This commit is contained in:
parent
9dfb2eb606
commit
58ee5c0a56
|
@ -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
|
||||
```hb
|
||||
Enum := enum {A, B, C}
|
||||
|
|
|
@ -3,7 +3,10 @@ use {
|
|||
lexer::{self, Lexer, TokenKind},
|
||||
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 {
|
||||
|
@ -64,8 +67,8 @@ fn token_group(kind: TokenKind) -> TokenGroup {
|
|||
Decl | Assign | BorAss | XorAss | BandAss | AddAss | SubAss | MulAss | DivAss | ModAss
|
||||
| ShrAss | ShlAss => TG::Assign,
|
||||
DQuote | Quote => TG::String,
|
||||
Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed | True
|
||||
| False | Null | Match | Enum => TG::Keyword,
|
||||
Slf | Return | If | Else | Loop | Break | Continue | Fn | Idk | Die | Struct | Packed
|
||||
| True | False | Null | Match | Enum => TG::Keyword,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -198,12 +201,18 @@ impl<'a> Formatter<'a> {
|
|||
return f.write_str(end);
|
||||
}
|
||||
|
||||
writeln!(f)?;
|
||||
self.depth += 1;
|
||||
if !end.is_empty() {
|
||||
writeln!(f)?;
|
||||
}
|
||||
|
||||
self.depth += !end.is_empty() as usize;
|
||||
let mut already_indented = end.is_empty();
|
||||
let res = (|| {
|
||||
for (i, stmt) in list.iter().enumerate() {
|
||||
for _ in 0..self.depth {
|
||||
f.write_str("\t")?;
|
||||
if !mem::take(&mut already_indented) {
|
||||
for _ in 0..self.depth {
|
||||
f.write_str("\t")?;
|
||||
}
|
||||
}
|
||||
let add_sep = fmt(self, stmt, f)?;
|
||||
if add_sep {
|
||||
|
@ -225,12 +234,14 @@ impl<'a> Formatter<'a> {
|
|||
}
|
||||
Ok(())
|
||||
})();
|
||||
self.depth -= 1;
|
||||
self.depth -= !end.is_empty() as usize;
|
||||
|
||||
for _ in 0..self.depth {
|
||||
f.write_str("\t")?;
|
||||
if !end.is_empty() {
|
||||
for _ in 0..self.depth {
|
||||
f.write_str("\t")?;
|
||||
}
|
||||
f.write_str(end)?;
|
||||
}
|
||||
f.write_str(end)?;
|
||||
res
|
||||
}
|
||||
|
||||
|
@ -269,6 +280,7 @@ impl<'a> Formatter<'a> {
|
|||
f.write_str("$: ")?;
|
||||
self.fmt(value, f)
|
||||
}
|
||||
Expr::Slf { .. } => f.write_str("Self"),
|
||||
Expr::String { literal, .. } => f.write_str(literal),
|
||||
Expr::Comment { literal, .. } => f.write_str(literal),
|
||||
Expr::Mod { path, .. } => write!(f, "@use(\"{path}\")"),
|
||||
|
@ -292,11 +304,15 @@ impl<'a> Formatter<'a> {
|
|||
f.write_str("struct {")?;
|
||||
self.fmt_list_low(f, trailing_comma, "}", ",", fields, |s, field, f| {
|
||||
match field {
|
||||
CommentOr::Or(StructField { name, ty, .. }) => {
|
||||
CommentOr::Or(Ok(StructField { name, ty, .. })) => {
|
||||
f.write_str(name)?;
|
||||
f.write_str(": ")?;
|
||||
s.fmt(ty, f)?
|
||||
}
|
||||
CommentOr::Or(Err(scope)) => {
|
||||
s.fmt_list(f, true, "", "", scope, Self::fmt)?;
|
||||
return Ok(false);
|
||||
}
|
||||
CommentOr::Comment { literal, .. } => {
|
||||
f.write_str(literal)?;
|
||||
f.write_str("\n")?;
|
||||
|
@ -570,6 +586,7 @@ pub mod test {
|
|||
|
||||
let mut ctx = Ctx::default();
|
||||
let ast = parser::Ast::new(ident, minned, &mut ctx, &mut parser::no_loader);
|
||||
log::info!("{}", ctx.errors.borrow());
|
||||
let mut output = String::new();
|
||||
write!(output, "{ast}").unwrap();
|
||||
|
||||
|
|
|
@ -136,6 +136,7 @@ pub enum TokenKind {
|
|||
Under = b'_',
|
||||
Tick = b'`',
|
||||
|
||||
Slf,
|
||||
Return,
|
||||
If,
|
||||
Match,
|
||||
|
@ -302,6 +303,7 @@ gen_token_kind! {
|
|||
Eof,
|
||||
Directive,
|
||||
#[keywords]
|
||||
Slf = b"Self",
|
||||
Return = b"return",
|
||||
If = b"if",
|
||||
Match = b"match",
|
||||
|
@ -401,6 +403,10 @@ impl<'a> Lexer<'a> {
|
|||
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> {
|
||||
if core::intrinsics::unlikely(self.pos >= self.source.len() as u32) {
|
||||
None
|
||||
|
|
|
@ -503,8 +503,8 @@ pub mod ty {
|
|||
Kind::Ptr(_) | Kind::Enum(_) | Kind::Builtin(_) => Loc::Reg,
|
||||
Kind::Struct(_) if tys.size_of(*self) == 0 => Loc::Reg,
|
||||
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
||||
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_) => {
|
||||
unreachable!()
|
||||
c @ (Kind::Func(_) | Kind::Global(_) | Kind::Module(_) | Kind::Const(_)) => {
|
||||
unreachable!("{c:?}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -823,6 +823,7 @@ pub struct Sig {
|
|||
#[derive(Default, Clone, Copy)]
|
||||
struct Func {
|
||||
file: Module,
|
||||
parent: ty::Id,
|
||||
name: Ident,
|
||||
base: Option<ty::Func>,
|
||||
expr: ExprRef,
|
||||
|
@ -859,6 +860,7 @@ pub struct Const {
|
|||
ast: ExprRef,
|
||||
name: Ident,
|
||||
file: Module,
|
||||
parent: ty::Id,
|
||||
}
|
||||
|
||||
// TODO: make into bit struct (width: u2, sub_offset: u3, offset: u27)
|
||||
|
@ -915,6 +917,7 @@ struct Struct {
|
|||
captures: ty::Tuple,
|
||||
explicit_alignment: Option<u8>,
|
||||
field_start: u32,
|
||||
ast: ExprRef,
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||
|
|
|
@ -300,8 +300,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
let token @ Token { start: pos, .. } = self.next();
|
||||
let prev_boundary = self.ns_bound;
|
||||
let prev_captured = self.ctx.captured.len();
|
||||
let mut must_trail = false;
|
||||
let mut expr = match token.kind {
|
||||
T::Ct => E::Ct { pos, value: self.ptr_expr()? },
|
||||
T::Slf => E::Slf { pos },
|
||||
T::Directive if self.lexer.slice(token.range()) == "use" => {
|
||||
self.expect_advance(TokenKind::LParen)?;
|
||||
let str = self.expect_advance(TokenKind::DQuote)?;
|
||||
|
@ -374,14 +376,19 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
let tok = s.token;
|
||||
Some(if s.advance_if(T::Comment) {
|
||||
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)?;
|
||||
s.expect_advance(T::Colon)?;
|
||||
CommentOr::Or(StructField {
|
||||
CommentOr::Or(Ok(StructField {
|
||||
pos: name.start,
|
||||
name: s.tok_str(name),
|
||||
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
|
||||
},
|
||||
trailing_comma: core::mem::take(&mut self.trailing_sep),
|
||||
trailing_comma: core::mem::take(&mut self.trailing_sep) || must_trail,
|
||||
},
|
||||
T::Enum => E::Enum {
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -651,11 +658,21 @@ impl<'a, 'b> Parser<'a, 'b> {
|
|||
&mut self,
|
||||
delim: 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>,
|
||||
) -> &'a [T] {
|
||||
let mut trailing_sep = false;
|
||||
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) {
|
||||
Some(val) => val,
|
||||
None => {
|
||||
|
@ -833,6 +850,10 @@ generate_expr! {
|
|||
pos: Pos,
|
||||
value: &'a Self,
|
||||
},
|
||||
/// `'Self'`
|
||||
Slf {
|
||||
pos: Pos,
|
||||
},
|
||||
/// `'"([^"]|\\")"'`
|
||||
String {
|
||||
pos: Pos,
|
||||
|
@ -931,7 +952,7 @@ generate_expr! {
|
|||
/// `'struct' LIST('{', ',', '}', Ident ':' Expr)`
|
||||
Struct {
|
||||
pos: Pos,
|
||||
fields: &'a [CommentOr<'a, StructField<'a>>],
|
||||
fields: &'a [CommentOr<'a, Result<StructField<'a>, &'a[Self]>>],
|
||||
captured: &'a [Ident],
|
||||
trailing_comma: bool,
|
||||
packed: bool,
|
||||
|
@ -1112,6 +1133,18 @@ pub trait Poser {
|
|||
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 {
|
||||
fn posi(&self) -> Pos {
|
||||
*self
|
||||
|
@ -1312,12 +1345,7 @@ impl Ast {
|
|||
}
|
||||
|
||||
pub fn find_decl(&self, id: Result<Ident, &str>) -> Option<(&Expr, Ident)> {
|
||||
self.exprs().iter().find_map(|expr| match expr {
|
||||
Expr::BinOp { left, op: TokenKind::Decl, .. } => {
|
||||
left.declares(id, &self.file).map(|id| (expr, id))
|
||||
}
|
||||
_ => None,
|
||||
})
|
||||
find_decl(self.exprs(), &self.file, id)
|
||||
}
|
||||
|
||||
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 {
|
||||
fn default() -> Self {
|
||||
Self(AstInner::new("".into(), "".into(), &mut Ctx::default(), &mut no_loader))
|
||||
|
|
239
lang/src/son.rs
239
lang/src/son.rs
|
@ -2342,6 +2342,7 @@ impl Scope {
|
|||
#[derive(Default, Clone)]
|
||||
pub struct ItemCtx {
|
||||
file: Module,
|
||||
parent: ty::Id,
|
||||
pos: Vec<Pos>,
|
||||
ret: Option<ty::Id>,
|
||||
task_base: usize,
|
||||
|
@ -2356,7 +2357,7 @@ pub struct 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.scope.vars.len(), 0);
|
||||
debug_assert_eq!(self.scope.aclasses.len(), 0);
|
||||
|
@ -2366,6 +2367,7 @@ impl ItemCtx {
|
|||
debug_assert_eq!(self.inline_aclass_base, 0);
|
||||
|
||||
self.file = file;
|
||||
self.parent = parent;
|
||||
self.ret = ret;
|
||||
self.task_base = task_base;
|
||||
|
||||
|
@ -2433,6 +2435,7 @@ impl Pool {
|
|||
fn push_ci(
|
||||
&mut self,
|
||||
file: Module,
|
||||
parent: ty::Id,
|
||||
ret: Option<ty::Id>,
|
||||
task_base: usize,
|
||||
target: &mut ItemCtx,
|
||||
|
@ -2443,7 +2446,7 @@ impl Pool {
|
|||
self.cis.push(ItemCtx::default());
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2718,10 +2721,11 @@ impl<'a> Codegen<'a> {
|
|||
self.ci.nodes[region].kind != Kind::Load
|
||||
|| self.ci.nodes[region].kind == Kind::Stck
|
||||
|| self.ci.nodes[region].ty.is_pointer(),
|
||||
"{:?} {} {}",
|
||||
"{:?} {} {} {:?}",
|
||||
self.ci.nodes.graphviz_in_browser(self.ty_display(ty::Id::VOID)),
|
||||
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);
|
||||
let (index, _) = self.ci.nodes.aclass_index(region);
|
||||
|
@ -2820,7 +2824,7 @@ impl<'a> Codegen<'a> {
|
|||
ty::Kind::NEVER => Value::NEVER,
|
||||
ty::Kind::Global(global) => self.gen_global(global),
|
||||
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),
|
||||
|
@ -2863,9 +2867,9 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
let expected = *self.ci.ret.get_or_insert(value.ty);
|
||||
self.assert_ty(pos, &mut value, expected, "return value");
|
||||
self.strip_ptr(&mut value);
|
||||
|
||||
if self.ci.inline_depth == 0 {
|
||||
self.strip_ptr(&mut value);
|
||||
debug_assert_ne!(self.ci.ctrl.get(), VOID);
|
||||
let mut inps = Vc::from([self.ci.ctrl.get(), value.id]);
|
||||
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));
|
||||
|
||||
let repl = StrongRef::new(NEVER, &mut self.ci.nodes);
|
||||
let (index, _) = self
|
||||
.ci
|
||||
.nodes
|
||||
.aclass_index(*self.ci.nodes[value.id].inputs.get(1).unwrap_or(&VOID));
|
||||
let (index, _) = self.ci.nodes.aclass_index(value.id);
|
||||
let aclass = (self.ci.inline_aclass_base <= index)
|
||||
.then(|| self.ci.scope.aclasses[index].dup(&mut self.ci.nodes));
|
||||
self.ci.inline_ret =
|
||||
|
@ -2964,7 +2965,7 @@ impl<'a> Codegen<'a> {
|
|||
ty::Kind::NEVER => Value::NEVER,
|
||||
ty::Kind::Global(global) => self.gen_global(global),
|
||||
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) => {
|
||||
|
@ -2972,7 +2973,23 @@ impl<'a> Codegen<'a> {
|
|||
self.gen_enum_variant(pos, e, intrnd)
|
||||
}
|
||||
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
|
||||
.tys
|
||||
.struct_fields(s)
|
||||
|
@ -2984,15 +3001,66 @@ impl<'a> Codegen<'a> {
|
|||
pos,
|
||||
fa!(
|
||||
"the '{}' does not have this field, \
|
||||
but it does have '{field_list}'",
|
||||
but it does have '{field_list}'",
|
||||
self.ty_display(tty)
|
||||
),
|
||||
);
|
||||
return Value::NEVER;
|
||||
};
|
||||
|
||||
Some(Value::ptr(self.offset(vtarget.id, offset)).ty(ty))
|
||||
Value::NEVER
|
||||
}
|
||||
}
|
||||
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(
|
||||
pos,
|
||||
|
@ -3203,11 +3271,13 @@ impl<'a> Codegen<'a> {
|
|||
Some(bop)
|
||||
}
|
||||
ty::Kind::Struct(s) if op.is_homogenous() => {
|
||||
debug_assert!(lhs.ptr);
|
||||
self.ci.nodes.lock(lhs.id);
|
||||
let rhs = self.raw_expr_ctx(right, Ctx::default().with_ty(lhs.ty));
|
||||
self.ci.nodes.unlock(lhs.id);
|
||||
let mut rhs = rhs?;
|
||||
self.strip_var(&mut rhs);
|
||||
debug_assert!(rhs.ptr);
|
||||
self.assert_ty(pos, &mut rhs, lhs.ty, "struct operand");
|
||||
let dst = self.new_stack(pos, lhs.ty);
|
||||
self.struct_op(left.pos(), op, s, dst, lhs.id, rhs.id);
|
||||
|
@ -4082,8 +4152,8 @@ impl<'a> Codegen<'a> {
|
|||
Some(Value::VOID)
|
||||
}
|
||||
ref e => {
|
||||
self.error_unhandled_ast(e, "bruh");
|
||||
Value::NEVER
|
||||
let ty = self.ty(e);
|
||||
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> {
|
||||
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 {
|
||||
self.error(func.pos(), fa!("compiler cant (yet) call '{}'", self.ty_display(ty)));
|
||||
return Value::NEVER;
|
||||
|
@ -4333,7 +4408,8 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
fn gen_const(&mut self, cnst: ty::Const, ctx: Ctx) -> Option<Value> {
|
||||
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 Expr::BinOp { left, right, .. } = c.ast.get(f) else { unreachable!() };
|
||||
|
||||
|
@ -4344,7 +4420,8 @@ impl<'a> Codegen<'a> {
|
|||
})
|
||||
.unwrap_or_else(|_| unreachable!())?;
|
||||
self.strip_var(&mut value);
|
||||
self.ci.file = prev;
|
||||
self.ci.file = prev_file;
|
||||
self.ci.parent = prev_parent;
|
||||
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> {
|
||||
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 &Expr::Closure { args: cargs, ret, .. } = expr.get(fast) else {
|
||||
unreachable!();
|
||||
|
@ -4488,7 +4565,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
let base = self.ci.scope.vars.len();
|
||||
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);
|
||||
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");
|
||||
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));
|
||||
|
||||
|
@ -4695,7 +4772,7 @@ impl<'a> Codegen<'a> {
|
|||
let ast = &self.files[file.index()];
|
||||
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();
|
||||
|
||||
log::info!("{}", self.ast_display(expr));
|
||||
|
@ -4852,11 +4929,11 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
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 {
|
||||
self.parse_ty(file, expr, None)
|
||||
fn ty_in(&mut self, file: Module, parent: ty::Id, expr: &Expr) -> ty::Id {
|
||||
self.parse_ty(TyScope { file, parent, name: None }, expr)
|
||||
}
|
||||
|
||||
fn ty_display(&self, ty: ty::Id) -> ty::Display {
|
||||
|
@ -5117,7 +5194,7 @@ impl<'a> Codegen<'a> {
|
|||
_ => unreachable!(),
|
||||
})
|
||||
.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
|
||||
.into_iter()
|
||||
.map(|(v, id)| {
|
||||
|
@ -5170,7 +5247,7 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
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();
|
||||
|
||||
self.expr(&(Expr::Return { pos: expr.pos(), val: Some(expr) }));
|
||||
|
@ -5216,6 +5293,17 @@ impl<'a> Codegen<'a> {
|
|||
from_file: Module,
|
||||
file: Module,
|
||||
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 {
|
||||
let ty = if let Ok(id) = id
|
||||
&& let Some(ty) = self.find_local_ty(id)
|
||||
|
@ -5229,7 +5317,9 @@ impl<'a> Codegen<'a> {
|
|||
} else {
|
||||
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 {
|
||||
Ok(_) => {
|
||||
debug_assert_eq!(from_file, file);
|
||||
|
@ -5264,10 +5354,22 @@ impl<'a> Codegen<'a> {
|
|||
self.tys
|
||||
.ins
|
||||
.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()
|
||||
} 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
|
||||
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 {
|
||||
Expr::Slf { .. } => sc.parent,
|
||||
Expr::Mod { id, .. } => id.into(),
|
||||
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)
|
||||
}
|
||||
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)
|
||||
}
|
||||
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 }
|
||||
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::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)
|
||||
}
|
||||
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 _)
|
||||
}
|
||||
Expr::Slice { size, item, .. } => {
|
||||
let ty = self.parse_ty(file, item, None);
|
||||
let ty = self.parse_ty(sc.anon(), item);
|
||||
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)
|
||||
}
|
||||
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 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) {
|
||||
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);
|
||||
for field in fields.iter().filter_map(CommentOr::or).filter_map(Result::ok) {
|
||||
let ty = self.parse_ty(sc.anon(), &field.ty);
|
||||
let field = StructField { name: self.tys.names.intern(field.name), ty };
|
||||
self.tys.tmp.struct_fields.push(field);
|
||||
}
|
||||
|
@ -5367,11 +5470,12 @@ impl<'a> Codegen<'a> {
|
|||
.ins
|
||||
.structs
|
||||
.push(Struct {
|
||||
file,
|
||||
file: sc.file,
|
||||
pos,
|
||||
name: name.unwrap_or_default(),
|
||||
name: sc.name.unwrap_or_default(),
|
||||
field_start: self.tys.ins.struct_fields.len() as _,
|
||||
explicit_alignment: packed.then_some(1),
|
||||
ast: ExprRef::new(expr),
|
||||
..Default::default()
|
||||
})
|
||||
.into();
|
||||
|
@ -5382,7 +5486,7 @@ impl<'a> Codegen<'a> {
|
|||
ty
|
||||
}
|
||||
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) {
|
||||
return ty;
|
||||
}
|
||||
|
@ -5398,9 +5502,9 @@ impl<'a> Codegen<'a> {
|
|||
.ins
|
||||
.enums
|
||||
.push(Enum {
|
||||
file,
|
||||
file: sc.file,
|
||||
pos,
|
||||
name: name.unwrap_or_default(),
|
||||
name: sc.name.unwrap_or_default(),
|
||||
field_start: self.tys.ins.enum_fields.len() as _,
|
||||
})
|
||||
.into();
|
||||
|
@ -5410,27 +5514,28 @@ impl<'a> Codegen<'a> {
|
|||
self.tys.syms.insert(sym, ty, &self.tys.ins);
|
||||
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 {
|
||||
file,
|
||||
file: sc.file,
|
||||
parent: sc.parent,
|
||||
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);
|
||||
parser::find_symbol(&self.files[sc.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);
|
||||
let ty = self.parse_ty(sc.anon(), &arg.ty);
|
||||
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");
|
||||
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 })
|
||||
},
|
||||
|
@ -5441,12 +5546,25 @@ impl<'a> Codegen<'a> {
|
|||
|
||||
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)),
|
||||
_ if let Some(name) = sc.name => self.eval_global(sc.file, name, expr),
|
||||
_ => 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)]
|
||||
mod tests {
|
||||
use {
|
||||
|
@ -5503,6 +5621,7 @@ mod tests {
|
|||
loops;
|
||||
pointers;
|
||||
structs;
|
||||
struct_scopes;
|
||||
enums;
|
||||
nullable_types;
|
||||
struct_operators;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
main:
|
||||
ADDI64 r254, r254, -136d
|
||||
ST r31, r254, 80a, 56h
|
||||
ADDI64 r254, r254, -104d
|
||||
ST r31, r254, 48a, 56h
|
||||
LRA r32, r0, :glob_stru
|
||||
JAL r31, r0, :new_stru
|
||||
ST r1, r32, 0a, 16h
|
||||
|
@ -19,33 +19,29 @@ main:
|
|||
2: LI64 r34, 1d
|
||||
ST r34, r32, 0a, 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, 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
|
||||
CP r32, r33
|
||||
8: JNE r32, r36, :3
|
||||
LD r32, r254, 64a, 8h
|
||||
LD r32, r254, 32a, 8h
|
||||
JEQ r32, r33, :4
|
||||
LI64 r32, 100d
|
||||
CP r1, r32
|
||||
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, 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
|
||||
7: LD r37, r254, 64a, 8h
|
||||
7: LD r37, r254, 32a, 8h
|
||||
JNE r32, r36, :5
|
||||
JEQ r37, r33, :6
|
||||
LI64 r32, 10d
|
||||
|
@ -65,8 +61,8 @@ main:
|
|||
ST r1, r37, 0a, 16h
|
||||
ADD64 r32, r32, r34
|
||||
JMP :8
|
||||
1: LD r31, r254, 80a, 56h
|
||||
ADDI64 r254, r254, 136d
|
||||
1: LD r31, r254, 48a, 56h
|
||||
ADDI64 r254, r254, 104d
|
||||
JALA r0, r31, 0a
|
||||
new_stru:
|
||||
ADDI64 r254, r254, -16d
|
||||
|
@ -76,6 +72,6 @@ new_stru:
|
|||
LD r1, r13, 0a, 16h
|
||||
ADDI64 r254, r254, 16d
|
||||
JALA r0, r31, 0a
|
||||
code size: 736
|
||||
code size: 684
|
||||
ret: 0
|
||||
status: Ok(())
|
||||
|
|
0
lang/tests/son_tests_struct_scopes.txt
Normal file
0
lang/tests/son_tests_struct_scopes.txt
Normal file
Loading…
Reference in a new issue