nlua0.zig (3922B)
1 //! "nlua" is an abbreviation for nvim flavored lua, i e lua with the 2 //! extended standard library functionality added by nvim such as json, mpack 3 //! and libuv and a range of vim.* utility functions. 4 //! 5 //! nlua0 is an interpreter for the "bootstrap" lua code we need to run before 6 //! nvim can be built, in order to run lua scripts which process and generate 7 //! more .c code, which still need these extensions. 8 const std = @import("std"); 9 const ziglua = @import("ziglua"); 10 const options = @import("options"); 11 12 const embedded_data = @import("embedded_data"); 13 14 // these are common dependencies used by many generators 15 const hashy = @embedFile("gen/hashy.lua"); 16 const c_grammar = @embedFile("gen/c_grammar.lua"); 17 18 const Lua = ziglua.Lua; 19 20 extern "c" fn luaopen_mpack(ptr: *anyopaque) c_int; 21 extern "c" fn luaopen_lpeg(ptr: *anyopaque) c_int; 22 extern "c" fn luaopen_bit(ptr: *anyopaque) c_int; 23 extern "c" fn luaopen_luv(ptr: *anyopaque) c_int; 24 25 fn init() !*Lua { 26 // Initialize the Lua vm 27 var lua = try Lua.init(std.heap.c_allocator); 28 lua.openLibs(); 29 30 // this sets _G.vim by itself, so we don't need to 31 try lua.loadBuffer(embedded_data.shared_module, "shared.lua"); 32 lua.call(.{ .results = 1 }); 33 34 try lua.loadBuffer(embedded_data.inspect_module, "inspect.lua"); 35 lua.call(.{ .results = 1 }); 36 lua.setField(-2, "inspect"); 37 38 try lua.loadBuffer(embedded_data.iter_module, "iter.lua"); 39 lua.call(.{ .results = 1 }); 40 lua.setField(-2, "iter"); 41 42 _ = try lua.getGlobal("package"); 43 _ = lua.getField(-1, "preload"); 44 try lua.loadBuffer(hashy, "hashy.lua"); // [package, preload, hashy] 45 lua.setField(-2, "gen.hashy"); 46 try lua.loadBuffer(c_grammar, "c_grammar.lua"); // [package, preload, c_grammar] 47 lua.setField(-2, "gen.c_grammar"); 48 lua.pop(2); 49 50 const retval = luaopen_mpack(lua); 51 if (retval != 1) return error.LoadError; 52 _ = lua.getField(-1, "NIL"); // [vim, mpack, NIL] 53 lua.setField(-3, "NIL"); // vim.NIL = mpack.NIL (wow BOB wow) 54 lua.setField(-2, "mpack"); 55 56 const retval2 = luaopen_lpeg(lua); 57 if (retval2 != 1) return error.LoadError; 58 lua.setField(-3, "lpeg"); 59 60 const retval3 = luaopen_luv(lua); 61 if (retval3 != 1) return error.LoadError; 62 lua.setField(-3, "uv"); 63 64 lua.pop(2); 65 66 if (!options.use_luajit) { 67 lua.pop(luaopen_bit(lua)); 68 } 69 return lua; 70 } 71 72 pub fn main() !void { 73 const argv = std.os.argv; 74 75 const lua = try init(); 76 defer lua.deinit(); 77 78 if (argv.len < 2) { 79 std.debug.print("USAGE: nlua0 script.lua args...\n\n", .{}); 80 return; 81 } 82 lua.createTable(@intCast(argv.len - 2), 1); 83 for (0.., argv[1..]) |i, arg| { 84 _ = lua.pushString(std.mem.span(arg)); 85 lua.rawSetIndex(-2, @intCast(i)); 86 } 87 lua.setGlobal("arg"); 88 89 _ = try lua.getGlobal("debug"); 90 _ = lua.getField(-1, "traceback"); 91 try lua.loadFile(std.mem.span(argv[1])); 92 lua.protectedCall(.{ .msg_handler = -2 }) catch |e| { 93 if (e == error.LuaRuntime) { 94 const msg = try lua.toString(-1); 95 std.debug.print("{s}\n", .{msg}); 96 } 97 return e; 98 }; 99 } 100 101 fn do_ret1(lua: *Lua, str: [:0]const u8) !void { 102 try lua.loadString(str); 103 try lua.protectedCall(.{ .results = 1 }); 104 } 105 106 test "simple test" { 107 const lua = try init(); 108 defer lua.deinit(); 109 110 try do_ret1(lua, "return vim.isarray({2,3})"); 111 try std.testing.expectEqual(true, lua.toBoolean(-1)); 112 lua.pop(1); 113 114 try do_ret1(lua, "return vim.isarray({a=2,b=3})"); 115 try std.testing.expectEqual(false, lua.toBoolean(-1)); 116 lua.pop(1); 117 118 try do_ret1(lua, "return vim.inspect(vim.mpack.decode('\\146\\42\\69'))"); 119 try std.testing.expectEqualStrings("{ 42, 69 }", try lua.toString(-1)); 120 lua.pop(1); 121 122 try do_ret1(lua, "return require'bit'.band(7,12)"); 123 try std.testing.expectEqualStrings("4", try lua.toString(-1)); 124 lua.pop(1); 125 }