From e3e16f5d051c2b941d5e4ee1a64b235286a85cdf Mon Sep 17 00:00:00 2001 From: Ginger Bill Date: Thu, 26 Jan 2017 20:00:16 +0000 Subject: [PATCH] Library names - Only link with used foreign libraries --- code/demo.odin | 15 +--- core/_preload.odin | 8 +- core/math.odin | 28 +++---- core/mem.odin | 6 +- core/opengl.odin | 49 ++++++------ core/os_windows.odin | 3 +- core/sys/windows.odin | 169 +++++++++++++++++++++--------------------- src/check_decl.c | 23 ++++++ src/check_expr.c | 3 + src/checker.c | 131 +++++++++++++++++--------------- src/entity.c | 15 ++++ src/ir.c | 24 +++++- src/main.c | 9 ++- src/parser.c | 109 ++++++++++++++++----------- 14 files changed, 341 insertions(+), 251 deletions(-) diff --git a/code/demo.odin b/code/demo.odin index 38ed7a94a..88aa651c0 100644 --- a/code/demo.odin +++ b/code/demo.odin @@ -9,21 +9,8 @@ #import "sync.odin"; #import "utf8.odin"; - 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]); + fmt.println("GOOGOLPLEX"); } /* diff --git a/core/_preload.odin b/core/_preload.odin index 6199d6e4d..96bf61f9b 100644 --- a/core/_preload.odin +++ b/core/_preload.odin @@ -109,11 +109,11 @@ type_info_base :: proc(info: ^Type_Info) -> ^Type_Info { -assume :: proc(cond: bool) #foreign "llvm.assume" +assume :: proc(cond: bool) #foreign __llvm_core "llvm.assume"; -__debug_trap :: proc() #foreign "llvm.debugtrap" -__trap :: proc() #foreign "llvm.trap" -read_cycle_counter :: proc() -> u64 #foreign "llvm.readcyclecounter" +__debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap"; +__trap :: proc() #foreign __llvm_core "llvm.trap"; +read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter"; Allocator_Mode :: enum u8 { diff --git a/core/math.odin b/core/math.odin index f89c004aa..6913b9652 100644 --- a/core/math.odin +++ b/core/math.odin @@ -24,14 +24,14 @@ Mat2 :: [2]Vec2; Mat3 :: [3]Vec3; Mat4 :: [4]Vec4; -sqrt :: proc(x: f32) -> f32 #foreign "llvm.sqrt.f32" -sqrt :: proc(x: f64) -> f64 #foreign "llvm.sqrt.f64" +sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32"; +sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64"; -sin :: proc(x: f32) -> f32 #foreign "llvm.sin.f32" -sin :: proc(x: f64) -> f64 #foreign "llvm.sin.f64" +sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32"; +sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64"; -cos :: proc(x: f32) -> f32 #foreign "llvm.cos.f32" -cos :: proc(x: f64) -> f64 #foreign "llvm.cos.f64" +cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32"; +cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64"; tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); } tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); } @@ -42,16 +42,16 @@ lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; } sign :: proc(x: f32) -> f32 { if x >= 0 { return +1; } return -1; } sign :: proc(x: f64) -> f64 { if x >= 0 { return +1; } return -1; } -bit_reverse :: proc(b: u16) -> u16 #foreign "llvm.bitreverse.i16" -bit_reverse :: proc(b: u32) -> u32 #foreign "llvm.bitreverse.i32" -bit_reverse :: proc(b: u64) -> u64 #foreign "llvm.bitreverse.i64" +bit_reverse :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bitreverse.i16"; +bit_reverse :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bitreverse.i32"; +bit_reverse :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bitreverse.i64"; -byte_swap :: proc(b: u16) -> u16 #foreign "llvm.bswap.i16" -byte_swap :: proc(b: u32) -> u32 #foreign "llvm.bswap.i32" -byte_swap :: proc(b: u64) -> u64 #foreign "llvm.bswap.i64" +byte_swap :: proc(b: u16) -> u16 #foreign __llvm_core "llvm.bswap.i16"; +byte_swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32"; +byte_swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64"; -fmuladd :: proc(a, b, c: f32) -> f32 #foreign "llvm.fmuladd.f32" -fmuladd :: proc(a, b, c: f64) -> f64 #foreign "llvm.fmuladd.f64" +fmuladd :: proc(a, b, c: f32) -> f32 #foreign __llvm_core "llvm.fmuladd.f32"; +fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64"; copy_sign :: proc(x, y: f32) -> f32 { diff --git a/core/mem.odin b/core/mem.odin index 79248ca77..d0e010a78 100644 --- a/core/mem.odin +++ b/core/mem.odin @@ -2,7 +2,7 @@ #import "os.odin"; set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" { - llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign "llvm.memset.p0i8.i64" + llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64"; llvm_memset_64bit(data, cast(byte)value, len, 1, false); return data; } @@ -13,14 +13,14 @@ zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" { copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" { // NOTE(bill): This _must_ implemented like C's memmove - llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memmove.p0i8.p0i8.i64" + llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64"; llvm_memmove_64bit(dst, src, len, 1, false); return dst; } copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" { // NOTE(bill): This _must_ implemented like C's memcpy - llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign "llvm.memcpy.p0i8.p0i8.i64" + llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64"; llvm_memcpy_64bit(dst, src, len, 1, false); return dst; } diff --git a/core/opengl.odin b/core/opengl.odin index 2b357d63c..760658baf 100644 --- a/core/opengl.odin +++ b/core/opengl.odin @@ -1,36 +1,37 @@ -#foreign_system_library "opengl32" when ODIN_OS == "windows"; +#foreign_system_library "opengl32.lib" when ODIN_OS == "windows"; #import win32 "sys/windows.odin" when ODIN_OS == "windows"; #include "opengl_constants.odin"; -Clear :: proc(mask: u32) #foreign "glClear" -ClearColor :: proc(r, g, b, a: f32) #foreign "glClearColor" -Begin :: proc(mode: i32) #foreign "glBegin" -End :: proc() #foreign "glEnd" -Finish :: proc() #foreign "glFinish" -BlendFunc :: proc(sfactor, dfactor: i32) #foreign "glBlendFunc" -Enable :: proc(cap: i32) #foreign "glEnable" -Disable :: proc(cap: i32) #foreign "glDisable" -GenTextures :: proc(count: i32, result: ^u32) #foreign "glGenTextures" -DeleteTextures:: proc(count: i32, result: ^u32) #foreign "glDeleteTextures" -TexParameteri :: proc(target, pname, param: i32) #foreign "glTexParameteri" -TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign "glTexParameterf" -BindTexture :: proc(target: i32, texture: u32) #foreign "glBindTexture" -LoadIdentity :: proc() #foreign "glLoadIdentity" -Viewport :: proc(x, y, width, height: i32) #foreign "glViewport" -Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign "glOrtho" -Color3f :: proc(r, g, b: f32) #foreign "glColor3f" -Vertex3f :: proc(x, y, z: f32) #foreign "glVertex3f" +Clear :: proc(mask: u32) #foreign opengl32 "glClear"; +ClearColor :: proc(r, g, b, a: f32) #foreign opengl32 "glClearColor"; +Begin :: proc(mode: i32) #foreign opengl32 "glBegin"; +End :: proc() #foreign opengl32 "glEnd"; +Finish :: proc() #foreign opengl32 "glFinish"; +BlendFunc :: proc(sfactor, dfactor: i32) #foreign opengl32 "glBlendFunc"; +Enable :: proc(cap: i32) #foreign opengl32 "glEnable"; +Disable :: proc(cap: i32) #foreign opengl32 "glDisable"; +GenTextures :: proc(count: i32, result: ^u32) #foreign opengl32 "glGenTextures"; +DeleteTextures:: proc(count: i32, result: ^u32) #foreign opengl32 "glDeleteTextures"; +TexParameteri :: proc(target, pname, param: i32) #foreign opengl32 "glTexParameteri"; +TexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign opengl32 "glTexParameterf"; +BindTexture :: proc(target: i32, texture: u32) #foreign opengl32 "glBindTexture"; +LoadIdentity :: proc() #foreign opengl32 "glLoadIdentity"; +Viewport :: proc(x, y, width, height: i32) #foreign opengl32 "glViewport"; +Ortho :: proc(left, right, bottom, top, near, far: f64) #foreign opengl32 "glOrtho"; +Color3f :: proc(r, g, b: f32) #foreign opengl32 "glColor3f"; +Vertex3f :: proc(x, y, z: f32) #foreign opengl32 "glVertex3f"; TexImage2D :: proc(target, level, internal_format, width, height, border, - format, _type: i32, pixels: rawptr) #foreign "glTexImage2D" + format, _type: i32, pixels: rawptr) #foreign opengl32 "glTexImage2D"; -GetError :: proc() -> i32 #foreign "glGetError" -GetString :: proc(name: i32) -> ^byte #foreign "glGetString" -GetIntegerv :: proc(name: i32, v: ^i32) #foreign "glGetIntegerv" +GetError :: proc() -> i32 #foreign opengl32 "glGetError"; +GetString :: proc(name: i32) -> ^byte #foreign opengl32 "glGetString"; +GetIntegerv :: proc(name: i32, v: ^i32) #foreign opengl32 "glGetIntegerv"; +string_data :: proc(s: string) -> ^u8 #inline { return ^s[0]; } -_libgl := win32.LoadLibraryA((cast(string)"opengl32.dll\x00").data); +_libgl := win32.LoadLibraryA(string_data("opengl32.dll\x00")); GetProcAddress :: proc(name: string) -> proc() #cc_c { assert(name[name.count-1] == 0); diff --git a/core/os_windows.odin b/core/os_windows.odin index 9154d1bb4..acfb02116 100644 --- a/core/os_windows.odin +++ b/core/os_windows.odin @@ -265,8 +265,7 @@ exit :: proc(code: int) { current_thread_id :: proc() -> int { - GetCurrentThreadId :: proc() -> u32 #foreign - return cast(int)GetCurrentThreadId(); + return cast(int)win32.GetCurrentThreadId(); } diff --git a/core/sys/windows.odin b/core/sys/windows.odin index 424cefe73..85a53a712 100644 --- a/core/sys/windows.odin +++ b/core/sys/windows.odin @@ -1,5 +1,8 @@ -#foreign_system_library "user32" when ODIN_OS == "windows"; -#foreign_system_library "gdi32" when ODIN_OS == "windows"; +#foreign_system_library "kernel32.lib"; +#foreign_system_library "user32.lib"; +#foreign_system_library "gdi32.lib"; +#foreign_system_library "winmm.lib"; +#foreign_system_library "opengl32.lib"; HANDLE :: rawptr; HWND :: HANDLE; @@ -124,43 +127,43 @@ GET_FILEEX_INFO_LEVELS :: i32; GetFileExInfoStandard: GET_FILEEX_INFO_LEVELS : 0; GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1; -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 +GetLastError :: proc() -> i32 #foreign kernel32; +ExitProcess :: proc(exit_code: u32) #foreign kernel32; +GetDesktopWindow :: proc() -> HWND #foreign user32; +GetCursorPos :: proc(p: ^POINT) -> i32 #foreign user32; +ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign user32; +GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign kernel32; +GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign gdi32; +PostQuitMessage :: proc(exit_code: i32) #foreign user32; +SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign user32; -QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign -QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign +QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32; +QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32; -Sleep :: proc(ms: i32) -> i32 #foreign +Sleep :: proc(ms: i32) -> i32 #foreign kernel32; -OutputDebugStringA :: proc(c_str: ^u8) #foreign +OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32; -RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign +RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32; 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 + param: rawptr) -> HWND #foreign user32; -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 +ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32; +TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign user32; +DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign user32; +UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign user32; PeekMessageA :: proc(msg: ^MSG, hwnd: HWND, - msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign + msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32; -DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign +DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32; -AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign -GetActiveWindow :: proc() -> HWND #foreign +AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32; +GetActiveWindow :: proc() -> HWND #foreign user32; GetQueryPerformanceFrequency :: proc() -> i64 { @@ -169,34 +172,34 @@ GetQueryPerformanceFrequency :: proc() -> i64 { return r; } -GetCommandLineA :: proc() -> ^u8 #foreign -GetSystemMetrics :: proc(index: i32) -> i32 #foreign -GetCurrentThreadId :: proc() -> u32 #foreign +GetCommandLineA :: proc() -> ^u8 #foreign kernel32; +GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32; +GetCurrentThreadId :: proc() -> u32 #foreign kernel32; -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 +timeGetTime :: proc() -> u32 #foreign winmm; +GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign kernel32; +FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign kernel32; +FileTimeToSystemTime :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign kernel32; +SystemTimeToFileTime :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign kernel32; // File Stuff -CloseHandle :: proc(h: HANDLE) -> i32 #foreign -GetStdHandle :: proc(h: i32) -> HANDLE #foreign +CloseHandle :: proc(h: HANDLE) -> i32 #foreign kernel32; +GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32; CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32, security: rawptr, - 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 + creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32; +ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32; +WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32; -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 +GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign kernel32; +GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign kernel32; +GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32; -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 +GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign kernel32; +SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32; -SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign +SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32; HANDLE_FLAG_INHERIT :: 1; HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2; @@ -250,10 +253,10 @@ INVALID_SET_FILE_POINTER :: ~cast(u32)0; -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 +HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign kernel32; +HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32; +HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign kernel32; +GetProcessHeap :: proc () -> HANDLE #foreign kernel32; HEAP_ZERO_MEMORY :: 0x00000008; @@ -268,27 +271,27 @@ SECURITY_ATTRIBUTES :: struct #ordered { INFINITE :: 0xffffffff; -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 +CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32; +ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32; +WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32; -InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign -InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign -InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign -InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign -InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign +InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32; +InterlockedExchange :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32; +InterlockedExchangeAdd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32; +InterlockedAnd :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32; +InterlockedOr :: proc(dst: ^i32, desired: i32) -> i32 #foreign kernel32; -InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign -InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign -InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign -InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign -InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign +InterlockedCompareExchange64 :: proc(dst: ^i64, exchange, comparand: i64) -> i64 #foreign kernel32; +InterlockedExchange64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; +InterlockedExchangeAdd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; +InterlockedAnd64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; +InterlockedOr64 :: proc(dst: ^i64, desired: i64) -> i64 #foreign kernel32; -_mm_pause :: proc() #foreign -ReadWriteBarrier :: proc() #foreign -WriteBarrier :: proc() #foreign -ReadBarrier :: proc() #foreign +_mm_pause :: proc() #foreign kernel32; +ReadWriteBarrier :: proc() #foreign kernel32; +WriteBarrier :: proc() #foreign kernel32; +ReadBarrier :: proc() #foreign kernel32; // GDI @@ -321,17 +324,15 @@ StretchDIBits :: proc (hdc: HDC, x_src, y_src, width_src, header_src: i32, bits: rawptr, bits_info: ^BITMAPINFO, usage: u32, - rop: u32) -> i32 #foreign + rop: u32) -> i32 #foreign gdi32; -LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign -FreeLibrary :: proc (h: HMODULE) #foreign -GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign - -GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign - +LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign kernel32; +FreeLibrary :: proc (h: HMODULE) #foreign kernel32; +GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32; +GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32; // Windows OpenGL PFD_TYPE_RGBA :: 0; @@ -358,7 +359,7 @@ PFD_STEREO_DONTCARE :: 0x80000000; HGLRC :: HANDLE; PROC :: type proc() #cc_c; -wglCreateContextAttribsARBType :: proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; +wglCreateContextAttribsARBType :: type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC; PIXELFORMATDESCRIPTOR :: struct #ordered { @@ -392,11 +393,11 @@ PIXELFORMATDESCRIPTOR :: struct #ordered { damage_mask: u32, } -GetDC :: proc(h: HANDLE) -> HDC #foreign -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 +GetDC :: proc(h: HANDLE) -> HDC #foreign user32; +SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR ) -> BOOL #foreign user32; +ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32; +SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign user32; +ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32; WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091; WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092; @@ -404,15 +405,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 -wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign -wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign -wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign +wglCreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32; +wglMakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32; +wglGetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32; +wglDeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32; -GetKeyState :: proc(v_key: i32) -> i16 #foreign -GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign +GetKeyState :: proc(v_key: i32) -> i16 #foreign user32; +GetAsyncKeyState :: proc(v_key: i32) -> i16 #foreign user32; is_key_down :: proc(key: Key_Code) -> bool #inline { return GetAsyncKeyState(cast(i32)key) < 0; } diff --git a/src/check_decl.c b/src/check_decl.c index a97b1b90e..f2a62c957 100644 --- a/src/check_decl.c +++ b/src/check_decl.c @@ -319,6 +319,29 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) { name = pd->foreign_name; } + AstNode *foreign_library = d->proc_lit->ProcLit.foreign_library; + if (foreign_library == NULL) { + error(e->token, "#foreign procedures must declare which library they are from"); + } else if (foreign_library->kind != AstNode_Ident) { + error_node(foreign_library, "#foreign library names must be an identifier"); + } else { + String name = foreign_library->Ident.string; + Entity *found = scope_lookup_entity(c->context.scope, name); + if (found == NULL) { + if (str_eq(name, str_lit("_"))) { + error_node(foreign_library, "`_` cannot be used as a value type"); + } else { + error_node(foreign_library, "Undeclared name: %.*s", LIT(name)); + } + } else if (found->kind != Entity_LibraryName) { + error_node(foreign_library, "`_` cannot be used as a library name"); + } else { + // TODO(bill): Extra stuff to do with library names? + e->Procedure.foreign_library = found; + add_entity_use(c, foreign_library, found); + } + } + e->Procedure.is_foreign = true; e->Procedure.foreign_name = name; diff --git a/src/check_expr.c b/src/check_expr.c index 65850a03b..039795fae 100644 --- a/src/check_expr.c +++ b/src/check_expr.c @@ -985,6 +985,9 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type, Type case Entity_ImportName: error_node(n, "Use of import `%.*s` not in selector", LIT(e->ImportName.name)); return; + case Entity_LibraryName: + error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(e->LibraryName.name)); + return; case Entity_Nil: o->mode = Addressing_Value; diff --git a/src/checker.c b/src/checker.c index c4a5f8cba..645a37f89 100644 --- a/src/checker.c +++ b/src/checker.c @@ -266,7 +266,6 @@ typedef struct CheckerInfo { MapIsize type_info_map; // Key: Type * isize type_info_count; Entity * implicit_values[ImplicitValue_Count]; - Array(String) foreign_libraries; // For the linker } CheckerInfo; typedef struct Checker { @@ -476,7 +475,9 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit continue; } - if (e->kind == Entity_ImportName && gone_thru_file) { + if ((e->kind == Entity_ImportName || + e->kind == Entity_LibraryName) + && gone_thru_file) { continue; } @@ -515,13 +516,14 @@ Entity *scope_insert_entity(Scope *s, Entity *entity) { Entity *prev = NULL; if (found) { prev = *found; - if (prev->kind != Entity_Procedure && + if (prev->kind != Entity_Procedure || entity->kind != Entity_Procedure) { return prev; } } - if (prev != NULL && entity->kind == Entity_Procedure) { + if (prev != NULL && + entity->kind == Entity_Procedure) { if (s->is_global) { return prev; } @@ -605,6 +607,9 @@ void init_universal_scope(BuildContext *bc) { add_global_constant(a, str_lit("false"), t_untyped_bool, make_exact_value_bool(false)); add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil)); + add_global_entity(make_entity_library_name(a, universal_scope, + make_token_ident(str_lit("__llvm_core")), t_invalid, + str_lit(""), str_lit("__llvm_core"))); // TODO(bill): Set through flags in the compiler add_global_string_constant(a, str_lit("ODIN_OS"), bc->ODIN_OS); @@ -643,7 +648,6 @@ void init_checker_info(CheckerInfo *i) { map_entity_init(&i->foreign_procs, a); map_isize_init(&i->type_info_map, a); map_ast_file_init(&i->files, a); - array_init(&i->foreign_libraries, a); i->type_info_count = 0; } @@ -658,7 +662,6 @@ void destroy_checker_info(CheckerInfo *i) { map_entity_destroy(&i->foreign_procs); map_isize_destroy(&i->type_info_map); map_ast_file_destroy(&i->files); - array_free(&i->foreign_libraries); } @@ -843,17 +846,6 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn map_decl_info_set(&c->info.entities, hash_pointer(e), d); } -// NOTE(bill): Returns true if it's added -bool try_add_foreign_library_path(Checker *c, String import_file) { - for_array(i, c->info.foreign_libraries) { - String import = c->info.foreign_libraries.e[i]; - if (str_eq(import, import_file)) { - return false; - } - } - array_add(&c->info.foreign_libraries, import_file); - return true; -} void add_type_info_type(Checker *c, Type *t) { @@ -1047,6 +1039,9 @@ MapEntity generate_minimum_dependency_map(CheckerInfo *info, Entity *start) { if ((e->Procedure.tags & ProcTag_export) != 0) { add_dependency_to_map(&map, info, e); } + if (e->Procedure.is_foreign) { + add_dependency_to_map(&map, info, e->Procedure.foreign_library); + } } } @@ -1555,6 +1550,43 @@ void check_all_global_entities(Checker *c) { } +String path_to_entity_name(String name, String fullpath) { + if (name.len != 0) { + return name; + } + // NOTE(bill): use file name (without extension) as the identifier + // If it is a valid identifier + String filename = fullpath; + isize slash = 0; + isize dot = 0; + for (isize i = filename.len-1; i >= 0; i--) { + u8 c = filename.text[i]; + if (c == '/' || c == '\\') { + break; + } + slash = i; + } + + filename.text += slash; + filename.len -= slash; + + dot = filename.len; + while (dot --> 0) { + u8 c = filename.text[dot]; + if (c == '.') { + break; + } + } + + filename.len = dot; + + if (is_string_an_identifier(filename)) { + return filename; + } else { + return str_lit("_"); + } +} + void check_import_entities(Checker *c, MapScope *file_scopes) { for_array(i, c->delayed_imports) { Scope *parent_scope = c->delayed_imports.e[i].parent; @@ -1615,49 +1647,23 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { if (e->scope == parent_scope) { continue; } - // NOTE(bill): Do not add other imported entities - bool ok = add_entity(c, parent_scope, NULL, e); - if (ok && id->is_import) { // `#import`ed entities don't get exported - map_bool_set(&parent_scope->implicit, hash_pointer(e), true); + switch (e->kind) { + case Entity_ImportName: + case Entity_LibraryName: + break; + default: { + bool ok = add_entity(c, parent_scope, NULL, e); + if (ok && id->is_import) { // `#import`ed entities don't get exported + map_bool_set(&parent_scope->implicit, hash_pointer(e), true); + } + } break; } } } else { - String import_name = id->import_name.string; - if (import_name.len == 0) { - // NOTE(bill): use file name (without extension) as the identifier - // If it is a valid identifier - String filename = id->fullpath; - isize slash = 0; - isize dot = 0; - for (isize i = filename.len-1; i >= 0; i--) { - u8 c = filename.text[i]; - if (c == '/' || c == '\\') { - break; - } - slash = i; - } - - filename.text += slash; - filename.len -= slash; - - dot = filename.len; - while (dot --> 0) { - u8 c = filename.text[dot]; - if (c == '.') { - break; - } - } - - filename.len = dot; - - if (is_string_an_identifier(filename)) { - import_name = filename; - } else { - error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(filename)); - } - } - - if (import_name.len > 0) { + String import_name = path_to_entity_name(id->import_name.string, id->fullpath); + if (str_eq(import_name, str_lit("_"))) { + error(token, "File name, %.*s, cannot be as an import name as it is not a valid identifier", LIT(id->import_name.string)); + } else { GB_ASSERT(id->import_name.pos.line != 0); id->import_name.string = import_name; Entity *e = make_entity_import_name(c->allocator, parent_scope, id->import_name, t_invalid, @@ -1690,7 +1696,16 @@ void check_import_entities(Checker *c, MapScope *file_scopes) { file_str = import_file; } - try_add_foreign_library_path(c, file_str); + String library_name = path_to_entity_name(fl->library_name.string, file_str); + if (str_eq(library_name, str_lit("_"))) { + error(fl->token, "File name, %.*s, cannot be as a library name as it is not a valid identifier", LIT(fl->library_name.string)); + } else { + GB_ASSERT(fl->library_name.pos.line != 0); + fl->library_name.string = library_name; + Entity *e = make_entity_library_name(c->allocator, parent_scope, fl->library_name, t_invalid, + file_str, library_name); + add_entity(c, parent_scope, NULL, e); + } } } diff --git a/src/entity.c b/src/entity.c index 4991c8d37..3464ad82e 100644 --- a/src/entity.c +++ b/src/entity.c @@ -12,6 +12,7 @@ typedef enum ImplicitValueId ImplicitValueId; ENTITY_KIND(Procedure) \ ENTITY_KIND(Builtin) \ ENTITY_KIND(ImportName) \ + ENTITY_KIND(LibraryName) \ ENTITY_KIND(Nil) \ ENTITY_KIND(ImplicitValue) \ ENTITY_KIND(Count) @@ -72,6 +73,7 @@ struct Entity { struct { bool is_foreign; String foreign_name; + Entity * foreign_library; String link_name; u64 tags; OverloadKind overload_kind; @@ -85,6 +87,11 @@ struct Entity { Scope *scope; bool used; } ImportName; + struct { + String path; + String name; + bool used; + } LibraryName; i32 Nil; struct { // TODO(bill): Should this be a user-level construct rather than compiler-level? @@ -178,6 +185,14 @@ Entity *make_entity_import_name(gbAllocator a, Scope *scope, Token token, Type * return entity; } +Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type *type, + String path, String name) { + Entity *entity = alloc_entity(a, Entity_LibraryName, scope, token, type); + entity->LibraryName.path = path; + entity->LibraryName.name = name; + return entity; +} + Entity *make_entity_nil(gbAllocator a, String name, Type *type) { Token token = make_token_ident(name); Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type); diff --git a/src/ir.c b/src/ir.c index f808ac17e..80c9949ea 100644 --- a/src/ir.c +++ b/src/ir.c @@ -43,13 +43,15 @@ typedef struct irModule { Array(irProcedure *) procs; // NOTE(bill): All procedures with bodies irValueArray procs_to_generate; // NOTE(bill): Procedures to generate + + Array(String) foreign_library_paths; // Only the ones that were used } irModule; // NOTE(bill): For more info, see https://en.wikipedia.org/wiki/Dominator_(graph_theory) typedef struct irDomNode { irBlock * idom; // Parent (Immediate Dominator) Array(irBlock *) children; - i32 pre, post; // Ordering in tree + i32 pre, post; // Ordering in tree } irDomNode; @@ -5037,6 +5039,7 @@ void ir_init_module(irModule *m, Checker *c, BuildContext *build_context) { map_string_init(&m->type_names, heap_allocator()); array_init(&m->procs, heap_allocator()); array_init(&m->procs_to_generate, heap_allocator()); + array_init(&m->foreign_library_paths, heap_allocator()); // Default states m->stmt_state_flags = 0; @@ -5100,7 +5103,9 @@ void ir_destroy_module(irModule *m) { map_ir_value_destroy(&m->members); map_string_destroy(&m->type_names); map_ir_debug_info_destroy(&m->debug_info); + array_free(&m->procs); array_free(&m->procs_to_generate); + array_free(&m->foreign_library_paths); gb_arena_free(&m->arena); } @@ -5199,6 +5204,22 @@ irValue *ir_type_info_member_offset(irProcedure *proc, irValue *data, isize coun return offset; } +void ir_add_foreign_library_path(irModule *m, Entity *e) { + GB_ASSERT(e != NULL); + String library_path = e->LibraryName.path; + if (library_path.len == 0) { + return; + } + + for_array(path_index, m->foreign_library_paths) { + String path = m->foreign_library_paths.e[path_index]; + if (str_eq(path, library_path)) { + return; + } + } + array_add(&m->foreign_library_paths, library_path); +} + void ir_gen_tree(irGen *s) { irModule *m = &s->module; CheckerInfo *info = m->info; @@ -5318,6 +5339,7 @@ void ir_gen_tree(irGen *s) { AstNode *body = pd->body; if (e->Procedure.is_foreign) { name = e->token.string; // NOTE(bill): Don't use the mangled name + ir_add_foreign_library_path(m, e->Procedure.foreign_library); } if (pd->foreign_name.len > 0) { name = pd->foreign_name; diff --git a/src/main.c b/src/main.c index eead1daf3..6e9afda3d 100644 --- a/src/main.c +++ b/src/main.c @@ -235,13 +235,14 @@ int main(int argc, char **argv) { timings_start_section(&timings, str_lit("msvc-link")); - gbString lib_str = gb_string_make(heap_allocator(), "\"Kernel32.lib\""); + gbString lib_str = gb_string_make(heap_allocator(), ""); // defer (gb_string_free(lib_str)); char lib_str_buf[1024] = {0}; - for_array(i, checker.info.foreign_libraries) { - String lib = checker.info.foreign_libraries.e[i]; + for_array(i, ir_gen.module.foreign_library_paths) { + String lib = ir_gen.module.foreign_library_paths.e[i]; + gb_printf_err("Linking lib: %.*s\n", LIT(lib)); isize len = gb_snprintf(lib_str_buf, gb_size_of(lib_str_buf), - " \"%.*s.lib\"", LIT(lib)); + " \"%.*s\"", LIT(lib)); lib_str = gb_string_appendc(lib_str, lib_str_buf); } diff --git a/src/parser.c b/src/parser.c index 10f2275f7..c208a260f 100644 --- a/src/parser.c +++ b/src/parser.c @@ -124,11 +124,12 @@ AstNodeArray make_ast_node_array(AstFile *f) { AstNode *expr; \ }) \ AST_NODE_KIND(ProcLit, "procedure literal", struct { \ - AstNode *type; \ - AstNode *body; \ - u64 tags; \ - String foreign_name; \ - String link_name; \ + AstNode *type; \ + AstNode *body; \ + u64 tags; \ + AstNode *foreign_library; \ + String foreign_name; \ + String link_name; \ }) \ AST_NODE_KIND(CompoundLit, "compound literal", struct { \ AstNode *type; \ @@ -302,6 +303,7 @@ AST_NODE_KIND(_DeclBegin, "", i32) \ }) \ AST_NODE_KIND(ForeignLibrary, "foreign library", struct { \ Token token, filepath; \ + Token library_name; \ String base_dir; \ AstNode *cond; \ bool is_system; \ @@ -774,11 +776,12 @@ AstNode *make_ellipsis(AstFile *f, Token token, AstNode *expr) { } -AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, String foreign_name, String link_name) { +AstNode *make_proc_lit(AstFile *f, AstNode *type, AstNode *body, u64 tags, AstNode *foreign_library, String foreign_name, String link_name) { AstNode *result = make_node(f, AstNode_ProcLit); result->ProcLit.type = type; result->ProcLit.body = body; result->ProcLit.tags = tags; + result->ProcLit.foreign_library = foreign_library; result->ProcLit.foreign_name = foreign_name; result->ProcLit.link_name = link_name; return result; @@ -1112,14 +1115,6 @@ AstNode *make_enum_type(AstFile *f, Token token, AstNode *base_type, AstNodeArra return result; } -AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, AstNode *cond, bool is_system) { - AstNode *result = make_node(f, AstNode_ForeignLibrary); - result->ForeignLibrary.token = token; - result->ForeignLibrary.filepath = filepath; - result->ForeignLibrary.cond = cond; - result->ForeignLibrary.is_system = is_system; - return result; -} AstNode *make_value_decl(AstFile *f, bool is_var, AstNodeArray names, AstNode *type, AstNodeArray values) { AstNode *result = make_node(f, AstNode_ValueDecl); @@ -1141,6 +1136,16 @@ AstNode *make_import_decl(AstFile *f, Token token, bool is_import, Token relpath return result; } +AstNode *make_foreign_library(AstFile *f, Token token, Token filepath, Token library_name, AstNode *cond, bool is_system) { + AstNode *result = make_node(f, AstNode_ForeignLibrary); + result->ForeignLibrary.token = token; + result->ForeignLibrary.filepath = filepath; + result->ForeignLibrary.library_name = library_name; + result->ForeignLibrary.cond = cond; + result->ForeignLibrary.is_system = is_system; + return result; +} + bool next_token(AstFile *f) { Token prev = f->curr_token; @@ -1316,7 +1321,7 @@ bool is_semicolon_optional_for_node(AstFile *f, AstNode *s) { case AstNode_EnumType: return true; case AstNode_ProcLit: - return true; + return s->ProcLit.body != NULL; case AstNode_ValueDecl: if (!s->ValueDecl.is_var) { @@ -1366,7 +1371,7 @@ void expect_semicolon(AstFile *f, AstNode *s) { AstNode * parse_expr(AstFile *f, bool lhs); -AstNode * parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_); +AstNode * parse_proc_type(AstFile *f, AstNode **foreign_library, String *foreign_name, String *link_name); AstNodeArray parse_stmt_list(AstFile *f); AstNode * parse_stmt(AstFile *f); AstNode * parse_body(AstFile *f); @@ -1508,7 +1513,7 @@ bool is_foreign_name_valid(String name) { return true; } -void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) { +void parse_proc_tags(AstFile *f, u64 *tags, AstNode **foreign_library_token, String *foreign_name, String *link_name, ProcCallingConvention *calling_convention) { // TODO(bill): Add this to procedure literals too GB_ASSERT(tags != NULL); GB_ASSERT(link_name != NULL); @@ -1528,6 +1533,7 @@ void parse_proc_tags(AstFile *f, u64 *tags, String *foreign_name, String *link_n if (str_eq(tag_name, str_lit("foreign"))) { check_proc_add_tag(f, tag_expr, tags, ProcTag_foreign, tag_name); + *foreign_library_token = parse_identifier(f); if (f->curr_token.kind == Token_String) { *foreign_name = f->curr_token.string; // TODO(bill): Check if valid string @@ -1785,9 +1791,10 @@ AstNode *parse_operand(AstFile *f, bool lhs) { // Parse Procedure Type or Literal case Token_proc: { Token token = f->curr_token; + AstNode *foreign_library = NULL; String foreign_name = {0}; String link_name = {0}; - AstNode *type = parse_proc_type(f, &foreign_name, &link_name); + AstNode *type = parse_proc_type(f, &foreign_library, &foreign_name, &link_name); u64 tags = type->ProcType.tags; if (f->curr_token.kind == Token_OpenBrace) { @@ -1800,11 +1807,11 @@ AstNode *parse_operand(AstFile *f, bool lhs) { body = parse_body(f); f->curr_proc = curr_proc; - return make_proc_lit(f, type, body, tags, foreign_name, link_name); + return make_proc_lit(f, type, body, tags, foreign_library, foreign_name, link_name); } if ((tags & ProcTag_foreign) != 0) { - return make_proc_lit(f, type, NULL, tags, foreign_name, link_name); + return make_proc_lit(f, type, NULL, tags, foreign_library, foreign_name, link_name); } if (tags != 0) { syntax_error(token, "A procedure type cannot have tags"); @@ -2312,7 +2319,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) { -AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) { +AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign_name_, String *link_name_) { AstNodeArray params = {0}; AstNodeArray results = {0}; @@ -2322,12 +2329,14 @@ AstNode *parse_proc_type(AstFile *f, String *foreign_name_, String *link_name_) u64 tags = 0; String foreign_name = {0}; String link_name = {0}; + AstNode *foreign_library = NULL; ProcCallingConvention cc = ProcCC_Odin; - parse_proc_tags(f, &tags, &foreign_name, &link_name, &cc); + parse_proc_tags(f, &tags, &foreign_library, &foreign_name, &link_name, &cc); - if (foreign_name_) *foreign_name_ = foreign_name; - if (link_name_) *link_name_ = link_name; + if (foreign_library_) *foreign_library_ = foreign_library; + if (foreign_name_) *foreign_name_ = foreign_name; + if (link_name_) *link_name_ = link_name; return make_proc_type(f, proc_token, params, results, tags, cc); } @@ -2644,7 +2653,7 @@ AstNode *parse_identifier_or_type(AstFile *f) { case Token_proc: { Token token = f->curr_token; - AstNode *pt = parse_proc_type(f, NULL, NULL); + AstNode *pt = parse_proc_type(f, NULL, NULL, NULL); if (pt->ProcType.tags != 0) { syntax_error(token, "A procedure type cannot have tags"); } @@ -3327,6 +3336,21 @@ AstNode *parse_stmt(AstFile *f) { return s; } else if (str_eq(tag, str_lit("foreign_system_library"))) { AstNode *cond = NULL; + Token lib_name = {0}; + + switch (f->curr_token.kind) { + case Token_Ident: + lib_name = f->curr_token; + next_token(f); + break; + default: + lib_name.pos = f->curr_token.pos; + break; + } + + if (str_eq(lib_name.string, str_lit("_"))) { + syntax_error(lib_name, "Illegal #foreign_library name: `_`"); + } Token file_path = expect_token(f, Token_String); if (allow_token(f, Token_when)) { @@ -3334,7 +3358,7 @@ AstNode *parse_stmt(AstFile *f) { } if (f->curr_proc == NULL) { - s = make_foreign_library(f, hash_token, file_path, cond, true); + s = make_foreign_library(f, hash_token, file_path, lib_name, cond, true); } else { syntax_error(token, "You cannot use #foreign_system_library within a procedure. This must be done at the file scope"); s = make_bad_decl(f, token, file_path); @@ -3343,6 +3367,21 @@ AstNode *parse_stmt(AstFile *f) { return s; } else if (str_eq(tag, str_lit("foreign_library"))) { AstNode *cond = NULL; + Token lib_name = {0}; + + switch (f->curr_token.kind) { + case Token_Ident: + lib_name = f->curr_token; + next_token(f); + break; + default: + lib_name.pos = f->curr_token.pos; + break; + } + + if (str_eq(lib_name.string, str_lit("_"))) { + syntax_error(lib_name, "Illegal #foreign_library name: `_`"); + } Token file_path = expect_token(f, Token_String); if (allow_token(f, Token_when)) { @@ -3350,7 +3389,7 @@ AstNode *parse_stmt(AstFile *f) { } if (f->curr_proc == NULL) { - s = make_foreign_library(f, hash_token, file_path, cond, false); + s = make_foreign_library(f, hash_token, file_path, lib_name, cond, false); } else { syntax_error(token, "You cannot use #foreign_library within a procedure. This must be done at the file scope"); s = make_bad_decl(f, token, file_path); @@ -3513,22 +3552,6 @@ bool try_add_import_path(Parser *p, String path, String rel_path, TokenPos pos) return true; } - -// // NOTE(bill): Returns true if it's added -// bool try_add_foreign_library_path(Parser *p, String import_file) { -// gb_mutex_lock(&p->mutex); - -// for_array(i, p->foreign_libraries) { -// String import = p->foreign_libraries.e[i]; -// if (str_eq(import, import_file)) { -// return false; -// } -// } -// array_add(&p->foreign_libraries, import_file); -// gb_mutex_unlock(&p->mutex); -// return true; -// } - gb_global Rune illegal_import_runes[] = { '"', '\'', '`', ' ', '\t', '\r', '\n', '\v', '\f', '\\', // NOTE(bill): Disallow windows style filepaths