فهرست منبع

Fix pointer differences (issue #11); remove #dll_import

Ginger Bill 8 سال پیش
والد
کامیت
f47f25f942
9فایلهای تغییر یافته به همراه145 افزوده شده و 91 حذف شده
  1. 18 1
      code/demo.odin
  2. 1 1
      core/os_windows.odin
  3. 67 55
      core/sys/windows.odin
  4. 13 0
      src/check_expr.c
  5. 4 4
      src/check_stmt.c
  6. 1 1
      src/checker.c
  7. 8 2
      src/ir.c
  8. 3 3
      src/ir_print.c
  9. 30 24
      src/parser.c

+ 18 - 1
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();
 }
+*/

+ 1 - 1
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();
 }
 

+ 67 - 55
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; }
 

+ 13 - 0
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)) {

+ 4 - 4
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;
 

+ 1 - 1
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;
 

+ 8 - 2
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) {

+ 3 - 3
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 ");

+ 30 - 24
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) {