commit e24c536: [Minor] Update lua-tableshape to 2.6.0

Vsevolod Stakhov vsevolod at rspamd.com
Sun Apr 9 11:49:03 UTC 2023


Author: Vsevolod Stakhov
Date: 2023-04-09 12:42:03 +0100
URL: https://github.com/rspamd/rspamd/commit/e24c536e5989e2b6d46cd8fb35667c860a175324 (HEAD -> master)

[Minor] Update lua-tableshape to 2.6.0
Issue: #4455

---
 contrib/DEPENDENCY_INFO.md            |   2 +-
 contrib/lua-tableshape/tableshape.lua | 828 ++++++++++++++++++++++++++--------
 2 files changed, 642 insertions(+), 188 deletions(-)

diff --git a/contrib/DEPENDENCY_INFO.md b/contrib/DEPENDENCY_INFO.md
index 49eca0992..745b60d76 100644
--- a/contrib/DEPENDENCY_INFO.md
+++ b/contrib/DEPENDENCY_INFO.md
@@ -17,7 +17,7 @@
 | lua-lpeg               | 1.0     | MIT                 | YES     | rspamd text + alloc|
 | lua-moses              | ?       | MIT                 | NO      |                    |
 | lua-lupa               | ?       | MIT                 | NO      |                    |
-| lua-tableshape         | ae67256 | MIT                 | NO      |                    |
+| lua-tableshape         | 2.6.0   | MIT                 | NO      |                    |
 | mumhash                | ?       | MIT                 | NO      |                    |
 | ngx-http-parser        | 2.2.0   | MIT                 | YES     | spamc support      |
 | Mozilla-PublicSuffix   | ?       | MIT                 | NO      |                    |
diff --git a/contrib/lua-tableshape/tableshape.lua b/contrib/lua-tableshape/tableshape.lua
index 0f1f710f6..ccc735519 100644
--- a/contrib/lua-tableshape/tableshape.lua
+++ b/contrib/lua-tableshape/tableshape.lua
@@ -1,4 +1,5 @@
-local OptionalType, TaggedType, types
+local OptionalType, TaggedType, types, is_type
+local BaseType, TransformNode, SequenceNode, FirstOfNode, DescribeNode, NotType, Literal
 local FailedTransform = { }
 local unpack = unpack or table.unpack
 local clone_state
@@ -22,11 +23,9 @@ clone_state = function(state_obj)
   end
   return out
 end
-local BaseType, TransformNode, SequenceNode, FirstOfNode, DescribeNode
-local describe_literal
-describe_literal = function(val)
-  local _exp_0 = type(val)
-  if "string" == _exp_0 then
+local describe_type
+describe_type = function(val)
+  if type(val) == "string" then
     if not val:match('"') then
       return "\"" .. tostring(val) .. "\""
     elseif not val:match("'") then
@@ -34,13 +33,23 @@ describe_literal = function(val)
     else
       return "`" .. tostring(val) .. "`"
     end
+  elseif BaseType:is_base_type(val) then
+    return val:_describe()
   else
-    if BaseType:is_base_type(val) then
-      return val:_describe()
-    else
-      return tostring(val)
+    return tostring(val)
+  end
+end
+local coerce_literal
+coerce_literal = function(value)
+  local _exp_0 = type(value)
+  if "string" == _exp_0 or "number" == _exp_0 or "boolean" == _exp_0 then
+    return Literal(value)
+  elseif "table" == _exp_0 then
+    if BaseType:is_base_type(value) then
+      return value
     end
   end
+  return nil, "failed to coerce literal into type, use types.literal() to test for literal value"
 end
 local join_names
 join_names = function(items, sep, last_sep)
