From d699ccfb0c3500becfec9b02c24dc858d54c5a6e Mon Sep 17 00:00:00 2001 From: Nicolas Hillegeer Date: Mon, 28 Apr 2014 14:12:51 +0200 Subject: test: fix the cimport method This commit will hopefully allow the cimport method to be used just as one would use #inclue in C. It follows the following method: 1. create a pseudoheader file that #include's all the requested header files 2. runs the pseudoheader through the C preprocessor (it will try various compilers if available on the system). 3. runs the preprocessed file through a C formatter, which attempts to group statements on one line. For example, a struct definition that was formerly on several lines will take just one line after formatting. This is done so that unique declarations can be detected. Duplicates are thus easy to remove. 4. remove lines that are too complex for the LuaJIT C parser (such as: Objective-C block syntax, crazy enums defined on linux, ...) 5. remove duplicate declarations 6. pass result to ffi.cdef --- test/unit/helpers.moon | 97 +++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 81 insertions(+), 16 deletions(-) (limited to 'test/unit/helpers.moon') diff --git a/test/unit/helpers.moon b/test/unit/helpers.moon index 77d491a008..e84c569143 100644 --- a/test/unit/helpers.moon +++ b/test/unit/helpers.moon @@ -1,4 +1,19 @@ ffi = require 'ffi' +lpeg = require 'lpeg' +formatc = require 'test.unit.formatc' +Set = require 'test.unit.set' +Preprocess = require 'test.unit.preprocess' + +-- add some standard header locations +-- TODO(aktau, jszakmeister): optionally pass more header locations via env +Preprocess.add_to_include_path('./src') +Preprocess.add_to_include_path('./.deps/usr/include') +Preprocess.add_to_include_path('./build/config') + +if ffi.abi('32bit') + Preprocess.add_to_include_path('/opt/neovim-deps/32/include') +else + Preprocess.add_to_include_path('/opt/neovim-deps/include') -- load neovim shared library testlib = os.getenv 'NVIM_TEST_LIB' @@ -7,22 +22,72 @@ unless testlib libnvim = ffi.load testlib --- Luajit ffi parser doesn't understand preprocessor directives, so --- this helper function removes common directives before passing it the to ffi. --- It will return a pointer to the library table, emulating 'requires' -cimport = (path) -> - header_file = io.open path, 'rb' - - if not header_file - error "cannot find #{path}" - - header = header_file\read '*a' - header_file.close! - header = string.gsub header, '#include[^\n]*\n', '' - header = string.gsub header, '#ifndef[^\n]*\n', '' - header = string.gsub header, '#define[^\n]*\n', '' - header = string.gsub header, '#endif[^\n]*\n', '' - ffi.cdef header +trim = (s) -> + s\match'^%s*(.*%S)' or '' + +-- a Set that keeps around the lines we've already seen +export cdefs +if cdefs == nil + cdefs = Set! + +export imported +if imported == nil + imported = Set! + +-- some things are just too complex for the LuaJIT C parser to digest. We +-- usually don't need them anyway. +filter_complex_blocks = (body) -> + result = {} + for line in body\gmatch("[^\r\n]+") + -- remove all lines that contain Objective-C block syntax, the LuaJIT ffi + -- doesn't understand it. + if string.find(line, "(^)", 1, true) ~= nil + continue + if string.find(line, "_ISwupper", 1, true) ~= nil + continue + result[#result + 1] = line + table.concat(result, "\n") + +-- use this helper to import C files, you can pass multiple paths at once, +-- this helper will return the C namespace of the nvim library. +-- cimport = (path) -> +cimport = (...) -> + -- filter out paths we've already imported + paths = [path for path in *{...} when not imported\contains(path)] + for path in *paths + imported\add(path) + + if #paths == 0 + return libnvim + + -- preprocess the header + stream = Preprocess.preprocess_stream(unpack(paths)) + body = stream\read("*a") + stream\close! + + -- format it (so that the lines are "unique" statements), also filter out + -- Objective-C blocks + body = formatc(body) + body = filter_complex_blocks(body) + + -- add the formatted lines to a set + new_cdefs = Set! + for line in body\gmatch("[^\r\n]+") + new_cdefs\add(trim(line)) + + -- subtract the lines we've already imported from the new lines, then add + -- the new unique lines to the old lines (so they won't be imported again) + new_cdefs\diff(cdefs) + cdefs\union(new_cdefs) + + if new_cdefs\size! == 0 + -- if there's no new lines, just return + return libnvim + + -- request a sorted version of the new lines (same relative order as the + -- original preprocessed file) and feed that to the LuaJIT ffi + new_lines = new_cdefs\to_table! + ffi.cdef(table.concat(new_lines, "\n")) return libnvim -- cgit