some syntax changes
mainly added the explicit type for declarations Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
parent
8ad58ee6b6
commit
f59c0c1092
|
@ -299,17 +299,17 @@ main := fn(): uint {
|
||||||
main := fn(): uint {
|
main := fn(): uint {
|
||||||
a := &1
|
a := &1
|
||||||
|
|
||||||
b := @as(?^uint, null)
|
b: ?^uint = null
|
||||||
if decide() b = a
|
if decide() b = a
|
||||||
|
|
||||||
if b == null return 9001
|
if b == null return 9001
|
||||||
|
|
||||||
c := @as(?uint, *b)
|
c: ?uint = *b
|
||||||
if decide() c = null
|
if decide() c = null
|
||||||
|
|
||||||
if c != null return 42
|
if c != null return 42
|
||||||
|
|
||||||
d := @as(?u16, null)
|
d: ?u16 = null
|
||||||
if decide() d = 1
|
if decide() d = 1
|
||||||
|
|
||||||
if d == null return 69
|
if d == null return 69
|
||||||
|
@ -331,7 +331,7 @@ main := fn(): uint {
|
||||||
|
|
||||||
if bar != null return 420
|
if bar != null return 420
|
||||||
|
|
||||||
g := @as(?^uint, null)
|
g: ?^uint = null
|
||||||
g = a
|
g = a
|
||||||
|
|
||||||
_rd := *g
|
_rd := *g
|
||||||
|
@ -452,8 +452,8 @@ main := fn(): uint {
|
||||||
hardcoded_pointer := @as(^u8, @bitcast(10))
|
hardcoded_pointer := @as(^u8, @bitcast(10))
|
||||||
ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6))
|
ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6))
|
||||||
embedded_array := @as([15]u8, @embed("text.txt"))
|
embedded_array := @as([15]u8, @embed("text.txt"))
|
||||||
two_fields := @len(foo.Type)
|
two_fields := @lenof(foo.Type)
|
||||||
string_length := @len("foo\0")
|
string_length := @lenof("foo\0")
|
||||||
the_struct_kind := @kindof(foo.Type)
|
the_struct_kind := @kindof(foo.Type)
|
||||||
return @inline(foo.foo)
|
return @inline(foo.foo)
|
||||||
}
|
}
|
||||||
|
@ -482,7 +482,7 @@ arbitrary text
|
||||||
- `@eca(...<expr>)`: invoke `eca` instruction, where return type is inferred and `<expr>...` are arguments passed to the call in the standard call convention
|
- `@eca(...<expr>)`: invoke `eca` instruction, where return type is inferred and `<expr>...` are arguments passed to the call in the standard call convention
|
||||||
- `@embed(<string>)`: include relative file as an array of bytes
|
- `@embed(<string>)`: include relative file as an array of bytes
|
||||||
- `@inline(<func>, ...<args>)`: equivalent to `<func>(...<args>)` but function is guaranteed to inline, compiler will otherwise never inline
|
- `@inline(<func>, ...<args>)`: equivalent to `<func>(...<args>)` but function is guaranteed to inline, compiler will otherwise never inline
|
||||||
- `@len(<ty>)`: reports a length of the type of indexing purposes or length ot a string constant
|
- `@lenof(<ty>)`: reports a length of the type of indexing purposes or length ot a string constant
|
||||||
- `@kindof(<ty>)`: gives an u8 integer describing the kind of type as an index to array `[Builtin, Struct, Tuple, Enum, Union, Ptr, Slice, Opt, Func, Template, Global, Const, Module]`
|
- `@kindof(<ty>)`: gives an u8 integer describing the kind of type as an index to array `[Builtin, Struct, Tuple, Enum, Union, Ptr, Slice, Opt, Func, Template, Global, Const, Module]`
|
||||||
- `@Any()`: generic parameter based on inference, TBD: this will ake arguments in the future that restrict what is accepted
|
- `@Any()`: generic parameter based on inference, TBD: this will ake arguments in the future that restrict what is accepted
|
||||||
- `@error(...<expr>)`: emit compiler error, if reachable, and use arguments to construct a message, can display strings and types
|
- `@error(...<expr>)`: emit compiler error, if reachable, and use arguments to construct a message, can display strings and types
|
||||||
|
@ -544,7 +544,7 @@ fib_iter := fn(n: uint): uint {
|
||||||
#### arrays
|
#### arrays
|
||||||
```hb
|
```hb
|
||||||
main := fn(): uint {
|
main := fn(): uint {
|
||||||
addr := @as(u16, 0x1FF)
|
addr: u16 = 0x1FF
|
||||||
msg := u8.[0, 0, @intcast(addr), @intcast(addr >> 8)]
|
msg := u8.[0, 0, @intcast(addr), @intcast(addr >> 8)]
|
||||||
_force_stack := &msg
|
_force_stack := &msg
|
||||||
|
|
||||||
|
@ -579,10 +579,10 @@ foo := fn(a: uint, b: uint, c: uint): uint {
|
||||||
|
|
||||||
#### idk
|
#### idk
|
||||||
```hb
|
```hb
|
||||||
_edge_case := @as(uint, idk)
|
_edge_case: uint = idk
|
||||||
|
|
||||||
main := fn(): uint {
|
main := fn(): uint {
|
||||||
big_array := @as([128]u8, idk)
|
big_array: [128]u8 = idk
|
||||||
i := 0
|
i := 0
|
||||||
loop if i >= 128 break else {
|
loop if i >= 128 break else {
|
||||||
big_array[i] = 69
|
big_array[i] = 69
|
||||||
|
@ -637,11 +637,11 @@ Vec := fn($Elem: type): type return struct {
|
||||||
vec.cap *= 2
|
vec.cap *= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
new_alloc := @as(?^Elem, @bitcast(malloc(vec.cap * @sizeof(Elem), @alignof(Elem))))
|
new_alloc: ?^Elem = @bitcast(malloc(vec.cap * @sizeof(Elem), @alignof(Elem)))
|
||||||
if new_alloc == null return null
|
if new_alloc == null return null
|
||||||
|
|
||||||
src_cursor := vec.data
|
src_cursor := vec.data
|
||||||
dst_cursor := @as(^Elem, new_alloc)
|
dst_cursor: ^Elem = new_alloc
|
||||||
end := vec.data + vec.len
|
end := vec.data + vec.len
|
||||||
|
|
||||||
loop if src_cursor == end break else {
|
loop if src_cursor == end break else {
|
||||||
|
@ -711,7 +711,7 @@ main := fn(): uint {
|
||||||
nums := Nums.(1, 2, 3, 4)
|
nums := Nums.(1, 2, 3, 4)
|
||||||
i := 0
|
i := 0
|
||||||
sum := 0
|
sum := 0
|
||||||
$loop if i == @len(Nums) break else {
|
$loop if i == @lenof(Nums) break else {
|
||||||
sum += nums[i]
|
sum += nums[i]
|
||||||
i += 1
|
i += 1
|
||||||
}
|
}
|
||||||
|
@ -837,7 +837,7 @@ main := fn(): int {
|
||||||
Color := struct {b: u8}
|
Color := struct {b: u8}
|
||||||
main := fn(): void {
|
main := fn(): void {
|
||||||
color := Color.(0)
|
color := Color.(0)
|
||||||
n := @as(u8, 1)
|
n: u8 = 1
|
||||||
loop {
|
loop {
|
||||||
if color.b == 255 | color.b == 0 {
|
if color.b == 255 | color.b == 0 {
|
||||||
n = -n
|
n = -n
|
||||||
|
@ -913,12 +913,12 @@ $H := 3
|
||||||
$W := 3
|
$W := 3
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
y := @as(int, 0)
|
y: int = 0
|
||||||
loop if y == H break else {
|
loop if y == H break else {
|
||||||
x := @as(int, 0)
|
x: int = 0
|
||||||
loop if x == W break else {
|
loop if x == W break else {
|
||||||
c_r := @as(f64, @itf(x))
|
c_r: f64 = @itf(x)
|
||||||
c_i := @as(f64, @itf(y))
|
c_i: f64 = @itf(y)
|
||||||
if c_i * c_r >= 10.0 return 0
|
if c_i * c_r >= 10.0 return 0
|
||||||
x += 1
|
x += 1
|
||||||
}
|
}
|
||||||
|
|
|
@ -558,7 +558,9 @@ impl<'a> Formatter<'a> {
|
||||||
f.write_str(op.name())?;
|
f.write_str(op.name())?;
|
||||||
f.write_str(" ")?;
|
f.write_str(" ")?;
|
||||||
} else {
|
} else {
|
||||||
|
if op != TokenKind::Colon {
|
||||||
f.write_str(" ")?;
|
f.write_str(" ")?;
|
||||||
|
}
|
||||||
f.write_str(op.name())?;
|
f.write_str(op.name())?;
|
||||||
f.write_str(" ")?;
|
f.write_str(" ")?;
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,6 +287,10 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unit_expr(&mut self) -> Option<Expr<'a>> {
|
fn unit_expr(&mut self) -> Option<Expr<'a>> {
|
||||||
|
self.unit_expr_low(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unit_expr_low(&mut self, eat_tail: bool) -> Option<Expr<'a>> {
|
||||||
use {Expr as E, TokenKind as T};
|
use {Expr as E, TokenKind as T};
|
||||||
|
|
||||||
if matches!(
|
if matches!(
|
||||||
|
@ -498,7 +502,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
Some(adv)
|
Some(adv)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
item: self.ptr_unit_expr()?,
|
item: self.arena.alloc(self.unit_expr_low(false)?),
|
||||||
pos,
|
pos,
|
||||||
},
|
},
|
||||||
T::Band | T::Mul | T::Xor | T::Sub | T::Que | T::Not | T::Dot => E::UnOp {
|
T::Band | T::Mul | T::Xor | T::Sub | T::Que | T::Not | T::Dot => E::UnOp {
|
||||||
|
@ -551,9 +555,13 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
tok => self.report(token.start, format_args!("unexpected token: {tok}"))?,
|
tok => self.report(token.start, format_args!("unexpected token: {tok}"))?,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if eat_tail {
|
||||||
loop {
|
loop {
|
||||||
let token = self.token;
|
let token = self.token;
|
||||||
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack) {
|
if matches!(
|
||||||
|
token.kind,
|
||||||
|
T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack | T::Colon
|
||||||
|
) {
|
||||||
self.next();
|
self.next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -574,6 +582,15 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
self.arena.alloc(index)
|
self.arena.alloc(index)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
T::Colon => E::BinOp {
|
||||||
|
left: {
|
||||||
|
self.declare_rec(&expr, false);
|
||||||
|
self.arena.alloc(expr)
|
||||||
|
},
|
||||||
|
pos,
|
||||||
|
op: T::Colon,
|
||||||
|
right: self.ptr_expr()?,
|
||||||
|
},
|
||||||
T::Dot => E::Field {
|
T::Dot => E::Field {
|
||||||
target: self.arena.alloc(expr),
|
target: self.arena.alloc(expr),
|
||||||
pos: token.start,
|
pos: token.start,
|
||||||
|
@ -585,6 +602,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
_ => break,
|
_ => break,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if matches!(token.kind, T::Loop | T::LBrace | T::Fn | T::Struct) {
|
if matches!(token.kind, T::Loop | T::LBrace | T::Fn | T::Struct) {
|
||||||
self.pop_scope(frame);
|
self.pop_scope(frame);
|
||||||
|
@ -1456,7 +1474,7 @@ pub fn find_decl<'a>(
|
||||||
id: DeclId,
|
id: DeclId,
|
||||||
) -> Option<(&'a Expr<'a>, Ident)> {
|
) -> Option<(&'a Expr<'a>, Ident)> {
|
||||||
exprs.iter().find_map(|expr| match expr {
|
exprs.iter().find_map(|expr| match expr {
|
||||||
Expr::BinOp { left, op: TokenKind::Decl, .. } => {
|
Expr::BinOp { left, op: TokenKind::Decl | TokenKind::Colon, .. } => {
|
||||||
left.declares(id, file).map(|id| (expr, id))
|
left.declares(id, file).map(|id| (expr, id))
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
|
|
|
@ -1081,6 +1081,21 @@ impl<'a> Codegen<'a> {
|
||||||
self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)))
|
self.error(pos, fa!("cant logically negate '{}'", self.ty_display(val.ty)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Expr::BinOp {
|
||||||
|
left,
|
||||||
|
op: TokenKind::Colon,
|
||||||
|
right: &Expr::BinOp { left: ty, op: TokenKind::Assign, right, pos },
|
||||||
|
..
|
||||||
|
} => {
|
||||||
|
let ty = self.ty(ty);
|
||||||
|
let mut right = self.checked_expr(right, ty, "declaration")?;
|
||||||
|
|
||||||
|
if right.ty.loc(self.tys) == Loc::Stack {
|
||||||
|
self.spill(pos, &mut right);
|
||||||
|
}
|
||||||
|
self.assign_pattern(left, right);
|
||||||
|
Some(Value::VOID)
|
||||||
|
}
|
||||||
Expr::BinOp { left, op: TokenKind::Decl, right, pos } => {
|
Expr::BinOp { left, op: TokenKind::Decl, right, pos } => {
|
||||||
let mut right = self.expr(right)?;
|
let mut right = self.expr(right)?;
|
||||||
|
|
||||||
|
@ -1342,14 +1357,21 @@ impl<'a> Codegen<'a> {
|
||||||
let align = self.tys.align_of(ty);
|
let align = self.tys.align_of(ty);
|
||||||
self.gen_inferred_const(ctx, ty::Id::DINT, align)
|
self.gen_inferred_const(ctx, ty::Id::DINT, align)
|
||||||
}
|
}
|
||||||
Expr::Directive { name: "len", args: [ety], .. } => {
|
Expr::Directive { name: "lenof", args: [ety], .. } => {
|
||||||
let ty = self.expr(ety)?;
|
let ty = self.expr(ety)?;
|
||||||
let len = match self.ci.nodes[ty.id].kind {
|
let len = match self.ci.nodes[ty.id].kind {
|
||||||
Kind::CInt { value }
|
Kind::CInt { value } => match self.tys.len_of(ty::Id::from(value as u64)) {
|
||||||
if let Some(len) = self.tys.len_of(ty::Id::from(value as u64)) =>
|
Some(len) => len,
|
||||||
{
|
None => {
|
||||||
len
|
return self.error(
|
||||||
|
ety.pos(),
|
||||||
|
fa!(
|
||||||
|
"'@len' only supports structs and arrays or strings. got {}",
|
||||||
|
self.ty_display(ty::Id::from(value as u64))
|
||||||
|
),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
},
|
||||||
Kind::Global { global } => self.tys.ins.globals[global].data.len() as u32 - 1,
|
Kind::Global { global } => self.tys.ins.globals[global].data.len() as u32 - 1,
|
||||||
_ => {
|
_ => {
|
||||||
return self
|
return self
|
||||||
|
@ -2839,7 +2861,10 @@ impl<'a> Codegen<'a> {
|
||||||
let prev_parent = mem::replace(&mut self.ci.parent, c.parent);
|
let prev_parent = mem::replace(&mut self.ci.parent, c.parent);
|
||||||
let f = &self.files[c.file];
|
let f = &self.files[c.file];
|
||||||
let value = match c.ast.get(f) {
|
let value = match c.ast.get(f) {
|
||||||
Expr::BinOp { left, op: TokenKind::Decl, right, .. } => left
|
&Expr::BinOp { left, op: TokenKind::Decl, right, .. }
|
||||||
|
| &Expr::BinOp {
|
||||||
|
left, op: TokenKind::Colon, right: &Expr::BinOp { right, .. }, ..
|
||||||
|
} => left
|
||||||
.find_pattern_path(c.name, right, |expr, is_ct| {
|
.find_pattern_path(c.name, right, |expr, is_ct| {
|
||||||
debug_assert!(is_ct);
|
debug_assert!(is_ct);
|
||||||
self.ptr_expr_ctx(expr, ctx)
|
self.ptr_expr_ctx(expr, ctx)
|
||||||
|
@ -3945,7 +3970,9 @@ impl<'a> Codegen<'a> {
|
||||||
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
|
Expr::Directive { name: "TypeOf", args: [expr], .. } => self.infer_type(expr),
|
||||||
Expr::Directive { name: "ChildOf", args: [aty], .. } => {
|
Expr::Directive { name: "ChildOf", args: [aty], .. } => {
|
||||||
let ty = self.parse_ty(sc.anon(), aty);
|
let ty = self.parse_ty(sc.anon(), aty);
|
||||||
let Some(ty) = self.tys.base_of(ty).or(self.tys.inner_of(ty)) else {
|
let Some(ty) =
|
||||||
|
self.tys.base_of(ty).or(self.tys.inner_of(ty)).or(self.tys.elem_of(ty))
|
||||||
|
else {
|
||||||
return self.error_low(
|
return self.error_low(
|
||||||
sc.file,
|
sc.file,
|
||||||
aty.pos(),
|
aty.pos(),
|
||||||
|
|
|
@ -616,12 +616,11 @@ impl core::fmt::Display for Display<'_> {
|
||||||
K::Slice(idx) => {
|
K::Slice(idx) => {
|
||||||
let array = self.tys.ins.slices[idx];
|
let array = self.tys.ins.slices[idx];
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
self.rety(array.elem).fmt(f)?;
|
if let Some(len) = array.len() {
|
||||||
if array.len != ArrayLen::MAX {
|
len.fmt(f)?;
|
||||||
f.write_str("; ")?;
|
|
||||||
array.len.fmt(f)?;
|
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")?;
|
||||||
|
self.rety(array.elem).fmt(f)
|
||||||
}
|
}
|
||||||
K::Const(idx) => {
|
K::Const(idx) => {
|
||||||
let cnst = &self.tys.ins.consts[idx];
|
let cnst = &self.tys.ins.consts[idx];
|
||||||
|
@ -1260,6 +1259,7 @@ impl Types {
|
||||||
pub fn len_of(&self, ty: Id) -> Option<u32> {
|
pub fn len_of(&self, ty: Id) -> Option<u32> {
|
||||||
Some(match ty.expand() {
|
Some(match ty.expand() {
|
||||||
Kind::Struct(s) => self.struct_field_range(s).len() as _,
|
Kind::Struct(s) => self.struct_field_range(s).len() as _,
|
||||||
|
Kind::Tuple(s) => self.ins.tuples[s].fields.len() as _,
|
||||||
Kind::Slice(s) => self.ins.slices[s].len()? as _,
|
Kind::Slice(s) => self.ins.slices[s].len()? as _,
|
||||||
_ => return None,
|
_ => return None,
|
||||||
})
|
})
|
||||||
|
@ -1274,6 +1274,13 @@ impl Types {
|
||||||
pub fn tuple_fields(&self, tuple: Tuple) -> &[Id] {
|
pub fn tuple_fields(&self, tuple: Tuple) -> &[Id] {
|
||||||
&self.ins.args[self.ins.tuples[tuple].fields.range()]
|
&self.ins.args[self.ins.tuples[tuple].fields.range()]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn elem_of(&self, ty: Id) -> Option<Id> {
|
||||||
|
match ty.expand() {
|
||||||
|
Kind::Slice(s) => Some(self.ins.slices[s].elem),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OptLayout {
|
pub struct OptLayout {
|
||||||
|
|
Loading…
Reference in a new issue