@@ -66,13 +75,6 @@ end
 do
   local _class_0
   local _base_0 = {
-    __eq = function(self, other)
-      if BaseType:is_base_type(other) then
-        return other(self)
-      else
-        return self(other[1])
-      end
-    end,
     __div = function(self, fn)
       return TransformNode(self, fn)
     end,
@@ -83,20 +85,46 @@ do
         return _with_0
       end
     end,
-    __mul = function(self, right)
-      return SequenceNode(self, right)
+    __mul = function(_left, _right)
+      local left, err = coerce_literal(_left)
+      if not (left) then
+        error("left hand side of multiplication: " .. tostring(_left) .. ": " .. tostring(err))
+      end
+      local right
+      right, err = coerce_literal(_right)
+      if not (right) then
+        error("right hand side of multiplication: " .. tostring(_right) .. ": " .. tostring(err))
+      end
+      return SequenceNode(left, right)
     end,
-    __add = function(self, right)
-      if self.__class == FirstOfNode then
+    __add = function(_left, _right)
+      local left, err = coerce_literal(_left)
+      if not (left) then
+        error("left hand side of addition: " .. tostring(_left) .. ": " .. tostring(err))
+      end
+      local right
+      right, err = coerce_literal(_right)
+      if not (right) then
+        error("right hand side of addition: " .. tostring(_right) .. ": " .. tostring(err))
+      end
+      if left.__class == FirstOfNode then
         local options = {
-          unpack(self.options)
+          unpack(left.options)
         }
         table.insert(options, right)
         return FirstOfNode(unpack(options))
+      elseif right.__class == FirstOfNode then
+        return FirstOfNode(left, unpack(right.options))
       else
-        return FirstOfNode(self, right)
+        return FirstOfNode(left, right)
       end
     end,
+    __unm = function(self, right)
+      return NotType(right)
+    end,
+    __tostring = function(self)
+      return self:_describe()
+    end,
     _describe = function(self)
       return error("Node missing _describe: " .. tostring(self.__class.__name))
     end,
@@ -141,25 +169,8 @@ do
         tag = name
       })
     end,
-    clone_opts = function(self, merge)
-      local opts
-      if self.opts then
-        do
-          local _tbl_0 = { }
-          for k, v in pairs(self.opts) do
-            _tbl_0[k] = v
-          end
-          opts = _tbl_0
-        end
-      else
-        opts = { }
-      end
-      if merge then
-        for k, v in pairs(merge) do
-          opts[k] = v
-        end
-      end
-      return opts
+    clone_opts = function(self)
+      return error("clone_opts is not longer supported")
     end,
     __call = function(self, ...)
       return self:check_value(...)
@@ -167,11 +178,7 @@ do
   }
   _base_0.__index = _base_0
   _class_0 = setmetatable({
-    __init = function(self)
-      if self.opts then
-        self._describe = self.opts.describe
-      end
-    end,
+    __init = function(self, opts) end,
     __base = _base_0,
     __name = "BaseType"
   }, {
@@ -185,35 +192,24 @@ do
   _base_0.__class = _class_0
   local self = _class_0
   self.is_base_type = function(self, val)
-    if not (type(val) == "table") then
-      return false
-    end
-    local cls = val and val.__class
-    if not (cls) then
-      return false
-    end
-    if BaseType == cls then
-      return true
+    do
+      local mt = type(val) == "table" and getmetatable(val)
+      if mt then
+        if mt.__class then
+          return mt.__class.is_base_type == BaseType.is_base_type
+        end
+      end
     end
-    return self:is_base_type(cls.__parent)
+    return false
   end
   self.__inherited = function(self, cls)
     cls.__base.__call = cls.__call
-    cls.__base.__eq = self.__eq
     cls.__base.__div = self.__div
     cls.__base.__mod = self.__mod
     cls.__base.__mul = self.__mul
     cls.__base.__add = self.__add
-    local mt = getmetatable(cls)
-    local create = mt.__call
-    mt.__call = function(cls, ...)
-      local ret = create(cls, ...)
-      if ret.opts and ret.opts.optional then
-        return ret:is_optional()
-      else
-        return ret
-      end
-    end
+    cls.__base.__unm = self.__unm
+    cls.__base.__tostring = self.__tostring
   end
   BaseType = _class_0
 end
@@ -274,8 +270,6 @@ do
     end
   })
   _base_0.__class = _class_0
-  local self = _class_0
-  self.transformer = true
   if _parent_0.__inherited then
     _parent_0.__inherited(_parent_0, _class_0)
   end
@@ -293,11 +287,7 @@ do
         local _list_0 = self.sequence
         for _index_0 = 1, #_list_0 do
           local i = _list_0[_index_0]
-          if type(i) == "table" and i._describe then
-            _accum_0[_len_0] = i:_describe()
-          else
-            _accum_0[_len_0] = describe_literal(i)
-          end
+          _accum_0[_len_0] = describe_type(i)
           _len_0 = _len_0 + 1
         end
         item_names = _accum_0
@@ -346,8 +336,6 @@ do
     end
   })
   _base_0.__class = _class_0
