implementing struct method for non generic contexts
This commit is contained in:
parent
58ee5c0a56
commit
24a3aed360
321
lang/src/son.rs
321
lang/src/son.rs
|
@ -27,6 +27,7 @@ use {
|
|||
},
|
||||
hashbrown::hash_map,
|
||||
hbbytecode::DisasmError,
|
||||
std::intrinsics::vtable_size,
|
||||
};
|
||||
|
||||
const VOID: Nid = 0;
|
||||
|
@ -2954,125 +2955,10 @@ impl<'a> Codegen<'a> {
|
|||
None
|
||||
}
|
||||
Expr::Field { target, name, pos } => {
|
||||
let mut vtarget = self.raw_expr(target)?;
|
||||
self.strip_var(&mut vtarget);
|
||||
self.implicit_unwrap(pos, &mut vtarget);
|
||||
let tty = vtarget.ty;
|
||||
|
||||
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)).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::Enum(e) => {
|
||||
let intrnd = self.tys.names.project(name);
|
||||
self.gen_enum_variant(pos, e, intrnd)
|
||||
}
|
||||
ty::Kind::Struct(s) => {
|
||||
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)
|
||||
.iter()
|
||||
.map(|f| self.tys.names.ident_str(f.name))
|
||||
.intersperse("', '")
|
||||
.collect::<String>();
|
||||
self.error(
|
||||
pos,
|
||||
fa!(
|
||||
"the '{}' does not have this field, \
|
||||
but it does have '{field_list}'",
|
||||
self.ty_display(tty)
|
||||
),
|
||||
);
|
||||
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,
|
||||
fa!(
|
||||
"the '{}' is not a struct, or pointer to one, or enum, \
|
||||
fo field access does not make sense",
|
||||
self.ty_display(tty)
|
||||
),
|
||||
);
|
||||
Value::NEVER
|
||||
}
|
||||
}
|
||||
self.gen_field(ctx, target, pos, name)?.ok().or_else(|| {
|
||||
self.error(pos, "method can not be used like this");
|
||||
Value::NEVER
|
||||
})
|
||||
}
|
||||
Expr::UnOp { op: TokenKind::Band, val, pos } => {
|
||||
let ctx = Ctx { ty: ctx.ty.and_then(|ty| self.tys.base_of(ty)) };
|
||||
|
@ -4158,6 +4044,126 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
fn gen_field(
|
||||
&mut self,
|
||||
ctx: Ctx,
|
||||
target: &Expr,
|
||||
pos: Pos,
|
||||
name: &str,
|
||||
) -> Option<Result<Value, (ty::Id, Value)>> {
|
||||
let mut vtarget = self.raw_expr(target)?;
|
||||
self.strip_var(&mut vtarget);
|
||||
self.implicit_unwrap(pos, &mut vtarget);
|
||||
let tty = vtarget.ty;
|
||||
|
||||
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)).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::Enum(e) => {
|
||||
let intrnd = self.tys.names.project(name);
|
||||
self.gen_enum_variant(pos, e, intrnd)
|
||||
}
|
||||
ty::Kind::Struct(s) => {
|
||||
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),
|
||||
)
|
||||
&& let ty::Kind::Func(_) = ty.expand()
|
||||
{
|
||||
return Some(Err((ty, vtarget)));
|
||||
} else {
|
||||
let field_list = self
|
||||
.tys
|
||||
.struct_fields(s)
|
||||
.iter()
|
||||
.map(|f| self.tys.names.ident_str(f.name))
|
||||
.intersperse("', '")
|
||||
.collect::<String>();
|
||||
self.error(
|
||||
pos,
|
||||
fa!(
|
||||
"the '{}' does not have this field, \
|
||||
but it does have '{field_list}'",
|
||||
self.ty_display(tty)
|
||||
),
|
||||
);
|
||||
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.map(Ok);
|
||||
};
|
||||
|
||||
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,
|
||||
fa!(
|
||||
"the '{}' is not a struct, or pointer to one, or enum, \
|
||||
fo field access does not make sense",
|
||||
self.ty_display(tty)
|
||||
),
|
||||
);
|
||||
Value::NEVER
|
||||
}
|
||||
}
|
||||
.map(Ok)
|
||||
}
|
||||
|
||||
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);
|
||||
|
@ -4231,12 +4237,25 @@ impl<'a> Codegen<'a> {
|
|||
}
|
||||
|
||||
fn gen_call(&mut self, func: &Expr, args: &[Expr], inline: bool) -> Option<Value> {
|
||||
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, mut caller) = match *func {
|
||||
Expr::Field { target, pos, name } => {
|
||||
match self.gen_field(Ctx::default(), target, pos, name)? {
|
||||
Ok(mut fexpr) => {
|
||||
self.assert_ty(func.pos(), &mut fexpr, ty::Id::TYPE, "function");
|
||||
(
|
||||
ty::Id::from(match self.ci.nodes[fexpr.id].kind {
|
||||
Kind::CInt { value } => value as u64,
|
||||
_ => unreachable!(),
|
||||
}),
|
||||
None,
|
||||
)
|
||||
}
|
||||
Err((ty, val)) => (ty, Some(val)),
|
||||
}
|
||||
}
|
||||
ref e => (self.ty(e), None),
|
||||
};
|
||||
|
||||
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;
|
||||
|
@ -4250,14 +4269,15 @@ impl<'a> Codegen<'a> {
|
|||
let ast = &self.files[file.index()];
|
||||
let &Expr::Closure { args: cargs, body, .. } = expr.get(ast) else { unreachable!() };
|
||||
|
||||
if args.len() != cargs.len() {
|
||||
let arg_count = args.len() + caller.is_some() as usize;
|
||||
if arg_count != cargs.len() {
|
||||
self.error(
|
||||
func.pos(),
|
||||
fa!(
|
||||
"expected {} function argumenr{}, got {}",
|
||||
cargs.len(),
|
||||
if cargs.len() == 1 { "" } else { "s" },
|
||||
args.len()
|
||||
arg_count
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -4273,6 +4293,32 @@ impl<'a> Codegen<'a> {
|
|||
if is_inline || inline {
|
||||
let var_base = self.ci.scope.vars.len();
|
||||
let aclass_base = self.ci.scope.aclasses.len();
|
||||
|
||||
if let Some(caller) = &mut caller
|
||||
&& let (Some(Arg::Value(ty)), Some(carg)) = (tys.next(self.tys), cargs.next())
|
||||
{
|
||||
match (caller.ty.is_pointer(), ty.is_pointer()) {
|
||||
(true, false) => {
|
||||
caller.ty = self.tys.base_of(caller.ty).unwrap();
|
||||
caller.ptr = true;
|
||||
}
|
||||
(false, true) => {
|
||||
caller.ty = self.tys.make_ptr(caller.ty);
|
||||
caller.ptr = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
self.assert_ty(func.pos(), caller, ty, "caller");
|
||||
self.ci.scope.vars.push(Variable::new(
|
||||
carg.id,
|
||||
ty,
|
||||
caller.ptr,
|
||||
caller.id,
|
||||
&mut self.ci.nodes,
|
||||
))
|
||||
}
|
||||
|
||||
while let (Some(aty), Some(arg)) = (tys.next(self.tys), args.next()) {
|
||||
let carg = cargs.next().unwrap();
|
||||
let var = match aty {
|
||||
|
@ -4356,6 +4402,27 @@ impl<'a> Codegen<'a> {
|
|||
self.make_func_reachable(fu);
|
||||
let mut inps = Vc::from([NEVER]);
|
||||
let mut clobbered_aliases = BitSet::default();
|
||||
|
||||
if let Some(caller) = &mut caller
|
||||
&& let (Some(Arg::Value(ty)), Some(carg)) = (tys.next(self.tys), cargs.next())
|
||||
{
|
||||
match (caller.ty.is_pointer(), ty.is_pointer()) {
|
||||
(true, false) => {
|
||||
caller.ty = self.tys.base_of(caller.ty).unwrap();
|
||||
caller.ptr = true;
|
||||
}
|
||||
(false, true) => {
|
||||
caller.ty = self.tys.make_ptr(caller.ty);
|
||||
caller.ptr = false;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
self.assert_ty(func.pos(), caller, ty, fa!("caller argument {}", carg.name));
|
||||
self.add_clobbers(*caller, &mut clobbered_aliases);
|
||||
self.ci.nodes.lock(caller.id);
|
||||
inps.push(caller.id);
|
||||
}
|
||||
|
||||
while let (Some(ty), Some(arg)) = (tys.next(self.tys), args.next()) {
|
||||
let carg = cargs.next().unwrap();
|
||||
let Arg::Value(ty) = ty else { continue };
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
main:
|
||||
LI64 r13, 1d
|
||||
CP r1, r13
|
||||
JALA r0, r31, 0a
|
||||
code size: 32
|
||||
ret: 1
|
||||
status: Ok(())
|
Loading…
Reference in a new issue