added foreign block info
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 2 May 2022 19:09:02 +0000 (14:09 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 2 May 2022 19:09:02 +0000 (14:09 -0500)
15 files changed:
core/type_info/type_info.onyx
include/astnodes.h
include/wasm_emit.h
modules/ncurses/build.onyx [new file with mode: 0644]
modules/ncurses/build.sh
modules/ncurses/module.onyx
modules/ncurses/ncurses.c
modules/ncurses/onyx_ncurses.so
scripts/c_binding.onyx
src/builtins.c
src/onyx.c
src/parser.c
src/symres.c
src/wasm_emit.c
src/wasm_type_table.h

index 254753c13e537df1a87aeb07f9144ba66e29560e..ca84d3cd828acf7a63913fcca40948c68a36f469 100644 (file)
@@ -187,3 +187,38 @@ get_type_info :: (t: type_expr) -> ^Type_Info {
 
     return type_table[cast(i32) t];
 }
+
+
+
+
+//
+// I have a small feeling I am going to rename "type_info" at some point soon,
+// which makes including this here make even more sense.
+//
+
+//
+// Foreign Blocks
+// Because foreign blocks can generate a lot of data, and their data is only
+// really helpful in a handful of cases, you need to pass "--generate-foreign-bindings"
+// to have these arrays filled out.
+//
+
+foreign_block :: #distinct u32
+
+foreign_blocks: [] ^Foreign_Block;
+
+Foreign_Block :: struct {
+    module_name: str;
+    funcs: [] Foreign_Function;
+
+    Foreign_Function :: struct {
+        name: str;
+        type: type_expr;
+    }
+}
+
+get_foreign_block :: (f: foreign_block) -> ^Foreign_Block {
+    if ~~f < cast(i32) 0 || ~~f >= cast(i32) foreign_blocks.count do return null;
+
+    return foreign_blocks[cast(i32) f];
+}
\ No newline at end of file
index f7cb27409cb119ce768642b2d737138c169bb3c8..358c67f5905a6167836c6fd1ca4ce7ebdb35d647 100644 (file)
@@ -1329,6 +1329,8 @@ struct AstForeignBlock {
     Scope* scope;
     OnyxToken *module_name;
     bh_arr(struct Entity *) captured_entities;
+
+    u32 foreign_block_number;
 };
 
 typedef enum EntityState {
@@ -1507,6 +1509,7 @@ struct CompileOptions {
     
     b32 use_post_mvp_features : 1;
     b32 use_multi_threading   : 1;
+    b32 generate_foreign_info : 1;
 
     Runtime runtime;
 
@@ -1591,6 +1594,8 @@ extern AstType  *builtin_callsite_type;
 extern AstType  *builtin_any_type;
 extern AstType  *builtin_code_type;
 extern AstTyped *type_table_node;
+extern AstTyped *foreign_blocks_node;
+extern AstType  *foreign_block_type;
 extern AstFunction *builtin_initialize_data_segments;
 extern AstFunction *builtin_run_init_procedures;
 extern bh_arr(AstFunction *) init_procedures;
index 71141188f0e58366a5482ff74d43c4be10b29404..c9f10ab02ccff120db270dc35b56826c19825f5a 100644 (file)
@@ -645,6 +645,9 @@ typedef struct OnyxWasmModule {
 
     bh_arr(ForRemoveInfo) for_remove_info;
 
+    bh_arr(AstForeignBlock *) foreign_blocks;
+    u32 next_foreign_block_idx;
+
     // NOTE: Used internally as a map from strings that represent function types,
     // 0x7f 0x7f : 0x7f ( (i32, i32) -> i32 )
     // to the function type index if it has been created.
diff --git a/modules/ncurses/build.onyx b/modules/ncurses/build.onyx
new file mode 100644 (file)
index 0000000..ccdf032
--- /dev/null
@@ -0,0 +1,37 @@
+#load "core/std"
+#load "scripts/c_binding"
+#load "./module"
+
+use package core
+use package c_binding
+
+main :: () {
+    result := build_c_binding(.{
+        output_file = "modules/ncurses/ncurses.c",
+        foreign_block = (package ncurses).foreign_block,
+
+        cast_map = .[
+            .{ (package ncurses).WINDOW, "WINDOW *" },
+        ],
+
+        preamble = .[
+"""
+#include "ncurses.h"
+
+#define __get_stdscr() ((unsigned long int) stdscr)
+
+void __get_yx    (WINDOW *w, int *y, int *x) { getyx(w, *y, *x); }
+void __get_par_yx(WINDOW *w, int *y, int *x) { getparyx(w, *y, *x); }
+void __get_beg_yx(WINDOW *w, int *y, int *x) { getbegyx(w, *y, *x); }
+void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); }
+"""
+        ],
+    });
+
+    if !result {
+        println("Failed to make c-file.");
+        os.exit(1);
+    } else {
+        println("Sucessfully made ncurses.c");
+    }
+}
\ No newline at end of file
index caff9ee25f89db64b8f3b14c14415a00b3cf048e..2412b3802335b7210c26d9efa33b625047e5b9d1 100755 (executable)
@@ -1,4 +1,4 @@
 #!/bin/sh
 
-onyx run scripts/c_binding.onyx modules/ncurses/module.onyx > modules/ncurses/ncurses.c
+onyx run modules/ncurses/build.onyx --generate-foreign-info
 gcc -shared -fPIC -I include -I lib/common/include -O2 modules/ncurses/ncurses.c -o modules/ncurses/onyx_ncurses.so -lncurses
index 5908a1f3e85cd1ba90ef9ec40820a7f6ddcc1175..2ce788879d240a7f62aaa23bf349490a75208aab 100644 (file)
@@ -2,32 +2,18 @@ package ncurses
 
 use package core {cptr, conv, string}
 
-
-#library "onyx_ncurses"
-#foreign "onyx_ncurses" {
-
-/*
-use CBindings
-CBindings :: struct {
-    name :: "onyx_ncurses"
-    file_prefix :: """
-#include "ncurses.h"
-
-WINDOW *__get_stdscr() {
-    return stdscr;
+#local Building_Library :: #defined ((package runtime).Generated_Foreign_Info)
+
+#if Building_Library {
+    // "Forward" the foreign block info to the public scope
+    // if foreign block information was generated.
+    foreign_block :: __foreign_block
+} else {
+    // Otherwise, require the library to be included.
+    #library "onyx_ncurses"
 }
 
-void __get_yx    (WINDOW *w, int *y, int *x) { getyx(w, *y, *x); }
-void __get_par_yx(WINDOW *w, int *y, int *x) { getparyx(w, *y, *x); }
-void __get_beg_yx(WINDOW *w, int *y, int *x) { getbegyx(w, *y, *x); }
-void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); }
-
-"""
-    cast_map :: (#type struct {type: type_expr; name: str;}).[
-        .{ WINDOW, "WINDOW *" },
-   ]
-*/
-
+#local __foreign_block :: #foreign "onyx_ncurses" {
     // initscr
     initscr   :: () -> WINDOW ---
     endwin    :: () -> i32    ---
@@ -356,7 +342,7 @@ void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); }
     getmouse :: (@out event: ^MEvent) -> i32 ---
     ungetmouse :: (@out event: ^MEvent) -> i32 ---
     mousemask :: (newmask: mmask_t, @out oldmask: ^mmask_t) -> mmask_t ---
-    wenclone :: (w: WINDOW, y, x: i32) -> bool ---
+    wenclose :: (w: WINDOW, y, x: i32) -> bool ---
     mouse_trafo :: (py, px: ^i32, to_screen: bool) -> bool ---
     wmouse_trafo :: (w: WINDOW, py, px: ^i32, to_screen: bool) -> bool ---
     mouseinterval :: (erval: i32) -> i32 ---
@@ -376,6 +362,21 @@ void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); }
     NCURSES_ACS  :: (a: i32) -> chtype ---
 }
 