-  local self = _class_0
-  self.transformer = true
   if _parent_0.__inherited then
     _parent_0.__inherited(_parent_0, _class_0)
   end
@@ -365,11 +353,7 @@ do
         local _list_0 = self.options
         for _index_0 = 1, #_list_0 do
           local i = _list_0[_index_0]
-          if type(i) == "table" and i._describe then
-            _accum_0[_len_0] = i:_describe()
-          else
-            _accum_0[_len_0] = describe_literal(i)
-          end
+          _accum_0[_len_0] = describe_type(i)
           _len_0 = _len_0 + 1
         end
         item_names = _accum_0
@@ -421,8 +405,6 @@ do
     end
   })
   _base_0.__class = _class_0
-  local self = _class_0
-  self.transformer = true
   if _parent_0.__inherited then
     _parent_0.__inherited(_parent_0, _class_0)
   end
@@ -502,6 +484,66 @@ do
   end
   DescribeNode = _class_0
 end
+local AnnotateNode
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    format_error = function(self, value, err)
+      return tostring(tostring(value)) .. ": " .. tostring(err)
+    end,
+    _transform = function(self, value, state)
+      local new_value, state_or_err = self.base_type:_transform(value, state)
+      if new_value == FailedTransform then
+        return FailedTransform, self:format_error(value, state_or_err)
+      else
+        return new_value, state_or_err
+      end
+    end,
+    _describe = function(self)
+      if self.base_type._describe then
+        return self.base_type:_describe()
+      end
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, base_type, opts)
+      self.base_type = assert(coerce_literal(base_type))
+      if opts then
+        if opts.format_error then
+          self.format_error = assert(types.func:transform(opts.format_error))
+        end
+      end
+    end,
+    __base = _base_0,
+    __name = "AnnotateNode",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  AnnotateNode = _class_0
+end
 do
   local _class_0
   local _parent_0 = BaseType
@@ -549,13 +591,16 @@ do
     end,
     _describe = function(self)
       local base_description = self.base_type:_describe()
-      return tostring(base_description) .. " tagged " .. tostring(describe_literal(self.tag))
+      return tostring(base_description) .. " tagged " .. tostring(describe_type(self.tag_name))
     end
   }
   _base_0.__index = _base_0
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
     __init = function(self, base_type, opts)
+      if opts == nil then
+        opts = { }
+      end
       self.base_type = base_type
       self.tag_name = assert(opts.tag, "tagged type missing tag")
       self.tag_type = type(self.tag_name)
@@ -673,10 +718,9 @@ do
   _base_0.__index = _base_0
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
-    __init = function(self, base_type, opts)
-      self.base_type, self.opts = base_type, opts
-      _class_0.__parent.__init(self)
-      return assert(BaseType:is_base_type(base_type), "expected a type checker")
+    __init = function(self, base_type)
+      self.base_type = base_type
+      return assert(BaseType:is_base_type(self.base_type), "expected a type checker")
     end,
     __base = _base_0,
     __name = "OptionalType",
@@ -761,7 +805,7 @@ do
     _transform = function(self, value, state)
       local got = type(value)
       if self.t ~= got then
-        return FailedTransform, "expected type " .. tostring(describe_literal(self.t)) .. ", got " .. tostring(describe_literal(got))
+        return FailedTransform, "expected type " .. tostring(describe_type(self.t)) .. ", got " .. tostring(describe_type(got))
       end
       if self.length_type then
         local len = #value
@@ -780,12 +824,12 @@ do
       else
         l = types.range(left, right)
       end
-      return Type(self.t, self:clone_opts({
+      return Type(self.t, {
         length = l
-      }))
+      })
     end,
     _describe = function(self)
-      local t = "type " .. tostring(describe_literal(self.t))
+      local t = "type " .. tostring(describe_type(self.t))
       if self.length_type then
         t = t .. " length_type " .. tostring(self.length_type:_describe())
       end
@@ -796,11 +840,12 @@ do
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
     __init = function(self, t, opts)
-      self.t, self.opts = t, opts
-      if self.opts then
-        self.length_type = self.opts.length
+      self.t = t
+      if opts then
+        if opts.length then
+          self.length_type = assert(coerce_literal(opts.length))
+        end
       end
-      return _class_0.__parent.__init(self)
     end,
     __base = _base_0,
     __name = "Type",
@@ -847,7 +892,7 @@ do
           return FailedTransform, "non number field: " .. tostring(i)
         end
         if not (i == k) then
