foobar
This commit is contained in:
parent
5555b9865a
commit
cac99cd34d
312
hblang/README.md
312
hblang/README.md
|
@ -47,22 +47,22 @@ main := fn(): int {
|
||||||
#### arithmetic
|
#### arithmetic
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1;
|
return 10 - 20 / 2 + 4 * (2 + 2) - 4 * 4 + 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### functions
|
#### functions
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return add_one(10) + add_two(20);
|
return add_one(10) + add_two(20)
|
||||||
}
|
}
|
||||||
|
|
||||||
add_two := fn(x: int): int {
|
add_two := fn(x: int): int {
|
||||||
return x + 2;
|
return x + 2
|
||||||
}
|
}
|
||||||
|
|
||||||
add_one := fn(x: int): int {
|
add_one := fn(x: int): int {
|
||||||
return x + 1;
|
return x + 1
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -71,12 +71,11 @@ add_one := fn(x: int): int {
|
||||||
// commant is an item
|
// commant is an item
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
// comment is a statement
|
// comment is a statement
|
||||||
foo(/* comment is an exprression /* if you are crazy */ */);
|
foo(/* comment is an exprression /* if you are crazy */ */)
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
foo := fn(comment: void): void
|
foo := fn(comment: void): void return /* comment evaluates to void */
|
||||||
return /* comment evaluates to void */;
|
|
||||||
|
|
||||||
// comments might be formatted in the future
|
// comments might be formatted in the future
|
||||||
```
|
```
|
||||||
|
@ -84,14 +83,14 @@ foo := fn(comment: void): void
|
||||||
#### if_statements
|
#### if_statements
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return fib(10);
|
return fib(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
fib := fn(x: int): int {
|
fib := fn(x: int): int {
|
||||||
if x <= 2 {
|
if x <= 2 {
|
||||||
return 1;
|
return 1
|
||||||
} else {
|
} else {
|
||||||
return fib(x - 1) + fib(x - 2);
|
return fib(x - 1) + fib(x - 2)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
@ -99,55 +98,55 @@ fib := fn(x: int): int {
|
||||||
#### variables
|
#### variables
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
ඞ := 1;
|
ඞ := 1
|
||||||
b := 2;
|
b := 2
|
||||||
ඞ = ඞ + 1;
|
ඞ += 1
|
||||||
return ඞ - b;
|
return ඞ - b
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### loops
|
#### loops
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return fib(10);
|
return fib(10)
|
||||||
}
|
}
|
||||||
|
|
||||||
fib := fn(n: int): int {
|
fib := fn(n: int): int {
|
||||||
a := 0;
|
a := 0
|
||||||
b := 1;
|
b := 1
|
||||||
loop {
|
loop {
|
||||||
if n == 0 break;
|
if n == 0 break
|
||||||
c := a + b;
|
c := a + b
|
||||||
a = b;
|
a = b
|
||||||
b = c;
|
b = c
|
||||||
n -= 1;
|
n -= 1
|
||||||
|
|
||||||
stack_reclamation_edge_case := 0;
|
stack_reclamation_edge_case := 0
|
||||||
|
|
||||||
continue;
|
continue
|
||||||
}
|
}
|
||||||
return a;
|
return a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### pointers
|
#### pointers
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
a := 1;
|
a := 1
|
||||||
b := &a;
|
b := &a
|
||||||
modify(b);
|
modify(b)
|
||||||
drop(a);
|
drop(a)
|
||||||
stack_reclamation_edge_case := 0;
|
stack_reclamation_edge_case := 0
|
||||||
return *b - 2;
|
return *b - 2
|
||||||
}
|
}
|
||||||
|
|
||||||
modify := fn(a: ^int): void {
|
modify := fn(a: ^int): void {
|
||||||
*a = 2;
|
*a = 2
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
drop := fn(a: int): void {
|
drop := fn(a: int): void {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -164,21 +163,21 @@ Ty2 := struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
finst := Ty2.{ ty: Ty.{ a: 4, b: 1 }, c: 3 };
|
finst := Ty2.{ty: Ty.{a: 4, b: 1}, c: 3}
|
||||||
inst := odher_pass(finst);
|
inst := odher_pass(finst)
|
||||||
if inst.c == 3 {
|
if inst.c == 3 {
|
||||||
return pass(&inst.ty);
|
return pass(&inst.ty)
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pass := fn(t: ^Ty): int {
|
pass := fn(t: ^Ty): int {
|
||||||
.{ a, b } := *t;
|
.{a, b} := *t
|
||||||
return a - b;
|
return a - b
|
||||||
}
|
}
|
||||||
|
|
||||||
odher_pass := fn(t: Ty2): Ty2 {
|
odher_pass := fn(t: Ty2): Ty2 {
|
||||||
return t;
|
return t
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -195,51 +194,51 @@ Rect := struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
a := Point.(1, 2);
|
a := Point.(1, 2)
|
||||||
b := Point.(3, 4);
|
b := Point.(3, 4)
|
||||||
|
|
||||||
d := Rect.(a + b, b - a);
|
d := Rect.(a + b, b - a)
|
||||||
d2 := Rect.(Point.(0, 0) - b, a);
|
d2 := Rect.(Point.(0, 0) - b, a)
|
||||||
d2 = d2 + d;
|
d2 += d
|
||||||
|
|
||||||
c := d2.a + d2.b;
|
c := d2.a + d2.b
|
||||||
return c.x + c.y;
|
return c.x + c.y
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### global_variables
|
#### global_variables
|
||||||
```hb
|
```hb
|
||||||
global_var := 10;
|
global_var := 10
|
||||||
|
|
||||||
complex_global_var := fib(global_var) - 5;
|
complex_global_var := fib(global_var) - 5
|
||||||
|
|
||||||
fib := fn(n: int): int {
|
fib := fn(n: int): int {
|
||||||
if 2 > n {
|
if 2 > n {
|
||||||
return n;
|
return n
|
||||||
}
|
}
|
||||||
return fib(n - 1) + fib(n - 2);
|
return fib(n - 1) + fib(n - 2)
|
||||||
}
|
}
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return complex_global_var;
|
return complex_global_var
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
note: values of global variables are evaluated at compile time
|
note: values of global variables are evaluated at compile time
|
||||||
|
|
||||||
#### directives
|
#### directives
|
||||||
```hb
|
```hb
|
||||||
foo := @use("foo.hb");
|
foo := @use("foo.hb")
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
byte := @as(u8, 10);
|
byte := @as(u8, 10)
|
||||||
same_type_as_byte := @as(@TypeOf(byte), 30);
|
same_type_as_byte := @as(@TypeOf(byte), 30)
|
||||||
wide_uint := @as(u32, 40);
|
wide_uint := @as(u32, 40)
|
||||||
truncated_uint := @as(u8, @intcast(wide_uint));
|
truncated_uint := @as(u8, @intcast(wide_uint))
|
||||||
size_of_Type_in_bytes := @sizeof(foo.Type);
|
size_of_Type_in_bytes := @sizeof(foo.Type)
|
||||||
align_of_Type_in_bytes := @alignof(foo.Type);
|
align_of_Type_in_bytes := @alignof(foo.Type)
|
||||||
hardcoded_pointer := @as(^u8, @bitcast(10));
|
hardcoded_pointer := @as(^u8, @bitcast(10))
|
||||||
ecall_that_returns_int := @eca(int, 1, foo.Type.(10, 20), 5, 6);
|
ecall_that_returns_int := @eca(int, 1, foo.Type.(10, 20), 5, 6)
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
// in module: foo.hb
|
// in module: foo.hb
|
||||||
|
@ -262,65 +261,65 @@ Type := struct {
|
||||||
#### c_strings
|
#### c_strings
|
||||||
```hb
|
```hb
|
||||||
str_len := fn(str: ^u8): int {
|
str_len := fn(str: ^u8): int {
|
||||||
len := 0;
|
len := 0
|
||||||
loop if *str == 0 break else {
|
loop if *str == 0 break else {
|
||||||
len += 1;
|
len += 1
|
||||||
str += 1;
|
str += 1
|
||||||
}
|
}
|
||||||
return len;
|
return len
|
||||||
}
|
}
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
// when string ends with '\0' its a C string and thus type is '^u8'
|
// when string ends with '\0' its a C string and thus type is '^u8'
|
||||||
some_str := "abඞ\n\r\t\{ff}\{fff0f0ff}\0";
|
some_str := "abඞ\n\r\t\{ff}\{fff0f0ff}\0"
|
||||||
len := str_len(some_str);
|
len := str_len(some_str)
|
||||||
some_other_str := "fff\0";
|
some_other_str := "fff\0"
|
||||||
lep := str_len(some_other_str);
|
lep := str_len(some_other_str)
|
||||||
return lep + len;
|
return lep + len
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### struct_patterns
|
#### struct_patterns
|
||||||
```hb
|
```hb
|
||||||
.{ fib, fib_iter, Fiber } := @use("fibs.hb");
|
.{fib, fib_iter, Fiber} := @use("fibs.hb")
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
.{ a, b } := Fiber.{ a: 10, b: 10 };
|
.{a, b} := Fiber.{a: 10, b: 10}
|
||||||
return fib(a) - fib_iter(b);
|
return fib(a) - fib_iter(b)
|
||||||
}
|
}
|
||||||
|
|
||||||
// in module: fibs.hb
|
// in module: fibs.hb
|
||||||
|
|
||||||
Fiber := struct { a: u8, b: u8 };
|
Fiber := struct {a: u8, b: u8}
|
||||||
|
|
||||||
fib := fn(n: int): int if n < 2 {
|
fib := fn(n: int): int if n < 2 {
|
||||||
return n;
|
return n
|
||||||
} else {
|
} else {
|
||||||
return fib(n - 1) + fib(n - 2);
|
return fib(n - 1) + fib(n - 2)
|
||||||
};
|
}
|
||||||
|
|
||||||
fib_iter := fn(n: int): int {
|
fib_iter := fn(n: int): int {
|
||||||
a := 0;
|
a := 0
|
||||||
b := 1;
|
b := 1
|
||||||
loop if n == 0 break else {
|
loop if n == 0 break else {
|
||||||
c := a + b;
|
c := a + b
|
||||||
a = b;
|
a = b
|
||||||
b = c;
|
b = c
|
||||||
n -= 1;
|
n -= 1
|
||||||
}
|
}
|
||||||
return a;
|
return a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### arrays
|
#### arrays
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
arr := [int].(1, 2, 4);
|
arr := [int].(1, 2, 4)
|
||||||
return pass(&arr);
|
return pass(&arr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pass := fn(arr: ^[int; 3]): int {
|
pass := fn(arr: ^[int; 3]): int {
|
||||||
return arr[0] + arr[1] + arr[arr[1]];
|
return arr[0] + arr[1] + arr[arr[1]]
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -329,13 +328,13 @@ pass := fn(arr: ^[int; 3]): int {
|
||||||
#### comptime_pointers
|
#### comptime_pointers
|
||||||
```hb
|
```hb
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
$integer := 7;
|
$integer := 7
|
||||||
modify(&integer);
|
modify(&integer)
|
||||||
return integer;
|
return integer
|
||||||
}
|
}
|
||||||
|
|
||||||
modify := fn($num: ^int): void {
|
modify := fn($num: ^int): void {
|
||||||
$: *num = 0;
|
$: *num = 0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -344,116 +343,111 @@ modify := fn($num: ^int): void {
|
||||||
MALLOC_SYS_CALL := 69
|
MALLOC_SYS_CALL := 69
|
||||||
FREE_SYS_CALL := 96
|
FREE_SYS_CALL := 96
|
||||||
|
|
||||||
malloc := fn(size: uint, align: uint): ^void
|
malloc := fn(size: uint, align: uint): ^void return @eca(^void, MALLOC_SYS_CALL, size, align)
|
||||||
return @eca(^void, MALLOC_SYS_CALL, size, align);
|
free := fn(ptr: ^void, size: uint, align: uint): void return @eca(void, FREE_SYS_CALL, ptr, size, align)
|
||||||
|
|
||||||
free := fn(ptr: ^void, size: uint, align: uint): void
|
|
||||||
return @eca(void, FREE_SYS_CALL, ptr, size, align);
|
|
||||||
|
|
||||||
Vec := fn($Elem: type): type {
|
Vec := fn($Elem: type): type {
|
||||||
return struct {
|
return struct {
|
||||||
data: ^Elem,
|
data: ^Elem,
|
||||||
len: uint,
|
len: uint,
|
||||||
cap: uint,
|
cap: uint,
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new := fn($Elem: type): Vec(Elem) return Vec(Elem).{ data: @bitcast(0), len: 0, cap: 0 };
|
new := fn($Elem: type): Vec(Elem) return Vec(Elem).{data: @bitcast(0), len: 0, cap: 0}
|
||||||
|
|
||||||
deinit := fn($Elem: type, vec: ^Vec(Elem)): void {
|
deinit := fn($Elem: type, vec: ^Vec(Elem)): void {
|
||||||
free(@bitcast(vec.data), vec.cap * @sizeof(Elem), @alignof(Elem));
|
free(@bitcast(vec.data), vec.cap * @sizeof(Elem), @alignof(Elem));
|
||||||
*vec = new(Elem);
|
*vec = new(Elem)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
push := fn($Elem: type, vec: ^Vec(Elem), value: Elem): ^Elem {
|
push := fn($Elem: type, vec: ^Vec(Elem), value: Elem): ^Elem {
|
||||||
if vec.len == vec.cap {
|
if vec.len == vec.cap {
|
||||||
if vec.cap == 0 {
|
if vec.cap == 0 {
|
||||||
vec.cap = 1;
|
vec.cap = 1
|
||||||
} else {
|
} else {
|
||||||
vec.cap *= 2;
|
vec.cap *= 2
|
||||||
}
|
}
|
||||||
|
|
||||||
new_alloc := @as(^Elem, @bitcast(malloc(vec.cap * @sizeof(Elem), @alignof(Elem))));
|
new_alloc := @as(^Elem, @bitcast(malloc(vec.cap * @sizeof(Elem), @alignof(Elem))))
|
||||||
if new_alloc == 0 return 0;
|
if new_alloc == 0 return 0
|
||||||
|
|
||||||
src_cursor := vec.data;
|
src_cursor := vec.data
|
||||||
dst_cursor := new_alloc;
|
dst_cursor := 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 {
|
||||||
*dst_cursor = *src_cursor;
|
*dst_cursor = *src_cursor
|
||||||
src_cursor += 1;
|
src_cursor += 1
|
||||||
dst_cursor += 1;
|
dst_cursor += 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if vec.len != 0 {
|
if vec.len != 0 {
|
||||||
free(@bitcast(vec.data), vec.len * @sizeof(Elem), @alignof(Elem));
|
free(@bitcast(vec.data), vec.len * @sizeof(Elem), @alignof(Elem))
|
||||||
}
|
}
|
||||||
vec.data = new_alloc;
|
vec.data = new_alloc
|
||||||
}
|
}
|
||||||
|
|
||||||
slot := vec.data + vec.len;
|
slot := vec.data + vec.len;
|
||||||
*slot = value;
|
*slot = value
|
||||||
vec.len += 1;
|
vec.len += 1
|
||||||
return slot;
|
return slot
|
||||||
}
|
}
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
vec := new(int);
|
vec := new(int)
|
||||||
push(int, &vec, 69);
|
push(int, &vec, 69)
|
||||||
res := *vec.data;
|
res := *vec.data
|
||||||
deinit(int, &vec);
|
deinit(int, &vec)
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### generic_functions
|
#### generic_functions
|
||||||
```hb
|
```hb
|
||||||
add := fn($T: type, a: T, b: T): T return a + b;
|
add := fn($T: type, a: T, b: T): T return a + b
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return add(u32, 2, 2) - add(int, 1, 3);
|
return add(u32, 2, 2) - add(int, 1, 3)
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### fb_driver
|
#### fb_driver
|
||||||
```hb
|
```hb
|
||||||
arm_fb_ptr := fn(): int return 100;
|
arm_fb_ptr := fn(): int return 100
|
||||||
x86_fb_ptr := fn(): int return 100;
|
x86_fb_ptr := fn(): int return 100
|
||||||
|
|
||||||
|
|
||||||
check_platform := fn(): int {
|
check_platform := fn(): int {
|
||||||
return x86_fb_ptr();
|
return x86_fb_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
set_pixel := fn(x: int, y: int, width: int): int {
|
set_pixel := fn(x: int, y: int, width: int): int {
|
||||||
pix_offset := y * width + x;
|
pix_offset := y * width + x
|
||||||
|
return 0
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
fb_ptr := check_platform();
|
fb_ptr := check_platform()
|
||||||
width := 100;
|
width := 100
|
||||||
height := 30;
|
height := 30
|
||||||
x:= 0;
|
x := 0
|
||||||
y:= 0;
|
y := 0
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
if x <= height + 1 {
|
if x <= height + 1 {
|
||||||
set_pixel(x,y,width);
|
set_pixel(x, y, width)
|
||||||
x = x + 1;
|
x += 1
|
||||||
} else {
|
} else {
|
||||||
set_pixel(x,y,width);
|
set_pixel(x, y, width)
|
||||||
x = 0;
|
x = 0
|
||||||
y = y + 1;
|
y += 1
|
||||||
}
|
}
|
||||||
if y == width {
|
if y == width {
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -490,33 +484,33 @@ main := fn(): int {
|
||||||
x: 0,
|
x: 0,
|
||||||
y: 2,
|
y: 2,
|
||||||
},
|
},
|
||||||
};
|
}
|
||||||
|
|
||||||
soupan := 1;
|
soupan := 1
|
||||||
if *(&pixel.point.x + soupan) != 2 {
|
if *(&pixel.point.x + soupan) != 2 {
|
||||||
return 0;
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
if *(&pixel.point.y - 1) != 0 {
|
if *(&pixel.point.y - 1) != 0 {
|
||||||
return 64;
|
return 64
|
||||||
}
|
}
|
||||||
|
|
||||||
return pixel.point.x + pixel.point.y + pixel.color.r
|
return pixel.point.x + pixel.point.y + pixel.color.r
|
||||||
+ pixel.color.g + pixel.color.b + pixel.color.a;
|
+ pixel.color.g + pixel.color.b + pixel.color.a
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### struct_return_from_module_function
|
#### struct_return_from_module_function
|
||||||
```hb
|
```hb
|
||||||
bar := @use("bar.hb");
|
bar := @use("bar.hb")
|
||||||
|
|
||||||
main := fn(): int {
|
main := fn(): int {
|
||||||
return 7 - bar.foo().x - bar.foo().y - bar.foo().z;
|
return 7 - bar.foo().x - bar.foo().y - bar.foo().z
|
||||||
}
|
}
|
||||||
|
|
||||||
// in module: bar.hb
|
// in module: bar.hb
|
||||||
|
|
||||||
foo := fn(): struct { x: int, y: u32, z: u32 } {
|
foo := fn(): struct {x: int, y: u32, z: u32} {
|
||||||
return .{ x: 3, y: 2, z: 2 };
|
return .{x: 3, y: 2, z: 2}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
|
@ -1382,7 +1382,13 @@ impl Codegen {
|
||||||
} else {
|
} else {
|
||||||
let values = captured
|
let values = captured
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&id| E::Ident { pos: 0, id, name: "booodab", index: u16::MAX })
|
.map(|&id| E::Ident {
|
||||||
|
pos: 0,
|
||||||
|
is_ct: false,
|
||||||
|
id,
|
||||||
|
name: "booodab",
|
||||||
|
index: u16::MAX,
|
||||||
|
})
|
||||||
.map(|expr| self.expr(&expr))
|
.map(|expr| self.expr(&expr))
|
||||||
.collect::<Option<Vec<_>>>()?;
|
.collect::<Option<Vec<_>>>()?;
|
||||||
let values_size =
|
let values_size =
|
||||||
|
@ -3221,7 +3227,9 @@ mod tests {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let input = find_block(input, ident);
|
let input = find_block(input, ident).trim();
|
||||||
|
|
||||||
|
parser::test::format(ident, input);
|
||||||
|
|
||||||
let mut module_map = Vec::new();
|
let mut module_map = Vec::new();
|
||||||
let mut last_start = 0;
|
let mut last_start = 0;
|
||||||
|
@ -3245,7 +3253,7 @@ mod tests {
|
||||||
let mut codegen = super::Codegen {
|
let mut codegen = super::Codegen {
|
||||||
files: module_map
|
files: module_map
|
||||||
.iter()
|
.iter()
|
||||||
.map(|&(path, content)| parser::Ast::new(path, content, &loader))
|
.map(|&(path, content)| parser::Ast::new(path, content, &loader, false))
|
||||||
.collect(),
|
.collect(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
};
|
};
|
||||||
|
|
|
@ -261,6 +261,18 @@ impl<'a> Lexer<'a> {
|
||||||
Some(c)
|
Some(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn last(&mut self) -> Token {
|
||||||
|
let mut token = self.next();
|
||||||
|
loop {
|
||||||
|
let next = self.next();
|
||||||
|
if next.kind == TokenKind::Eof {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
token = next;
|
||||||
|
}
|
||||||
|
token
|
||||||
|
}
|
||||||
|
|
||||||
pub fn next(&mut self) -> Token {
|
pub fn next(&mut self) -> Token {
|
||||||
use TokenKind as T;
|
use TokenKind as T;
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -424,7 +424,7 @@ pub fn parse_from_fs(extra_threads: usize, root: &str) -> io::Result<Vec<Ast>> {
|
||||||
let mut file = std::fs::File::open(path)?;
|
let mut file = std::fs::File::open(path)?;
|
||||||
file.read_to_end(buffer)?;
|
file.read_to_end(buffer)?;
|
||||||
let src = std::str::from_utf8(buffer).map_err(InvalidFileData)?;
|
let src = std::str::from_utf8(buffer).map_err(InvalidFileData)?;
|
||||||
Ok(Ast::new(path, src, &loader))
|
Ok(Ast::new(path, src, &loader, false))
|
||||||
};
|
};
|
||||||
|
|
||||||
let thread = || {
|
let thread = || {
|
||||||
|
@ -543,6 +543,33 @@ pub struct Options {
|
||||||
pub extra_threads: usize,
|
pub extra_threads: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn format_to(
|
||||||
|
ast: &parser::Ast,
|
||||||
|
source: &str,
|
||||||
|
out: &mut impl std::io::Write,
|
||||||
|
) -> std::io::Result<()> {
|
||||||
|
parser::with_fmt_source(source, || {
|
||||||
|
for (i, expr) in ast.exprs().iter().enumerate() {
|
||||||
|
write!(out, "{expr}")?;
|
||||||
|
if let Some(expr) = ast.exprs().get(i + 1)
|
||||||
|
&& let Some(rest) = source.get(expr.pos() as usize..)
|
||||||
|
{
|
||||||
|
if parser::insert_needed_semicolon(rest) {
|
||||||
|
write!(out, ";")?;
|
||||||
|
}
|
||||||
|
if parser::preserve_newlines(&source[..expr.pos() as usize]) > 1 {
|
||||||
|
writeln!(out)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if i + 1 != ast.exprs().len() {
|
||||||
|
writeln!(out)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::io::Result::Ok(())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn run_compiler(
|
pub fn run_compiler(
|
||||||
root_file: &str,
|
root_file: &str,
|
||||||
options: Options,
|
options: Options,
|
||||||
|
@ -550,30 +577,10 @@ pub fn run_compiler(
|
||||||
) -> io::Result<()> {
|
) -> io::Result<()> {
|
||||||
let parsed = parse_from_fs(options.extra_threads, root_file)?;
|
let parsed = parse_from_fs(options.extra_threads, root_file)?;
|
||||||
|
|
||||||
fn format_to(ast: &parser::Ast, out: &mut impl std::io::Write) -> std::io::Result<()> {
|
|
||||||
let source = std::fs::read_to_string(&*ast.path)?;
|
|
||||||
parser::with_fmt_source(&source, || {
|
|
||||||
for (i, expr) in ast.exprs().iter().enumerate() {
|
|
||||||
write!(out, "{expr}")?;
|
|
||||||
if let Some(expr) = ast.exprs().get(i + 1)
|
|
||||||
&& let Some(rest) = source.get(expr.pos() as usize..)
|
|
||||||
{
|
|
||||||
if parser::insert_needed_semicolon(rest) {
|
|
||||||
write!(out, ";")?;
|
|
||||||
}
|
|
||||||
for _ in 1..parser::preserve_newlines(&source[..expr.pos() as usize]) {
|
|
||||||
writeln!(out)?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
writeln!(out)?;
|
|
||||||
}
|
|
||||||
std::io::Result::Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn format_ast(ast: parser::Ast) -> std::io::Result<()> {
|
fn format_ast(ast: parser::Ast) -> std::io::Result<()> {
|
||||||
let mut output = Vec::new();
|
let mut output = Vec::new();
|
||||||
format_to(&ast, &mut output)?;
|
let source = std::fs::read_to_string(&*ast.path)?;
|
||||||
|
format_to(&ast, &source, &mut output)?;
|
||||||
std::fs::write(&*ast.path, output)?;
|
std::fs::write(&*ast.path, output)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -583,7 +590,9 @@ pub fn run_compiler(
|
||||||
format_ast(parsed)?;
|
format_ast(parsed)?;
|
||||||
}
|
}
|
||||||
} else if options.fmt_current {
|
} else if options.fmt_current {
|
||||||
format_to(&parsed.into_iter().next().unwrap(), &mut std::io::stdout())?;
|
let ast = parsed.into_iter().next().unwrap();
|
||||||
|
let source = std::fs::read_to_string(&*ast.path)?;
|
||||||
|
format_to(&ast, &source, &mut std::io::stdout())?;
|
||||||
} else {
|
} else {
|
||||||
let mut codegen = codegen::Codegen::default();
|
let mut codegen = codegen::Codegen::default();
|
||||||
codegen.files = parsed;
|
codegen.files = parsed;
|
||||||
|
|
|
@ -70,10 +70,16 @@ pub struct Parser<'a, 'b> {
|
||||||
trailing_sep: bool,
|
trailing_sep: bool,
|
||||||
idents: Vec<ScopeIdent>,
|
idents: Vec<ScopeIdent>,
|
||||||
captured: Vec<Ident>,
|
captured: Vec<Ident>,
|
||||||
|
loose: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'b> Parser<'a, 'b> {
|
impl<'a, 'b> Parser<'a, 'b> {
|
||||||
pub fn new(arena: &'b Arena<'a>, symbols: &'b mut Symbols, loader: Loader<'b>) -> Self {
|
pub fn new(
|
||||||
|
arena: &'b Arena<'a>,
|
||||||
|
symbols: &'b mut Symbols,
|
||||||
|
loader: Loader<'b>,
|
||||||
|
loose: bool,
|
||||||
|
) -> Self {
|
||||||
let mut lexer = Lexer::new("");
|
let mut lexer = Lexer::new("");
|
||||||
Self {
|
Self {
|
||||||
loader,
|
loader,
|
||||||
|
@ -86,6 +92,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
trailing_sep: false,
|
trailing_sep: false,
|
||||||
idents: Vec::new(),
|
idents: Vec::new(),
|
||||||
captured: Vec::new(),
|
captured: Vec::new(),
|
||||||
|
loose,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -213,7 +220,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let index = self.idents.binary_search_by_key(&id, |s| s.ident).expect("fck up");
|
let index = self.idents.binary_search_by_key(&id, |s| s.ident).expect("fck up");
|
||||||
if std::mem::replace(&mut self.idents[index].declared, true) {
|
if std::mem::replace(&mut self.idents[index].declared, true) && !self.loose {
|
||||||
self.report_pos(
|
self.report_pos(
|
||||||
pos,
|
pos,
|
||||||
format_args!("redeclaration of identifier: {}", self.lexer.slice(ident::range(id))),
|
format_args!("redeclaration of identifier: {}", self.lexer.slice(ident::range(id))),
|
||||||
|
@ -316,11 +323,12 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
}
|
}
|
||||||
token.start
|
token.start
|
||||||
},
|
},
|
||||||
|
trailing_comma: std::mem::take(&mut self.trailing_sep),
|
||||||
},
|
},
|
||||||
T::Ident | T::CtIdent => {
|
T::Ident | T::CtIdent => {
|
||||||
let (id, index) = self.resolve_ident(token);
|
let (id, index) = self.resolve_ident(token);
|
||||||
let name = self.move_str(token);
|
let name = self.move_str(token);
|
||||||
E::Ident { pos: token.start, name, id, index }
|
E::Ident { pos: token.start, is_ct: token.kind == T::CtIdent, name, id, index }
|
||||||
}
|
}
|
||||||
T::If => E::If {
|
T::If => E::If {
|
||||||
pos: token.start,
|
pos: token.start,
|
||||||
|
@ -348,7 +356,13 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
let (id, index) = s.resolve_ident(name);
|
let (id, index) = s.resolve_ident(name);
|
||||||
s.declare(name.start, id, None);
|
s.declare(name.start, id, None);
|
||||||
s.expect_advance(T::Colon);
|
s.expect_advance(T::Colon);
|
||||||
Arg { name: s.move_str(name), id, index, ty: s.expr() }
|
Arg {
|
||||||
|
name: s.move_str(name),
|
||||||
|
is_ct: name.kind == T::CtIdent,
|
||||||
|
id,
|
||||||
|
index,
|
||||||
|
ty: s.expr(),
|
||||||
|
}
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
ret: {
|
ret: {
|
||||||
|
@ -461,7 +475,7 @@ impl<'a, 'b> Parser<'a, 'b> {
|
||||||
s.expr()
|
s.expr()
|
||||||
} else {
|
} else {
|
||||||
let (id, index) = s.resolve_ident(name_tok);
|
let (id, index) = s.resolve_ident(name_tok);
|
||||||
Expr::Ident { pos: name_tok.start, id, name, index }
|
Expr::Ident { pos: name_tok.start, is_ct: false, id, name, index }
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
@ -566,6 +580,7 @@ pub fn find_symbol(symbols: &[Symbol], id: Ident) -> &Symbol {
|
||||||
pub struct Arg<'a> {
|
pub struct Arg<'a> {
|
||||||
pub name: &'a str,
|
pub name: &'a str,
|
||||||
pub id: Ident,
|
pub id: Ident,
|
||||||
|
pub is_ct: bool,
|
||||||
pub index: IdentIndex,
|
pub index: IdentIndex,
|
||||||
pub ty: Expr<'a>,
|
pub ty: Expr<'a>,
|
||||||
}
|
}
|
||||||
|
@ -592,19 +607,21 @@ macro_rules! generate_expr {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn used_bytes(&self) -> usize {
|
pub fn used_bytes(&self) -> usize {
|
||||||
match self {$(
|
match self {$(
|
||||||
Self::$variant { $($field,)* } => {
|
Self::$variant { $($field,)* } => {
|
||||||
#[allow(clippy::size_of_ref)]
|
#[allow(clippy::size_of_ref)]
|
||||||
let fields = [$(($field as *const _ as usize - self as *const _ as usize, std::mem::size_of_val($field)),)*];
|
let fields = [$(($field as *const _ as usize - self as *const _ as usize, std::mem::size_of_val($field)),)*];
|
||||||
let (last, size) = fields.iter().copied().max().unwrap();
|
let (last, size) = fields.iter().copied().max().unwrap();
|
||||||
last + size
|
last + size
|
||||||
},
|
},
|
||||||
)*}
|
)*}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
(@filed_names $variant:ident $ident1:ident) => { Self::$variant { $ident1: a } };
|
||||||
|
|
||||||
(@first ($($first:tt)*), $($rest:tt)*) => { $($first)* };
|
(@first ($($first:tt)*), $($rest:tt)*) => { $($first)* };
|
||||||
(@last ($($ign:tt)*), $($rest:tt)*) => { $($rest)* };
|
(@last ($($ign:tt)*), $($rest:tt)*) => { $($rest)* };
|
||||||
(@last ($($last:tt)*),) => { $($last)* };
|
(@last ($($last:tt)*),) => { $($last)* };
|
||||||
|
@ -616,7 +633,7 @@ generate_expr! {
|
||||||
pub enum Expr<'a> {
|
pub enum Expr<'a> {
|
||||||
Ct {
|
Ct {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
value: &'a Expr<'a>,
|
value: &'a Self,
|
||||||
},
|
},
|
||||||
String {
|
String {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
|
@ -649,6 +666,7 @@ generate_expr! {
|
||||||
},
|
},
|
||||||
Ident {
|
Ident {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
|
is_ct: bool,
|
||||||
id: Ident,
|
id: Ident,
|
||||||
name: &'a str,
|
name: &'a str,
|
||||||
index: IdentIndex,
|
index: IdentIndex,
|
||||||
|
@ -685,6 +703,7 @@ generate_expr! {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
fields: &'a [(&'a str, Self)],
|
fields: &'a [(&'a str, Self)],
|
||||||
captured: &'a [Ident],
|
captured: &'a [Ident],
|
||||||
|
trailing_comma: bool,
|
||||||
},
|
},
|
||||||
Ctor {
|
Ctor {
|
||||||
pos: Pos,
|
pos: Pos,
|
||||||
|
@ -809,6 +828,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
thread_local! {
|
thread_local! {
|
||||||
static INDENT: Cell<usize> = const { Cell::new(0) };
|
static INDENT: Cell<usize> = const { Cell::new(0) };
|
||||||
|
static DISPLAY_BUFFER: Cell<String> = const { Cell::new(String::new()) };
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fmt_list<T>(
|
fn fmt_list<T>(
|
||||||
|
@ -874,7 +894,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
Consecutive => Expr::UnOp { .. },
|
Consecutive => Expr::UnOp { .. },
|
||||||
}
|
}
|
||||||
|
|
||||||
let source = unsafe { &*FMT_SOURCE.with(|s| s.get()) };
|
let source: &str = unsafe { &*FMT_SOURCE.with(|s| s.get()) };
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
Self::Ct { value, .. } => write!(f, "$: {}", value),
|
Self::Ct { value, .. } => write!(f, "$: {}", value),
|
||||||
|
@ -886,9 +906,11 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
write!(f, "@{name}(")?;
|
write!(f, "@{name}(")?;
|
||||||
fmt_list(f, false, ")", args, std::fmt::Display::fmt)
|
fmt_list(f, false, ")", args, std::fmt::Display::fmt)
|
||||||
}
|
}
|
||||||
Self::Struct { fields, .. } => {
|
Self::Struct { fields, trailing_comma, .. } => {
|
||||||
write!(f, "struct {{")?;
|
write!(f, "struct {{")?;
|
||||||
fmt_list(f, true, "}", fields, |(name, val), f| write!(f, "{name}: {val}",))
|
fmt_list(f, trailing_comma, "}", fields, |(name, val), f| {
|
||||||
|
write!(f, "{name}: {val}",)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
Self::Ctor { ty, fields, trailing_comma, .. } => {
|
Self::Ctor { ty, fields, trailing_comma, .. } => {
|
||||||
if let Some(ty) = ty {
|
if let Some(ty) = ty {
|
||||||
|
@ -912,8 +934,8 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
fmt_list(f, trailing_comma, ")", fields, std::fmt::Display::fmt)
|
fmt_list(f, trailing_comma, ")", fields, std::fmt::Display::fmt)
|
||||||
}
|
}
|
||||||
Self::Slice { item, size, .. } => match size {
|
Self::Slice { item, size, .. } => match size {
|
||||||
Some(size) => write!(f, "[{size}]{item}"),
|
Some(size) => write!(f, "[{item}; {size}]"),
|
||||||
None => write!(f, "[]{item}"),
|
None => write!(f, "[{item}]"),
|
||||||
},
|
},
|
||||||
Self::Index { base, index } => write!(f, "{base}[{index}]"),
|
Self::Index { base, index } => write!(f, "{base}[{index}]"),
|
||||||
Self::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)),
|
Self::UnOp { op, val, .. } => write!(f, "{op}{}", Unary(val)),
|
||||||
|
@ -929,7 +951,12 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
Self::Loop { body, .. } => write!(f, "loop {body}"),
|
Self::Loop { body, .. } => write!(f, "loop {body}"),
|
||||||
Self::Closure { ret, body, args, .. } => {
|
Self::Closure { ret, body, args, .. } => {
|
||||||
write!(f, "fn(")?;
|
write!(f, "fn(")?;
|
||||||
fmt_list(f, false, "", args, |arg, f| write!(f, "{}: {}", arg.name, arg.ty))?;
|
fmt_list(f, false, "", args, |arg, f| {
|
||||||
|
if arg.is_ct {
|
||||||
|
write!(f, "$")?;
|
||||||
|
}
|
||||||
|
write!(f, "{}: {}", arg.name, arg.ty)
|
||||||
|
})?;
|
||||||
write!(f, "): {ret} {body}")?;
|
write!(f, "): {ret} {body}")?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -939,7 +966,8 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
}
|
}
|
||||||
Self::Return { val: Some(val), .. } => write!(f, "return {val}"),
|
Self::Return { val: Some(val), .. } => write!(f, "return {val}"),
|
||||||
Self::Return { val: None, .. } => write!(f, "return"),
|
Self::Return { val: None, .. } => write!(f, "return"),
|
||||||
Self::Ident { name, .. } => write!(f, "{name}"),
|
Self::Ident { name, is_ct: true, .. } => write!(f, "${name}"),
|
||||||
|
Self::Ident { name, is_ct: false, .. } => write!(f, "{name}"),
|
||||||
Self::Block { stmts, .. } => {
|
Self::Block { stmts, .. } => {
|
||||||
write!(f, "{{")?;
|
write!(f, "{{")?;
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
|
@ -956,7 +984,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
if insert_needed_semicolon(rest) {
|
if insert_needed_semicolon(rest) {
|
||||||
write!(f, ";")?;
|
write!(f, ";")?;
|
||||||
}
|
}
|
||||||
for _ in 1..preserve_newlines(&source[..expr.pos() as usize]) {
|
if preserve_newlines(&source[..expr.pos() as usize]) > 1 {
|
||||||
writeln!(f)?;
|
writeln!(f)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -974,13 +1002,25 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
Self::Number { value, .. } => write!(f, "{value}"),
|
Self::Number { value, .. } => write!(f, "{value}"),
|
||||||
Self::Bool { value, .. } => write!(f, "{value}"),
|
Self::Bool { value, .. } => write!(f, "{value}"),
|
||||||
Self::BinOp {
|
Self::BinOp {
|
||||||
left: left @ Self::Ident { id, .. },
|
left,
|
||||||
op: TokenKind::Assign,
|
op: TokenKind::Assign,
|
||||||
right: Self::BinOp { left: Self::Ident { id: oid, .. }, op, right },
|
right: Self::BinOp { left: lleft, op, right },
|
||||||
} if id == oid => {
|
} if DISPLAY_BUFFER.with(|cb| {
|
||||||
|
use std::fmt::Write;
|
||||||
|
let mut b = cb.take();
|
||||||
|
write!(b, "{lleft}").unwrap();
|
||||||
|
let len = b.len();
|
||||||
|
write!(b, "{left}").unwrap();
|
||||||
|
let (lleft, left) = b.split_at(len);
|
||||||
|
let res = lleft == left;
|
||||||
|
b.clear();
|
||||||
|
cb.set(b);
|
||||||
|
res
|
||||||
|
}) =>
|
||||||
|
{
|
||||||
write!(f, "{left} {op}= {right}")
|
write!(f, "{left} {op}= {right}")
|
||||||
}
|
}
|
||||||
Self::BinOp { left, right, op } => {
|
Self::BinOp { right, op, left } => {
|
||||||
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
|
let display_branch = |f: &mut std::fmt::Formatter, expr: &Self| {
|
||||||
if let Self::BinOp { op: lop, .. } = expr
|
if let Self::BinOp { op: lop, .. } = expr
|
||||||
&& op.precedence() > lop.precedence()
|
&& op.precedence() > lop.precedence()
|
||||||
|
@ -992,7 +1032,24 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
};
|
};
|
||||||
|
|
||||||
display_branch(f, left)?;
|
display_branch(f, left)?;
|
||||||
write!(f, " {op} ")?;
|
if let Some(mut prev) = source.get(..right.pos() as usize) {
|
||||||
|
prev = prev.trim_end();
|
||||||
|
let estimate_bound =
|
||||||
|
prev.rfind(|c: char| c.is_ascii_whitespace()).map_or(prev.len(), |i| i + 1);
|
||||||
|
let exact_bound = lexer::Lexer::new(&prev[estimate_bound..]).last().start;
|
||||||
|
prev = &prev[..exact_bound as usize + estimate_bound];
|
||||||
|
if preserve_newlines(prev) > 0 {
|
||||||
|
writeln!(f)?;
|
||||||
|
for _ in 0..INDENT.with(|i| i.get()) + 1 {
|
||||||
|
write!(f, "\t")?;
|
||||||
|
}
|
||||||
|
write!(f, "{op} ")?;
|
||||||
|
} else {
|
||||||
|
write!(f, " {op} ")?;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
write!(f, " {op} ")?;
|
||||||
|
}
|
||||||
display_branch(f, right)
|
display_branch(f, right)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,8 +1057,7 @@ impl<'a> std::fmt::Display for Expr<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn preserve_newlines(source: &str) -> usize {
|
pub fn preserve_newlines(source: &str) -> usize {
|
||||||
let trailing_whitespace = &source[source.trim_end().len()..];
|
source[source.trim_end().len()..].chars().filter(|&c| c == '\n').count()
|
||||||
trailing_whitespace.chars().filter(|&c| c == '\n').count().min(2)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn insert_needed_semicolon(source: &str) -> bool {
|
pub fn insert_needed_semicolon(source: &str) -> bool {
|
||||||
|
@ -1028,10 +1084,10 @@ impl AstInner<[Symbol]> {
|
||||||
.0
|
.0
|
||||||
}
|
}
|
||||||
|
|
||||||
fn new(content: &str, path: &str, loader: Loader) -> NonNull<Self> {
|
fn new(content: &str, path: &str, loader: Loader, loose: bool) -> NonNull<Self> {
|
||||||
let arena = Arena::default();
|
let arena = Arena::default();
|
||||||
let mut syms = Vec::new();
|
let mut syms = Vec::new();
|
||||||
let mut parser = Parser::new(&arena, &mut syms, loader);
|
let mut parser = Parser::new(&arena, &mut syms, loader, loose);
|
||||||
let exprs = parser.file(content, path) as *const [Expr<'static>];
|
let exprs = parser.file(content, path) as *const [Expr<'static>];
|
||||||
|
|
||||||
syms.sort_unstable_by_key(|s| s.name);
|
syms.sort_unstable_by_key(|s| s.name);
|
||||||
|
@ -1063,8 +1119,8 @@ impl AstInner<[Symbol]> {
|
||||||
pub struct Ast(NonNull<AstInner<[Symbol]>>);
|
pub struct Ast(NonNull<AstInner<[Symbol]>>);
|
||||||
|
|
||||||
impl Ast {
|
impl Ast {
|
||||||
pub fn new(path: &str, content: &str, loader: Loader) -> Self {
|
pub fn new(path: &str, content: &str, loader: Loader, loose: bool) -> Self {
|
||||||
Self(AstInner::new(content, path, loader))
|
Self(AstInner::new(content, path, loader, loose))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exprs(&self) -> &[Expr] {
|
pub fn exprs(&self) -> &[Expr] {
|
||||||
|
@ -1094,7 +1150,7 @@ impl std::fmt::Display for Ast {
|
||||||
|
|
||||||
impl Default for Ast {
|
impl Default for Ast {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self(AstInner::new("", "", &no_loader))
|
Self(AstInner::new("", "", &no_loader, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1268,16 +1324,11 @@ impl Drop for ArenaChunk {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
pub mod test {
|
||||||
fn format(ident: &str, input: &str) {
|
pub fn format(ident: &str, input: &str) {
|
||||||
let ast = super::Ast::new(ident, input, &super::no_loader);
|
let ast = super::Ast::new(ident, input, &|_, _| Ok(0), true);
|
||||||
let mut output = String::new();
|
let mut output = Vec::new();
|
||||||
super::with_fmt_source(input, || {
|
crate::format_to(&ast, input, &mut output).unwrap();
|
||||||
for expr in ast.exprs() {
|
|
||||||
use std::fmt::Write;
|
|
||||||
writeln!(output, "{expr}").unwrap();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let input_path = format!("formatter_{ident}.expected");
|
let input_path = format!("formatter_{ident}.expected");
|
||||||
let output_path = format!("formatter_{ident}.actual");
|
let output_path = format!("formatter_{ident}.actual");
|
||||||
|
@ -1308,13 +1359,13 @@ mod test {
|
||||||
|
|
||||||
test! {
|
test! {
|
||||||
comments => "// comment\n// comment\n\n// comment\n\n\
|
comments => "// comment\n// comment\n\n// comment\n\n\
|
||||||
/* comment */\n/* comment */\n\n/* comment */\n";
|
/* comment */\n/* comment */\n\n/* comment */";
|
||||||
some_ordinary_code => "loft := fn(): int return loft(1, 2, 3);\n";
|
some_ordinary_code => "loft := fn(): int return loft(1, 2, 3)";
|
||||||
some_arg_per_line_code => "loft := fn(): int return loft(\
|
some_arg_per_line_code => "loft := fn(): int return loft(\
|
||||||
\n\t1,\n\t2,\n\t3,\n);\n";
|
\n\t1,\n\t2,\n\t3,\n)";
|
||||||
some_ordinary_struct => "loft := fn(): int return loft.{a: 1, b: 2};\n";
|
some_ordinary_struct => "loft := fn(): int return loft.{a: 1, b: 2}";
|
||||||
some_ordinary_fild_per_lin_struct => "loft := fn(): int return loft.{\
|
some_ordinary_fild_per_lin_struct => "loft := fn(): int return loft.{\
|
||||||
\n\ta: 1,\n\tb: 2,\n};\n";
|
\n\ta: 1,\n\tb: 2,\n}";
|
||||||
code_block => "loft := fn(): int {\n\tloft();\n\treturn 1;\n}\n";
|
code_block => "loft := fn(): int {\n\tloft()\n\treturn 1\n}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
code size: 1503
|
code size: 1504
|
||||||
ret: 69
|
ret: 69
|
||||||
status: Ok(())
|
status: Ok(())
|
||||||
|
|
Loading…
Reference in a new issue