diff --git a/code/demo.odin b/code/demo.odin index 2882a27f2..38ed7a94a 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -11,6 +11,22 @@ main :: proc() { + b : [1000]byte; + + using fmt; + + println(); + println("Pointer of Address 0"); + println(^b[0]); + println(); + println("Pointer of Address 50"); + println(^b[50]); + println(); + println("Difference between 50 and 0"); + println(^b[50] - ^b[0]); +} + +/* foo :: proc(x: ^i32) -> (int, int) { fmt.println("^int"); return 123, cast(int)(x^); @@ -22,7 +38,7 @@ main :: proc() { THINGI :: 14451; THINGF :: 14451.1; - a: i32 = 111111; + a: i32 = #line; b: f32; c: rawptr; fmt.println(foo(^a)); @@ -53,3 +69,4 @@ main :: proc() { f = foo; f(); } +*/ diff --git a/core/os_windows.odin b/core/os_windows.odin index 0dfcebe4a..9154d1bb4 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -265,7 +265,7 @@ exit :: proc(code: int) { current_thread_id :: proc() -> int { - GetCurrentThreadId :: proc() -> u32 #foreign #dll_import + GetCurrentThreadId :: proc() -> u32 #foreign return cast(int)GetCurrentThreadId(); } diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 28ad4df08..424cefe73 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -91,6 +91,12 @@ FILETIME :: struct #ordered { lo, hi: u32, } +SYSTEMTIME :: struct #ordered { + year, month: u16, + day_of_week, day: u16, + hour, minute, second, millisecond: u16, +} + BY_HANDLE_FILE_INFORMATION :: struct #ordered { file_attributes: u32, creation_time, @@ -118,43 +124,43 @@ GET_FILEEX_INFO_LEVELS :: i32; GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0; GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1; -GetLastError :: proc() -> i32 #foreign #dll_import -ExitProcess :: proc(exit_code: u32) #foreign #dll_import -GetDesktopWindow :: proc() -> HWND #foreign #dll_import -GetCursorPos :: proc(p: ^POINT) -> i32 #foreign #dll_import -ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign #dll_import -GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign #dll_import -GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign #dll_import -PostQuitMessage :: proc(exit_code: i32) #foreign #dll_import -SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign #dll_import +GetLastError :: proc() -> i32 #foreign +ExitProcess :: proc(exit_code: u32) #foreign +GetDesktopWindow :: proc() -> HWND #foreign +GetCursorPos :: proc(p: ^POINT) -> i32 #foreign +ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign +GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign +GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign +PostQuitMessage :: proc(exit_code: i32) #foreign +SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign -QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign #dll_import -QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign #dll_import +QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign +QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign -Sleep :: proc(ms: i32) -> i32 #foreign #dll_import +Sleep :: proc(ms: i32) -> i32 #foreign -OutputDebugStringA :: proc(c_str: ^u8) #foreign #dll_import +OutputDebugStringA :: proc(c_str: ^u8) #foreign -RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign #dll_import +RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign CreateWindowExA :: proc(ex_style: u32, class_name, title: ^u8, style: u32, x, y, w, h: i32, parent: HWND, menu: HMENU, instance: HINSTANCE, - param: rawptr) -> HWND #foreign #dll_import + param: rawptr) -> HWND #foreign -ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign #dll_import -TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign #dll_import -DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign #dll_import -UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign #dll_import +ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign +TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign +DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign +UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign PeekMessageA :: proc(msg: ^MSG, hwnd: HWND, - msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign #dll_import + msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign -DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign #dll_import +DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign -AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign #dll_import -GetActiveWindow :: proc() -> HWND #foreign #dll_import +AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign +GetActiveWindow :: proc() -> HWND #foreign GetQueryPerformanceFrequency :: proc() -> i64 { @@ -163,28 +169,34 @@ GetQueryPerformanceFrequency :: proc() -> i64 { return r; } -GetCommandLineA :: proc() -> ^u8 #foreign #dll_import -GetSystemMetrics :: proc(index: i32) -> i32 #foreign #dll_import -GetCurrentThreadId :: proc() -> u32 #foreign #dll_import +GetCommandLineA :: proc() -> ^u8 #foreign +GetSystemMetrics :: proc(index: i32) -> i32 #foreign +GetCurrentThreadId :: proc() -> u32 #foreign + +timeGetTime :: proc() -> u32 #foreign +GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign +FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign +FileTimeToSystemTime :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign +SystemTimeToFileTime :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign // File Stuff -CloseHandle :: proc(h: HANDLE) -> i32 #foreign #dll_import -GetStdHandle :: proc(h: i32) -> HANDLE #foreign #dll_import +CloseHandle :: proc(h: HANDLE) -> i32 #foreign +GetStdHandle :: proc(h: i32) -> HANDLE #foreign CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32, security: rawptr, - creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign #dll_import -ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import -WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign #dll_import + creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign +ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign +WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign -GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign #dll_import -GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign #dll_import -GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign #dll_import +GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign +GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign +GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign -GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign #dll_import -SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign #dll_import +GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign +SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign -SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign #dll_import +SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign HANDLE_FLAG_INHERIT :: 1; HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2; @@ -238,10 +250,10 @@ INVALID_SET_FILE_POINTER :: ~cast(u32)0; -HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign #dll_import -HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign #dll_import -HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign #dll_import -GetProcessHeap :: proc () -> HANDLE #foreign #dll_import +HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign +HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign +HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign +GetProcessHeap :: proc () -> HANDLE #foreign HEAP_ZERO_MEMORY :: 0x00000008; @@ -256,9 +268,9 @@ SECURITY_ATTRIBUTES :: struct #ordered { INFINITE :: 0xffffffff; -CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign #dll_import -ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign #dll_import -WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign #dll_import +CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign +ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign +WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign @@ -309,7 +321,7 @@ StretchDIBits :: proc (hdc: HDC, x_src, y_src, width_src, header_src: i32, bits: rawptr, bits_info: ^BITMAPINFO, usage: u32, - rop: u32) -> i32 #foreign #dll_import + rop: u32) -> i32 #foreign @@ -381,10 +393,10 @@ PIXELFORMATDESCRIPTOR :: struct #ordered { } GetDC :: proc(h: HANDLE) -> HDC #foreign -SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign #dll_import -ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign #dll_import -SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign #dll_import -ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign #dll_import +SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign +ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign +SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign +ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091; WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092; @@ -392,15 +404,15 @@ WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126; WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001; WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002; -wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign #dll_import -wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign #dll_import -wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign #dll_import -wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign #dll_import +wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign +wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign +wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign +wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign -GetKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import -GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign #dll_import +GetKeyState :: proc(v_key: i32) -> i16 #foreign +GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; } diff --git a/src/check_expr.c b/src/check_expr.c index dd92fc38e..65850a03b 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -3882,6 +3882,19 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint o->value = make_exact_value_from_basic_literal(*bl); case_end; + case_ast_node(bd, BasicDirective, node); + if (str_eq(bd->name, str_lit("file"))) { + o->type = t_untyped_string; + o->value = make_exact_value_string(bd->token.pos.file); + } else if (str_eq(bd->name, str_lit("line"))) { + o->type = t_untyped_integer; + o->value = make_exact_value_integer(bd->token.pos.line); + } else { + GB_PANIC("Unknown basic basic directive"); + } + o->mode = Addressing_Constant; + case_end; + case_ast_node(pl, ProcLit, node); Type *type = check_type(c, pl->type); if (type == NULL || !is_type_proc(type)) { diff --git a/src/check_stmt.c b/src/check_stmt.c index be364559d..fd8e22908 100644 --- a/src/check_stmt.c +++ b/src/check_stmt.c @@ -527,7 +527,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { case_ast_node(rs, ReturnStmt, node); GB_ASSERT(c->proc_stack.count > 0); - if (c->in_defer) { + if (c->context.in_defer) { error(rs->token, "You cannot `return` within a defer statement"); // TODO(bill): Should I break here? break; @@ -1046,10 +1046,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) { if (is_ast_node_decl(ds->stmt)) { error(ds->token, "You cannot defer a declaration"); } else { - bool out_in_defer = c->in_defer; - c->in_defer = true; + bool out_in_defer = c->context.in_defer; + c->context.in_defer = true; check_stmt(c, ds->stmt, 0); - c->in_defer = out_in_defer; + c->context.in_defer = out_in_defer; } case_end; diff --git a/src/checker.c b/src/checker.c index 983198f38..c4a5f8cba 100644 --- a/src/checker.c +++ b/src/checker.c @@ -250,6 +250,7 @@ typedef struct CheckerContext { Scope * scope; DeclInfo * decl; u32 stmt_state_flags; + bool in_defer; // TODO(bill): Actually handle correctly } CheckerContext; // NOTE(bill): Symbol tables @@ -288,7 +289,6 @@ typedef struct Checker { CheckerContext context; Array(Type *) proc_stack; - bool in_defer; // TODO(bill): Actually handle correctly bool done_preload; } Checker; diff --git a/src/ir.c b/src/ir.c index 4f1ca5f9d..f808ac17e 100644 --- a/src/ir.c +++ b/src/ir.c @@ -1479,12 +1479,13 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue * return ir_emit_ptr_offset(proc, ptr, offset); } else if (is_type_pointer(t_left) && is_type_pointer(t_right)) { GB_ASSERT(is_type_integer(type)); - Type *ptr_type = t_left; irModule *m = proc->module; + Type *ptr_type = base_type(t_left); + GB_ASSERT(!is_type_rawptr(ptr_type)); + irValue *elem_size = ir_make_const_int(m->allocator, type_size_of(m->sizes, m->allocator, ptr_type->Pointer.elem)); irValue *x = ir_emit_conv(proc, left, type); irValue *y = ir_emit_conv(proc, right, type); irValue *diff = ir_emit_arith(proc, op, x, y, type); - irValue *elem_size = ir_make_const_int(m->allocator, type_size_of(m->sizes, m->allocator, ptr_type)); return ir_emit_arith(proc, Token_Quo, diff, elem_size, type); } } @@ -2547,6 +2548,11 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(token_strings[bl->kind])); case_end; + case_ast_node(bd, BasicDirective, expr); + TokenPos pos = bd->token.pos; + GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name)); + case_end; + case_ast_node(i, Ident, expr); Entity *e = *map_entity_get(&proc->module->info->uses, hash_pointer(expr)); if (e->kind == Entity_Builtin) { diff --git a/src/ir_print.c b/src/ir_print.c index 7a3032367..11d46deb7 100644 --- a/src/ir_print.c +++ b/src/ir_print.c @@ -1235,9 +1235,9 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) { void ir_print_proc(irFileBuffer *f, irModule *m, irProcedure *proc) { if (proc->body == NULL) { ir_fprintf(f, "declare "); - if (proc->tags & ProcTag_dll_import) { - ir_fprintf(f, "dllimport "); - } + // if (proc->tags & ProcTag_dll_import) { + // ir_fprintf(f, "dllimport "); + // } } else { ir_fprintf(f, "\n"); ir_fprintf(f, "define "); diff --git a/src/parser.c b/src/parser.c index 7549245f4..10f2275f7 100644 --- a/src/parser.c +++ b/src/parser.c @@ -70,7 +70,7 @@ typedef enum ProcTag { ProcTag_link_name = 1<<12, ProcTag_inline = 1<<13, ProcTag_no_inline = 1<<14, - ProcTag_dll_import = 1<<15, + // ProcTag_dll_import = 1<<15, // ProcTag_dll_export = 1<<16, } ProcTag; @@ -113,9 +113,13 @@ AstNodeArray make_ast_node_array(AstFile *f) { #define AST_NODE_KINDS \ - AST_NODE_KIND(BasicLit, "basic literal", Token) \ - AST_NODE_KIND(Ident, "identifier", Token) \ - AST_NODE_KIND(Ellipsis, "ellipsis", struct { \ + AST_NODE_KIND(Ident, "identifier", Token) \ + AST_NODE_KIND(BasicLit, "basic literal", Token) \ + AST_NODE_KIND(BasicDirective, "basic directive", struct { \ + Token token; \ + String name; \ + }) \ + AST_NODE_KIND(Ellipsis, "ellipsis", struct { \ Token token; \ AstNode *expr; \ }) \ @@ -420,10 +424,12 @@ gb_inline bool is_ast_node_when_stmt(AstNode *node) { Token ast_node_token(AstNode *node) { switch (node->kind) { - case AstNode_BasicLit: - return node->BasicLit; case AstNode_Ident: return node->Ident; + case AstNode_BasicLit: + return node->BasicLit; + case AstNode_BasicDirective: + return node->BasicDirective.token; case AstNode_ProcLit: return ast_node_token(node->ProcLit.type); case AstNode_CompoundLit: @@ -741,15 +747,22 @@ AstNode *make_interval_expr(AstFile *f, Token op, AstNode *left, AstNode *right) +AstNode *make_ident(AstFile *f, Token token) { + AstNode *result = make_node(f, AstNode_Ident); + result->Ident = token; + return result; +} + AstNode *make_basic_lit(AstFile *f, Token basic_lit) { AstNode *result = make_node(f, AstNode_BasicLit); result->BasicLit = basic_lit; return result; } -AstNode *make_ident(AstFile *f, Token token) { - AstNode *result = make_node(f, AstNode_Ident); - result->Ident = token; +AstNode *make_basic_directive(AstFile *f, Token token, String name) { + AstNode *result = make_node(f, AstNode_BasicDirective); + result->BasicDirective.token = token; + result->BasicDirective.name = name; return result; } @@ -1543,7 +1556,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n ELSE_IF_ADD_TAG(no_bounds_check) ELSE_IF_ADD_TAG(inline) ELSE_IF_ADD_TAG(no_inline) - ELSE_IF_ADD_TAG(dll_import) + // ELSE_IF_ADD_TAG(dll_import) // ELSE_IF_ADD_TAG(dll_export) else if (str_eq(tag_name, str_lit("cc_odin"))) { if (cc == ProcCC_Invalid) { @@ -1570,7 +1583,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n syntax_error_node(tag_expr, "Multiple calling conventions for procedure type"); } } else { - syntax_error_node(tag_expr, "Unknown procedure tag"); + syntax_error_node(tag_expr, "Unknown procedure tag #%.*s\n", LIT(tag_name)); } #undef ELSE_IF_ADD_TAG @@ -1752,17 +1765,9 @@ AstNode *parse_operand(AstFile *f, bool lhs) { Token token = expect_token(f, Token_Hash); Token name = expect_token(f, Token_Ident); if (str_eq(name.string, str_lit("file"))) { - Token token = name; - token.kind = Token_String; - token.string = token.pos.file; - return make_basic_lit(f, token); + return make_basic_directive(f, token, name.string); } else if (str_eq(name.string, str_lit("line"))) { - Token token = name; - token.kind = Token_Integer; - char *str = gb_alloc_array(gb_arena_allocator(&f->arena), char, 20); - gb_i64_to_str(token.pos.line, str, 10); - token.string = make_string_c(str); - return make_basic_lit(f, token); + return make_basic_directive(f, token, name.string); } else if (str_eq(name.string, str_lit("run"))) { AstNode *expr = parse_expr(f, false); operand = make_run_expr(f, token, name, expr); @@ -3077,20 +3082,21 @@ AstNode *parse_defer_stmt(AstFile *f) { } Token token = expect_token(f, Token_defer); - AstNode *statement = parse_stmt(f); - switch (statement->kind) { + AstNode *stmt = parse_stmt(f); + switch (stmt->kind) { case AstNode_EmptyStmt: syntax_error(token, "Empty statement after defer (e.g. `;`)"); break; case AstNode_DeferStmt: syntax_error(token, "You cannot defer a defer statement"); + stmt = stmt->DeferStmt.stmt; break; case AstNode_ReturnStmt: syntax_error(token, "You cannot a return statement"); break; } - return make_defer_stmt(f, token, statement); + return make_defer_stmt(f, token, stmt); } AstNode *parse_asm_stmt(AstFile *f) {