-          return FailedTransform, "non array index, got " .. tostring(describe_literal(i)) .. " but expected " .. tostring(describe_literal(k))
+          return FailedTransform, "non array index, got " .. tostring(describe_type(i)) .. " but expected " .. tostring(describe_type(k))
         end
         k = k + 1
       end
@@ -857,9 +902,8 @@ do
   _base_0.__index = _base_0
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
-    __init = function(self, opts)
-      self.opts = opts
-      return _class_0.__parent.__init(self)
+    __init = function(self, ...)
+      return _class_0.__parent.__init(self, ...)
     end,
     __base = _base_0,
     __name = "ArrayType",
@@ -904,7 +948,7 @@ do
           if type(i) == "table" and i._describe then
             _accum_0[_len_0] = i:_describe()
           else
-            _accum_0[_len_0] = describe_literal(i)
+            _accum_0[_len_0] = describe_type(i)
           end
           _len_0 = _len_0 + 1
         end
@@ -947,9 +991,8 @@ do
   _base_0.__index = _base_0
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
-    __init = function(self, options, opts)
-      self.options, self.opts = options, opts
-      _class_0.__parent.__init(self)
+    __init = function(self, options)
+      self.options = options
       assert(type(self.options) == "table", "expected table for options in one_of")
       local fast_opts = types.array_of(types.number + types.string)
       if fast_opts(self.options) then
@@ -1004,11 +1047,7 @@ do
         local _list_0 = self.types
         for _index_0 = 1, #_list_0 do
           local i = _list_0[_index_0]
-          if type(i) == "table" and i._describe then
-            _accum_0[_len_0] = i:_describe()
-          else
-            _accum_0[_len_0] = describe_literal(i)
-          end
+          _accum_0[_len_0] = describe_type(i)
           _len_0 = _len_0 + 1
         end
         item_names = _accum_0
@@ -1030,9 +1069,8 @@ do
   _base_0.__index = _base_0
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
-    __init = function(self, types, opts)
-      self.types, self.opts = types, opts
-      _class_0.__parent.__init(self)
+    __init = function(self, types)
+      self.types = types
       assert(type(self.types) == "table", "expected table for first argument")
       local _list_0 = self.types
       for _index_0 = 1, #_list_0 do
