From feff2374e040858da9b5a75dc5142a5782326954 Mon Sep 17 00:00:00 2001 From: CapsAdmin Date: Sat, 18 May 2024 07:02:19 +0700 Subject: [PATCH] more work on typed ffi --- .../luajit/src/platforms/unix/filesystem.nlua | 4 +- .../src/platforms/windows/filesystem.nlua | 2 +- nattlua/c_declarations/analyzer.lua | 13 +++ nattlua/c_declarations/parser.lua | 16 +++ nattlua/definitions/index.nlua | 3 +- nattlua/definitions/lua/luajit.nlua | 107 +++++++++++++++++- nattlua/definitions/typed_ffi.nlua | 88 -------------- nattlua/definitions/utility.nlua | 2 - nattlua/types/table.lua | 2 +- .../nattlua/analyzer/complex/ffi_example.nlua | 4 +- test/nattlua/analyzer/typed_ffi.lua | 5 + test/nattlua/c_declarations.lua | 2 +- test/nattlua/c_declarations/cdef.nlua | 9 +- 13 files changed, 156 insertions(+), 101 deletions(-) delete mode 100644 nattlua/definitions/typed_ffi.nlua diff --git a/examples/projects/luajit/src/platforms/unix/filesystem.nlua b/examples/projects/luajit/src/platforms/unix/filesystem.nlua index fe7acb29..0863ce16 100644 --- a/examples/projects/luajit/src/platforms/unix/filesystem.nlua +++ b/examples/projects/luajit/src/platforms/unix/filesystem.nlua @@ -183,7 +183,7 @@ do local dot = string.byte(".") - local function is_dots(ptr: {[number] = number}) + local function is_dots(ptr: FFIArray<|3, number|>) if ptr[0] == dot then if ptr[1] == dot and ptr[2] == 0 then return true end @@ -240,4 +240,4 @@ do end end -return fs +return fs \ No newline at end of file diff --git a/examples/projects/luajit/src/platforms/windows/filesystem.nlua b/examples/projects/luajit/src/platforms/windows/filesystem.nlua index 4648af7e..7281cb88 100644 --- a/examples/projects/luajit/src/platforms/windows/filesystem.nlua +++ b/examples/projects/luajit/src/platforms/windows/filesystem.nlua @@ -122,7 +122,7 @@ do ) local dot = string.byte(".") - local function is_dots(ptr: {[number] = number}) + local function is_dots(ptr: FFIArray<|3, number|>) if ptr[0] == dot then if ptr[1] == dot and ptr[2] == 0 then return true end diff --git a/nattlua/c_declarations/analyzer.lua b/nattlua/c_declarations/analyzer.lua index b7304ed4..71dea4ef 100644 --- a/nattlua/c_declarations/analyzer.lua +++ b/nattlua/c_declarations/analyzer.lua @@ -146,6 +146,13 @@ function META:WalkCDeclaration_(node, walk_up) if node.modifiers then handle_modifiers(self, node) end + if node.tokens["..."] and node.type == "expression" then + self.cdecl.of = { + type = "va_list", + } + self.cdecl = assert(self.cdecl.of) + end + if not walk_up then return end if node.parent.kind == "c_declaration" then @@ -364,7 +371,13 @@ local function cast(self, node, out) return Tuple({}):AddRemainder(Tuple({Any()}):SetRepeat(math.huge)) end + local tbl = typs:Get(LString(t)) or self.typs_write:Get(LString(t)) + + if tbl then return (tbl) end + return (Number()) + elseif node.type == "va_list" then + return Tuple({}):AddRemainder(Tuple({Any()}):SetRepeat(math.huge)) elseif node.type == "function" then local args = {} local rets = {} diff --git a/nattlua/c_declarations/parser.lua b/nattlua/c_declarations/parser.lua index 47824e0b..cffe41d7 100644 --- a/nattlua/c_declarations/parser.lua +++ b/nattlua/c_declarations/parser.lua @@ -58,6 +58,22 @@ function META:IsInArguments() -- void foo(void (*)(int, int)) -- I guess it still works as a hacky solution if self:IsTokenValue(",", i) then return true end + + if self:IsTokenValue("(", i) and self:IsTokenValue(")", i + 1) then + return false + end + + if + self:IsTokenValue(")", i) and + ( + self:IsTokenValue(";", i + 1) or + self:IsTokenType("end_of_file", i + 1) + ) + and + not self:IsTokenValue(")", i - 1) + then + return true + end end end diff --git a/nattlua/definitions/index.nlua b/nattlua/definitions/index.nlua index 08c8c0b9..00af19af 100644 --- a/nattlua/definitions/index.nlua +++ b/nattlua/definitions/index.nlua @@ -11,5 +11,4 @@ import("./lua/table.nlua") import("./lua/string.nlua") import("./lua/math.nlua") import("./lua/os.nlua") -import("./lua/coroutine.nlua") -import("./typed_ffi.nlua") \ No newline at end of file +import("./lua/coroutine.nlua") \ No newline at end of file diff --git a/nattlua/definitions/lua/luajit.nlua b/nattlua/definitions/lua/luajit.nlua index 996b7ad7..140f1790 100644 --- a/nattlua/definitions/lua/luajit.nlua +++ b/nattlua/definitions/lua/luajit.nlua @@ -1,3 +1,60 @@ +function FFIPointer<|T: any|> + if T == nil then return T end + + -- https://github.com/LuaJIT/LuaJIT/blob/v2.1/src/lj_carith.c#L96-L159 + return { + @MetaTable = self, + [number] = T, + __tostring = function(self: ref self) + return "Pointer(" .. tostring(self[number]) .. ")" + end, + __index = function(self: ref self, key: ref string) + return self[number][key] + end, + __le = function(self: ref self, other: ref self) + return Boolean() + end, + __lt = function(self: ref self, other: ref self) + return Boolean() + end, + __add = function(self: ref self, other: ref self | number) + return FFIPointer<|T|> + end, + __sub = function(self: ref self, other: ref self | number) + return FFIPointer<|T|> + end, + } +end + +function FFIArray<|size: number, T: any|> + if T == nil then return T end + + return { + @MetaTable = self, + [0 .. (size - 1)] = T, + __tostring = function(self: ref self) + return "Array" .. tostring(size) .. "(" .. tostring(self[0]) .. ")" + end, + __index = function(self: ref self, key: ref string) + return self[number][key] + end, + __le = function(self: ref self, other: ref self) + return Boolean() + end, + __lt = function(self: ref self, other: ref self) + return Boolean() + end, + __add = function(self: ref self, other: ref self | number) + return FFIPointer<|T|> + end, + __sub = function(self: ref self, other: ref self | number) + return FFIPointer<|T|> + end, + } +end + +type cdata = FFIPointer<|number|> +type cdata.@TypeOverride = "cdata" type Modules["ffi"] = { errno = function=(nil | number)>(number), os = "Windows" | "Linux" | "OSX" | "BSD" | "POSIX" | "Other", @@ -135,4 +192,52 @@ type Modules["jit.util"] = { funcuvname = function=(func: Function, index: number)>(number, number), -- Gets a constant at a certain index in a function. funck = function=(func: Function, index: number)>(any), -} \ No newline at end of file +} +local type ffi = require("ffi") +type _G.ffi = ffi + +analyzer function ffi.sizeof(cdecl: any, len: nil | number) + return require("nattlua.c_declarations.main").sizeof(cdecl, len) +end + +analyzer function ffi.cdef(cdecl: string, ...: ...any) + return require("nattlua.c_declarations.main").cdef(cdecl, ...) +end + +§env.typesystem.ffi:Get(types.ConstString("cdef")):SetPreventInputArgumentExpansion(true) + +analyzer function ffi.cast(cdecl: string, src: any) + return require("nattlua.c_declarations.main").cast(cdecl, src) +end + +analyzer function ffi.typeof(cdecl: string, ...: ...any) + return require("nattlua.c_declarations.main").typeof(cdecl, ...) +end + +§env.typesystem.ffi:Get(types.ConstString("typeof")):SetPreventInputArgumentExpansion(true) + +analyzer function ffi.get_type(cdecl: string, ...: ...any) + return require("nattlua.c_declarations.main").get_type(cdecl, ...) +end + +analyzer function ffi.new(cdecl: any, ...: ...any) + return require("nattlua.c_declarations.main").new(cdecl, ...) +end + +analyzer function ffi.metatype(ctype: any, meta: any) + return require("nattlua.c_declarations.main").metatype(ctype, meta) +end + +analyzer function ffi.load(lib: string) + return require("nattlua.c_declarations.main").load(lib) +end + +analyzer function ffi.gc(ctype: any, callback: Function) + return ctype +end + +function FFIType<|str: string|> + return number +end + +type ffi.string = function=(FFIPointer<|number|> | string, number | nil)>(string) \ No newline at end of file diff --git a/nattlua/definitions/typed_ffi.nlua b/nattlua/definitions/typed_ffi.nlua deleted file mode 100644 index 52ed5781..00000000 --- a/nattlua/definitions/typed_ffi.nlua +++ /dev/null @@ -1,88 +0,0 @@ -local type ffi = require("ffi") -type _G.ffi = ffi - -analyzer function ffi.sizeof(cdecl: any, len: nil | number) - return require("nattlua.c_declarations.main").sizeof(cdecl, len) -end - -analyzer function ffi.cdef(cdecl: string, ...: ...any) - return require("nattlua.c_declarations.main").cdef(cdecl, ...) -end - -§env.typesystem.ffi:Get(types.ConstString("cdef")):SetPreventInputArgumentExpansion(true) - -analyzer function ffi.cast(cdecl: string, src: any) - return require("nattlua.c_declarations.main").cast(cdecl, src) -end - -analyzer function ffi.typeof(cdecl: string, ...: ...any) - return require("nattlua.c_declarations.main").typeof(cdecl, ...) -end - -§env.typesystem.ffi:Get(types.ConstString("typeof")):SetPreventInputArgumentExpansion(true) - -analyzer function ffi.get_type(cdecl: string, ...: ...any) - return require("nattlua.c_declarations.main").get_type(cdecl, ...) -end - -analyzer function ffi.new(cdecl: any, ...: ...any) - return require("nattlua.c_declarations.main").new(cdecl, ...) -end - -analyzer function ffi.metatype(ctype: any, meta: any) - return require("nattlua.c_declarations.main").metatype(ctype, meta) -end - -analyzer function ffi.load(lib: string) - return require("nattlua.c_declarations.main").load(lib) -end - -analyzer function ffi.gc(ctype: any, callback: Function) - return ctype -end - -function FFIArray<|size: number, T: any|> - return { - @MetaTable = self, - [0 .. (size - 1)] = T, - __tostring = function(self: ref self) - return "Array" .. tostring(size) .. "(" .. tostring(self[0]) .. ")" - end, - __add = function(self: ref self, other: ref self | number) - return self - end, - __sub = function(self: ref self, other: ref self | number) - return self - end, - } -end - -function FFIPointer<|T: any|> - if T == nil then return T end - - return { - @MetaTable = self, - [0] = T, - __tostring = function(self: ref self) - return "Pointer(" .. tostring(self[0]) .. ")" - end, - __index = function(self: ref self, key: ref string) - return self[0][key] - end, - __call = function(self: ref self, ...) - return self[0](...) - end, - __add = function(self: ref self, other: ref self | number) - return self - end, - __sub = function(self: ref self, other: ref self | number) - return self - end, - } -end - -function FFIType<|str: string|> - return number -end - -type ffi.string = function=(cdata | FFIPointer<|number|>, number | nil)>(string) \ No newline at end of file diff --git a/nattlua/definitions/utility.nlua b/nattlua/definitions/utility.nlua index 76a5cb83..85dddbc0 100644 --- a/nattlua/definitions/utility.nlua +++ b/nattlua/definitions/utility.nlua @@ -4,8 +4,6 @@ type integer = number type Table = {[any] = any} | {} type Function = function=(...any)>(...any) type userdata = Table -type cdata = {[number] = any} -type cdata.@TypeOverride = "cdata" type ctype = any type thread = Table type empty_function = function=(...)>(...any) diff --git a/nattlua/types/table.lua b/nattlua/types/table.lua index 4a35fed7..75816970 100644 --- a/nattlua/types/table.lua +++ b/nattlua/types/table.lua @@ -123,7 +123,7 @@ function META:__tostring() local analyzer = context:GetCurrentAnalyzer() if analyzer then - local str = func:Call(analyzer, Tuple({self})):GetFirstValue() + local str = analyzer:Assert(func:Call(analyzer, Tuple({self}))):GetFirstValue() if str and str:IsLiteral() then self.suppress = false diff --git a/test/nattlua/analyzer/complex/ffi_example.nlua b/test/nattlua/analyzer/complex/ffi_example.nlua index 1150b63b..4f4cdb5e 100644 --- a/test/nattlua/analyzer/complex/ffi_example.nlua +++ b/test/nattlua/analyzer/complex/ffi_example.nlua @@ -56,7 +56,7 @@ end local gbuf_n = 1024 local gbuf = ffi.new("char [?]", gbuf_n) -local function buf_grow(len: any, nokeep: boolean | nil) +local function buf_grow(len: number, nokeep: boolean | nil) if len > gbuf_n then gbuf_n = len local newbuf = ffi.new("char [?]", gbuf_n) @@ -190,4 +190,4 @@ function _M.mask(automate: ac_t, str: string, p: string, ignore_case: boolean) end end -return _M +return _M \ No newline at end of file diff --git a/test/nattlua/analyzer/typed_ffi.lua b/test/nattlua/analyzer/typed_ffi.lua index 4943268b..916513aa 100644 --- a/test/nattlua/analyzer/typed_ffi.lua +++ b/test/nattlua/analyzer/typed_ffi.lua @@ -353,6 +353,11 @@ analyze[=[ local info = {} as AddressInfo addrinfo_get_ip(info) ]=] + +do + return +end + analyze[[ local x = tostring(_ as FFIArray<| 1, diff --git a/test/nattlua/c_declarations.lua b/test/nattlua/c_declarations.lua index 7a3daec6..c696811a 100644 --- a/test/nattlua/c_declarations.lua +++ b/test/nattlua/c_declarations.lua @@ -358,6 +358,7 @@ do -- functions test[[ void (**NAME()) ;]] test[[ void (** volatile NAME()) ;]] test[[ void (* volatile * volatile NAME()) ;]] + test[[ void __ptr32**NAME() ;]] test[[ void (__ptr32**NAME()) ;]] test[[ void (__stdcall*NAME()) ;]] end @@ -554,7 +555,6 @@ do -- struct and union declarations test[[ struct TYPE { char *(*(**FIELD[][8])())[]; }; ]] test([[ %{struct|union} NAME(NAME)(]] .. [[ %{struct|union} NAME);]]) - test[[ struct TYPE { int FIELD; } ]] -- without ; end diff --git a/test/nattlua/c_declarations/cdef.nlua b/test/nattlua/c_declarations/cdef.nlua index e9132227..fdd934be 100644 --- a/test/nattlua/c_declarations/cdef.nlua +++ b/test/nattlua/c_declarations/cdef.nlua @@ -44,7 +44,7 @@ do struct MyStruct faz; ]] attest.equal(vars.faz, typs.MyStruct) - attest.equal(assert(vars.bar)[0], _ as {a = number}) + attest.equal(assert(vars.bar)[0], _ as nil | {a = number}) end do @@ -117,4 +117,11 @@ do MyStruct = {a = number}, MyStruct2 = {}, }) +end + +do + local vars, typs = cdef([[ + int readdir(void *dirp); + ]]) + attest.equal(vars.readdir, _ as function=(any)>(number)) end \ No newline at end of file