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 {
a := &1
b := @as(?^uint, null)
b: ?^uint = null
if decide() b = a
if b == null return 9001
c := @as(?uint, *b)
c: ?uint = *b
if decide() c = null
if c != null return 42
d := @as(?u16, null)
d: ?u16 = null
if decide() d = 1
if d == null return 69
@ -331,7 +331,7 @@ main := fn(): uint {
if bar != null return 420
g := @as(?^uint, null)
g: ?^uint = null
g = a
_rd := *g
@ -452,8 +452,8 @@ main := fn(): uint {
hardcoded_pointer := @as(^u8, @bitcast(10))
ecall_that_returns_uint := @as(uint, @eca(1, foo.Type.(10, 20), 5, 6))
embedded_array := @as([15]u8, @embed("text.txt"))
two_fields := @len(foo.Type)
string_length := @len("foo\0")
two_fields := @lenof(foo.Type)
string_length := @lenof("foo\0")
the_struct_kind := @kindof(foo.Type)
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
- `@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
- `@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]`
- `@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
@ -544,7 +544,7 @@ fib_iter := fn(n: uint): uint {
#### arrays
```hb
main := fn(): uint {
addr := @as(u16, 0x1FF)
addr: u16 = 0x1FF
msg := u8.[0, 0, @intcast(addr), @intcast(addr >> 8)]
_force_stack := &msg
@ -579,10 +579,10 @@ foo := fn(a: uint, b: uint, c: uint): uint {
#### idk
```hb
_edge_case := @as(uint, idk)
_edge_case: uint = idk
main := fn(): uint {
big_array := @as([128]u8, idk)
big_array: [128]u8 = idk
i := 0
loop if i >= 128 break else {
big_array[i] = 69
@ -637,11 +637,11 @@ Vec := fn($Elem: type): type return struct {
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
src_cursor := vec.data
dst_cursor := @as(^Elem, new_alloc)
dst_cursor: ^Elem = new_alloc
end := vec.data + vec.len
loop if src_cursor == end break else {
@ -711,7 +711,7 @@ main := fn(): uint {
nums := Nums.(1, 2, 3, 4)
i := 0
sum := 0
$loop if i == @len(Nums) break else {
$loop if i == @lenof(Nums) break else {
sum += nums[i]
i += 1
}
@ -837,7 +837,7 @@ main := fn(): int {
Color := struct {b: u8}
main := fn(): void {
color := Color.(0)
n := @as(u8, 1)
n: u8 = 1
loop {
if color.b == 255 | color.b == 0 {
n = -n
@ -913,12 +913,12 @@ $H := 3
$W := 3
main := fn(): int {
y := @as(int, 0)
y: int = 0
loop if y == H break else {
x := @as(int, 0)
x: int = 0
loop if x == W break else {
c_r := @as(f64, @itf(x))
c_i := @as(f64, @itf(y))
c_r: f64 = @itf(x)
c_i: f64 = @itf(y)
if c_i * c_r >= 10.0 return 0
x += 1
}

View file

@ -558,7 +558,9 @@ impl<'a> Formatter<'a> {
f.write_str(op.name())?;
f.write_str(" ")?;
} else {
f.write_str(" ")?;
if op != TokenKind::Colon {
f.write_str(" ")?;
}
f.write_str(op.name())?;
f.write_str(" ")?;
}

View file

@ -287,6 +287,10 @@ impl<'a, 'b> Parser<'a, 'b> {
}
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};
if matches!(
@ -498,7 +502,7 @@ impl<'a, 'b> Parser<'a, 'b> {
Some(adv)
}
},
item: self.ptr_unit_expr()?,
item: self.arena.alloc(self.unit_expr_low(false)?),
pos,
},
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}"))?,
};
loop {
let token = self.token;
if matches!(token.kind, T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack) {
self.next();
}
if eat_tail {
loop {
let token = self.token;
if matches!(
token.kind,
T::LParen | T::Ctor | T::Dot | T::Tupl | T::Arr | T::LBrack | T::Colon
) {
self.next();
}
expr = match token.kind {
T::LParen => Expr::Call {
func: self.arena.alloc(expr),
args: self.collect_list(T::Comma, T::RParen, Self::expr),
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)
expr = match token.kind {
T::LParen => Expr::Call {
func: self.arena.alloc(expr),
args: self.collect_list(T::Comma, T::RParen, Self::expr),
trailing_comma: core::mem::take(&mut self.trailing_sep),
},
},
T::Dot => E::Field {
target: self.arena.alloc(expr),
pos: token.start,
name: {
let token = self.expect_advance(T::Ident)?;
self.tok_str(token)
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)
},
},
},
_ => break,
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 {
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,
) -> Option<(&'a Expr<'a>, Ident)> {
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))
}
_ => None,

View file

@ -1081,6 +1081,21 @@ impl<'a> Codegen<'a> {
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 } => {
let mut right = self.expr(right)?;
@ -1342,14 +1357,21 @@ impl<'a> Codegen<'a> {
let align = self.tys.align_of(ty);
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 len = match self.ci.nodes[ty.id].kind {
Kind::CInt { value }
if let Some(len) = self.tys.len_of(ty::Id::from(value as u64)) =>
{
len
}
Kind::CInt { value } => match self.tys.len_of(ty::Id::from(value as u64)) {
Some(len) => len,
None => {
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,
_ => {
return self
@ -2839,7 +2861,10 @@ impl<'a> Codegen<'a> {
let prev_parent = mem::replace(&mut self.ci.parent, c.parent);
let f = &self.files[c.file];
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| {
debug_assert!(is_ct);
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: "ChildOf", args: [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(
sc.file,
aty.pos(),

View file

@ -616,12 +616,11 @@ impl core::fmt::Display for Display<'_> {
K::Slice(idx) => {
let array = self.tys.ins.slices[idx];
f.write_str("[")?;
self.rety(array.elem).fmt(f)?;
if array.len != ArrayLen::MAX {
f.write_str("; ")?;
array.len.fmt(f)?;
if let Some(len) = array.len() {
len.fmt(f)?;
}
f.write_str("]")
f.write_str("]")?;
self.rety(array.elem).fmt(f)
}
K::Const(idx) => {
let cnst = &self.tys.ins.consts[idx];
@ -1260,6 +1259,7 @@ impl Types {
pub fn len_of(&self, ty: Id) -> Option<u32> {
Some(match ty.expand() {
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 _,
_ => return None,
})
@ -1274,6 +1274,13 @@ impl Types {
pub fn tuple_fields(&self, tuple: Tuple) -> &[Id] {
&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 {