some syntax changes

mainly added the explicit type for declarations

Signed-off-by: Jakub Doka <jakub.doka2@gmail.com>
This commit is contained in:
Jakub Doka 2024-12-20 11:32:18 +01:00
parent 8ad58ee6b6
commit f59c0c1092
No known key found for this signature in database
GPG key ID: C6E9A89936B8C143
5 changed files with 117 additions and 63 deletions

View file

@ -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
} }

View file

@ -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 {
f.write_str(" ")?; if op != TokenKind::Colon {
f.write_str(" ")?;
}
f.write_str(op.name())?; f.write_str(op.name())?;
f.write_str(" ")?; f.write_str(" ")?;
} }

View file

@ -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,38 +555,52 @@ 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}"))?,
}; };
loop { if eat_tail {
let token = self.token; loop {
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack) { let token = self.token;
self.next(); if matches!(
} token.kind,
T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack | T::Colon
) {
self.next();
}
expr = match token.kind { expr = match token.kind {
T::LParen => Expr::Call { T::LParen => Expr::Call {
func: self.arena.alloc(expr), func: self.arena.alloc(expr),
args: self.collect_list(T::Comma, T::RParen, Self::expr), args: self.collect_list(T::Comma, T::RParen, Self::expr),
trailing_comma: core::mem::take(&mut self.trailing_sep), trailing_comma: core::mem::take(&mut self.trailing_sep),
},
T::Ctor => self.ctor(token.start, Some(expr)),
T::Tupl => self.tupl(token.start, Some(expr), ListKind::Tuple),
T::Arr => self.tupl(token.start, Some(expr), ListKind::Array),
T::LBrack => E::Index {
base: self.arena.alloc(expr),
index: {
let index = self.expr()?;
self.expect_advance(T::RBrack)?;
self.arena.alloc(index)
}, },
}, T::Ctor => self.ctor(token.start, Some(expr)),
T::Dot => E::Field { T::Tupl => self.tupl(token.start, Some(expr), ListKind::Tuple),
target: self.arena.alloc(expr), T::Arr => self.tupl(token.start, Some(expr), ListKind::Array),
pos: token.start, T::LBrack => E::Index {
name: { base: self.arena.alloc(expr),
let token = self.expect_advance(T::Ident)?; index: {
self.tok_str(token) let index = self.expr()?;
self.expect_advance(T::RBrack)?;
self.arena.alloc(index)
},
}, },
}, T::Colon => E::BinOp {
_ => break, left: {
self.declare_rec(&expr, false);
self.arena.alloc(expr)
},
pos,
op: T::Colon,
right: self.ptr_expr()?,
},
T::Dot => E::Field {
target: self.arena.alloc(expr),
pos: token.start,
name: {
let token = self.expect_advance(T::Ident)?;
self.tok_str(token)
},
},
_ => break,
}
} }
} }
@ -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,

View file

@ -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(),

View file

@ -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 {