mirror of
https://github.com/odin-lang/Odin.git
synced 2026-02-15 15:44:04 +00:00
Update and regression test old demos
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
set exe_name=odin.exe
|
||||
|
||||
:: Debug = 0, Release = 1
|
||||
set release_mode=1
|
||||
set release_mode=0
|
||||
set compiler_flags= -nologo -Oi -TC -fp:fast -fp:except- -Gm- -MP -FC -GS- -EHsc- -GR-
|
||||
|
||||
if %release_mode% EQU 0 ( rem Debug
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "win32.odin" when ODIN_OS == "windows";
|
||||
#import win32 "sys/windows.odin" when ODIN_OS == "windows";
|
||||
#import wgl "sys/wgl.odin" when ODIN_OS == "windows";
|
||||
#import "fmt.odin";
|
||||
#import "math.odin";
|
||||
#import "os.odin";
|
||||
@@ -12,11 +13,11 @@ time_now :: proc() -> f64 {
|
||||
|
||||
counter: i64;
|
||||
win32.QueryPerformanceCounter(^counter);
|
||||
result := counter as f64 / win32_perf_count_freq as f64;
|
||||
result := cast(f64)counter / cast(f64)win32_perf_count_freq;
|
||||
return result;
|
||||
}
|
||||
win32_print_last_error :: proc() {
|
||||
err_code := win32.GetLastError() as int;
|
||||
err_code := cast(int)win32.GetLastError();
|
||||
if err_code != 0 {
|
||||
fmt.println("GetLastError: %", err_code);
|
||||
}
|
||||
@@ -24,42 +25,42 @@ win32_print_last_error :: proc() {
|
||||
|
||||
// Yuk!
|
||||
to_c_string :: proc(s: string) -> []u8 {
|
||||
c_str := new_slice(u8, s.count+1);
|
||||
copy(c_str, s as []byte);
|
||||
c_str[s.count] = 0;
|
||||
c_str := make([]u8, len(s)+1);
|
||||
copy(c_str, cast([]byte)s);
|
||||
c_str[len(s)] = 0;
|
||||
return c_str;
|
||||
}
|
||||
|
||||
|
||||
Window :: struct {
|
||||
width, height: int;
|
||||
wc: win32.WNDCLASSEXA;
|
||||
dc: win32.HDC;
|
||||
hwnd: win32.HWND;
|
||||
opengl_context, rc: win32.HGLRC;
|
||||
c_title: []u8;
|
||||
width, height: int,
|
||||
wc: win32.WndClassExA,
|
||||
dc: win32.Hdc,
|
||||
hwnd: win32.Hwnd,
|
||||
opengl_context, rc: wgl.Hglrc,
|
||||
c_title: []u8,
|
||||
}
|
||||
|
||||
make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC) -> (Window, bool) {
|
||||
make_window :: proc(title: string, msg, height: int, window_proc: win32.Wnd_Proc) -> (Window, bool) {
|
||||
using win32;
|
||||
|
||||
w: Window;
|
||||
w.width, w.height = msg, height;
|
||||
|
||||
class_name := "Win32-Odin-Window\x00";
|
||||
c_class_name := class_name.data;
|
||||
if title[title.count-1] != 0 {
|
||||
c_class_name := ^class_name[0];
|
||||
if title[len(title)-1] != 0 {
|
||||
w.c_title = to_c_string(title);
|
||||
} else {
|
||||
w.c_title = title as []u8;
|
||||
w.c_title = cast([]u8)title;
|
||||
}
|
||||
|
||||
instance := GetModuleHandleA(nil);
|
||||
|
||||
w.wc = WNDCLASSEXA{
|
||||
size = size_of(WNDCLASSEXA) as u32,
|
||||
w.wc = WndClassExA{
|
||||
size = size_of(WndClassExA),
|
||||
style = CS_VREDRAW | CS_HREDRAW,
|
||||
instance = instance as HINSTANCE,
|
||||
instance = cast(Hinstance)instance,
|
||||
class_name = c_class_name,
|
||||
wnd_proc = window_proc,
|
||||
};
|
||||
@@ -70,10 +71,10 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
||||
}
|
||||
|
||||
w.hwnd = CreateWindowExA(0,
|
||||
c_class_name, w.c_title.data,
|
||||
c_class_name, ^w.c_title[0],
|
||||
WS_VISIBLE | WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||
CW_USEDEFAULT, CW_USEDEFAULT,
|
||||
w.width as i32, w.height as i32,
|
||||
cast(i32)w.width, cast(i32)w.height,
|
||||
nil, nil, instance, nil);
|
||||
|
||||
if w.hwnd == nil {
|
||||
@@ -85,7 +86,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
||||
|
||||
{
|
||||
pfd := PIXELFORMATDESCRIPTOR{
|
||||
size = size_of(PIXELFORMATDESCRIPTOR) as u32,
|
||||
size = size_of(PIXELFORMATDESCRIPTOR),
|
||||
version = 1,
|
||||
flags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
|
||||
pixel_type = PFD_TYPE_RGBA,
|
||||
@@ -97,19 +98,20 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
||||
};
|
||||
|
||||
SetPixelFormat(w.dc, ChoosePixelFormat(w.dc, ^pfd), nil);
|
||||
w.opengl_context = wglCreateContext(w.dc);
|
||||
wglMakeCurrent(w.dc, w.opengl_context);
|
||||
w.opengl_context = wgl.CreateContext(w.dc);
|
||||
wgl.MakeCurrent(w.dc, w.opengl_context);
|
||||
|
||||
attribs := [8]i32{
|
||||
WGL_CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||
WGL_CONTEXT_MINOR_VERSION_ARB, 1,
|
||||
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||
wgl.CONTEXT_MAJOR_VERSION_ARB, 2,
|
||||
wgl.CONTEXT_MINOR_VERSION_ARB, 1,
|
||||
wgl.CONTEXT_PROFILE_MASK_ARB, wgl.CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
|
||||
0, // NOTE(bill): tells the proc that this is the end of attribs
|
||||
};
|
||||
|
||||
wglCreateContextAttribsARB := wglGetProcAddress(("wglCreateContextAttribsARB\x00" as string).data) as wglCreateContextAttribsARBType;
|
||||
w.rc = wglCreateContextAttribsARB(w.dc, 0, ^attribs[0]);
|
||||
wglMakeCurrent(w.dc, w.rc);
|
||||
wgl_str := "wglCreateContextAttribsARB\x00";
|
||||
wglCreateContextAttribsARB := cast(wgl.Create_Context_Attribs_ARB_Type)wgl.GetProcAddress(^wgl_str[0]);
|
||||
w.rc = wglCreateContextAttribsARB(w.dc, nil, ^attribs[0]);
|
||||
wgl.MakeCurrent(w.dc, w.rc);
|
||||
SwapBuffers(w.dc);
|
||||
}
|
||||
|
||||
@@ -117,7 +119,7 @@ make_window :: proc(title: string, msg, height: int, window_proc: win32.WNDPROC)
|
||||
}
|
||||
|
||||
destroy_window :: proc(w: ^Window) {
|
||||
free(w.c_title.data);
|
||||
free(w.c_title);
|
||||
}
|
||||
|
||||
display_window :: proc(w: ^Window) {
|
||||
@@ -129,7 +131,7 @@ run :: proc() {
|
||||
using win32;
|
||||
using math;
|
||||
|
||||
win32_proc :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #no_inline {
|
||||
win32_proc :: proc(hwnd: win32.Hwnd, msg: u32, wparam: win32.Wparam, lparam: win32.Lparam) -> win32.Lresult #no_inline {
|
||||
if msg == WM_DESTROY || msg == WM_CLOSE || msg == WM_QUIT {
|
||||
os.exit(0);
|
||||
return 0;
|
||||
@@ -137,7 +139,7 @@ run :: proc() {
|
||||
return DefWindowProcA(hwnd, msg, wparam, lparam);
|
||||
}
|
||||
|
||||
window, window_success := make_window("Odin Language Demo", 854, 480, win32_proc);
|
||||
window, window_success := make_window("Odin Language Demo", 854, 480, cast(Wnd_Proc)win32_proc);
|
||||
if !window_success {
|
||||
return;
|
||||
}
|
||||
@@ -153,10 +155,10 @@ run :: proc() {
|
||||
|
||||
for running {
|
||||
curr_time := time_now();
|
||||
dt := (curr_time - prev_time) as f32;
|
||||
dt := cast(f32)(curr_time - prev_time);
|
||||
prev_time = curr_time;
|
||||
|
||||
msg: MSG;
|
||||
msg: Msg;
|
||||
for PeekMessageA(^msg, nil, 0, 0, PM_REMOVE) > 0 {
|
||||
if msg.message == WM_QUIT {
|
||||
running = false;
|
||||
@@ -178,7 +180,7 @@ run :: proc() {
|
||||
if is_key_down(Key_Code.UP) { v[1] += 1; }
|
||||
if is_key_down(Key_Code.DOWN) { v[1] -= 1; }
|
||||
|
||||
v = vec2_norm0(v);
|
||||
v = norm(v);
|
||||
|
||||
pos += v * Vec2{SPEED * dt};
|
||||
}
|
||||
@@ -188,8 +190,8 @@ run :: proc() {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
gl.LoadIdentity();
|
||||
gl.Ortho(0, window.width as f64,
|
||||
0, window.height as f64, 0, 1);
|
||||
gl.Ortho(0, cast(f64)window.width,
|
||||
0, cast(f64)window.height, 0, 1);
|
||||
|
||||
draw_rect :: proc(x, y, w, h: f32) {
|
||||
gl.Begin(gl.TRIANGLES);
|
||||
@@ -207,9 +209,14 @@ run :: proc() {
|
||||
draw_rect(pos.x, pos.y, 50, 50);
|
||||
|
||||
display_window(^window);
|
||||
ms_to_sleep := (16 - 1000*dt) as i32;
|
||||
ms_to_sleep := cast(i32)(16 - 1000*dt);
|
||||
if ms_to_sleep > 0 {
|
||||
win32.Sleep(ms_to_sleep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
main :: proc() {
|
||||
run();
|
||||
}
|
||||
|
||||
@@ -136,7 +136,7 @@ bounds_checking :: proc() {
|
||||
|
||||
{
|
||||
base: [10]int;
|
||||
s := base[2:6];
|
||||
s := base[2..6];
|
||||
a, b := -1, 6;
|
||||
|
||||
#no_bounds_check {
|
||||
@@ -164,7 +164,7 @@ type_introspection :: proc() {
|
||||
info = type_info_of_val(x); // by value
|
||||
// See: runtime.odin
|
||||
|
||||
match type i in info {
|
||||
match i in info {
|
||||
case Type_Info.Integer:
|
||||
fmt.println("integer!");
|
||||
case Type_Info.Float:
|
||||
@@ -174,7 +174,7 @@ type_introspection :: proc() {
|
||||
}
|
||||
|
||||
// Unsafe cast
|
||||
integer_info := cast(^Type_Info.Integer)info;
|
||||
integer_info := cast(^Type_Info.Integer)cast(rawptr)info;
|
||||
}
|
||||
|
||||
{
|
||||
@@ -263,12 +263,12 @@ crazy_introspection :: proc() {
|
||||
}
|
||||
|
||||
fruit_ti := type_info(Fruit);
|
||||
name := (cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
|
||||
info := cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
|
||||
name := (union_cast(^Type_Info.Named)fruit_ti).name; // Unsafe casts
|
||||
info, _ := union_cast(^Type_Info.Enum)type_info_base(fruit_ti); // Unsafe casts
|
||||
|
||||
fmt.printf("% :: enum % {\n", name, info.base);
|
||||
for i := 0; i < info.values.count; i += 1 {
|
||||
fmt.printf("\t%\t= %,\n", info.names[i], info.values[i]);
|
||||
fmt.printf("%s :: enum %T {\n", name, info.base);
|
||||
for i := 0; i < len(info.values); i++ {
|
||||
fmt.printf("\t%s\t= %v,\n", info.names[i], info.values[i]);
|
||||
}
|
||||
fmt.printf("}\n");
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,14 @@
|
||||
#import "fmt.odin"
|
||||
#import "utf8.odin"
|
||||
#import "hash.odin"
|
||||
#import "mem.odin"
|
||||
#import "fmt.odin";
|
||||
#import "utf8.odin";
|
||||
#import "hash.odin";
|
||||
#import "mem.odin";
|
||||
|
||||
main :: proc() {
|
||||
{ // New Standard Library stuff
|
||||
s := "Hello"
|
||||
s := "Hello";
|
||||
fmt.println(s,
|
||||
utf8.valid_string(s),
|
||||
hash.murmur64(s.data, s.count))
|
||||
hash.murmur64(cast([]byte)s));
|
||||
|
||||
// utf8.odin
|
||||
// hash.odin
|
||||
@@ -19,15 +19,15 @@ main :: proc() {
|
||||
}
|
||||
|
||||
{
|
||||
arena: mem.Arena
|
||||
mem.init_arena_from_context(^arena, mem.megabytes(16)) // Uses default allocator
|
||||
defer mem.free_arena(^arena)
|
||||
arena: mem.Arena;
|
||||
mem.init_arena_from_context(^arena, mem.megabytes(16)); // Uses default allocator
|
||||
defer mem.free_arena(^arena);
|
||||
|
||||
push_allocator mem.arena_allocator(^arena) {
|
||||
x := new(int)
|
||||
x^ = 1337
|
||||
x := new(int);
|
||||
x^ = 1337;
|
||||
|
||||
fmt.println(x^)
|
||||
fmt.println(x^);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -48,14 +48,14 @@ main :: proc() {
|
||||
|
||||
// You can also "push" a context
|
||||
|
||||
c := current_context() // Create copy of the allocator
|
||||
c.allocator = mem.arena_allocator(^arena)
|
||||
c := context; // Create copy of the allocator
|
||||
c.allocator = mem.arena_allocator(^arena);
|
||||
|
||||
push_context c {
|
||||
x := new(int)
|
||||
x^ = 365
|
||||
x := new(int);
|
||||
x^ = 365;
|
||||
|
||||
fmt.println(x^)
|
||||
fmt.println(x^);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,12 +42,12 @@ syntax :: proc() {
|
||||
};
|
||||
Thing2 :: struct {x: f32, y: int, z: ^[]int};
|
||||
|
||||
// Slice interals are now just a `ptr+count`
|
||||
slice: []int; compile_assert(size_of_val(slice) == 2*size_of(int));
|
||||
// Slice interals are now just a `ptr+len+cap`
|
||||
slice: []int; compile_assert(size_of_val(slice) == 3*size_of(int));
|
||||
|
||||
// Helper type - Help the reader understand what it is quicker
|
||||
My_Int :: type int;
|
||||
My_Proc :: type proc(int) -> f32;
|
||||
My_Int :: #type int;
|
||||
My_Proc :: #type proc(int) -> f32;
|
||||
|
||||
|
||||
// All declarations with : are either variable or constant
|
||||
@@ -59,6 +59,7 @@ syntax :: proc() {
|
||||
c_proc :: proc() { /* code here */ };
|
||||
|
||||
|
||||
/*
|
||||
x += 1;
|
||||
x -= 1;
|
||||
// ++ and -- have been removed
|
||||
@@ -67,7 +68,7 @@ syntax :: proc() {
|
||||
// Question: Should they be added again?
|
||||
// They were removed as they are redundant and statements, not expressions
|
||||
// like in C/C++
|
||||
|
||||
*/
|
||||
|
||||
// You can now build files as a `.dll`
|
||||
// `odin build_dll demo.odin`
|
||||
@@ -85,7 +86,7 @@ syntax :: proc() {
|
||||
|
||||
Prefix_Type :: struct {x: int, y: f32, z: rawptr};
|
||||
|
||||
thread_local my_tls: Prefix_Type;
|
||||
#thread_local my_tls: Prefix_Type;
|
||||
|
||||
prefixes :: proc() {
|
||||
using var: Prefix_Type;
|
||||
@@ -98,7 +99,7 @@ prefixes :: proc() {
|
||||
|
||||
foo :: proc(using immutable pt: Prefix_Type, immutable int_ptr: ^int) {
|
||||
// int_ptr = nil; // Not valid
|
||||
int_ptr^ = 123; // Is valid
|
||||
// int_ptr^ = 123; // Not valid
|
||||
}
|
||||
|
||||
|
||||
@@ -154,6 +155,7 @@ foreign_procedures :: proc() {
|
||||
}
|
||||
|
||||
special_expressions :: proc() {
|
||||
/*
|
||||
// Block expression
|
||||
x := {
|
||||
a: f32 = 123;
|
||||
@@ -168,7 +170,7 @@ special_expressions :: proc() {
|
||||
// TODO: Type cohesion is not yet finished
|
||||
give 123;
|
||||
}; // semicolon is required as it's an expression
|
||||
|
||||
*/
|
||||
|
||||
// This is allows for inline blocks of code and will be a useful feature to have when
|
||||
// macros will be implemented into the language
|
||||
@@ -191,17 +193,17 @@ loops :: proc() {
|
||||
break;
|
||||
}
|
||||
|
||||
for i in 0..<123 { // 123 exclusive
|
||||
for i in 0..123 { // 123 exclusive
|
||||
}
|
||||
|
||||
for i in 0...122 { // 122 inclusive
|
||||
for i in 0..123-1 { // 122 inclusive
|
||||
}
|
||||
|
||||
for val, idx in 12..<16 {
|
||||
for val, idx in 12..16 {
|
||||
fmt.println(val, idx);
|
||||
}
|
||||
|
||||
primes := [...]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||
primes := [..]int{2, 3, 5, 7, 11, 13, 17, 19};
|
||||
|
||||
for p in primes {
|
||||
fmt.println(p);
|
||||
@@ -224,7 +226,7 @@ loops :: proc() {
|
||||
when false {
|
||||
for i, size := 0; i < name.count; i += size {
|
||||
r: rune;
|
||||
r, size = utf8.decode_rune(name[i:]);
|
||||
r, size = utf8.decode_rune(name[i..]);
|
||||
fmt.printf("%r\n", r);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -174,7 +174,8 @@ murmur64 :: proc(data: []byte) -> u64 {
|
||||
len -= 4;
|
||||
}
|
||||
|
||||
data8 := slice_to_bytes(data32[i..])[..3];
|
||||
// TODO(bill): Fix this
|
||||
#no_bounds_check data8 := slice_to_bytes(data32[i..])[..3];
|
||||
match len {
|
||||
case 3:
|
||||
h2 ~= cast(u32)data8[2] << 16;
|
||||
|
||||
@@ -7,6 +7,7 @@ CONTEXT_FLAGS_ARB :: 0x2094;
|
||||
CONTEXT_PROFILE_MASK_ARB :: 0x9126;
|
||||
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
|
||||
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
|
||||
CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x00000002;
|
||||
|
||||
Hglrc :: Handle;
|
||||
Color_Ref :: u32;
|
||||
|
||||
@@ -249,12 +249,10 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
|
||||
operand->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
if (is_type_any(type)) {
|
||||
target_type = t_any;
|
||||
} else {
|
||||
target_type = default_type(operand->type);
|
||||
target_type = default_type(operand->type);
|
||||
if (!is_type_any(type)) {
|
||||
GB_ASSERT_MSG(is_type_typed(target_type), "%s", type_to_string(type));
|
||||
}
|
||||
GB_ASSERT_MSG(is_type_typed(target_type), "%s", type_to_string(type));
|
||||
add_type_info_type(c, type);
|
||||
add_type_info_type(c, target_type);
|
||||
}
|
||||
|
||||
@@ -1264,8 +1264,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
|
||||
case Entity_TypeName: {
|
||||
Type *t = base_type(e->type);
|
||||
if (is_type_union(t)) {
|
||||
for (isize i = 0; i < t->Record.variant_count; i++) {
|
||||
TokenPos pos = ast_node_token(expr).pos;
|
||||
for (isize i = 1; i < t->Record.variant_count; i++) {
|
||||
Entity *f = t->Record.variants[i];
|
||||
// gb_printf_err("%s\n", type_to_string(f->type));
|
||||
Entity *found = scope_insert_entity(c->context.scope, f);
|
||||
if (found != NULL) {
|
||||
gbString expr_str = expr_to_string(expr);
|
||||
|
||||
12
src/ir.c
12
src/ir.c
@@ -4263,8 +4263,10 @@ irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
|
||||
|
||||
irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr);
|
||||
irValue *count = ir_slice_count(proc, s);
|
||||
irValue *capacity = ir_slice_capacity(proc, s);
|
||||
count = ir_emit_arith(proc, Token_Mul, count, ir_const_int(proc->module->allocator, elem_size), t_int);
|
||||
ir_fill_slice(proc, slice, ptr, count, count);
|
||||
capacity = ir_emit_arith(proc, Token_Mul, capacity, ir_const_int(proc->module->allocator, elem_size), t_int);
|
||||
ir_fill_slice(proc, slice, ptr, count, capacity);
|
||||
return ir_emit_load(proc, slice);
|
||||
} break;
|
||||
|
||||
@@ -4602,6 +4604,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
|
||||
ir_emit_store(proc, v, ir_emit_down_cast(proc, ir_build_expr(proc, ce->expr), type));
|
||||
return ir_addr(v);
|
||||
}
|
||||
case Token_union_cast: {
|
||||
ir_emit_comment(proc, str_lit("Cast - union_cast"));
|
||||
// NOTE(bill): Needed for dereference of pointer conversion
|
||||
Type *type = type_of_expr(proc->module->info, expr);
|
||||
irValue *v = ir_add_local_generated(proc, type);
|
||||
ir_emit_store(proc, v, ir_emit_union_cast(proc, ir_build_expr(proc, ce->expr), type, ast_node_token(expr).pos));
|
||||
return ir_addr(v);
|
||||
}
|
||||
default:
|
||||
GB_PANIC("Unknown cast expression");
|
||||
}
|
||||
|
||||
@@ -2272,6 +2272,7 @@ AstNode *parse_value_decl(AstFile *f, AstNodeArray lhs) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
AstNode *parse_simple_stmt(AstFile *f, bool in_stmt_ok) {
|
||||
AstNodeArray lhs = parse_lhs_expr_list(f);
|
||||
Token token = f->curr_token;
|
||||
@@ -3290,7 +3291,7 @@ AstNode *parse_stmt(AstFile *f) {
|
||||
return ast_using_stmt(f, token, list);
|
||||
}
|
||||
|
||||
AstNode *decl = parse_simple_stmt(f, false);
|
||||
AstNode *decl = parse_value_decl(f, list);
|
||||
expect_semicolon(f, decl);
|
||||
|
||||
if (decl->kind == AstNode_ValueDecl) {
|
||||
|
||||
Reference in New Issue
Block a user