diff --git a/self_hosted/create_llvm_ir.jou b/self_hosted/create_llvm_ir.jou index 1ecf2545..ddd0d4ff 100644 --- a/self_hosted/create_llvm_ir.jou +++ b/self_hosted/create_llvm_ir.jou @@ -796,17 +796,11 @@ class AstToIR: self->do_statement(&body->statements[i]) def call_the_special_startup_function(self) -> None: - if WINDOWS: - name = "_jou_windows_startup" - elif MACOS: - name = "_jou_macos_startup" - elif NETBSD: - name = "_jou_netbsd_startup" - else: + if not (WINDOWS or MACOS or NETBSD): return functype = LLVMFunctionType(LLVMVoidType(), NULL, 0, False as int) - func = LLVMAddFunction(self->module, name, functype) + func = LLVMAddFunction(self->module, "_jou_startup", functype) LLVMBuildCall2(self->builder, functype, func, NULL, 0, "") def define_function_or_method(self, funcdef: AstFunctionOrMethod*, self_type: Type*) -> None: diff --git a/self_hosted/evaluate.jou b/self_hosted/evaluate.jou index 863bc152..355885f1 100644 --- a/self_hosted/evaluate.jou +++ b/self_hosted/evaluate.jou @@ -12,6 +12,8 @@ def get_special_constant(name: byte*) -> int: return WINDOWS as int if strcmp(name, "MACOS") == 0: return MACOS as int + if strcmp(name, "NETBSD") == 0: + return NETBSD as int return -1 diff --git a/self_hosted/main.jou b/self_hosted/main.jou index c5d75170..8be8f3aa 100644 --- a/self_hosted/main.jou +++ b/self_hosted/main.jou @@ -172,15 +172,9 @@ class Compiler: def determine_automagic_files(self) -> None: self->automagic_files[0] = malloc(strlen(self->stdlib_path) + 40) sprintf(self->automagic_files[0], "%s/_assert_fail.jou", self->stdlib_path) - if WINDOWS: - self->automagic_files[1] = malloc(strlen(self->stdlib_path) + 40) - sprintf(self->automagic_files[1], "%s/_windows_startup.jou", self->stdlib_path) - if MACOS: - self->automagic_files[1] = malloc(strlen(self->stdlib_path) + 40) - sprintf(self->automagic_files[1], "%s/_macos_startup.jou", self->stdlib_path) - if NETBSD: + if WINDOWS or MACOS or NETBSD: self->automagic_files[1] = malloc(strlen(self->stdlib_path) + 40) - sprintf(self->automagic_files[1], "%s/_netbsd_startup.jou", self->stdlib_path) + sprintf(self->automagic_files[1], "%s/_jou_startup.jou", self->stdlib_path) def parse_all_files(self) -> None: queue: ParseQueueItem* = malloc(50 * sizeof queue[0]) diff --git a/src/codegen.c b/src/codegen.c index a596d70a..364e77eb 100644 --- a/src/codegen.c +++ b/src/codegen.c @@ -417,17 +417,8 @@ static int find_block(const CfGraph *cfg, const CfBlock *b) #if defined(_WIN32) || defined(__APPLE__) || defined(__NetBSD__) static void codegen_call_to_the_special_startup_function(const struct State *st) { - const char *name; -#if defined _WIN32 - name = "_jou_windows_startup"; -#elif defined __APPLE__ - name = "_jou_macos_startup"; -#else - name = "_jou_netbsd_startup"; -#endif - LLVMTypeRef functype = LLVMFunctionType(LLVMVoidType(), NULL, 0, false); - LLVMValueRef func = LLVMAddFunction(st->module, name, functype); + LLVMValueRef func = LLVMAddFunction(st->module, "_jou_startup", functype); LLVMBuildCall2(st->builder, functype, func, NULL, 0, ""); } #endif diff --git a/src/main.c b/src/main.c index f11d687f..c37a9882 100644 --- a/src/main.c +++ b/src/main.c @@ -455,15 +455,13 @@ int main(int argc, char **argv) } include_special_stdlib_file(&compst, "_assert_fail.jou"); -#ifdef _WIN32 - include_special_stdlib_file(&compst, "_windows_startup.jou"); -#endif -#ifdef __APPLE__ - include_special_stdlib_file(&compst, "_macos_startup.jou"); -#endif -#ifdef __NetBSD__ + +#if defined(__NetBSD__) assert(sizeof(FILE) == 152); // magic number in the startup file - include_special_stdlib_file(&compst, "_netbsd_startup.jou"); +#endif + +#if defined(_WIN32) || defined(__APPLE__) || defined(__NetBSD__) + include_special_stdlib_file(&compst, "_jou_startup.jou"); #endif parse_file(&compst, command_line_args.infile, NULL); diff --git a/stdlib/_jou_startup.jou b/stdlib/_jou_startup.jou new file mode 100644 index 00000000..c2b58498 --- /dev/null +++ b/stdlib/_jou_startup.jou @@ -0,0 +1,48 @@ +# On many platforms, a call to the _jou_startup() function is inserted to +# the start of main() in every Jou program. +# +# On Windows, the C "global variables" stdin, stdout and stderr are +# actually macros: +# +# $ printf "#include \nstdin\nstdout\nstderr\n" | x86_64-w64-mingw32-cpp | tail -3 +# (__acrt_iob_func(0)) +# (__acrt_iob_func(1)) +# (__acrt_iob_func(2)) +# +# For simplicity, Jou redefines them as variables with the same +# names and assigns the correct values to them. +# +# There seems to be a similar situation on most other platforms. +# +# We can't import FILE from io.jou here, because then we would be +# trying to define a variable that already exists. +if WINDOWS or MACOS or NETBSD: + global stdin: void* + global stdout: void* + global stderr: void* + +if WINDOWS: + declare __acrt_iob_func(index: int) -> void* + + def _jou_startup() -> None: + stdin = __acrt_iob_func(0) + stdout = __acrt_iob_func(1) + stderr = __acrt_iob_func(2) + +if MACOS: + declare global __stdinp: void* + declare global __stdoutp: void* + declare global __stderrp: void* + + def _jou_startup() -> None: + stdin = __stdinp + stdout = __stdoutp + stderr = __stderrp + +if NETBSD: + declare global __sF: byte[152][3] # sizeof(FILE) == 152 + + def _jou_startup() -> None: + stdin = &__sF[0] + stdout = &__sF[1] + stderr = &__sF[2] diff --git a/stdlib/_macos_startup.jou b/stdlib/_macos_startup.jou deleted file mode 100644 index 1d8baae8..00000000 --- a/stdlib/_macos_startup.jou +++ /dev/null @@ -1,26 +0,0 @@ -# A call to the _jou_macos_startup() function is inserted to the -# start of every Jou program when compiling for MacOS. - -# On macos, the C "global variables" stdin, stdout and stderr have -# different names. For simplicity, Jou redefines them as variables -# with the same names and assigns the correct values to them. -# -# We can't import FILE from io.jou here, because then we would be -# trying to define a variable that already exists. -global stdin: void* -global stdout: void* -global stderr: void* -declare global __stdinp: void* -declare global __stdoutp: void* -declare global __stderrp: void* - -def _jou_macos_startup() -> None: - stdin = __stdinp - stdout = __stdoutp - stderr = __stderrp - -# On linux, C's errno is a macro that expands to (*__errno_location()). -# On macos it expands to (*__error()) instead. Let's make it consistent. -declare __error() -> int* -def __errno_location() -> int*: - return __error() diff --git a/stdlib/_netbsd_startup.jou b/stdlib/_netbsd_startup.jou deleted file mode 100644 index e22d4bc9..00000000 --- a/stdlib/_netbsd_startup.jou +++ /dev/null @@ -1,23 +0,0 @@ -# A call to the _jou_netbsd_startup() function is inserted to the -# start of every Jou program when compiling for NetBSD. - -# On NetBSD, these std* things are macros -# expanding to elements of the __sF array -# of FILE structs. - -declare global __sF: byte[152][3] # sizeof(FILE) == 152 -global stdin: void* -global stdout: void* -global stderr: void* - -def _jou_netbsd_startup() -> None: - stdin = &__sF[0] - stdout = &__sF[1] - stderr = &__sF[2] - -# Jou uses __errno_location, -# NetBSD has __ernno() - -declare __errno() -> int* -def __errno_location() -> int*: - return __errno() diff --git a/stdlib/_windows_startup.jou b/stdlib/_windows_startup.jou deleted file mode 100644 index 878f9622..00000000 --- a/stdlib/_windows_startup.jou +++ /dev/null @@ -1,32 +0,0 @@ -# A call to the _jou_windows_startup() function is inserted to the -# start of every Jou program when compiling for Windows. - -# On Windows, the C "global variables" stdin, stdout and stderr are -# actually macros: -# -# $ printf "#include \nstdin\nstdout\nstderr\n" | x86_64-w64-mingw32-cpp | tail -3 -# (__acrt_iob_func(0)) -# (__acrt_iob_func(1)) -# (__acrt_iob_func(2)) -# -# For simplicity, Jou redefines them as variables with the same -# names and assigns the correct values to them. -# -# We can't import FILE from io.jou here, because then we would be -# trying to define a variable that already exists. -global stdin: void* -global stdout: void* -global stderr: void* - -declare __acrt_iob_func(index: int) -> void* - -def _jou_windows_startup() -> None: - stdin = __acrt_iob_func(0) - stdout = __acrt_iob_func(1) - stderr = __acrt_iob_func(2) - -# On linux, C's errno is a macro that expands to (*__errno_location()). -# On Windows it expands to (*_errno()) instead. Let's make it consistent. -declare _errno() -> int* -def __errno_location() -> int*: - return _errno() diff --git a/stdlib/errno.jou b/stdlib/errno.jou index 9fd56299..a74fcae2 100644 --- a/stdlib/errno.jou +++ b/stdlib/errno.jou @@ -1,12 +1,35 @@ # C's errno is actually a macro that expands to a function call. -# See also _windows_startup.jou -declare __errno_location() -> int* +# The function name varies by platform. +if WINDOWS: + declare _errno() -> int* +elif MACOS: + declare __error() -> int* +elif NETBSD: + declare __errno() -> int* +else: + declare __errno_location() -> int* -def set_errno(value: int) -> None: - *__errno_location() = value - -def get_errno() -> int: - return *__errno_location() +# TODO: Ideally we would be able to place the if statements inside the functions. +if WINDOWS: + def set_errno(value: int) -> None: + *_errno() = value + def get_errno() -> int: + return *_errno() +elif MACOS: + def set_errno(value: int) -> None: + *__error() = value + def get_errno() -> int: + return *__error() +elif NETBSD: + def set_errno(value: int) -> None: + *__errno() = value + def get_errno() -> int: + return *__errno() +else: + def set_errno(value: int) -> None: + *__errno_location() = value + def get_errno() -> int: + return *__errno_location() # Convert an error code into a string. Do not modify or free() the returned string. declare strerror(errno_value: int) -> byte* diff --git a/tests/should_succeed/compiler_cli.jou b/tests/should_succeed/compiler_cli.jou index 7cda3192..24ab52e7 100644 --- a/tests/should_succeed/compiler_cli.jou +++ b/tests/should_succeed/compiler_cli.jou @@ -48,7 +48,7 @@ def main() -> int: # Test that double-verbose kinda works, without asserting the output in too much detail. # See README for an explanation of why CFG is twice. - # TODO: shouldn't need to hide stdlib/io.jou or _windows_startup or _assert_fail stuff, ideally it would be precompiled + # TODO: shouldn't need to hide special stdlib/_... files, ideally they would be precompiled run_jou("-vv examples/hello.jou | grep === | grep -v stdlib/io.jou | grep -v stdlib/_") # Output: ===== Tokens for file "examples/hello.jou" ===== # Output: ===== AST for file "examples/hello.jou" =====