+// Types have to always be included
+WINDOW :: #distinct u64
+SCREEN :: #distinct u64
+chtype :: u32
+attr_t :: u32
+
+mmask_t :: u64
+MEvent :: struct {
+    id: u16;
+    x, y, z: i32;
+    bstate: mmask_t;
+}
+
+
+#if !Building_Library {
 
 stdscr    :: __get_stdscr
 getyx     :: __get_yx
@@ -431,18 +432,6 @@ mvwprintw :: (w: WINDOW, y, x: i32, fmt: str, args: ..any) {
     mvwaddnstr(w, y, x, to_output);
 }
 
-WINDOW :: #distinct u64
-SCREEN :: #distinct u64
-chtype :: u32
-attr_t :: u32
-
-mmask_t :: u64
-MEvent :: struct {
-    id: u16;
-    x, y, z: i32;
-    bstate: mmask_t;
-}
-
 BUTTON1_RELEASED       :: 0x01 << (0 * 6)
 BUTTON1_PRESSED        :: 0x02 << (0 * 6)
 BUTTON1_CLICKED        :: 0x04 << (0 * 6)
@@ -601,3 +590,6 @@ KEY_SUSPEND :: 0627         /* suspend key */
 KEY_UNDO :: 0630               /* undo key */
 KEY_MOUSE :: 0631              /* Mouse event has occurred */
 
