#module_parameters(STATIC := true); c_context: #Context; #scope_export; using #import,file "../module.jai"(STATIC = STATIC); expose :: (L: *State, proc: $T, $caller_code := #caller_code, $loc := #caller_location) #modify { return T.(*Type_Info).type == .PROCEDURE, "expose must take a procedure"; } #expand { #insert -> string { info := T.(*Type_Info_Procedure); code := compiler_get_nodes(caller_code); call := code.(*Code_Procedure_Call); proc := call.arguments_sorted[1].(*Code_Ident); basic.assert(proc.kind == .IDENT, "must be an identifier", loc = loc); body_builder: basic.String_Builder; args_builder: basic.String_Builder; call_builder: basic.String_Builder; rets_builder: basic.String_Builder; if info.return_types.count != 0 { basic.append(*call_builder, "\t\t\t\t"); for info.return_types { basic.print_to_builder(*call_builder, "r%", it_index); if it_index < info.return_types.count -1 { basic.append(*call_builder, ", "); } } basic.append(*call_builder, " := "); } basic.append(*call_builder, "proc("); for < info.argument_types { index := -(it_index + 1); basic.print_to_builder(*args_builder, "\t\t\ta% := %;\n", it_index, gen_stack_pull(it, index)); basic.print_to_builder(*call_builder, "a%", it_index); if it_index > 0 { basic.append(*call_builder, ", "); } } basic.append(*call_builder, ");"); for info.return_types { basic.print_to_builder(*rets_builder, "\t\t\t\t%;", gen_stack_push(it, it_index)); if it_index < info.return_types.count - 1 { basic.append(*rets_builder, "\n"); } } return basic.sprint(#string END lua_name :: "%1"; lua_wrapper :: (L: *State) -> s32 #c_call { %2 push_context c_context { %3 %4 } return %5; } END, proc.name, basic.builder_to_string(*args_builder), basic.builder_to_string(*call_builder), basic.builder_to_string(*rets_builder), info.return_types.count, ); } info := T.(*Type_Info_Procedure); pushcclosure(L, lua_wrapper, info.argument_types.count.(s32)); setfield(L, LUA_GLOBALSINDEX, lua_name); } #scope_file; gen_stack_pull :: (info: *Type_Info, index: int) -> string { if info.type == { case .BOOL; return basic.tprint("get_lua_bool(L, %)", index); case .INTEGER; return basic.tprint("tointeger(L, %)", index); case .FLOAT; return basic.tprint("tonumber(L, %)", index); case .STRING; return basic.tprint("get_lua_string(L, %)", index); case .STRUCT; return basic.tprint("get_lua_table(L, %, %)", info.(*Type_Info_Struct).name, index); case; basic.assert(false, "% (%)", info.type, index); } return ""; } gen_stack_push :: (info: *Type_Info, index: int) -> string { if info.type == { case .BOOL; return basic.tprint("pushboolean(L, r%.(s32))", index); case .INTEGER; return basic.tprint("pushinteger(L, r%)", index); case; basic.assert(false, "% (%)", info.type, index); } return ""; } get_lua_string :: inline (L: *State, index: s32) -> string #c_call { len: u64; ptr := tolstring(L, index, *len); return string.{ data = ptr, count = xx len }; } get_lua_bool :: inline (L: *State, index: s32) -> bool #c_call { return toboolean(L, index) == 1; } get_lua_table :: (L: *State, $T: Type, index: s32) -> T #c_call { push_context c_context { return get_lua_table(L, T.(*Type_Info_Struct), index).(*T).*; } } temp_storage: [4096]u8; temp_offset: int; get_lua_table :: (L: *State, info: *Type_Info_Struct, index: s32) -> *void { res := temp_storage.data + temp_offset; memset(res, 0, info.runtime_size); temp_offset = (temp_offset + info.runtime_size) % temp_storage.count; for info.members { defer settop(L, -2); pushlstring(L, it.name.data, xx it.name.count); rawget(L, -2); vp: *void; if it.type.type == { case .BOOL; v := get_lua_bool(L, -1); vp = *v; case .INTEGER; v := tointeger(L, -1); if it.type.runtime_size == { case 1; vp = *(v.(u8, no_check)); case 2; vp = *(v.(u16, no_check)); case 4; vp = *(v.(u32, no_check)); case 8; vp = *(v.(u64, no_check)); } case .FLOAT; v := tonumber(L, -1); if it.type.runtime_size == { case 4; vp = *(v.(float32, no_check)); case 8; vp = *(v.(float64, no_check)); } case .STRING; v := get_lua_string(L, -1); vp = *v; case .STRUCT; v := get_lua_table(L, it.type.(*Type_Info_Struct), -1); vp = *v; case; basic.assert(false, "% (%)", info.type, index); } memcpy(res + it.offset_in_bytes, vp, it.type.runtime_size); } return res; } basic :: #import "Basic"; // @future #import "Compiler";