Browse Source

Add luacheck config and configuration for Travis CI (#2790)

* Move luacheck conf and fix Travis for all possible filenames
* Add lua script to help with luacheck config
* Add xargs approach for current luac.cross file checking
* Enable luacheck but do not break build
galjonsfigur 4 years ago
parent
commit
7de8a01705
6 changed files with 1158 additions and 3 deletions
  1. 5 3
      .travis.yml
  2. 1 0
      CONTRIBUTING.md
  3. 883 0
      tools/luacheck_config.lua
  4. 139 0
      tools/luacheck_config_helper.lua
  5. 113 0
      tools/travis/localua.sh
  6. 17 0
      tools/travis/run-luacheck.sh

+ 5 - 3
.travis.yml

@@ -30,6 +30,8 @@ script:
 - if [ "$OS" = "windows" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/ci-build-windows-ms.sh; fi
 - if [ "$OS" = "linux" -a "$TRAVIS_PULL_REQUEST" != "false" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/pr-build.sh; fi
 - cd "$TRAVIS_BUILD_DIR"
-- LUA_FILES=`find lua_modules lua_examples -iname "*.lua"`
-- echo checking $LUA_FILES
-- $LUACC -p $LUA_FILES
+- echo "checking:"
+- find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo
+- find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 $LUACC -p
+- if [ "$OS" = "linux" ]; then bash "$TRAVIS_BUILD_DIR"/tools/travis/run-luacheck.sh || true ; fi
+

File diff suppressed because it is too large
+ 1 - 0
CONTRIBUTING.md


+ 883 - 0
tools/luacheck_config.lua

@@ -0,0 +1,883 @@
+local empty = { }
+local read_write = {read_only = false}
+
+stds.nodemcu_libs = {
+  read_globals = {
+    adc = {
+      fields = {
+        INIT_ADC = empty,
+        INIT_VDD33 = empty,
+        force_init_mode = empty,
+        read = empty,
+        readvdd33 = empty
+      }
+    },
+    ads1115 = {
+      fields = {
+        ADDR_GND = empty,
+        ADDR_SCL = empty,
+        ADDR_SDA = empty,
+        ADDR_VDD = empty,
+        CMODE_TRAD = empty,
+        CMODE_WINDOW = empty,
+        COMP_1CONV = empty,
+        COMP_2CONV = empty,
+        COMP_4CONV = empty,
+        CONTINUOUS = empty,
+        CONV_RDY_1 = empty,
+        CONV_RDY_2 = empty,
+        CONV_RDY_4 = empty,
+        DIFF_0_1 = empty,
+        DIFF_0_3 = empty,
+        DIFF_1_3 = empty,
+        DIFF_2_3 = empty,
+        DR_128SPS = empty,
+        DR_1600SPS = empty,
+        DR_16SPS = empty,
+        DR_2400SPS = empty,
+        DR_250SPS = empty,
+        DR_32SPS = empty,
+        DR_3300SPS = empty,
+        DR_475SPS = empty,
+        DR_490SPS = empty,
+        DR_64SPS = empty,
+        DR_860SPS = empty,
+        DR_8SPS = empty,
+        DR_920SPS = empty,
+        GAIN_0_256V = empty,
+        GAIN_0_512V = empty,
+        GAIN_1_024V = empty,
+        GAIN_2_048V = empty,
+        GAIN_4_096V = empty,
+        GAIN_6_144V = empty,
+        SINGLE_0 = empty,
+        SINGLE_1 = empty,
+        SINGLE_2 = empty,
+        SINGLE_3 = empty,
+        SINGLE_SHOT = empty,
+        ads1015 = empty,
+        ads1115 = empty,
+        read = empty,
+        reset = empty,
+      }
+    },
+    adxl345 = {
+      fields = {
+          read = empty,
+          setup = empty
+      }
+    },
+    am2320 = {
+      fields = {
+          read = empty,
+          setup = empty
+      }
+    },
+    apa102 = {
+      fields = {
+        write = empty
+      }
+    },
+    bit = {
+       fields = {
+         arshift = empty,
+         band = empty,
+         bit = empty,
+         bnot = empty,
+         bor = empty,
+         bxor = empty,
+         clear = empty,
+         isclear = empty,
+         isset = empty,
+         lshift = empty,
+         rshift = empty,
+         set = empty
+      }
+    },
+    bloom = {
+      fields = {
+        create = empty
+      }
+    },
+    bme280 = {
+      fields = {
+        altitude = empty,
+        baro = empty,
+        dewpoint = empty,
+        humi = empty,
+        qfe2qnh = empty,
+        read = empty,
+        setup = empty,
+        startreadout = empty,
+        temp = empty
+      }
+    },
+    bme680 = {
+      fields = {
+        altitude = empty,
+        dewpoint = empty,
+        qfe2qnh = empty,
+        read = empty,
+        setup = empty,
+        startreadout = empty
+      }
+    },
+    bmp085 = {
+      fields = {
+        pressure = empty,
+        pressure_raw = empty,
+        setup = empty,
+        temperature = empty
+      }
+    },
+    coap = {
+      fields = {
+        CON = empty,
+        Client = empty,
+        EXI = empty,
+        JSON = empty,
+        LINKFORMAT = empty,
+        NON = empty,
+        OCTET_STREAM = empty,
+        Server = empty,
+        TEXT_PLAIN = empty,
+        XML = empty
+      }
+    },
+    color_utils = {
+      fields = {
+        colorWheel = empty,
+        grb2hsv = empty,
+        hsv2grb = empty,
+        hsv2grbw = empty
+      }
+    },
+    cron = {
+      fields = {
+        reset = empty,
+        schedule = empty
+      }
+    },
+    crypto = {
+      fields = {
+        decrypt = empty,
+        encrypt = empty,
+        fhash = empty,
+        hash = empty,
+        hmac = empty,
+        mask = empty,
+        new_hash = empty,
+        new_hmac = empty,
+        sha1 = empty,
+        toBase64 = empty,
+        toHex = empty
+      }
+    },
+    dht = {
+      fields = {
+        ERROR_CHECKSUM = empty,
+        ERROR_TIMEOUT = empty,
+        OK = empty,
+        read = empty,
+        read11 = empty,
+        readxx = empty
+      }
+    },
+    encoder = {
+      fields = {
+        fromBase64 = empty,
+        fromHex = empty,
+        toBase64 = empty,
+        toHex = empty
+      }
+    },
+    enduser_setup = {
+      fields = {
+        manual = empty,
+        start = empty,
+        stop = empty
+      }
+    },
+    file = {
+      fields = {
+        close = empty,
+        exists = empty,
+        flush = empty,
+        fsinfo = empty,
+        getcontents = empty,
+        list = empty,
+        on = empty,
+        open = empty,
+        putcontents = empty,
+        read = empty,
+        readline = empty,
+        remove = empty,
+        rename = empty,
+        seek = empty,
+        stat = empty,
+        write = empty,
+        writeline = empty
+      }
+    },
+    gdbstub = {
+      fields = {
+        brk = empty,
+        gdboutput = empty,
+        open = empty
+      }
+    },
+    gpio = {
+      fields = {
+        FLOAT = empty,
+        HIGH = empty,
+        INPUT = empty,
+        INT = empty,
+        LOW = empty,
+        OPENDRAIN = empty,
+        OUTPUT = empty,
+        PULLUP = empty,
+        mode = empty,
+        read = empty,
+        serout = empty,
+        trig = empty,
+        write = empty,
+        pulse = {
+          fields = {
+            adjust = empty,
+            cancel = empty,
+            getstate = empty,
+            start = empty,
+            stop = empty,
+            update = empty
+          }
+        }
+      }
+    },
+    hdc1080 = {
+      fields = {
+        read = empty,
+        setup = empty
+      }
+    },
+    hmc5883 = {
+      fields = {
+        read = empty,
+        setup = empty
+      }
+    },
+    http = {
+      fields = {
+        ERROR = empty,
+        OK = empty,
+        delete = empty,
+        get = empty,
+        post = empty,
+        put = empty,
+        request = empty
+      }
+    },
+    hx711 = {
+      fields = {
+        init = empty,
+        read = empty
+      }
+    },
+    i2c = {
+      fields = {
+        FAST = empty,
+        FASTPLUS = empty,
+        RECEIVER = empty,
+        SLOW = empty,
+        TRANSMITTER = empty,
+        address = empty,
+        read = empty,
+        setup = empty,
+        start = empty,
+        stop = empty,
+        write = empty
+      }
+    },
+    l3g4200d = {
+      fields = {
+        read = empty,
+        setup = empty
+      }
+    },
+    mcp4725 = {
+      fields = {
+        PWRDN_100K = empty,
+        PWRDN_1K = empty,
+        PWRDN_500K = empty,
+        PWRDN_NONE = empty,
+        read = empty,
+        write = empty
+      }
+    },
+    mdns = {
+      fields = {
+        close = empty,
+        register = empty
+      }
+    },
+    mqtt = {
+      fields = {
+        CONNACK_ACCEPTED = empty,
+        CONNACK_REFUSED_BAD_USER_OR_PASS = empty,
+        CONNACK_REFUSED_ID_REJECTED = empty,
+        CONNACK_REFUSED_NOT_AUTHORIZED = empty,
+        CONNACK_REFUSED_PROTOCOL_VER = empty,
+        CONNACK_REFUSED_SERVER_UNAVAILABLE = empty,
+        CONN_FAIL_DNS = empty,
+        CONN_FAIL_NOT_A_CONNACK_MSG = empty,
+        CONN_FAIL_SERVER_NOT_FOUND = empty,
+        CONN_FAIL_TIMEOUT_RECEIVING = empty,
+        CONN_FAIL_TIMEOUT_SENDING = empty,
+        Client = empty
+      }
+    },
+    net = {
+      fields = {
+        TCP = empty,
+        UDP = empty,
+        cert = empty,
+        createConnection = empty,
+        createServer = empty,
+        createUDPSocket = empty,
+        dns = {
+          fields = {
+            getdnsserver = empty,
+            resolve = empty,
+            setdnsserver = empty
+          }
+        },
+        multicastJoin = empty,
+        multicastLeave = empty
+      }
+    },
+    node = {
+      fields = {
+        CPU160MHZ = empty,
+        CPU80MHZ = empty,
+        bootreason = empty,
+        chipid = empty,
+        compile = empty,
+        dsleep = empty,
+        dsleepMax = empty,
+        dsleepsetoption = empty,
+        flashid = empty,
+        flashindex = empty,
+        flashreload = empty,
+        flashsize = empty,
+        getcpufreq = empty,
+        getpartitiontable = empty,
+        heap = empty,
+        info = empty,
+        input = empty,
+        osprint = empty,
+        output = empty,
+        random = empty,
+        readrcr = empty,
+        readvdd33 = empty,
+        restart = empty,
+        restore = empty,
+        setcpufreq = empty,
+        setpartitiontable = empty,
+        sleep = empty,
+        stripdebug = empty,
+        writercr = empty,
+        egc = {
+          fields = {
+            setmode = empty,
+            meminfo = empty
+         }
+        },
+        task = {
+          fields = {
+            post = empty
+          }
+        }
+      }
+    },
+    ow = {
+      fields = {
+        check_crc16 = empty,
+        crc16 = empty,
+        crc8 = empty,
+        depower = empty,
+        read = empty,
+        read_bytes = empty,
+        reset = empty,
+        reset_search = empty,
+        search = empty,
+        select = empty,
+        setup = empty,
+        skip = empty,
+        target_search = empty,
+        write = empty,
+        write_bytes = empty
+      }
+    },
+    pcm = {
+      fields = {
+        RATE_10K = empty,
+        RATE_12K = empty,
+        RATE_16K = empty,
+        RATE_1K = empty,
+        RATE_2K = empty,
+        RATE_4K = empty,
+        RATE_5K = empty,
+        RATE_8K = empty,
+        SD = empty,
+        new = empty
+      }
+    },
+    pwm = {
+      fields = {
+        close = empty,
+        getclock = empty,
+        getduty = empty,
+        setclock = empty,
+        setduty = empty,
+        setup = empty,
+        start = empty,
+        stop = empty
+      }
+    },
+    pwm2 = {
+      fields = {
+        get_pin_data = empty,
+        get_timer_data = empty,
+        release_pin = empty,
+        set_duty = empty,
+        setup_pin_hz = empty,
+        setup_pin_sec = empty,
+        start = empty,
+        stop = empty,
+      }
+    },
+    rc = {
+      fields = {
+        send = empty
+      }
+    },
+    rfswitch = {
+      fields = {
+        send = empty
+      }
+    },
+    rotary = {
+      fields = {
+        ALL = empty,
+        CLICK = empty,
+        DBLCLICK = empty,
+        LONGPRESS = empty,
+        PRESS = empty,
+        RELEASE = empty,
+        TURN = empty,
+        close = empty,
+        getpos = empty,
+        on = empty,
+        setup = empty
+      }
+    },
+    rtcfifo = {
+      fields = {
+        count = empty,
+        drop = empty,
+        dsleep_until_sample = empty,
+        peek = empty,
+        pop = empty,
+        prepare = empty,
+        put = empty,
+        ready = empty
+      }
+    },
+    rtcmem = {
+      fields = {
+        read32 = empty,
+        write32 = empty
+      }
+    },
+    rtctime = {
+      fields = {
+        adjust_delta = empty,
+        dsleep = empty,
+        dsleep_aligned = empty,
+        epoch2cal = empty,
+        get = empty,
+        set = empty
+      }
+    },
+    si7021 = {
+      fields = {
+        HEATER_DISABLE = empty,
+        HEATER_ENABLE = empty,
+        RH08_TEMP12 = empty,
+        RH10_TEMP13 = empty,
+        RH11_TEMP11 = empty,
+        RH12_TEMP14 = empty,
+        firmware = empty,
+        read = empty,
+        serial = empty,
+        setting = empty,
+        setup = empty
+      }
+    },
+    sigma_delta = {
+      fields = {
+        close = empty,
+        setprescale = empty,
+        setpwmduty = empty,
+        settarget = empty,
+        setup = empty
+      }
+    },
+    sjson = {
+      fields = {
+        decode = empty,
+        decoder = empty,
+        encode = empty,
+        encoder = empty
+      }
+    },
+    sntp = {
+      fields = {
+        getoffset = empty,
+        setoffset = empty,
+        sync = empty
+      }
+    },
+    somfy = {
+      fields = {
+        DOWN = empty,
+        PROG = empty,
+        STOP = empty,
+        UP = empty,
+        sendcommand = empty
+      }
+    },
+    spi = {
+      fields = {
+        CPHA_HIGH = empty,
+        CPHA_LOW = empty,
+        CPOL_HIGH = empty,
+        CPOL_LOW = empty,
+        DATABITS_8 = empty,
+        FULLDUPLEX = empty,
+        HALFDUPLEX = empty,
+        MASTER = empty,
+        SLAVE = empty,
+        get_miso = empty,
+        recv = empty,
+        send = empty,
+        set_clock_div = empty,
+        set_mosi = empty,
+        setup = empty,
+        transaction = empty
+      }
+    },
+    switec = {
+      fields = {
+        close = empty,
+        dequeue = empty,
+        getpos = empty,
+        moveto = empty,
+        reset = empty,
+        setup = empty
+      }
+    },
+    tcs34725 = {
+      fields = {
+        disable = empty,
+        enable = empty,
+        raw = empty,
+        setGain = empty,
+        setIntegrationTime = empty,
+        setup = empty
+      }
+    },
+    tls = {
+      fields = {
+        createConnection = empty,
+        setDebug = empty,
+        cert = {
+          fields = {
+            auth = empty,
+            verify = empty
+          }
+        }
+      }
+    },
+    tm1829 = {
+      fields = {
+        write = empty
+      }
+    },
+    tmr = {
+      fields = {
+        ALARM_AUTO = empty,
+        ALARM_SEMI = empty,
+        ALARM_SINGLE = empty,
+        create = empty,
+        delay = empty,
+        now = empty,
+        resume_all = empty,
+        softwd = empty,
+        suspend_all = empty,
+        time = empty,
+        wdclr = empty
+      }
+    },
+    tsl2561 = {
+      fields = {
+        ADDRESS_FLOAT = empty,
+        ADDRESS_GND = empty,
+        ADDRESS_VDD = empty,
+        GAIN_16X = empty,
+        GAIN_1X = empty,
+        INTEGRATIONTIME_101MS = empty,
+        INTEGRATIONTIME_13MS = empty,
+        INTEGRATIONTIME_402MS = empty,
+        PACKAGE_CS = empty,
+        PACKAGE_T_FN_CL = empty,
+        TSL2561_ERROR_I2CBUSY = empty,
+        TSL2561_ERROR_I2CINIT = empty,
+        TSL2561_ERROR_LAST = empty,
+        TSL2561_ERROR_NOINIT = empty,
+        TSL2561_OK = empty,
+        getlux = empty,
+        getrawchannels = empty,
+        init = empty,
+        settiming = empty
+      }
+    },
+    -- There would be too many fields for all the fonts and displays
+    u8g2 = {other_fields = true},
+    uart = {
+      fields = {
+        PARITY_EVEN = empty,
+        PARITY_NONE = empty,
+        PARITY_ODD = empty,
+        STOPBITS_1 = empty,
+        STOPBITS_1_5 = empty,
+        STOPBITS_2 = empty,
+        alt = empty,
+        getconfig = empty,
+        on = empty,
+        setup = empty,
+        write = empty
+      }
+    },
+    -- There would be too many fields for all the fonts and displays
+    ucg = {other_fields = true},
+    websocket = {
+      fields = {
+        createClient = empty
+      }
+    },
+    wifi = {
+      fields = {
+        COUNTRY_AUTO = empty,
+        COUNTRY_MANUAL = empty,
+        LIGHT_SLEEP = empty,
+        MODEM_SLEEP = empty,
+        NONE_SLEEP = empty,
+        NULLMODE = empty,
+        OPEN = empty,
+        PHYMODE_B = empty,
+        PHYMODE_G = empty,
+        PHYMODE_N = empty,
+        SOFTAP = empty,
+        STATION = empty,
+        STATIONAP = empty,
+        STA_APNOTFOUND = empty,
+        STA_CONNECTING = empty,
+        STA_FAIL = empty,
+        STA_GOTIP = empty,
+        STA_IDLE = empty,
+        STA_WRONGPWD = empty,
+        WEP = empty,
+        WPA2_PSK = empty,
+        WPA_PSK = empty,
+        WPA_WPA2_PSK = empty,
+        getchannel = empty,
+        getcountry = empty,
+        getdefaultmode = empty,
+        getmode = empty,
+        getphymode = empty,
+        nullmodesleep = empty,
+        resume = empty,
+        setcountry = empty,
+        setmaxtxpower = empty,
+        setmode = empty,
+        setphymode = empty,
+        sleeptype = empty,
+        startsmart = empty,
+        stopsmart = empty,
+        suspend = empty,
+        sta = {
+          fields = {
+            autoconnect = empty,
+            changeap = empty,
+            clearconfig = empty,
+            config = empty,
+            connect = empty,
+            disconnect = empty,
+            getap = empty,
+            getapindex = empty,
+            getapinfo = empty,
+            getbroadcast = empty,
+            getconfig = empty,
+            getdefaultconfig = empty,
+            gethostname = empty,
+            getip = empty,
+            getmac = empty,
+            getrssi = empty,
+            setaplimit = empty,
+            sethostname = empty,
+            setip = empty,
+            setmac = empty,
+            sleeptype = empty,
+            status = empty
+          }
+        },
+        ap = {
+          fields = {
+            config = empty,
+            deauth = empty,
+            getbroadcast = empty,
+            getclient = empty,
+            getconfig = empty,
+            getdefaultconfig = empty,
+            getip = empty,
+            getmac = empty,
+            setip = empty,
+            setmac = empty,
+            dhcp = {
+              fields = {
+                config = empty,
+                start = empty,
+                stop = empty
+              }
+            },
+          }
+        },
+        eventmon = {
+          fields = {
+            AP_PROBEREQRECVED = empty,
+            AP_STACONNECTED = empty,
+            AP_STADISCONNECTED = empty,
+            EVENT_MAX = empty,
+            STA_AUTHMODE_CHANGE = empty,
+            STA_CONNECTED = empty,
+            STA_DHCP_TIMEOUT = empty,
+            STA_DISCONNECTED = empty,
+            STA_GOT_IP = empty,
+            WIFI_MODE_CHANGED = empty,
+            register = empty,
+            unregister = empty,
+            reason = {
+              fields = {
+                ["4WAY_HANDSHAKE_TIMEOUT"] = empty,
+                ["802_1X_AUTH_FAILED"] = empty,
+                AKMP_INVALID = empty,
+                ASSOC_EXPIRE = empty,
+                ASSOC_FAIL = empty,
+                ASSOC_LEAVE = empty,
+                ASSOC_NOT_AUTHED = empty,
+                ASSOC_TOOMANY = empty,
+                AUTH_EXPIRE = empty,
+                AUTH_FAIL = empty,
+                AUTH_LEAVE = empty,
+                BEACON_TIMEOUT = empty,
+                CIPHER_SUITE_REJECTED = empty,
+                DISASSOC_PWRCAP_BAD = empty,
+                DISASSOC_SUPCHAN_BAD = empty,
+                GROUP_CIPHER_INVALID = empty,
+                GROUP_KEY_UPDATE_TIMEOUT = empty,
+                HANDSHAKE_TIMEOUT = empty,
+                IE_INVALID = empty,
+                IE_IN_4WAY_DIFFERS = empty,
+                INVALID_RSN_IE_CAP = empty,
+                MIC_FAILURE = empty,
+                NOT_ASSOCED = empty,
+                NOT_AUTHED = empty,
+                NO_AP_FOUND = empty,
+                PAIRWISE_CIPHER_INVALID = empty,
+                UNSPECIFIED = empty,
+                UNSUPP_RSN_IE_VERSION = empty
+              }
+            }
+          }
+        },
+        monitor = {
+          fields = {
+            channel = empty,
+            start = empty,
+            stop = empty
+          }
+        }
+      }
+    },
+    wps = {
+      fields = {
+        FAILED = empty,
+        SCAN_ERR = empty,
+        SUCCESS = empty,
+        TIMEOUT = empty,
+        WEP = empty,
+        disable = empty,
+        enable = empty,
+        start = empty
+      }
+    },
+    ws2801 = {
+      fields = {
+        init = empty,
+        write = empty
+      }
+    },
+    ws2812 = {
+      fields = {
+        FADE_IN = empty,
+        FADE_OUT = empty,
+        MODE_DUAL = empty,
+        MODE_SINGLE = empty,
+        SHIFT_CIRCULAR = empty,
+        SHIFT_LOGICAL = empty,
+        init = empty,
+        newBuffer = empty,
+        write = empty
+      }
+    },
+    ws2812_effects = {
+      fields = {
+        get_delay = empty,
+        get_speed = empty,
+        init = empty,
+        set_brightness = empty,
+        set_color = empty,
+        set_delay = empty,
+        set_mode = empty,
+        set_speed = empty,
+        start = empty,
+        stop = empty
+      }
+    },
+    xpt2046 = {
+      fields = {
+        getPosition = empty,
+        getPositionAvg = empty,
+        getRaw = empty,
+        init = empty,
+        isTouched = empty,
+        setCalibration = empty
+      }
+    },
+    pack = empty,
+    unpack  = empty,
+    size = empty
+  }
+}
+
+std = "lua51+nodemcu_libs"

+ 139 - 0
tools/luacheck_config_helper.lua

@@ -0,0 +1,139 @@
+#!/usr/bin/lua
+
+---
+-- Script to extract names and the functions themselves from NodeMCU modules and
+-- to help creating luacheck configuration.
+-- Usage: <in modules catalog> ../../tools/luacheck_config_helper.lua *.c (or filename for single module)
+
+local M = {}
+
+-- Recursive object dumper, for debugging.
+-- (c) 2010 David Manura, MIT License.
+-- From: https://github.com/davidm/lua-inspect/blob/master/lib/luainspect/dump.lua
+local ignore_keys_ = {lineinfo = true}
+local norecurse_keys_ = {parent = true, ast = true}
+local function dumpstring_key_(k, isseen, newindent)
+  local ks = type(k) == 'string' and k:match'^[%a_][%w_]*$' and k or
+             '[' .. M.dumpstring(k, isseen, newindent) .. ']'
+  return ks
+end
+
+local function sort_keys_(a, b)
+  if type(a) == 'number' and type(b) == 'number' then
+    return a < b
+  elseif type(a) == 'number' then
+    return false
+  elseif type(b) == 'number' then
+    return true
+  elseif type(a) == 'string' and type(b) == 'string' then
+    return a < b
+  else
+    return tostring(a) < tostring(b) -- arbitrary
+  end
+end
+
+function M.dumpstring(o, isseen, indent, key)
+  isseen = isseen or {}
+  indent = indent or ''
+
+  if type(o) == 'table' then
+    if isseen[o] or norecurse_keys_[key] then
+      return (type(o.tag) == 'string' and '`' .. o.tag .. ':' or '') .. tostring(o)
+    else isseen[o] = true end -- avoid recursion
+
+    local used = {}
+
+    local tag = o.tag
+    local s = '{'
+    if type(o.tag) == 'string' then
+      s = '`' .. tag .. s; used['tag'] = true
+    end
+    local newindent = indent .. '  '
+
+    local ks = {}; for k in pairs(o) do ks[#ks+1] = k end
+    table.sort(ks, sort_keys_)
+
+    local forcenummultiline
+    for k in pairs(o) do
+       if type(k) == 'number' and type(o[k]) == 'table' then forcenummultiline = true end
+    end
+
+    -- inline elements
+    for _,k in ipairs(ks) do
+      if ignore_keys_[k] then used[k] = true
+      elseif (type(k) ~= 'number' or not forcenummultiline) and
+              type(k) ~= 'table' and (type(o[k]) ~= 'table' or norecurse_keys_[k])
+      then
+        s = s .. dumpstring_key_(k, isseen, newindent) .. ' = ' .. M.dumpstring(o[k], isseen, newindent, k) .. ', '
+        used[k] = true
+      end
+    end
+
+    -- elements on separate lines
+    local done
+    for _,k in ipairs(ks) do
+      if not used[k] then
+        if not done then s = s .. '\n'; done = true end
+        s = s .. newindent .. dumpstring_key_(k, isseen) .. ' = ' .. M.dumpstring(o[k], isseen, newindent, k) .. ',\n'
+      end
+    end
+    s = s:gsub(',(%s*)$', '%1')
+    s = s .. (done and indent or '') .. '}'
+    return s
+  elseif type(o) == 'string' then
+    return string.format('%q', o)
+  else
+    return tostring(o)
+  end
+end
+-- End of dump.lua code
+
+local function printTables(fileName)
+
+  local findBegin, field
+  if type(fileName) ~= "string" then error("Wrong argument") end
+  local file = io.open(fileName, "r")
+  if not file then error("Can't open file") end
+  local result = {}
+  result.fields = {}
+
+  for line in file:lines() do
+    findBegin, _, field = string.find(line, "LROT_BEGIN%((%g+)%)")
+    if findBegin then
+      io.write(field.." = ")
+    end
+    findBegin, _, field = string.find(line, "LROT_PUBLIC_BEGIN%((%g+)%)")
+    if findBegin then
+      print(field.." = ")
+    end
+
+    findBegin, _, field = string.find(line, "LROT_FUNCENTRY%(%s?(%g+),")
+    if not findBegin then
+      findBegin, _, field = string.find(line, "LROT_NUMENTRY%(%s?(%g+),")
+    end
+    if not findBegin then
+      findBegin, _, field = string.find(line, "LROT_TABENTRY%(%s?(%g+),")
+    end
+
+    if findBegin then
+     if not  string.find(field, "__") then
+       result.fields[field] = {}
+     end
+    end
+
+    findBegin = string.find(line, "LROT_END")
+    if findBegin then
+      print(string.gsub(M.dumpstring(result), "{}", "empty")..',')
+      result = {}
+      result.fields = {}
+    end
+  end
+end
+
+local function main()
+  for i = 1, #arg do
+    printTables(arg[i])
+  end
+end
+
+main()

+ 113 - 0
tools/travis/localua.sh

@@ -0,0 +1,113 @@
+#!/bin/bash
+
+# Downloads and installs a self-contained Lua and LuaRocks.
+# Supports Linux, macOS and MSYS2.
+# Copyright (c) 2015-2019 Pierre Chapuis, MIT Licensed.
+# Latest stable version available at: https://loadk.com/localua.sh
+# Maintained at: https://github.com/oploadk/localua
+
+DEFAULT_LUA_V="5.3.5"
+DEFAULT_LR_V="3.0.4"
+
+usage () {
+    >&2 echo -e "USAGE: $0 output-dir [lua-version] [luarocks-version]\n"
+    >&2 echo -n "The first optional argument is the Lua version, "
+    >&2 echo -n "the second one is the LuaRocks version. "
+    >&2 echo -e "Defaults are Lua $DEFAULT_LUA_V and LuaRocks $DEFAULT_LR_V.\n"
+    >&2 echo -n "You can set a custom build directory with environment "
+    >&2 echo -e "variable LOCALUA_BUILD_DIRECTORY (not useful in general).\n"
+    >&2 echo -e "You can set a custom makefile target with LOCALUA_TARGET.\n"
+    >&2 echo -e "You can disable LUA_COMPAT by setting LOCALUA_NO_COMPAT.\n"
+    >&2 echo -e "You can skip luarocks by setting LOCALUA_NO_LUAROCKS."
+    exit 1
+}
+
+# Set output directory, Lua version and LuaRocks version
+
+ODIR="$1"
+[ -z "$ODIR" ] && usage
+
+LUA_V="$2"
+[ -z "$LUA_V" ] && LUA_V="$DEFAULT_LUA_V"
+
+LUA_SHORTV="$(echo $LUA_V | cut -c 1-3)"
+
+LR_V="$3"
+[ -z "$LR_V" ] && LR_V="$DEFAULT_LR_V"
+
+# Set build directory
+
+BDIR="$LOCALUA_BUILD_DIRECTORY"
+[ -z "$BDIR" ] && BDIR="$(mktemp -d /tmp/localua-XXXXXX)"
+
+# Create output directory and get absolute path
+
+mkdir -p "$ODIR"
+>/dev/null pushd "$ODIR"
+    ODIR="$(pwd)"
+>/dev/null popd
+
+# Download, unpack and build Lua and LuaRocks
+
+if [ -z "$LOCALUA_TARGET" ]; then
+    case "$(uname)" in
+        Linux)
+            LOCALUA_TARGET="linux";;
+        Darwin)
+            LOCALUA_TARGET="macosx";;
+        MSYS*)
+            LOCALUA_TARGET="msys";;
+        *)
+            LOCALUA_TARGET="posix";;
+    esac
+fi
+
+pushd "$BDIR"
+    wget "http://www.lua.org/ftp/lua-${LUA_V}.tar.gz"
+    tar xf "lua-${LUA_V}.tar.gz"
+    pushd "lua-${LUA_V}"
+        sed 's#"/usr/local/"#"'"$ODIR"'/"#' "src/luaconf.h" > "$BDIR/t"
+        mv "$BDIR/t" "src/luaconf.h"
+        if [ ! -z "$LOCALUA_NO_COMPAT" ]; then
+            sed 's#-DLUA_COMPAT_5_2##' "src/Makefile" > "$BDIR/t"
+            sed 's#-DLUA_COMPAT_ALL##' "$BDIR/t" > "src/Makefile"
+        fi
+
+        if [ "$LOCALUA_TARGET" = "msys" ]; then
+            >> "src/Makefile" echo
+            >> "src/Makefile" echo 'msys:' >> "src/Makefile"
+            >> "src/Makefile" echo -ne "\t"
+            >> "src/Makefile" echo '$(MAKE) "LUA_A=lua53.dll" "LUA_T=lua.exe" \'
+            >> "src/Makefile" echo -ne "\t"
+            >> "src/Makefile" echo '"AR=$(CC) -shared -Wl,--out-implib,liblua.dll.a -o" "RANLIB=strip --strip-unneeded" \'
+            >> "src/Makefile" echo -ne "\t"
+            >> "src/Makefile" echo '"SYSCFLAGS=-DLUA_BUILD_AS_DLL -DLUA_USE_POSIX -DLUA_USE_DLOPEN" "SYSLIBS=" "SYSLDFLAGS=-s" lua.exe'
+            >> "src/Makefile" echo -ne "\t"
+            >> "src/Makefile" echo '$(MAKE) "LUAC_T=luac.exe" luac.exe'
+
+            make -C src "$LOCALUA_TARGET" || exit 1
+            make \
+                TO_BIN="lua.exe luac.exe lua53.dll" \
+                TO_LIB="liblua.a liblua.dll.a" \
+                INSTALL_TOP="$ODIR" install || exit 1
+        else
+            make "$LOCALUA_TARGET" || exit 1
+            make INSTALL_TOP="$ODIR" install || exit 1
+        fi
+
+    popd
+    if [ -z "$LOCALUA_NO_LUAROCKS" ]; then
+        wget "http://luarocks.org/releases/luarocks-${LR_V}.tar.gz"
+        tar xf "luarocks-${LR_V}.tar.gz"
+        pushd "luarocks-${LR_V}"
+            ./configure --with-lua="$ODIR" --prefix="$ODIR" \
+                        --lua-version="$LUA_SHORTV" \
+                        --sysconfdir="$ODIR/luarocks" --force-config
+            make bootstrap
+        popd
+    fi
+popd
+
+# Cleanup
+
+rm -rf "$BDIR"

+ 17 - 0
tools/travis/run-luacheck.sh

@@ -0,0 +1,17 @@
+#!/bin/bash
+
+set -e
+
+echo "Installing Lua 5.3, LuaRocks and Luacheck"
+(
+  cd "$TRAVIS_BUILD_DIR" || exit
+  bash tools/travis/localua.sh cache/localua || exit
+  cache/localua/bin/luarocks install luacheck || exit
+)
+
+(
+  echo "Static analysys of:"
+  find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 echo
+)
+
+(find lua_modules lua_examples -iname "*.lua" -print0 | xargs -0 cache/localua/bin/luacheck --config tools/luacheck_config.lua) || exit

Some files were not shown because too many files changed in this diff