forked from AbleOS/holey-bytes
saving
This commit is contained in:
parent
acacd10ee9
commit
9ed3c7ab9e
|
@ -161,6 +161,27 @@ drop := fn(a: uint): void {
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
#### nullable_types
|
||||||
|
```hb
|
||||||
|
main := fn(): int {
|
||||||
|
a := &1
|
||||||
|
|
||||||
|
b := @as(?^uint, null)
|
||||||
|
if decide() b = a
|
||||||
|
|
||||||
|
if b == null return 9001
|
||||||
|
|
||||||
|
c := @as(?uint, *b)
|
||||||
|
if decide() c = null
|
||||||
|
|
||||||
|
if c != null return 42
|
||||||
|
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
decide := fn(): bool return true
|
||||||
|
```
|
||||||
|
|
||||||
#### structs
|
#### structs
|
||||||
```hb
|
```hb
|
||||||
Ty := struct {
|
Ty := struct {
|
||||||
|
@ -1196,3 +1217,4 @@ main := fn(): int {
|
||||||
opaque := fn(): Foo {
|
opaque := fn(): Foo {
|
||||||
return .(3, 2)
|
return .(3, 2)
|
||||||
}
|
}
|
||||||
|
```
|
||||||
|
|
131
lang/src/lib.rs
131
lang/src/lib.rs
|
@ -290,6 +290,7 @@ mod ty {
|
||||||
|
|
||||||
pub type Builtin = u32;
|
pub type Builtin = u32;
|
||||||
pub type Struct = u32;
|
pub type Struct = u32;
|
||||||
|
pub type Opt = u32;
|
||||||
pub type Ptr = u32;
|
pub type Ptr = u32;
|
||||||
pub type Func = u32;
|
pub type Func = u32;
|
||||||
pub type Global = u32;
|
pub type Global = u32;
|
||||||
|
@ -373,6 +374,7 @@ mod ty {
|
||||||
crate::SymKey::Struct(st.file, st.pos, st.captures)
|
crate::SymKey::Struct(st.file, st.pos, st.captures)
|
||||||
}
|
}
|
||||||
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]),
|
Kind::Ptr(p) => crate::SymKey::Pointer(&ctx.ptrs[p as usize]),
|
||||||
|
Kind::Opt(p) => crate::SymKey::Optional(&ctx.opts[p as usize]),
|
||||||
Kind::Func(f) => {
|
Kind::Func(f) => {
|
||||||
let fc = &ctx.funcs[f as usize];
|
let fc = &ctx.funcs[f as usize];
|
||||||
if let Some(base) = fc.base {
|
if let Some(base) = fc.base {
|
||||||
|
@ -441,6 +443,10 @@ mod ty {
|
||||||
matches!(self.expand(), Kind::Ptr(_)) || self.is_never()
|
matches!(self.expand(), Kind::Ptr(_)) || self.is_never()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn is_optional(self) -> bool {
|
||||||
|
matches!(self.expand(), Kind::Opt(_)) || self.is_never()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn try_upcast(self, ob: Self) -> Option<Self> {
|
pub fn try_upcast(self, ob: Self) -> Option<Self> {
|
||||||
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
|
let (oa, ob) = (Self(self.0.min(ob.0)), Self(self.0.max(ob.0)));
|
||||||
let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
|
let (a, b) = (oa.strip_pointer(), ob.strip_pointer());
|
||||||
|
@ -490,9 +496,16 @@ mod ty {
|
||||||
|
|
||||||
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
pub(crate) fn loc(&self, tys: &Types) -> Loc {
|
||||||
match self.expand() {
|
match self.expand() {
|
||||||
|
Kind::Opt(o)
|
||||||
|
if let ty = tys.ins.opts[o as usize].base
|
||||||
|
&& ty.loc(tys) == Loc::Reg
|
||||||
|
&& (ty.is_pointer() || tys.size_of(ty) < 8) =>
|
||||||
|
{
|
||||||
|
Loc::Reg
|
||||||
|
}
|
||||||
Kind::Ptr(_) | Kind::Builtin(_) => Loc::Reg,
|
Kind::Ptr(_) | 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(_) => Loc::Stack,
|
Kind::Struct(_) | Kind::Slice(_) | Kind::Opt(_) => Loc::Stack,
|
||||||
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(),
|
Kind::Func(_) | Kind::Global(_) | Kind::Module(_) => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -633,6 +646,7 @@ mod ty {
|
||||||
pub enum Kind {
|
pub enum Kind {
|
||||||
Builtin,
|
Builtin,
|
||||||
Struct,
|
Struct,
|
||||||
|
Opt,
|
||||||
Ptr,
|
Ptr,
|
||||||
Func,
|
Func,
|
||||||
Global,
|
Global,
|
||||||
|
@ -675,6 +689,10 @@ mod ty {
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
TK::Builtin(ty) => f.write_str(to_str(ty)),
|
||||||
|
TK::Opt(ty) => {
|
||||||
|
f.write_str("?")?;
|
||||||
|
self.rety(self.tys.ins.opts[ty as usize].base).fmt(f)
|
||||||
|
}
|
||||||
TK::Ptr(ty) => {
|
TK::Ptr(ty) => {
|
||||||
f.write_str("^")?;
|
f.write_str("^")?;
|
||||||
self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f)
|
self.rety(self.tys.ins.ptrs[ty as usize].base).fmt(f)
|
||||||
|
@ -730,6 +748,7 @@ type Size = u32;
|
||||||
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub enum SymKey<'a> {
|
pub enum SymKey<'a> {
|
||||||
Pointer(&'a Ptr),
|
Pointer(&'a Ptr),
|
||||||
|
Optional(&'a Opt),
|
||||||
Struct(FileId, Pos, ty::Tuple),
|
Struct(FileId, Pos, ty::Tuple),
|
||||||
FuncInst(ty::Func, ty::Tuple),
|
FuncInst(ty::Func, ty::Tuple),
|
||||||
Decl(FileId, Ident),
|
Decl(FileId, Ident),
|
||||||
|
@ -840,7 +859,12 @@ struct Struct {
|
||||||
field_start: u32,
|
field_start: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq, Hash)]
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
pub struct Opt {
|
||||||
|
base: ty::Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
pub struct Ptr {
|
pub struct Ptr {
|
||||||
base: ty::Id,
|
base: ty::Id,
|
||||||
}
|
}
|
||||||
|
@ -935,6 +959,7 @@ pub struct TypeIns {
|
||||||
structs: Vec<Struct>,
|
structs: Vec<Struct>,
|
||||||
fields: Vec<Field>,
|
fields: Vec<Field>,
|
||||||
ptrs: Vec<Ptr>,
|
ptrs: Vec<Ptr>,
|
||||||
|
opts: Vec<Opt>,
|
||||||
slices: Vec<Array>,
|
slices: Vec<Array>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1065,6 +1090,10 @@ trait TypeParser {
|
||||||
let base = self.parse_ty(file, val, None, files);
|
let base = self.parse_ty(file, val, None, files);
|
||||||
self.tys().make_ptr(base)
|
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 id.is_null() => id.len().into(),
|
Expr::Ident { id, .. } if id.is_null() => id.len().into(),
|
||||||
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
|
Expr::Ident { id, pos, .. } => self.find_type(pos, file, file, Ok(id), files),
|
||||||
Expr::Field { target, pos, name }
|
Expr::Field { target, pos, name }
|
||||||
|
@ -1206,64 +1235,44 @@ impl Types {
|
||||||
(ret, iter)
|
(ret, iter)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
|
fn make_opt(&mut self, base: ty::Id) -> ty::Id {
|
||||||
ty::Kind::Ptr(self.make_ptr_low(base)).compress()
|
self.make_generic_ty(
|
||||||
}
|
Opt { base },
|
||||||
|
|ins| &mut ins.opts,
|
||||||
fn make_ptr_low(&mut self, base: ty::Id) -> ty::Ptr {
|
|e| SymKey::Optional(e),
|
||||||
let ptr = Ptr { base };
|
ty::Kind::Opt,
|
||||||
let (entry, hash) = self.syms.entry(SymKey::Pointer(&ptr), &self.ins);
|
|
||||||
match entry {
|
|
||||||
hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|
|
||||||
hash_map::RawEntryMut::Vacant(v) => {
|
|
||||||
self.ins.ptrs.push(ptr);
|
|
||||||
v.insert(
|
|
||||||
ctx_map::Key {
|
|
||||||
value: ty::Kind::Ptr(self.ins.ptrs.len() as u32 - 1).compress(),
|
|
||||||
hash,
|
|
||||||
},
|
|
||||||
(),
|
|
||||||
)
|
)
|
||||||
.0
|
|
||||||
.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.expand()
|
|
||||||
.inner()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_array(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Id {
|
fn make_ptr(&mut self, base: ty::Id) -> ty::Id {
|
||||||
ty::Kind::Slice(self.make_array_low(ty, len)).compress()
|
self.make_generic_ty(
|
||||||
|
Ptr { base },
|
||||||
|
|ins| &mut ins.ptrs,
|
||||||
|
|e| SymKey::Pointer(e),
|
||||||
|
ty::Kind::Ptr,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_array_low(&mut self, ty: ty::Id, len: ArrayLen) -> ty::Slice {
|
fn make_array(&mut self, elem: ty::Id, len: ArrayLen) -> ty::Id {
|
||||||
self.syms
|
self.make_generic_ty(
|
||||||
.get_or_insert(SymKey::Array(&Array { elem: ty, len }), &mut self.ins, |ins| {
|
Array { elem, len },
|
||||||
ins.slices.push(Array { elem: ty, len });
|
|ins| &mut ins.slices,
|
||||||
ty::Kind::Slice(ins.slices.len() as u32 - 1).compress()
|
|e| SymKey::Array(e),
|
||||||
|
ty::Kind::Slice,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn make_generic_ty<T: Copy>(
|
||||||
|
&mut self,
|
||||||
|
ty: T,
|
||||||
|
get_col: fn(&mut TypeIns) -> &mut Vec<T>,
|
||||||
|
key: fn(&T) -> SymKey,
|
||||||
|
kind: fn(u32) -> ty::Kind,
|
||||||
|
) -> ty::Id {
|
||||||
|
*self.syms.get_or_insert(key(&{ ty }), &mut self.ins, |ins| {
|
||||||
|
get_col(ins).push(ty);
|
||||||
|
kind(get_col(ins).len() as u32 - 1).compress()
|
||||||
})
|
})
|
||||||
.expand()
|
|
||||||
.inner()
|
|
||||||
|
|
||||||
//let array = Array { ty, len };
|
|
||||||
//let (entry, hash) = self.syms.entry(SymKey::Array(&array), &self.ins);
|
|
||||||
//match entry {
|
|
||||||
// hash_map::RawEntryMut::Occupied(o) => o.get_key_value().0.value,
|
|
||||||
// hash_map::RawEntryMut::Vacant(v) => {
|
|
||||||
// self.ins.arrays.push(array);
|
|
||||||
// v.insert(
|
|
||||||
// ctx_map::Key {
|
|
||||||
// value: ty::Kind::Slice(self.ins.ptrs.len() as u32 - 1).compress(),
|
|
||||||
// hash,
|
|
||||||
// },
|
|
||||||
// (),
|
|
||||||
// )
|
|
||||||
// .0
|
|
||||||
// .value
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
//.expand()
|
|
||||||
//.inner()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn size_of(&self, ty: ty::Id) -> Size {
|
fn size_of(&self, ty: ty::Id) -> Size {
|
||||||
|
@ -1328,6 +1337,20 @@ impl Types {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn inner_of(&self, ty: ty::Id) -> Option<ty::Id> {
|
||||||
|
match ty.expand() {
|
||||||
|
ty::Kind::Opt(o) => Some(self.ins.opts[o as usize].base),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn opt_flag_field(&self, ty: ty::Id) -> (Offset, ty::Id) {
|
||||||
|
match ty.expand() {
|
||||||
|
ty::Kind::Ptr(_) => (0, ty::Id::UINT),
|
||||||
|
_ => todo!("{ty:?}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> {
|
fn find_struct_field(&self, s: ty::Struct, name: &str) -> Option<usize> {
|
||||||
let name = self.names.project(name)?;
|
let name = self.names.project(name)?;
|
||||||
self.struct_fields(s).iter().position(|f| f.name == name)
|
self.struct_fields(s).iter().position(|f| f.name == name)
|
||||||
|
|
|
@ -443,7 +443,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
pos
|
pos
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
T::Band | T::Mul | T::Xor | T::Sub => E::UnOp {
|
T::Band | T::Mul | T::Xor | T::Sub | T::Que => E::UnOp {
|
||||||
pos,
|
pos,
|
||||||
op: token.kind,
|
op: token.kind,
|
||||||
val: {
|
val: {
|
||||||
|
|
107
lang/src/son.rs
107
lang/src/son.rs
|
@ -654,6 +654,14 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn new_const(&mut self, ty: ty::Id, value: impl Into<i64>) -> Nid {
|
||||||
|
self.new_node_nop(ty, Kind::CInt { value: value.into() }, [VOID])
|
||||||
|
}
|
||||||
|
|
||||||
|
fn new_const_lit(&mut self, ty: ty::Id, value: impl Into<i64>) -> Value {
|
||||||
|
self.new_node_lit(ty, Kind::CInt { value: value.into() }, [VOID])
|
||||||
|
}
|
||||||
|
|
||||||
fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Value {
|
fn new_node_lit(&mut self, ty: ty::Id, kind: Kind, inps: impl Into<Vc>) -> Value {
|
||||||
Value::new(self.new_node(ty, kind, inps)).ty(ty)
|
Value::new(self.new_node(ty, kind, inps)).ty(ty)
|
||||||
}
|
}
|
||||||
|
@ -772,18 +780,14 @@ impl Nodes {
|
||||||
if let (&K::CInt { value: a }, &K::CInt { value: b }) =
|
if let (&K::CInt { value: a }, &K::CInt { value: b }) =
|
||||||
(&self[lhs].kind, &self[rhs].kind)
|
(&self[lhs].kind, &self[rhs].kind)
|
||||||
{
|
{
|
||||||
return Some(self.new_node(
|
return Some(self.new_const(ty, op.apply_binop(a, b, is_float)));
|
||||||
ty,
|
|
||||||
K::CInt { value: op.apply_binop(a, b, is_float) },
|
|
||||||
[ctrl],
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if lhs == rhs {
|
if lhs == rhs {
|
||||||
match op {
|
match op {
|
||||||
T::Sub => return Some(self.new_node(ty, K::CInt { value: 0 }, [ctrl])),
|
T::Sub => return Some(self.new_const(ty, 0)),
|
||||||
T::Add => {
|
T::Add => {
|
||||||
let rhs = self.new_node_nop(ty, K::CInt { value: 2 }, [ctrl]);
|
let rhs = self.new_const(ty, 2);
|
||||||
return Some(
|
return Some(
|
||||||
self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]),
|
self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, lhs, rhs]),
|
||||||
);
|
);
|
||||||
|
@ -813,11 +817,7 @@ impl Nodes {
|
||||||
&& let K::CInt { value: bv } = self[rhs].kind
|
&& let K::CInt { value: bv } = self[rhs].kind
|
||||||
{
|
{
|
||||||
// (a op #b) op #c => a op (#b op #c)
|
// (a op #b) op #c => a op (#b op #c)
|
||||||
let new_rhs = self.new_node_nop(
|
let new_rhs = self.new_const(ty, op.apply_binop(av, bv, is_float));
|
||||||
ty,
|
|
||||||
K::CInt { value: op.apply_binop(av, bv, is_float) },
|
|
||||||
[ctrl],
|
|
||||||
);
|
|
||||||
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
return Some(self.new_node(ty, K::BinOp { op }, [ctrl, a, new_rhs]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -834,7 +834,7 @@ impl Nodes {
|
||||||
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
|
&& let K::CInt { value } = self[self[lhs].inputs[2]].kind
|
||||||
{
|
{
|
||||||
// a * #n + a => a * (#n + 1)
|
// a * #n + a => a * (#n + 1)
|
||||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: value + 1 }, [ctrl]);
|
let new_rhs = self.new_const(ty, value + 1);
|
||||||
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
|
return Some(self.new_node(ty, K::BinOp { op: T::Mul }, [ctrl, rhs, new_rhs]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -843,7 +843,7 @@ impl Nodes {
|
||||||
&& let K::CInt { value: a } = self[rhs].kind
|
&& let K::CInt { value: a } = self[rhs].kind
|
||||||
&& let K::CInt { value: b } = self[self[lhs].inputs[2]].kind
|
&& let K::CInt { value: b } = self[self[lhs].inputs[2]].kind
|
||||||
{
|
{
|
||||||
let new_rhs = self.new_node_nop(ty, K::CInt { value: b - a }, [ctrl]);
|
let new_rhs = self.new_const(ty, b - a);
|
||||||
return Some(self.new_node(ty, K::BinOp { op: T::Add }, [
|
return Some(self.new_node(ty, K::BinOp { op: T::Add }, [
|
||||||
ctrl,
|
ctrl,
|
||||||
self[lhs].inputs[1],
|
self[lhs].inputs[1],
|
||||||
|
@ -864,17 +864,13 @@ impl Nodes {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
K::UnOp { op } => {
|
K::UnOp { op } => {
|
||||||
let &[ctrl, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
let &[_, oper] = self[target].inputs.as_slice() else { unreachable!() };
|
||||||
let ty = self[target].ty;
|
let ty = self[target].ty;
|
||||||
|
|
||||||
let is_float = self[oper].ty.is_float();
|
let is_float = self[oper].ty.is_float();
|
||||||
|
|
||||||
if let K::CInt { value } = self[oper].kind {
|
if let K::CInt { value } = self[oper].kind {
|
||||||
return Some(self.new_node(
|
return Some(self.new_const(ty, op.apply_unop(value, is_float)));
|
||||||
ty,
|
|
||||||
K::CInt { value: op.apply_unop(value, is_float) },
|
|
||||||
[ctrl],
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
K::If => {
|
K::If => {
|
||||||
|
@ -2307,21 +2303,31 @@ impl<'a> Codegen<'a> {
|
||||||
// ordered by complexity of the expression
|
// ordered by complexity of the expression
|
||||||
match *expr {
|
match *expr {
|
||||||
Expr::Null { pos } => {
|
Expr::Null { pos } => {
|
||||||
inference!(ty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
|
inference!(oty, ctx, self, pos, "null pointer", "@as(^<ty>, null)");
|
||||||
|
|
||||||
if !ty.is_pointer() {
|
let Some(ty) = self.tys.inner_of(oty) else {
|
||||||
self.report(
|
self.report(
|
||||||
pos,
|
pos,
|
||||||
fa!(
|
fa!(
|
||||||
"'null' expression was inferred to be '{}',
|
"'null' expression was inferred to be '{}',
|
||||||
which is not a pointer (and that is not supported yet)",
|
which is not optional",
|
||||||
self.ty_display(ty)
|
self.ty_display(oty)
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return Value::NEVER;
|
return Value::NEVER;
|
||||||
}
|
};
|
||||||
|
|
||||||
Some(self.ci.nodes.new_node_lit(ty, Kind::CInt { value: 0 }, [VOID]))
|
match oty.loc(self.tys) {
|
||||||
|
Loc::Reg => Some(self.ci.nodes.new_const_lit(oty, 0)),
|
||||||
|
Loc::Stack => {
|
||||||
|
let (off, flag_ty) = self.tys.opt_flag_field(ty);
|
||||||
|
let stack = self.new_stack(oty);
|
||||||
|
let offset = self.offset(stack, off);
|
||||||
|
let value = self.ci.nodes.new_const(flag_ty, 0);
|
||||||
|
self.store_mem(offset, flag_ty, value);
|
||||||
|
Some(Value::ptr(stack).ty(oty))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Expr::Idk { pos } => {
|
Expr::Idk { pos } => {
|
||||||
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
|
inference!(ty, ctx, self, pos, "value", "@as(<ty>, idk)");
|
||||||
|
@ -2340,20 +2346,14 @@ impl<'a> Codegen<'a> {
|
||||||
Value::NEVER
|
Value::NEVER
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Bool { value, .. } => Some(self.ci.nodes.new_node_lit(
|
Expr::Bool { value, .. } => Some(self.ci.nodes.new_const_lit(ty::Id::BOOL, value)),
|
||||||
ty::Id::BOOL,
|
Expr::Number { value, .. } => Some(self.ci.nodes.new_const_lit(
|
||||||
Kind::CInt { value: value as i64 },
|
|
||||||
[VOID],
|
|
||||||
)),
|
|
||||||
Expr::Number { value, .. } => Some(self.ci.nodes.new_node_lit(
|
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
||||||
Kind::CInt { value },
|
value,
|
||||||
[VOID],
|
|
||||||
)),
|
)),
|
||||||
Expr::Float { value, .. } => Some(self.ci.nodes.new_node_lit(
|
Expr::Float { value, .. } => Some(self.ci.nodes.new_const_lit(
|
||||||
ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32),
|
ctx.ty.filter(|ty| ty.is_float()).unwrap_or(ty::Id::F32),
|
||||||
Kind::CInt { value: value as _ },
|
value as i64,
|
||||||
[VOID],
|
|
||||||
)),
|
)),
|
||||||
Expr::Ident { id, .. }
|
Expr::Ident { id, .. }
|
||||||
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
if let Some(index) = self.ci.scope.vars.iter().rposition(|v| v.id == id) =>
|
||||||
|
@ -2551,11 +2551,7 @@ impl<'a> Codegen<'a> {
|
||||||
if val.ty.is_integer() {
|
if val.ty.is_integer() {
|
||||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
|
Some(self.ci.nodes.new_node_lit(val.ty, Kind::UnOp { op }, [VOID, val.id]))
|
||||||
} else if val.ty.is_float() {
|
} else if val.ty.is_float() {
|
||||||
let value = self.ci.nodes.new_node_nop(
|
let value = self.ci.nodes.new_const(val.ty, (-1f64).to_bits() as i64);
|
||||||
val.ty,
|
|
||||||
Kind::CInt { value: (-1f64).to_bits() as _ },
|
|
||||||
[VOID],
|
|
||||||
);
|
|
||||||
Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [
|
Some(self.ci.nodes.new_node_lit(val.ty, Kind::BinOp { op: TokenKind::Mul }, [
|
||||||
VOID, val.id, value,
|
VOID, val.id, value,
|
||||||
]))
|
]))
|
||||||
|
@ -2669,8 +2665,7 @@ impl<'a> Codegen<'a> {
|
||||||
let elem = self.tys.ins.slices[s as usize].elem;
|
let elem = self.tys.ins.slices[s as usize].elem;
|
||||||
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
|
let mut idx = self.expr_ctx(index, Ctx::default().with_ty(ty::Id::DEFAULT_INT))?;
|
||||||
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
|
self.assert_ty(index.pos(), &mut idx, ty::Id::DEFAULT_INT, "subscript");
|
||||||
let value = self.tys.size_of(elem) as i64;
|
let size = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
|
||||||
let size = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value }, [VOID]);
|
|
||||||
let inps = [VOID, idx.id, size];
|
let inps = [VOID, idx.id, size];
|
||||||
let offset =
|
let offset =
|
||||||
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps);
|
self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Mul }, inps);
|
||||||
|
@ -2690,18 +2685,16 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
Expr::Directive { name: "sizeof", args: [ty], .. } => {
|
||||||
let ty = self.ty(ty);
|
let ty = self.ty(ty);
|
||||||
Some(self.ci.nodes.new_node_lit(
|
Some(self.ci.nodes.new_const_lit(
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
||||||
Kind::CInt { value: self.tys.size_of(ty) as _ },
|
self.tys.size_of(ty),
|
||||||
[VOID],
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "alignof", args: [ty], .. } => {
|
Expr::Directive { name: "alignof", args: [ty], .. } => {
|
||||||
let ty = self.ty(ty);
|
let ty = self.ty(ty);
|
||||||
Some(self.ci.nodes.new_node_lit(
|
Some(self.ci.nodes.new_const_lit(
|
||||||
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
ctx.ty.filter(|ty| ty.is_integer()).unwrap_or(ty::Id::DEFAULT_INT),
|
||||||
Kind::CInt { value: self.tys.align_of(ty) as _ },
|
self.tys.align_of(ty),
|
||||||
[VOID],
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "bitcast", args: [val], pos } => {
|
Expr::Directive { name: "bitcast", args: [val], pos } => {
|
||||||
|
@ -3166,8 +3159,8 @@ impl<'a> Codegen<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Struct { .. } => {
|
Expr::Struct { .. } => {
|
||||||
let value = self.ty(expr).repr() as i64;
|
let value = self.ty(expr).repr();
|
||||||
Some(self.ci.nodes.new_node_lit(ty::Id::TYPE, Kind::CInt { value }, [VOID]))
|
Some(self.ci.nodes.new_const_lit(ty::Id::TYPE, value))
|
||||||
}
|
}
|
||||||
Expr::Ctor { pos, ty, fields, .. } => {
|
Expr::Ctor { pos, ty, fields, .. } => {
|
||||||
ctx.ty = ty.map(|ty| self.ty(ty)).or(ctx.ty);
|
ctx.ty = ty.map(|ty| self.ty(ty)).or(ctx.ty);
|
||||||
|
@ -3729,7 +3722,7 @@ impl<'a> Codegen<'a> {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
let off = self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value: off as i64 }, [VOID]);
|
let off = self.ci.nodes.new_const(ty::Id::INT, off);
|
||||||
let (aclass, mem) = self.ci.nodes.aclass_index(val);
|
let (aclass, mem) = self.ci.nodes.aclass_index(val);
|
||||||
let inps = [VOID, val, off];
|
let inps = [VOID, val, off];
|
||||||
let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
|
let seted = self.ci.nodes.new_node(ty::Id::INT, Kind::BinOp { op: TokenKind::Add }, inps);
|
||||||
|
@ -3914,9 +3907,7 @@ impl<'a> Codegen<'a> {
|
||||||
if matches!(op, TokenKind::Add | TokenKind::Sub)
|
if matches!(op, TokenKind::Add | TokenKind::Sub)
|
||||||
&& let Some(elem) = self.tys.base_of(upcasted)
|
&& let Some(elem) = self.tys.base_of(upcasted)
|
||||||
{
|
{
|
||||||
let value = self.tys.size_of(elem) as i64;
|
let cnst = self.ci.nodes.new_const(ty::Id::INT, self.tys.size_of(elem));
|
||||||
let cnst =
|
|
||||||
self.ci.nodes.new_node_nop(ty::Id::INT, Kind::CInt { value }, [VOID]);
|
|
||||||
oper.id =
|
oper.id =
|
||||||
self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [
|
self.ci.nodes.new_node(upcasted, Kind::BinOp { op: TokenKind::Mul }, [
|
||||||
VOID, oper.id, cnst,
|
VOID, oper.id, cnst,
|
||||||
|
@ -3975,9 +3966,8 @@ impl<'a> Codegen<'a> {
|
||||||
|
|
||||||
fn extend(&mut self, value: &mut Value, to: ty::Id) {
|
fn extend(&mut self, value: &mut Value, to: ty::Id) {
|
||||||
self.strip_ptr(value);
|
self.strip_ptr(value);
|
||||||
let val = (1i64 << (self.tys.size_of(value.ty) * 8)) - 1;
|
|
||||||
value.ty = to;
|
value.ty = to;
|
||||||
let mask = self.ci.nodes.new_node_nop(to, Kind::CInt { value: val }, [VOID]);
|
let mask = self.ci.nodes.new_const(to, (1i64 << (self.tys.size_of(value.ty) * 8)) - 1);
|
||||||
let inps = [VOID, value.id, mask];
|
let inps = [VOID, value.id, mask];
|
||||||
*value = self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps);
|
*value = self.ci.nodes.new_node_lit(to, Kind::BinOp { op: TokenKind::Band }, inps);
|
||||||
}
|
}
|
||||||
|
@ -4137,6 +4127,7 @@ mod tests {
|
||||||
variables;
|
variables;
|
||||||
loops;
|
loops;
|
||||||
pointers;
|
pointers;
|
||||||
|
nullable_types;
|
||||||
structs;
|
structs;
|
||||||
hex_octal_binary_literals;
|
hex_octal_binary_literals;
|
||||||
struct_operators;
|
struct_operators;
|
||||||
|
|
0
lang/tests/son_tests_nullable_types.txt
Normal file
0
lang/tests/son_tests_nullable_types.txt
Normal file
Loading…
Reference in a new issue