lint.lua revision 1.5
11.1Srillig#! /usr/bin/lua
21.5Srillig-- $NetBSD: lint.lua,v 1.5 2021/06/13 19:41:12 rillig Exp $
31.1Srillig
41.1Srillig--[[
51.1Srillig
61.1Srilligusage: lua ./lint.lua
71.1Srillig
81.4SrilligCheck that the argument handling code does not contain unintended
91.1Srilliginconsistencies.
101.1Srillig
111.1Srillig]]
121.1Srillig
131.3Srillig---@return string[]
141.1Srilliglocal function load_lines(fname)
151.1Srillig  local lines = {}
161.1Srillig
171.1Srillig  local f = assert(io.open(fname, "r"))
181.1Srillig  for line in f:lines() do
191.1Srillig    table.insert(lines, line)
201.1Srillig  end
211.1Srillig
221.1Srillig  f:close()
231.1Srillig
241.1Srillig  return lines
251.1Srilligend
261.1Srillig
271.1Srillig
281.1Srilliglocal function new_errors()
291.1Srillig  local errors = {}
301.1Srillig  errors.add = function(self, fmt, ...)
311.1Srillig    table.insert(self, string.format(fmt, ...))
321.1Srillig  end
331.1Srillig  errors.print = function(self)
341.1Srillig    for _, msg in ipairs(self) do
351.1Srillig      print(msg)
361.1Srillig    end
371.1Srillig  end
381.1Srillig  return errors
391.1Srilligend
401.1Srillig
411.1Srillig
421.1Srilliglocal function num(s)
431.1Srillig  if s == nil then return nil end
441.1Srillig  return tonumber(s)
451.1Srilligend
461.1Srillig
471.1Srillig
481.1Srillig-- After each macro ARGC, there must be the corresponding macros for ARG.
491.1Srilliglocal function check_args(errors)
501.1Srillig  local fname = "curses_commands.c"
511.1Srillig  local lines = load_lines(fname)
521.4Srillig  local curr_argc, curr_arg ---@type number|nil, number|nil
531.1Srillig
541.1Srillig  for lineno, line in ipairs(lines) do
551.1Srillig
561.5Srillig    local line_argc = num(line:match("^\tARGC%((%d+)"))
571.4Srillig    if line_argc and line_argc > 0 then
581.4Srillig      curr_argc, curr_arg = line_argc, 0
591.5Srillig      goto next
601.1Srillig    end
611.1Srillig
621.5Srillig    local line_arg = line:match("^\tARG_[%w_]+%(")
631.5Srillig    if line_arg and curr_arg then
641.5Srillig      curr_arg = curr_arg + 1
651.5Srillig      if curr_arg == curr_argc then
661.5Srillig        curr_argc, curr_arg = nil, nil
671.5Srillig      end
681.5Srillig    elseif line_arg then
691.1Srillig      errors:add("%s:%d: ARG without preceding ARGC", fname, lineno)
701.5Srillig    elseif curr_arg then
711.4Srillig      errors:add("%s:%d: expecting ARG %d, got %s",
721.4Srillig        fname, lineno, curr_arg, line)
731.4Srillig      curr_argc, curr_arg = nil, nil
741.1Srillig    end
751.1Srillig
761.5Srillig    ::next::
771.1Srillig  end
781.1Srilligend
791.1Srillig
801.1Srillig
811.1Srilliglocal function main(arg)
821.1Srillig  local errors = new_errors()
831.1Srillig  check_args(errors)
841.1Srillig  errors:print()
851.1Srillig  return #errors == 0
861.1Srilligend
871.1Srillig
881.1Srillig
891.1Srilligos.exit(main(arg))
90