heap_allocator : Allocator;
// The global temp allocator, set up upon program intialization.
-#local
+#local #thread_local
temp_state : arena.ArenaState;
temp_allocator : Allocator;
-init :: () {
- heap.init();
-
+init_temp_allocator :: () {
temp_state = arena.make(heap_allocator, TEMPORARY_ALLOCATOR_SIZE);
temp_allocator = as_allocator(^temp_state);
}
clear :: (arena: ^ArenaState) {
walker := arena.first_arena.next;
while walker != null {
+ next := walker.next;
raw_free(arena.backing_allocator, walker);
- walker = walker.next;
+ walker = next;
}
arena.size = sizeof rawptr;
--- /dev/null
+package cbindgen
+
+//
+// How to use Onyx's cbindgen
+//
+// 1. Use generate_c_binding(config) to create a C source file for a given foreign block.
+// 2. Use compile_c_file() to compile the C source file into a native library.
+// 3. Run the build file with the --generate-foreign-info flag enabled.
+//
+// Full example:
+// #load "core/std"
+// #load "./module"
+//
+// use core
+//
+// main :: () {
+// path := module_path(#file);
+// c_file_path := string.concat(path, "temporary.c");
+// success := cbindgen.generate_c_binding(.{
+// output_file = c_file_path,
+// foreign_block = something.foreign_block,
+// cast_map = .[],
+// custom_implementations = .[],
+// preamble = .[
+// """
+// #include "..."
+// #define ...
+// // ...
+// """
+// ],
+// });
+//
+// if !success do os.exit(1);
+//
+// success = cbindgen.compile_c_file(c_file_path, string.concat(path, "library"));
+// if !success do os.exit(1);
+//
+// os.remove_file(c_file_path);
+// }
+//
+
+#if #defined (runtime.Generated_Foreign_Info) {
+
+#if runtime.compiler_os == .Linux {
+ #if #defined (runtime.vars.CC) {
+ Linux_Compiler :: runtime.vars.CC
+ } else {
+ Linux_Compiler :: "/usr/bin/gcc"
+ }
+}
+
+
+use core
+use simd
+
+Cast_Mapping :: struct {
+ type: type_expr;
+ name: str;
+}
+
+Impl_Mapping :: struct {
+ name: str;
+ impl: str;
+}
+
+Binding_Config :: struct {
+ foreign_block: runtime.info.foreign_block;
+ preamble: [] str;
+ output_file: str;
+ cast_map: [] Cast_Mapping;
+ custom_implementations: [] Impl_Mapping;
+ name_map: (str) -> str = null_proc;
+}
+
+generate_c_binding :: (use binding_config: Binding_Config) -> bool {
+ wrote := false;
+ for file: os.with_file(output_file, .Write) {
+ writer := io.writer_make(file);
+ fb := runtime.info.get_foreign_block(foreign_block);
+
+ write_file_introduction(^writer, preamble, fb.module_name);
+
+ for fb.funcs {
+ for impl: custom_implementations {
+ if impl.name == it.name {
+ io.write(^writer, impl.impl);
+ io.write(^writer, "\n");
+ continue continue;
+ }
+ }
+
+ write_function_body(^writer, it, cast_map, name_map);
+ }
+
+ write_library_block(^writer, fb.funcs);
+ wrote = true;
+ }
+
+ return wrote;
+}
+
+//
+// Call as module_path(#file)
+module_path :: (file_path: str) -> str {
+ out := file_path;
+ while out.count > 0 {
+ if out[out.count - 1] == #char "/" || out[out.count - 1] == #char "\\" do break;
+ out.count -= 1;
+ }
+
+ return out;
+}
+
+//
+// This is not as platform independent as I would like.
+// I don't know the best, most compatible way to compile DLLs on Windows.
+// Maybe those DLL can be shipped with the library, as most Windows is x86_64.
+//
+compile_c_file :: (
+ path: str, dest: str,
+ includes: [] str = .[],
+ libraries: [] str = .[],
+ flags := "") -> bool {
+ #if runtime.compiler_os == .Linux {
+ args: [..] str;
+ args << "-shared";
+ args << "-fPIC";
+ args << path;
+
+ args << "-I";
+ args << "/usr/share/onyx/include";
+
+ for includes {
+ args << "-I";
+ args << it;
+ }
+
+ if flags != "" {
+ for string.split(flags, #char " ") do args << it;
+ }
+
+ args << "-o";
+ args << tprintf("{}.so", dest);
+
+ for libraries {
+ args << aprintf("-l{}", it);
+ }
+
+ proc := os.process_spawn(Linux_Compiler, args);
+ defer os.process_destroy(^proc);
+
+ proc_reader := io.reader_make(^proc);
+ output := io.read_all(^proc_reader);
+ defer memory.free_slice(^output);
+
+ exit := os.process_wait(^proc);
+ if exit != .Success {
+ eprintf("Failed to compile {}\n", path);
+ eprintf("{}\n", output);
+ }
+
+ return exit == .Success;
+ }
+
+ #if runtime.compiler_os == .Windows {
+ return true;
+ }
+}
+
+#local {
+
+ write_file_introduction :: (writer: ^io.Writer, preamble: [] str, name: str) {
+ io.write_format(writer, "//\n");
+ io.write_format(writer, "// THIS FILE WAS AUTOMATICALLY GENERATED.\n");
+ io.write_format(writer, "//\n");
+
+ for text: preamble {
+ io.write_format(writer, "{}\n", text);
+ }
+
+ io.write_format(writer, """
+#define ONYX_LIBRARY_NAME {}
+#include "onyx_library.h"
+
+#define P(i, k) (params->data[i].of.k)
+
+""", name);
+ }
+
+ write_function_body :: (writer, ff, cast_map, name_map) => {
+ use runtime.info;
+
+ method_type := ff.type;
+ method_info := cast (^Type_Info_Function) get_type_info(method_type);
+ assert(method_info.kind == .Function, "Expected function type.");
+
+ io.write_format(writer, "ONYX_DEF({}, (", ff.name);
+ i := 0;
+ for method_info.parameter_types {
+ io.write(writer, type_encoding(it));
+
+ if i != method_info.parameter_types.count - 1 {
+ io.write(writer, ", ");
+ }
+ i += 1;
+ }
+
+ io.write(writer, "), (");
+ io.write(writer, type_encoding(method_info.return_type));
+ io.write(writer, ")) {\n");
+
+ method_name := ff.name;
+ if name_map != null_proc {
+ method_name = name_map(method_name);
+ }
+
+ print_body(writer, method_name, method_info, cast_map);
+
+ io.write(writer, "}\n\n");
+ }
+
+ write_library_block :: (writer, funcs) => {
+ io.write(writer, "\n\n");
+ io.write(writer, "ONYX_LIBRARY {\n");
+ for funcs {
+ io.write_format(writer, " ONYX_FUNC({})\n", it.name);
+ }
+ io.write(writer, " NULL\n");
+ io.write(writer, "};");
+ }
+
+ print_body :: (writer, method_name, method_info, cast_map) => {
+ use runtime.info;
+ call := io.dynamic_string_stream_make();
+ defer io.dynamic_string_stream_free(^call);
+ callw := io.writer_make(^call);
+
+ param_num := 0;
+ for method_info.parameter_types {
+ if get_type_info(it).kind == .Slice {
+ io.write_format(^callw, "ONYX_PTR(P({}, i32)), P({}, i32)", param_num, param_num + 1);
+ param_num += 1;
+
+ } elseif is_pointer(it) {
+ io.write_format(^callw, "ONYX_PTR(P({}, i32))", param_num);
+
+ } else {
+ matched := false;
+ for^ m: cast_map {
+ if m.type == it {
+ io.write_format(^callw, "({}) P({}, {})", m.name, param_num, type_to_wasm_type(it));
+ matched = true;
+ break;
+ }
+ }
+
+ if !matched do io.write_format(^callw, "P({}, {})", param_num, type_to_wasm_type(it));
+ }
+
+ io.write_format(^callw, ", ");
+ param_num += 1;
+ }
+
+ call_str := call->to_str();
+ wasm_return_type := type_to_wasm_type(method_info.return_type);
+ switch wasm_return_type {
+ case "" do io.write_format(writer, " {}({});\n", method_name, call_str[0..call_str.count-2]);
+ case "i32" do io.write_format(writer, " results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+ case "i64" do io.write_format(writer, " results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+ case "f32" do io.write_format(writer, " results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+ case "f64" do io.write_format(writer, " results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+ }
+
+ io.write_format(writer, " return NULL;\n");
+ }
+
+ type_to_wasm_type :: (t: type_expr) -> str {
+ use runtime.info;
+
+ param_info := get_type_info(t);
+ switch param_info.kind {
+ case .Basic do switch t {
+ case bool do return "i32";
+ case i8 do return "i32";
+ case u8 do return "i32";
+ case i16 do return "i32";
+ case u16 do return "i32";
+ case i32 do return "i32";
+ case u32 do return "i32";
+ case i64 do return "i64";
+ case u64 do return "i64";
+
+ case f32 do return "f32";
+ case f64 do return "f64";
+
+ case rawptr do return "i32"; // This will have to depend on the pointer size...
+
+ case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "v128";
+
+ case type_expr do return "i32";
+ }
+
+ case .Pointer do return "i32"; // This will also have to depend on the pointer size...
+ case .Function do assert(false, "Passing functions between wasm and c is not yet supported.");
+ case .Array do return "i32";
+ case .Slice do assert(false, "ASDFASDF");
+ case .Enum do return type_to_wasm_type((cast(^Type_Info_Enum) param_info).backing_type);
+ case .Distinct do return type_to_wasm_type((cast(^Type_Info_Distinct) param_info).base_type);
+
+ case .Struct {
+ s_info := cast(^Type_Info_Struct) param_info;
+ if s_info.members.count == 1 {
+ return type_to_wasm_type(s_info.members[0].type);
+ }
+
+ assert(false, "Passing structures between wasm and c is not yet supported.");
+ }
+ }
+
+ return "";
+ }
+
+ type_encoding :: (t: type_expr) -> str {
+ use runtime.info;
+
+ param_info := get_type_info(t);
+ switch param_info.kind {
+ case .Basic do switch t {
+ case bool do return "WASM_I32";
+ case i8 do return "WASM_I32";
+ case u8 do return "WASM_I32";
+ case i16 do return "WASM_I32";
+ case u16 do return "WASM_I32";
+ case i32 do return "WASM_I32";
+ case u32 do return "WASM_I32";
+ case i64 do return "WASM_I64";
+ case u64 do return "WASM_I64";
+
+ case f32 do return "WASM_F32";
+ case f64 do return "WASM_F64";
+
+ case rawptr do return "WASM_I32"; // This will have to depend on the pointer size...
+
+ case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "WASM_V128";
+
+ case type_expr do return "WASM_I32";
+ }
+
+ case .Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
+ case .Function do assert(false, "Passing functions between wasm and c is not yet supported.");
+ case .Array do return "WASM_I32";
+ case .Slice do return "WASM_I32,WASM_I32";
+ case .Enum do return type_encoding((cast(^Type_Info_Enum) param_info).backing_type);
+ case .Distinct do return type_encoding((cast(^Type_Info_Distinct) param_info).base_type);
+
+ case .Struct {
+ s_info := cast(^Type_Info_Struct) param_info;
+ if s_info.members.count == 1 {
+ return type_encoding(s_info.members[0].type);
+ return;
+ }
+
+ assert(false, "Passing structures between wasm and c is not yet supported.");
+ }
+ }
+
+ return "";
+ }
+}
+
+}
__dir_open :: (path: str, dir: ^DirectoryData) -> bool ---
__dir_close :: (dir: DirectoryData) -> void ---
__dir_read :: (dir: DirectoryData, out_entry: ^os.DirectoryEntry) -> bool ---
+ __dir_create :: (path: str) -> bool ---
__dir_remove :: (path: str) -> bool ---
}
return fs.__dir_read(dir, out_entry);
}
+dir_create :: fs.__dir_create
dir_exists :: fs.__file_exists
dir_remove :: fs.__dir_remove
-dir_rename :: fs.__file_rename
\ No newline at end of file
+dir_rename :: fs.__file_rename
process_handle: Handle;
}
-process_spawn :: (path: str, args: [] str, non_blocking_io := false) -> Process {
- handle := __process_spawn(path, args, non_blocking_io);
+process_spawn :: (path: str, args: [] str, non_blocking_io := false, starting_directory := "") -> Process {
+ handle := __process_spawn(path, args, non_blocking_io, starting_directory);
return .{
.{ ^process_stream_vtable },
}
#foreign "onyx_runtime" {
- __process_spawn :: (path: str, args: [] str, non_blocking_io: bool) -> Process.Handle ---
+ __process_spawn :: (path: str, args: [] str, non_blocking_io: bool, starting_directory: str) -> Process.Handle ---
__process_read :: (handle: Process.Handle, buffer: [] u8) -> i32 ---
__process_write :: (handle: Process.Handle, buffer: [] u8) -> i32 ---
__process_kill :: (handle: Process.Handle) -> bool ---
__runtime_initialize :: () {
__initialize_data_segments();
- alloc.init();
+ alloc.heap.init();
__thread_initialize();
#if Multi_Threading_Enabled do thread.__initialize();
memory.set(__tls_base, 0, __tls_size);
}
+ alloc.init_temp_allocator();
+
__initialize(^context);
context.allocator = alloc.heap_allocator;
context.temp_allocator = alloc.temp_allocator;
if get_type_info(T).kind != .Function do return .[];
for tagged_procedures {
- if it.func == func do return it.tags;
+ if (*cast(^T) ^it.func) == func do return it.tags;
}
return .[];
#load "./onyx/fs"
#load "./onyx/cptr"
+ #load "./onyx/cbindgen"
}
#if runtime.runtime == .Wasi {
#load "./wasi/wasi"
GB_DLL_IMPORT BOOL WINAPI CopyFileW(wchar_t const *old_f, wchar_t const *new_f, BOOL fail_if_exists);
GB_DLL_IMPORT BOOL WINAPI MoveFileW(wchar_t const *old_f, wchar_t const *new_f);
GB_DLL_IMPORT BOOL WINAPI DeleteFileA (char const *path);
+GB_DLL_IMPORT BOOL WINAPI CreateDirectoryA(char const *path);
GB_DLL_IMPORT BOOL WINAPI RemoveDirectoryA(char const *path);
GB_DLL_IMPORT BOOL WINAPI MoveFileA (char const *old_path, char const *new_path);
const char* onyx_ast_node_kind_string(AstKind kind);
Package* package_lookup(char* package_name);
-Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_allocator alloc);
+Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_allocator alloc, OnyxFilePos pos);
void package_track_use_package(Package* package, Entity* entity);
void package_reinsert_use_packages(Package* package);
+++ /dev/null
-package c_binding
-
-use package core
-use package simd
-#local info :: package runtime.info
-
-#if !#defined((package runtime).Generated_Foreign_Info) {
- #error "Please run this script with the '--generate-foreign-info' flag."
-}
-
-Cast_Mapping :: struct {
- type: type_expr;
- name: str;
-}
-
-Impl_Mapping :: struct {
- name: str;
- impl: str;
-}
-
-Binding_Config :: struct {
- foreign_block: info.foreign_block;
- preamble: [] str;
- output_file: str;
- cast_map: [] Cast_Mapping;
- custom_implementations: [] Impl_Mapping;
- name_map: (str) -> str = null_proc;
-}
-
-build_c_binding :: (use binding_config: Binding_Config) -> bool {
- for file: os.with_file(output_file, .Write) {
- writer := io.writer_make(file);
- fb := info.get_foreign_block(foreign_block);
-
- write_file_introduction(^writer, preamble, fb.module_name);
-
- for fb.funcs {
- for impl: custom_implementations {
- if impl.name == it.name {
- io.write(^writer, impl.impl);
- io.write(^writer, "\n");
- continue continue;
- }
- }
-
- write_function_body(^writer, it, cast_map, name_map);
- }
-
- write_library_block(^writer, fb.funcs);
- }
-
- return true;
-}
-
-write_file_introduction :: (writer: ^io.Writer, preamble: [] str, name: str) {
- io.write_format(writer, "//\n");
- io.write_format(writer, "// THIS FILE WAS AUTOMATICALLY GENERATED.\n");
- io.write_format(writer, "//\n");
-
- for text: preamble {
- io.write_format(writer, "{}\n", text);
- }
-
- io.write_format(writer, """
-#define ONYX_LIBRARY_NAME {}
-#include "onyx_library.h"
-
-#define P(i, k) (params->data[i].of.k)
-
-""", name);
-}
-
-write_function_body :: (writer, ff, cast_map, name_map) => {
- use info;
-
- method_type := ff.type;
- method_info := cast (^Type_Info_Function) get_type_info(method_type);
- assert(method_info.kind == .Function, "Expected function type.");
-
- io.write_format(writer, "ONYX_DEF({}, (", ff.name);
- i := 0;
- for method_info.parameter_types {
- io.write(writer, type_encoding(it));
-
- if i != method_info.parameter_types.count - 1 {
- io.write(writer, ", ");
- }
- i += 1;
- }
-
- io.write(writer, "), (");
- io.write(writer, type_encoding(method_info.return_type));
- io.write(writer, ")) {\n");
-
- method_name := ff.name;
- if name_map != null_proc {
- method_name = name_map(method_name);
- }
-
- print_body(writer, method_name, method_info, cast_map);
-
- io.write(writer, "}\n\n");
-}
-
-write_library_block :: (writer, funcs) => {
- io.write(writer, "\n\n");
- io.write(writer, "ONYX_LIBRARY {\n");
- for funcs {
- io.write_format(writer, " ONYX_FUNC({})\n", it.name);
- }
- io.write(writer, " NULL\n");
- io.write(writer, "};");
-}
-
-print_body :: (writer, method_name, method_info, cast_map) => {
- use info;
- call := io.dynamic_string_stream_make();
- defer io.dynamic_string_stream_free(^call);
- callw := io.writer_make(^call);
-
- param_num := 0;
- for method_info.parameter_types {
- if get_type_info(it).kind == .Slice {
- io.write_format(^callw, "ONYX_PTR(P({}, i32)), P({}, i32)", param_num, param_num + 1);
- param_num += 1;
-
- } elseif is_pointer(it) {
- io.write_format(^callw, "ONYX_PTR(P({}, i32))", param_num);
-
- } else {
- matched := false;
- for^ m: cast_map {
- if m.type == it {
- io.write_format(^callw, "({}) P({}, {})", m.name, param_num, type_to_wasm_type(it));
- matched = true;
- break;
- }
- }
-
- if !matched do io.write_format(^callw, "P({}, {})", param_num, type_to_wasm_type(it));
- }
-
- io.write_format(^callw, ", ");
- param_num += 1;
- }
-
- call_str := call->to_str();
- wasm_return_type := type_to_wasm_type(method_info.return_type);
- switch wasm_return_type {
- case "" do io.write_format(writer, " {}({});\n", method_name, call_str[0..call_str.count-2]);
- case "i32" do io.write_format(writer, " results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
- case "i64" do io.write_format(writer, " results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
- case "f32" do io.write_format(writer, " results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
- case "f64" do io.write_format(writer, " results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
- }
-
- io.write_format(writer, " return NULL;\n");
-}
-
-type_to_wasm_type :: (t: type_expr) -> str {
- use info;
-
- param_info := get_type_info(t);
- switch param_info.kind {
- case .Basic do switch t {
- case bool do return "i32";
- case i8 do return "i32";
- case u8 do return "i32";
- case i16 do return "i32";
- case u16 do return "i32";
- case i32 do return "i32";
- case u32 do return "i32";
- case i64 do return "i64";
- case u64 do return "i64";
-
- case f32 do return "f32";
- case f64 do return "f64";
-
- case rawptr do return "i32"; // This will have to depend on the pointer size...
-
- case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "v128";
-
- case type_expr do return "i32";
- }
-
- case .Pointer do return "i32"; // This will also have to depend on the pointer size...
- case .Function do assert(false, "Passing functions between wasm and c is not yet supported.");
- case .Array do return "i32";
- case .Slice do assert(false, "ASDFASDF");
- case .Enum do return type_to_wasm_type((cast(^Type_Info_Enum) param_info).backing_type);
- case .Distinct do return type_to_wasm_type((cast(^Type_Info_Distinct) param_info).base_type);
-
- case .Struct {
- s_info := cast(^Type_Info_Struct) param_info;
- if s_info.members.count == 1 {
- return type_to_wasm_type(s_info.members[0].type);
- }
-
- assert(false, "Passing structures between wasm and c is not yet supported.");
- }
- }
-
- return "";
-}
-
-type_encoding :: (t: type_expr) -> str {
- use info;
-
- param_info := get_type_info(t);
- switch param_info.kind {
- case .Basic do switch t {
- case bool do return "WASM_I32";
- case i8 do return "WASM_I32";
- case u8 do return "WASM_I32";
- case i16 do return "WASM_I32";
- case u16 do return "WASM_I32";
- case i32 do return "WASM_I32";
- case u32 do return "WASM_I32";
- case i64 do return "WASM_I64";
- case u64 do return "WASM_I64";
-
- case f32 do return "WASM_F32";
- case f64 do return "WASM_F64";
-
- case rawptr do return "WASM_I32"; // This will have to depend on the pointer size...
-
- case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "WASM_V128";
-
- case type_expr do return "WASM_I32";
- }
-
- case .Pointer do return "WASM_I32"; // This will also have to depend on the pointer size...
- case .Function do assert(false, "Passing functions between wasm and c is not yet supported.");
- case .Array do return "WASM_I32";
- case .Slice do return "WASM_I32,WASM_I32";
- case .Enum do return type_encoding((cast(^Type_Info_Enum) param_info).backing_type);
- case .Distinct do return type_encoding((cast(^Type_Info_Distinct) param_info).base_type);
-
- case .Struct {
- s_info := cast(^Type_Info_Struct) param_info;
- if s_info.members.count == 1 {
- return type_encoding(s_info.members[0].type);
- return;
- }
-
- assert(false, "Passing structures between wasm and c is not yet supported.");
- }
- }
-
- return "";
-}
+++ /dev/null
-
-#load "core/std"
-use package core
-
-runtime :: package runtime
-
-Linux_Compiler :: "/usr/bin/gcc"
-
-
-//
-// Call as module_path(#file)
-module_path :: (file_path: str) -> str {
- out := file_path;
- while out.count > 0 {
- if out[out.count - 1] == #char "/" || out[out.count - 1] == #char "\\" do break;
- out.count -= 1;
- }
-
- return out;
-}
-
-compile_c_file :: (path: str, dest: str, includes: [] str = .[], libraries: [] str = .[], flags := "") -> bool {
- printf("Compiling '{}' -> '{}'.\n", path, dest);
-
- #if runtime.compiler_os == .Linux {
- args: [..] str;
- args << "-shared";
- args << "-fPIC";
- args << path;
-
- args << "-I";
- args << "/usr/share/onyx/include";
-
- for includes {
- args << "-I";
- args << it;
- }
-
- if flags != "" {
- for string.split(flags, #char " ") do args << it;
- }
-
- args << "-o";
- args << dest;
-
- for libraries {
- args << aprintf("-l{}", it);
- }
-
- proc := os.process_spawn(Linux_Compiler, args);
- defer os.process_destroy(^proc);
-
- proc_reader := io.reader_make(^proc);
- output := io.read_all(^proc_reader);
- defer memory.free_slice(^output);
-
- exit := os.process_wait(^proc);
- println(exit);
- println(output);
- return exit == .Success;
- }
-
- #if runtime.compiler_os == .Windows {
- return true;
- }
-}
\ No newline at end of file
Version :: SemVer.{0, 1, 1}
-use package core
-use package core.intrinsics.onyx {__initialize, __zero_value}
+use core
+use core.intrinsics.onyx {__initialize, __zero_value}
global_arguments: struct {
#tag "--config-file"
loaded_config_file := false;
defer if loaded_config_file do store_config_file();
- info :: package runtime.info
- command_procedures := info.get_procedures_with_tag(Command);
+ command_procedures := runtime.info.get_procedures_with_tag(Command);
defer delete(^command_procedures);
for command_procedures {
if it.tag.command == command {
printf("onyx-pkg version {}\n", Version);
printf("Package dependency resolver and synchronizer for Onyx.\n\nUsage:\n");
- info :: package runtime.info
- command_procedures := info.get_procedures_with_tag(Command);
+ command_procedures := runtime.info.get_procedures_with_tag(Command);
defer delete(^command_procedures);
for command_procedures {
printf("{}\n", it.tag.description);
if it.type != .Directory do continue;
if !array.contains(needed_dependency_folders, it->name()) {
- os.remove_directory(tprintf("{}/{}", config.config.lib_source_directory, it->name()));
+ package_folder := tprintf("{}/{}", config.config.lib_source_directory, it->name());
+ attempt_remove_native_library(package_folder);
+ os.remove_directory(package_folder);
}
}
}
}
+#tag Command.{ "rebuild", "Rebuild native library for a package", "package-or-url",
+"""
+package-or-url Git repository name or package name on disk to remove.
+"""
+}
+run_rebuild_command :: (args: [] cstr) {
+ if args.count < 1 {
+ eprintf("Expected package name.");
+ return;
+ }
+
+ dep := string.as_str(args[0]);
+
+ folder := dep;
+ if config.dependency_folders.folders->has(dep) {
+ folder = config.dependency_folders.folders[dep];
+ }
+
+ if rebuild_native_library(folder) {
+ printf("Successfully rebuilt {}.\n", dep);
+ } else {
+ printf("Failed to rebuild {}.\n", dep);
+ os.exit(1);
+ }
+}
+
+#local {
+ #if runtime.compiler_os == .Linux {
+ native_library_suffix :: ".so"
+ }
+ #if runtime.compiler_os == .Windows {
+ native_library_suffix :: ".dll"
+ }
+}
+
+
install_package :: (pack: Package, downgrade_if_necessary := false) -> (bool, installed_folder: str) {
if config.dependency_folders.folders->has(pack.repo) {
folder_name := config.dependency_folders.folders[pack.repo];
}
assert(config.dependency_folders.folders->has(pack.repo), "");
- folder_name := config.dependency_folders.folders[pack.repo];
- return true, folder_name;
+ folder_name := config.dependency_folders.folders[pack.repo];
+ install_success := run_native_library_installation(folder_name);
+ return install_success, folder_name;
}
uninstall_package :: (pack: Package) -> bool {
if os.file_exists(package_folder) {
// Should this check if the version to be deleted is the one that is actually installed?
+ attempt_remove_native_library(package_folder);
os.remove_directory(package_folder);
}
+
+ return true;
}
+
+ return false;
+}
+
+attempt_remove_native_library :: (package_folder: str) -> bool {
+ inner_config: Config;
+ for os.with_file(tprintf("{}/onyx-pkg.ini", package_folder)) {
+ r := io.reader_make(it);
+ result, error := parse_ini_file(^r, ^inner_config);
+
+ if result != .Success do return false;
+ if string.is_empty(inner_config.native_library.library) do return false;
+
+ os.remove_file(tprintf("{}/{}{}", config.config.lib_bin_directory, inner_config.native_library.library, native_library_suffix));
+ }
+
+ return true;
+}
+
+rebuild_native_library :: (folder: str) -> bool {
+ attempt_remove_native_library(tprintf("{}/{}", config.config.lib_source_directory, folder));
+ return run_native_library_installation(folder);
}
get_installed_version_of_package :: (package_path: str) -> SemVer {
return .{0, 0, 0};
}
+run_native_library_installation :: (folder: str) -> bool {
+ inner_config: Config;
+ for os.with_file(tprintf("{}/{}/onyx-pkg.ini", config.config.lib_source_directory, folder)) {
+ r := io.reader_make(it);
+ result, error := parse_ini_file(^r, ^inner_config);
+
+ if result != .Success do return false;
+ if string.is_empty(inner_config.native_library.build_cmd) do return true;
+
+ args := string.split(inner_config.native_library.build_cmd, #char " ", context.temp_allocator);
+ cmd := args[0];
+ args = args[1 .. args.count];
+
+ installed_dest := tprintf("{}/{}", config.config.lib_source_directory, folder);
+ build_proc := os.process_spawn(cmd, args, starting_directory=installed_dest);
+ build_result := os.process_wait(^build_proc);
+
+ if build_result != .Success {
+ eprintf("Failed to build native library in {}.\n", folder);
+ return false;
+ }
+
+ if !os.dir_exists(config.config.lib_bin_directory) {
+ if !os.dir_create(config.config.lib_bin_directory) {
+ eprintf("Failed to create native library directory, {}.\n", config.config.lib_bin_directory);
+ return false;
+ }
+ }
+
+ source_path := tprintf("{}/{}{}", installed_dest, inner_config.native_library.library, native_library_suffix);
+ dest_path := tprintf("{}/{}{}", config.config.lib_bin_directory, inner_config.native_library.library, native_library_suffix);
+ success := os.rename_file(source_path, dest_path);
+
+ if !success {
+ eprintf("Failed to move native library to final destination.\n {} -> {}\n", source_path, dest_path);
+ }
+
+ return success;
+ }
+}
+
#tag conv.Custom_Parse.{parse}
#tag conv.Custom_Format.{format}
version: SemVer;
}
-#local runtime :: package runtime
#if runtime.compiler_os == .Linux {
- git_path :: "/usr/bin/git"
+ git_path :: "git"
}
#if runtime.compiler_os == .Windows {
git_path :: "git.exe"
}
}
- if os.process_wait(^git_proc) == .Error {
- eprintf("Encountered error running 'git' command.");
- }
+ os.process_wait(^git_proc);
return versions;
}
}
config: Config = .{};
+ Native_Library :: struct {
+ build_cmd: str;
+ library: str;
+ }
+ native_library: Native_Library;
+
Dependencies :: struct {
dependencies: Map(str, SemVer);
}
parse_ini_file :: (r: ^io.Reader, output_ptr: any) -> (IniParseResult, IniParseError) {
- info :: package runtime.info
+ info :: runtime.info
line := 1;
error :: macro (msg: str) {
field_name := r->read_until(#char "=", allocator=context.temp_allocator);
assert(r->read_byte() == #char "=", "expected =");
- r->skip_whitespace();
field := info.get_struct_member(active_item_type, string.strip_whitespace(field_name));
target := cast(^u8) active_item_ptr + field.offset;
// If the type is a string, then the value can be the entire line
// of text. No need to force the quotes.
if field.type == str {
- *cast(^str) target = string.alloc_copy(value_string)
- |> string.strip_whitespace();
+ *cast(^str) target = value_string
+ |> string.strip_whitespace()
+ |> string.alloc_copy();
} else {
error(aprintf("Failed to parse value."));
}
write_ini_file :: (w: ^io.Writer, output: any) -> bool {
- info :: package runtime.info
+ info :: runtime.info
output_info := cast(^info.Type_Info_Struct) info.get_type_info(output.type);
if output_info.kind != .Struct do return false;
#load "core/std"
-use package core
-use package core.intrinsics.onyx { init }
-#local runtime :: package runtime
+use core
+use core.intrinsics.onyx { init }
Color :: enum {
White;
iter.parallel_for(cases, settings.threads, ^exec_context) {
// Weird macros mean I have to forward external names
- use package core
+ use core
print_color :: print_color;
args: [] str;
if (bsym->package == NULL)
symbol_builtin_introduce(context.global_scope, bsym->sym, bsym->node);
else {
- Package* p = package_lookup_or_create(bsym->package, context.global_scope, a);
+ Package* p = package_lookup_or_create(bsym->package, context.global_scope, a, context.global_scope->created_at);
assert(p);
symbol_builtin_introduce(p->scope, bsym->sym, bsym->node);
bsym++;
}
- Package* p = package_lookup_or_create("builtin", context.global_scope, a);
+ Package* p = package_lookup_or_create("builtin", context.global_scope, a, context.global_scope->created_at);
builtin_string_type = (AstType *) symbol_raw_resolve(p->scope, "str");
if (builtin_string_type == NULL) {
}
void introduce_build_options(bh_allocator a) {
- Package* p = package_lookup_or_create("runtime", context.global_scope, a);
+ Package* p = package_lookup_or_create("runtime", context.global_scope, a, context.global_scope->created_at);
AstType* Runtime_Type = (AstType *) symbol_raw_resolve(p->scope, "Runtime");
if (Runtime_Type == NULL) {
context.options = opts;
context.cycle_detected = 0;
- context.global_scope = scope_create(global_heap_allocator, NULL, (OnyxFilePos) { 0 });
+ OnyxFilePos internal_location = { 0 };
+ internal_location.filename = "<compiler internal>";
+ internal_location.line = 1;
+ internal_location.column = 1;
+ context.global_scope = scope_create(global_heap_allocator, NULL, internal_location);
sh_new_arena(context.packages);
// NOTE: This will be initialized upon the first call to entity_heap_insert.
int path_len = params->data[1].of.i32;
char path[512] = {0};
+ path_len = bh_min(path_len, 511);
strncpy(path, path_ptr, path_len);
path[path_len] = 0;
int path_len = params->data[1].of.i32;
char path[512] = {0};
+ path_len = bh_min(path_len, 511);
strncpy(path, path_ptr, path_len);
path[path_len] = 0;
int path_len = params->data[1].of.i32;
char path[512] = {0};
+ path_len = bh_min(path_len, 511);
strncpy(path, path_ptr, path_len);
path[path_len] = 0;
int old_path_len = params->data[1].of.i32;
char old_path[512] = {0};
+ old_path_len = bh_min(old_path_len, 511);
strncpy(old_path, old_path_ptr, old_path_len);
old_path[old_path_len] = 0;
int new_path_len = params->data[3].of.i32;
char new_path[512] = {0};
+ new_path_len = bh_min(new_path_len, 511);
strncpy(new_path, new_path_ptr, new_path_len);
new_path[new_path_len] = 0;
int path_len = params->data[1].of.i32;
char path[512] = {0};
+ path_len = bh_min(path_len, 511);
strncpy(path, path_ptr, path_len);
path[path_len] = 0;
return NULL;
}
+ONYX_DEF(__dir_create, (WASM_I32, WASM_I32), (WASM_I32)) {
+ char *path_ptr = ONYX_PTR(params->data[0].of.i32);
+ int path_len = params->data[1].of.i32;
+
+ char path[512] = {0};
+ path_len = bh_min(path_len, 511);
+ strncpy(path, path_ptr, path_len);
+ path[path_len] = 0;
+
+#ifdef _BH_WINDOWS
+ results->data[0] = WASM_I32_VAL(CreateDirectoryA(path, NULL));
+ return NULL;
+#endif
+
+#ifdef _BH_LINUX
+ results->data[0] = WASM_I32_VAL(mkdir(path, 0777) == 0);
+ return NULL;
+#endif
+}
+
ONYX_DEF(__dir_remove, (WASM_I32, WASM_I32), (WASM_I32)) {
char *path_ptr = ONYX_PTR(params->data[0].of.i32);
int path_len = params->data[1].of.i32;
char path[512] = {0};
+ path_len = bh_min(path_len, 511);
strncpy(path, path_ptr, path_len);
path[path_len] = 0;
#endif
} OnyxProcess;
-ONYX_DEF(__process_spawn, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I64)) {
+ONYX_DEF(__process_spawn, (WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I64)) {
char* process_str = ONYX_PTR(params->data[0].of.i32);
i32 process_len = params->data[1].of.i32;
i32 args_ptr = params->data[2].of.i32;
i32 args_len = params->data[3].of.i32;
b32 blocking_io = !params->data[4].of.i32;
+ char *cwd_str = ONYX_PTR(params->data[5].of.i32);
+ i32 cwd_len = params->data[6].of.i32;
char process_path[1024];
process_len = bh_min(1023, process_len);
memcpy(process_path, process_str, process_len);
process_path[process_len] = '\0';
+ char starting_dir[1024];
+ if (cwd_len > 0) {
+ cwd_len = bh_min(1023, cwd_len);
+ memcpy(starting_dir, cwd_str, cwd_len);
+ starting_dir[cwd_len] = '\0';
+ }
+
OnyxProcess *process = malloc(sizeof(OnyxProcess));
memset(process, 0, sizeof(*process));
process->magic_number = ONYX_PROCESS_MAGIC_NUMBER;
fcntl(1, F_SETFL, O_NONBLOCK);
}
- execv(process_path, process_args);
+ if (cwd_len > 0) {
+ chdir(starting_dir); // Switch current working directory.
+ }
+
+ execvp(process_path, process_args);
exit(-1);
break;
memset(&process->proc_info, 0, sizeof process->proc_info);
- success = CreateProcessA(process_path, cmdLine, &saAttr, &saAttr, 1, 0, NULL, NULL, &startup, &process->proc_info);
+ char *working_dir = NULL;
+ if (cwd_len > 0) {
+ working_dir = starting_dir;
+ }
+
+ success = CreateProcessA(process_path, cmdLine, &saAttr, &saAttr, 1, 0, NULL, working_dir, &startup, &process->proc_info);
if (!success) {
printf("FAILED TO CREATE PROCESS: %d\n", GetLastError());
wasm_val_init_ptr(&results->data[0], NULL); // Failed to run @LEAK
ONYX_FUNC(__dir_open)
ONYX_FUNC(__dir_read)
ONYX_FUNC(__dir_close)
+ ONYX_FUNC(__dir_create)
ONYX_FUNC(__dir_remove)
ONYX_FUNC(__spawn_thread)
static Package* parse_file_package(OnyxParser* parser) {
if (parser->curr->type != Token_Type_Keyword_Package) {
- return package_lookup_or_create("main", context.global_scope, parser->allocator);
+ return package_lookup_or_create("main", context.global_scope, parser->allocator, parser->curr->pos);
}
AstPackage* package_node = parse_package_expression(parser);
token_toggle_end(*symbol);
strncat(aggregate_name, (*symbol)->text, 2047);
- Package* newpackage = package_lookup_or_create(aggregate_name, context.global_scope, parser->allocator);
+ Package* newpackage = package_lookup_or_create(aggregate_name, context.global_scope, parser->allocator, package_node->token->pos);
AstPackage* pnode = make_node(AstPackage, Ast_Kind_Package);
pnode->token = *symbol;
}
}
-Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_allocator alloc) {
+Package* package_lookup_or_create(char* package_name, Scope* parent_scope, bh_allocator alloc, OnyxFilePos pos) {
i32 index = shgeti(context.packages, package_name);
if (index != -1) {
return context.packages[index].value;
shput(context.packages, pac_name, package);
+ if (!charset_contains(pac_name, '.')) {
+ AstPackage* package_node = onyx_ast_node_new(alloc, sizeof(AstPackage), Ast_Kind_Package);
+ package_node->package_name = package->name;
+ package_node->package = package;
+
+ symbol_raw_introduce(context.global_scope, pac_name, pos, (AstNode *) package_node);
+ }
+
return package;
}
}
AstNode *node = scope->symbols[index].value;
if (node != symbol) {
onyx_report_error(pos, Error_Critical, "Redeclaration of symbol '%s'.", name);
+
+ if (node->token) {
+ onyx_report_error(node->token->pos, Error_Critical, "Previous declaration was here.");
+ }
+
return 0;
}
return 1;
Hello, I am Billy!
-Go away!! 0xEDF4
+Go away!! (^Person) -> void
mean_person := Person_Vtable.{
greet = (use p: ^Person) {
- printf("Go away!! {}\n", ^greet);
+ printf("Go away!! {}\n", typeof greet);
}
}
billy->greet();
charles->greet();
-}
\ No newline at end of file
+}