+
+
+} // !Building_Library
\ No newline at end of file
index 029c211c7328846ea4af6d45a34479e76823640d..275ef36dd96f5be907f1ec472cc010c28b19c009 100644 (file)
@@ -1,9 +1,7 @@
 
 #include "ncurses.h"
 
-WINDOW *__get_stdscr() {
-    return stdscr;
-}
+#define __get_stdscr() ((unsigned long int) stdscr)
 
 void __get_yx    (WINDOW *w, int *y, int *x) { getyx(w, *y, *x); }
 void __get_par_yx(WINDOW *w, int *y, int *x) { getparyx(w, *y, *x); }
@@ -11,7 +9,6 @@ void __get_beg_yx(WINDOW *w, int *y, int *x) { getbegyx(w, *y, *x); }
 void __get_max_yx(WINDOW *w, int *y, int *x) { getmaxyx(w, *y, *x); }
 
 
-
 #define ONYX_LIBRARY_NAME onyx_ncurses
 #include "onyx_library.h"
 
@@ -522,7 +519,7 @@ ONYX_DEF(addchstr, (WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(addchnstr, (WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(addchnstr, (WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(addchnstr(ONYX_PTR(P(0, i32)), P(1, i32)));
     return NULL;
 }
@@ -532,7 +529,7 @@ ONYX_DEF(waddchstr, (WASM_I64, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(waddchnstr, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(waddchnstr, (WASM_I64, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(waddchnstr((WINDOW *) P(0, i64), ONYX_PTR(P(1, i32)), P(2, i32)));
     return NULL;
 }
@@ -542,7 +539,7 @@ ONYX_DEF(mvaddchstr, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(mvaddchnstr, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(mvaddchnstr, (WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(mvaddchnstr(P(0, i32), P(1, i32), ONYX_PTR(P(2, i32)), P(3, i32)));
     return NULL;
 }
@@ -552,7 +549,7 @@ ONYX_DEF(mvwaddchstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(mvwaddchnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(mvwaddchnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(mvwaddchnstr((WINDOW *) P(0, i64), P(1, i32), P(2, i32), ONYX_PTR(P(3, i32)), P(4, i32)));
     return NULL;
 }
@@ -562,7 +559,7 @@ ONYX_DEF(addstr, (WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(addnstr, (WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(addnstr, (WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(addnstr(ONYX_PTR(P(0, i32)), P(1, i32)));
     return NULL;
 }
@@ -572,7 +569,7 @@ ONYX_DEF(waddstr, (WASM_I64, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(waddnstr, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(waddnstr, (WASM_I64, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(waddnstr((WINDOW *) P(0, i64), ONYX_PTR(P(1, i32)), P(2, i32)));
     return NULL;
 }
@@ -582,7 +579,7 @@ ONYX_DEF(mvaddstr, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(mvaddnstr, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(mvaddnstr, (WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(mvaddnstr(P(0, i32), P(1, i32), ONYX_PTR(P(2, i32)), P(3, i32)));
     return NULL;
 }
@@ -592,7 +589,7 @@ ONYX_DEF(mvwaddstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(mvwaddnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(mvwaddnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(mvwaddnstr((WINDOW *) P(0, i64), P(1, i32), P(2, i32), ONYX_PTR(P(3, i32)), P(4, i32)));
     return NULL;
 }
@@ -892,7 +889,7 @@ ONYX_DEF(getstr, (WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(getnstr, (WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(getnstr, (WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(getnstr(ONYX_PTR(P(0, i32)), P(1, i32)));
     return NULL;
 }
@@ -902,7 +899,7 @@ ONYX_DEF(wgetstr, (WASM_I64, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(wgetnstr, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(wgetnstr, (WASM_I64, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(wgetnstr((WINDOW *) P(0, i64), ONYX_PTR(P(1, i32)), P(2, i32)));
     return NULL;
 }
@@ -912,7 +909,7 @@ ONYX_DEF(mvgetstr, (WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(mvgetnstr, (WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(mvgetnstr, (WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(mvgetnstr(P(0, i32), P(1, i32), ONYX_PTR(P(2, i32)), P(3, i32)));
     return NULL;
 }
@@ -922,7 +919,7 @@ ONYX_DEF(mvwgetstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
     return NULL;
 }
 
-ONYX_DEF(mvwgetnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32, WASM_I32), (WASM_I32)) {
+ONYX_DEF(mvwgetnstr, (WASM_I64, WASM_I32, WASM_I32, WASM_I32,WASM_I32), (WASM_I32)) {
     results->data[0] = WASM_I32_VAL(mvwgetnstr((WINDOW *) P(0, i64), P(1, i32), P(2, i32), ONYX_PTR(P(3, i32)), P(4, i32)));
     return NULL;
 }
@@ -1297,8 +1294,8 @@ ONYX_DEF(mousemask, (WASM_I64, WASM_I32), (WASM_I64)) {
     return NULL;
 }
 
-ONYX_DEF(wenclone, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
-    results->data[0] = WASM_I32_VAL(wenclone((WINDOW *) P(0, i64), P(1, i32), P(2, i32)));
+ONYX_DEF(wenclose, (WASM_I64, WASM_I32, WASM_I32), (WASM_I32)) {
+    results->data[0] = WASM_I32_VAL(wenclose((WINDOW *) P(0, i64), P(1, i32), P(2, i32)));
     return NULL;
 }
 
@@ -1616,7 +1613,7 @@ ONYX_LIBRARY {
     ONYX_FUNC(getmouse)
     ONYX_FUNC(ungetmouse)
     ONYX_FUNC(mousemask)
-    ONYX_FUNC(wenclone)
+    ONYX_FUNC(wenclose)
     ONYX_FUNC(mouse_trafo)
     ONYX_FUNC(wmouse_trafo)
     ONYX_FUNC(mouseinterval)
index e3be48003cbb007ba3792594380468bb36564e22..3ba7d3cf6961855261e7c7b45640a28b4ee6317f 100755 (executable)
Binary files a/modules/ncurses/onyx_ncurses.so and b/modules/ncurses/onyx_ncurses.so differ
index b4249abef1bd47816b7e24c06d9c67627e5b02dc..e506eeea71f3ceae15d0953143f652393efb9a5d 100644 (file)
@@ -1,62 +1,91 @@
-#load "core/std"
+package c_binding
 
 use package core
 use package simd
 
-CBindings :: (package ncurses).CBindings
+#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;
+}
 
-#if !#defined(CBindings) {
-    #error "Expected to find CBindings structure";
+Binding_Config :: struct {
+    foreign_block: type_info.foreign_block;
+    preamble: [] str;
+    output_file: str;
+    cast_map: [] Cast_Mapping;
 }
 
+build_c_binding :: (use binding_config: Binding_Config) -> bool {
+    for file: os.with_file(output_file, .Write) {
+        writer := io.writer_make(file);
+        fb := type_info.get_foreign_block(foreign_block);
 
+        write_file_introduction(^writer, preamble, fb.module_name);
 
-main :: (args: [] cstr) {
-    println(CBindings.file_prefix);
+        for fb.funcs {
+            write_function_body(^writer, it, cast_map);
+        }
+
+        write_library_block(^writer, fb.funcs);
+    }
 
-    printf("""
+    return true;
+}
+
+write_file_introduction :: (writer: ^io.Writer, preamble: [] str, name: str) {
+    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)
 
-""", CBindings.name);
+""", name);
+}
 
+write_function_body :: (writer, ff, cast_map) => {
     use type_info;
-    bind_info := cast(^Type_Info_Struct) get_type_info(CBindings);
-    for bind_info.methods {
-        method_type := it.func.type;
-        method_info := cast (^Type_Info_Function) get_type_info(method_type);
-        assert(method_info.kind == .Function, "Expected function type.");
-
-        printf("ONYX_DEF({}, (", it.name);
-        i := 0;
-        for method_info.parameter_types {
-            print_type_encoding(it);
-
-            if i != method_info.parameter_types.count - 1 {
-                print(", ");
-            }
-            i += 1;
-        }
 
-        print("), (");
-        print_type_encoding(method_info.return_type);
-        print(")) {\n");
-        print_body(it.name, method_info);
-        print("}\n\n");
+    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;
     }
 
-    print("\n\n");
-    print("ONYX_LIBRARY {\n");
-    for bind_info.methods {
-        printf("    ONYX_FUNC({})\n", it.name);
+    io.write(writer, "), (");
+    io.write(writer, type_encoding(method_info.return_type));
+    io.write(writer, ")) {\n");
+    print_body(writer, ff.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);
     }
-    print("    NULL\n");
-    print("};");
+    io.write(writer, "    NULL\n");
+    io.write(writer, "};");
 }
 
-print_body :: (method_name, method_info) => {
+print_body :: (writer, method_name, method_info, cast_map) => {
     use type_info;
     call := io.dynamic_string_stream_make();
     defer io.dynamic_string_stream_free(^call);
@@ -73,7 +102,7 @@ print_body :: (method_name, method_info) => {
 
         } else {
             matched := false;
-            for^ m: CBindings.cast_map {
+            for^ m: cast_map {
                 if m.type == it {
                     io.write_format(^callw, "({}) P({}, {})", m.name, param_num, type_to_wasm_type(it));
                     matched = true;
@@ -91,14 +120,14 @@ print_body :: (method_name, method_info) => {
     call_str := call->to_str();
     wasm_return_type := type_to_wasm_type(method_info.return_type);
     switch wasm_return_type {
-        case ""    do printf("    {}({});\n", method_name, call_str[0..call_str.count-2]);
-        case "i32" do printf("    results->data[0] = WASM_I32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
-        case "i64" do printf("    results->data[0] = WASM_I64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
-        case "f32" do printf("    results->data[0] = WASM_F32_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
-        case "f64" do printf("    results->data[0] = WASM_F64_VAL({}({}));\n", method_name, call_str[0..call_str.count-2]);
+        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]);
     }
 
-    printf("    return NULL;\n");
+    io.write_format(writer, "    return NULL;\n");
 }
 
 type_to_wasm_type :: (t: type_expr) -> str {
@@ -147,47 +176,49 @@ type_to_wasm_type :: (t: type_expr) -> str {
     return "";
 }
 
-print_type_encoding :: (t: type_expr) {
+type_encoding :: (t: type_expr) -> str {
     use type_info;
 
     param_info := get_type_info(t);
     switch param_info.kind {
         case .Basic do switch t {
-            case bool do print("WASM_I32");
-            case i8   do print("WASM_I32");
-            case u8   do print("WASM_I32");
-            case i16  do print("WASM_I32");
-            case u16  do print("WASM_I32");
-            case i32  do print("WASM_I32");
-            case u32  do print("WASM_I32");
-            case i64  do print("WASM_I64");
-            case u64  do print("WASM_I64");
-
-            case f32  do print("WASM_F32");
-            case f64  do print("WASM_F64");
-
-            case rawptr do print("WASM_I32"); // This will have to depend on the pointer size...
+            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 print("WASM_V128");
+            case i8x16, i16x8, i32x4, i64x2, f32x4, f64x2, v128 do return "WASM_V128";
 
-            case type_expr do print("WASM_I32");
+            case type_expr do return "WASM_I32";
         }
 
-        case .Pointer do print("WASM_I32"); // This will also have to depend on the pointer size...
+        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 print("WASM_I32");
-        case .Slice do print("WASM_I32, WASM_I32");
-        case .Enum do print_type_encoding((cast(^Type_Info_Enum) param_info).backing_type);
-        case .Distinct do print_type_encoding((cast(^Type_Info_Distinct) param_info).base_type);
+        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 {
-                print_type_encoding(s_info.members[0].type);
+                return type_encoding(s_info.members[0].type);
                 return;
             }
 
             assert(false, "Passing structures between wasm and c is not yet supported.");
         }
     }
+
+    return "";
 }
index 94d412edef282adf846b2c6d63db055e11baba15..7227d9fb1a3ef0683adb2db57c1c1ae7477baec3 100644 (file)
@@ -61,6 +61,8 @@ AstType  *builtin_any_type;
 AstType  *builtin_code_type;
 
 AstTyped    *type_table_node = NULL;
+AstTyped    *foreign_blocks_node = NULL;
+AstType     *foreign_block_type = NULL;
 AstFunction *builtin_initialize_data_segments = NULL;
 AstFunction *builtin_run_init_procedures = NULL;
 bh_arr(AstFunction *) init_procedures = NULL;
@@ -457,7 +459,9 @@ void initialize_builtins(bh_allocator a) {
 
     p = package_lookup("builtin.type_info");
     if (p != NULL) {
-        type_table_node = (AstTyped *) symbol_raw_resolve(p->scope, "type_table");
+        type_table_node     = (AstTyped *) symbol_raw_resolve(p->scope, "type_table");
+        foreign_blocks_node = (AstTyped *) symbol_raw_resolve(p->scope, "foreign_blocks");
+        foreign_block_type  = (AstType *)  symbol_raw_resolve(p->scope, "foreign_block");
     }
 
     fori (i, 0, Binary_Op_Count) {
@@ -531,5 +535,11 @@ void introduce_build_options(bh_allocator a) {
     arch_type->type_node = Arch_Type;
     add_entities_for_node(NULL, (AstNode *) arch_type, NULL, NULL);
     symbol_builtin_introduce(p->scope, "arch", (AstNode *) arch_type);
+
+    if (context.options->generate_foreign_info) {
+        AstNumLit* foreign_info = make_int_literal(a, 1);
+        foreign_info->type_node = (AstType *) &basic_type_bool;
+        symbol_builtin_introduce(p->scope, "Generated_Foreign_Info", (AstNode *) foreign_info);
+    }
 }
 
index 09ed47bccd74d5d59c61fe202bde3d356bac598f..f0db93104fde8bc9d822fdf32e7ebd5bf20a3a3f 100644 (file)
@@ -50,6 +50,7 @@ static const char* docstring = "Onyx compiler version " VERSION "\n"
     "\t--wasm-mvp              Use only WebAssembly MVP features.\n"
     "\t--multi-threaded        Enables multi-threading for this compilation.\n"
     "\t--doc <doc_file>\n"
+    "\t--generate-foreign-info\n"
     "\n"
     "Developer flags:\n"
     "\t--print-function-mappings Prints a mapping from WASM function index to source location.\n"
@@ -151,6 +152,9 @@ static CompileOptions compile_opts_parse(bh_allocator alloc, int argc, char *arg
             else if (!strcmp(argv[i], "--multi-threaded")) {
                 options.use_multi_threading = 1;
             }
+            else if (!strcmp(argv[i], "--generate-foreign-info")) {
+                options.generate_foreign_info = 1;
+            }
             else if (!strcmp(argv[i], "-I")) {
                 bh_arr_push(options.included_folders, argv[++i]);
             }
index cf0b5b792c3a7c3e4b1a8c1922768e599e5a0441..80ba0f8b2cd3b964547d2046ea1f2069c1e4e674 100644 (file)
@@ -2817,6 +2817,11 @@ static AstForeignBlock* parse_foreign_block(OnyxParser* parser, OnyxToken *token
     fb->token = token;
     fb->module_name = expect_token(parser, Token_Type_Literal_String);
 
+    //
+    // This has a fun implication that there cannot be foreign blocks in the builtin
+    // or type_info packages, as those are loaded before foreign_block_type has a value.
+    fb->type_node = foreign_block_type;
+
     bh_arr_new(global_heap_allocator, fb->captured_entities, 4);
     bh_arr_push(parser->alternate_entity_placement_stack, &fb->captured_entities);
 
index 51b5bf36ad90d0b6c44d92dda87f2953110370e1..16a03db6a1ec2564251ce63628307875943a7d20 100644 (file)
@@ -1624,7 +1624,12 @@ void symres_entity(Entity* ent) {
         case Entity_Type_Macro:                   ss = symres_macro(ent->macro); break;
         case Entity_Type_Constraint_Check:        ss = symres_constraint(ent->constraint); break;
         case Entity_Type_Polymorph_Query:         ss = symres_polyquery(ent->poly_query); break;
-        case Entity_Type_Foreign_Block:           ss = symres_foreign_block(ent->foreign_block); break;
+        case Entity_Type_Foreign_Block:           ss = symres_foreign_block(ent->foreign_block);
+                                                  if (context.options->generate_foreign_info) {
+                                                      next_state = Entity_State_Check_Types;
+                                                      ss = Symres_Success;
+                                                  }
+                                                  break;
 
         default: break;
     }
index bf1408896af248b9f6b61ec7002210c8cbbe423d..3d4bbae9cdc5313369d8187025e5109e16c13aa4 100644 (file)
@@ -2987,6 +2987,12 @@ EMIT_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Foreign_Block: {
+            AstForeignBlock *fb = (AstForeignBlock *) expr;
+            WID(WI_I32_CONST, fb->foreign_block_number);
+            break;
+        }
+
         default:
             bh_printf("Unhandled case: %d\n", expr->kind);
             DEBUG_HERE;
@@ -3721,6 +3727,13 @@ static void emit_memory_reservation(OnyxWasmModule* mod, AstMemRes* memres) {
         return;
     }
 
+    if (foreign_blocks_node != NULL && (AstMemRes *) foreign_blocks_node == memres) {
+        u64 foreign_blocks_location = build_foreign_blocks(mod);
+        memres->addr = foreign_blocks_location;
+
+        return;
+    }
+
     if (memres->threadlocal) {
         memres->addr = mod->next_tls_offset;
         bh_align(memres->addr, alignment);
@@ -3860,6 +3873,9 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
 
         .libraries = NULL,
         .library_paths = NULL,
+
+        .foreign_blocks = NULL,
+        .next_foreign_block_idx = 0,
     };
 
     bh_arena* eid = bh_alloc(global_heap_allocator, sizeof(bh_arena));
@@ -3892,6 +3908,7 @@ OnyxWasmModule onyx_wasm_module_create(bh_allocator alloc) {
     bh_arr_new(global_heap_allocator, module.deferred_stmts, 4);
     bh_arr_new(global_heap_allocator, module.local_allocations, 4);
     bh_arr_new(global_heap_allocator, module.stack_leave_patches, 4);
+    bh_arr_new(global_heap_allocator, module.foreign_blocks, 4);
 
     if (context.options->use_multi_threading) {
         WasmImport mem_import = {
@@ -3997,6 +4014,12 @@ void emit_entity(Entity* ent) {
             break;
         }
 
+        case Entity_Type_Foreign_Block: {
+            ent->foreign_block->foreign_block_number = module->next_foreign_block_idx++;
+            bh_arr_push(module->foreign_blocks, (AstForeignBlock *) ent->foreign_block);
+            break;
+        }
+
         case Entity_Type_Function: emit_function(module, ent->function); break;
         case Entity_Type_Global:   emit_global(module,   ent->global); break;
 
index b080855c161744da4a2a5bceb3bea644d393b08a..4e50e8e148be349f328dc770aef4305165fe3653 100644 (file)
@@ -596,5 +596,153 @@ u64 build_type_table(OnyxWasmModule* module) {
 
     return global_data_ptr;
 
+#undef WRITE_SLICE
+#undef WRITE_PTR
 #undef PATCH
 }
+
+
+
+static b32 build_foreign_blocks(OnyxWasmModule* module) {
+    bh_arr(u32) base_patch_locations=NULL;
+    bh_arr_new(global_heap_allocator, base_patch_locations, 256);
+
+#define PATCH (bh_arr_push(base_patch_locations, foreign_buffer.length))
+#define WRITE_PTR(val) \
+    bh_buffer_align(&foreign_buffer, POINTER_SIZE); \
+    PATCH; \
+    if (POINTER_SIZE == 4) bh_buffer_write_u32(&foreign_buffer, val); \
+    if (POINTER_SIZE == 8) bh_buffer_write_u64(&foreign_buffer, val); 
+#define WRITE_SLICE(ptr, count) \
+    WRITE_PTR(ptr); \
+    if (POINTER_SIZE == 4) bh_buffer_write_u32(&foreign_buffer, count); \
+    if (POINTER_SIZE == 8) bh_buffer_write_u64(&foreign_buffer, count); 
+
+    // This is the data behind the "type_table" slice in type_info.onyx
+    #if (POINTER_SIZE == 4)
+        #define Foreign_Block_Type u32
+    #else
+        #define Foreign_Block_Type u64
+    #endif
+    u32 block_count = bh_arr_length(module->foreign_blocks);
+    Foreign_Block_Type* foreign_info = bh_alloc_array(global_heap_allocator, Foreign_Block_Type, block_count); // HACK
+    memset(foreign_info, 0, block_count * sizeof(Foreign_Block_Type));
+
+    bh_buffer foreign_buffer;
+    bh_buffer_init(&foreign_buffer, global_heap_allocator, 4096);
+
+    // 
+    // This is necessary because 0 is an invalid offset to store in this
+    // buffer, as 0 will map to NULL. This could be a single byte insertion,
+    // but 64 bytes keeps better alignment.
+    bh_buffer_write_u64(&foreign_buffer, 0);
+
+    u32 index = 0;
+    bh_arr_each(AstForeignBlock *, pfb, module->foreign_blocks) {
+        AstForeignBlock *fb = *pfb;
+
+        u32 funcs_length = 0;
+
+        u32 *name_offsets = bh_alloc_array(global_scratch_allocator, u32, shlen(fb->scope->symbols));
+        u32 *name_lengths = bh_alloc_array(global_scratch_allocator, u32, shlen(fb->scope->symbols));
+        u32 *func_types   = bh_alloc_array(global_scratch_allocator, u32, shlen(fb->scope->symbols));
+
+        fori (i, 0, shlen(fb->scope->symbols)) {
+            AstFunction *func = (AstFunction *) fb->scope->symbols[i].value;
+            if (func->kind != Ast_Kind_Function) continue;
+
+            u32 func_name_base = foreign_buffer.length;
+            u32 func_name_length = func->foreign_name->length;
+            bh_buffer_append(&foreign_buffer, func->foreign_name->text, func_name_length);
+
+            name_offsets[funcs_length] = func_name_base;
+            name_lengths[funcs_length] = func_name_length;
+            func_types[funcs_length]   = func->type->id;
+            funcs_length++;
+        }
+
+        bh_buffer_align(&foreign_buffer, 8);
+        u32 funcs_base = foreign_buffer.length;
+
+        fori (i, 0, (i64) funcs_length) {
+            bh_buffer_align(&foreign_buffer, POINTER_SIZE);
+            WRITE_SLICE(name_offsets[i], name_lengths[i]);
+            bh_buffer_write_u32(&foreign_buffer, func_types[i]);
+        }
+
+        u32 name_base = foreign_buffer.length;
+        u32 name_length = fb->module_name->length;
+        bh_buffer_append(&foreign_buffer, fb->module_name->text, name_length);
+        bh_buffer_align(&foreign_buffer, 8);
+
+        foreign_info[index] = foreign_buffer.length;
+        WRITE_SLICE(name_base, name_length);
+        WRITE_SLICE(funcs_base, funcs_length);
+        index++;
+    }
+
+
+    if (context.options->verbose_output == 1) {
+        bh_printf("Foreign blocks size: %d bytes.\n", foreign_buffer.length);
+    }
+
+    u32 offset = module->next_datum_offset;
+    bh_align(offset, 8);
+
+    u64 foreign_blocks_location = offset;
+
+    WasmDatum foreign_blocks_data = {
+        .offset = offset,
+        .length = block_count * POINTER_SIZE,
+        .data = foreign_info,
+    };
+    bh_arr_push(module->data, foreign_blocks_data);
+
+    offset += foreign_blocks_data.length;
+
+    fori (i, 0, block_count) {
+        foreign_info[i] += offset;
+    }
+
+    bh_arr_each(u32, patch_loc, base_patch_locations) {
+        if (POINTER_SIZE == 4) {
+            u32* loc = bh_pointer_add(foreign_buffer.data, *patch_loc);
+            if (*loc == 0) continue;
+            
+            *loc += offset;
+        }
+        if (POINTER_SIZE == 8) {
+            u64* loc = bh_pointer_add(foreign_buffer.data, *patch_loc);
+            if (*loc == 0) continue;
+            
+            *loc += offset;
+        }
+    }
+
+    WasmDatum foreign_blocks_info_data = {
+        .offset = offset,
+        .length = foreign_buffer.length,
+        .data = foreign_buffer.data,
+    };
+    bh_arr_push(module->data, foreign_blocks_info_data);
+    offset += foreign_blocks_info_data.length;
+
+    u64 global_data_ptr = offset;
+
+    Foreign_Block_Type* tmp_data = bh_alloc(global_heap_allocator, 2 * POINTER_SIZE);
+    tmp_data[0] = foreign_blocks_location;
+    tmp_data[1] = block_count;
+    WasmDatum foreign_blocks_global_data = {
+        .offset = offset,
+        .length = 2 * POINTER_SIZE,
+        .data = tmp_data,
+    };
+    bh_arr_push(module->data, foreign_blocks_global_data);
+    offset += foreign_blocks_global_data.length;
+
+    module->next_datum_offset = offset;
+
+    return global_data_ptr;
+
+#undef PATCH
+}
\ No newline at end of file