@@ -1073,7 +1111,7 @@ do
   local _parent_0 = BaseType
   local _base_0 = {
     _describe = function(self)
-      return "array of " .. tostring(describe_literal(self.expected))
+      return "array of " .. tostring(describe_type(self.expected))
     end,
     _transform = function(self, value, state)
       local pass, err = types.table(value)
@@ -1095,7 +1133,7 @@ do
         local transformed_item
         if is_literal then
           if self.expected ~= item then
-            return FailedTransform, "array item " .. tostring(idx) .. ": expected " .. tostring(describe_literal(self.expected))
+            return FailedTransform, "array item " .. tostring(idx) .. ": expected " .. tostring(describe_type(self.expected))
           else
             transformed_item = item
           end
@@ -1139,12 +1177,13 @@ do
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
     __init = function(self, expected, opts)
-      self.expected, self.opts = expected, opts
-      if self.opts then
-        self.keep_nils = self.opts.keep_nils
-        self.length_type = self.opts.length
+      self.expected = expected
+      if opts then
+        self.keep_nils = opts.keep_nils and true
+        if opts.length then
+          self.length_type = assert(coerce_literal(opts.length))
+        end
       end
-      return _class_0.__parent.__init(self)
     end,
     __base = _base_0,
     __name = "ArrayOf",
@@ -1175,11 +1214,130 @@ do
   end
   ArrayOf = _class_0
 end
+local ArrayContains
+do
+  local _class_0
+  local _parent_0 = BaseType
+  local _base_0 = {
+    short_circuit = true,
+    keep_nils = false,
+    _describe = function(self)
+      return "array containing " .. tostring(describe_type(self.contains))
+    end,
+    _transform = function(self, value, state)
+      local pass, err = types.table(value)
+      if not (pass) then
+        return FailedTransform, err
+      end
+      local is_literal = not BaseType:is_base_type(self.contains)
+      local contains = false
+      local copy, k
+      for idx, item in ipairs(value) do
+        local skip_item = false
+        local transformed_item
+        if is_literal then
+          if self.contains == item then
+            contains = true
+          end
+          transformed_item = item
+        else
+          local item_val, new_state = self.contains:_transform(item, state)
+          if item_val == FailedTransform then
+            transformed_item = item
+          else
+            state = new_state
+            contains = true
+            if item_val == nil and not self.keep_nils then
+              skip_item = true
+            else
+              transformed_item = item_val
+            end
+          end
+        end
+        if transformed_item ~= item or skip_item then
+          if not (copy) then
+            do
+              local _accum_0 = { }
+              local _len_0 = 1
+              local _max_0 = idx - 1
+              for _index_0 = 1, _max_0 < 0 and #value + _max_0 or _max_0 do
+                local i = value[_index_0]
+                _accum_0[_len_0] = i
+                _len_0 = _len_0 + 1
+              end
+              copy = _accum_0
+            end
+            k = idx
+          end
+        end
+        if copy and not skip_item then
+          copy[k] = transformed_item
+          k = k + 1
+        end
+        if contains and self.short_circuit then
+          if copy then
+            for kdx = idx + 1, #value do
+              copy[k] = value[kdx]
+              k = k + 1
+            end
+          end
+          break
+        end
+      end
+      if not (contains) then
+        return FailedTransform, "expected " .. tostring(self:_describe())
+      end
+      return copy or value, state
+    end
+  }
+  _base_0.__index = _base_0
+  setmetatable(_base_0, _parent_0.__base)
+  _class_0 = setmetatable({
+    __init = function(self, contains, opts)
+      self.contains = contains
+      assert(self.contains, "missing contains")
+      if opts then
+        self.short_circuit = opts.short_circuit and true
+        self.keep_nils = opts.keep_nils and true
+      end
+    end,
+    __base = _base_0,
+    __name = "ArrayContains",
+    __parent = _parent_0
+  }, {
+    __index = function(cls, name)
+      local val = rawget(_base_0, name)
+      if val == nil then
+        local parent = rawget(cls, "__parent")
+        if parent then
+          return parent[name]
+        end
+      else
+        return val
+      end
+    end,
+    __call = function(cls, ...)
+      local _self_0 = setmetatable({}, _base_0)
+      cls.__init(_self_0, ...)
+      return _self_0
+    end
+  })
+  _base_0.__class = _class_0
+  local self = _class_0
+  self.type_err_message = "expecting table"
+  if _parent_0.__inherited then
+    _parent_0.__inherited(_parent_0, _class_0)
+  end
+  ArrayContains = _class_0
+end
 local MapOf
 do
   local _class_0
   local _parent_0 = BaseType
   local _base_0 = {
+    _describe = function(self)
+      return "map of " .. tostring(self.expected_key:_describe()) .. " -> " .. tostring(self.expected_value:_describe())
+    end,
     _transform = function(self, value, state)
       local pass, err = types.table(value)
       if not (pass) then
@@ -1196,7 +1354,7 @@ do
           local new_v = v
           if key_literal then
             if k ~= self.expected_key then
-              return FailedTransform, "map key expected " .. tostring(describe_literal(self.expected_key))
+              return FailedTransform, "map key expected " .. tostring(describe_type(self.expected_key))
             end
           else
             new_k, state = self.expected_key:_transform(k, state)
@@ -1206,7 +1364,7 @@ do
           end
           if value_literal then
             if v ~= self.expected_value then
-              return FailedTransform, "map value expected " .. tostring(describe_literal(self.expected_value))
+              return FailedTransform, "map value expected " .. tostring(describe_type(self.expected_value))
             end
           else
             new_v, state = self.expected_value:_transform(v, state)
@@ -1234,9 +1392,9 @@ do
   _base_0.__index = _base_0
   setmetatable(_base_0, _parent_0.__base)
   _class_0 = setmetatable({
-    __init = function(self, expected_key, expected_value, opts)
-      self.expected_key, self.expected_value, self.opts = expected_key, expected_value, opts
-      return _class_0.__parent.__init(self)
+    __init = function(self, expected_key, expected_value)
+      self.expected_key = coerce_literal(expected_key)
+      self.expected_value = coerce_literal(expected_value)
     end,
     __base = _base_0,
     __name = "MapOf",
@@ -1270,10 +1428,13 @@ do
   local _class_0
   local _parent_0 = BaseType
   local _base_0 = {
+    open = false,
+    check_all = false,
     is_open = function(self)
*** OUTPUT TRUNCATED, 590 LINES SKIPPED ***


More information about the Commits mailing list