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 {
|
||||
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
|
||||
}
|
||||
|
|
|
@ -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(" ")?;
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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(),
|
||||
|
|
|
@ -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 {
|
||||
|
|
Loading…
Reference in a new issue