diff test/call_suite_aggrs/mk-cases.lua @ 519:99819b874bac

test/call_suite_aggrs: - refactored generator code a bit to be simpler, write cleaner output, have better shareability and clarity - added rtypes w/ default value nil to config.lua, to self document - shared some code under test/common/ - fixed nonemptyaggrs sigs and cases.h (accidentally overwritten with cases having empty aggrs)
author Tassilo Philipp
date Mon, 11 Apr 2022 22:26:07 +0200
parents 01f928eb9584
children a2de1d0a73f3
line wrap: on
line diff
--- a/test/call_suite_aggrs/mk-cases.lua	Mon Apr 11 15:06:44 2022 +0200
+++ b/test/call_suite_aggrs/mk-cases.lua	Mon Apr 11 22:26:07 2022 +0200
@@ -8,25 +8,17 @@
 
 local max_numargs = 0
 
-local aggrs = { }
-local seen_aggrs = { }
 
 
-function canon_type(t)
-  -- aggregate types start with special (closing) char
-  c = ({ ['}'] = 'struct ', ['>'] = 'union  ' })[t:sub(1,1)]
-  if c ~= nil then
-    return c..'A'..t:sub(2)
-  end
-  return t
-end
-
 function put_sig_rtype_first(sig)
   return sig:sub(sig:find(')')+1,-1)..sig:sub(1,sig:find(')')-1)
 end
 
 
-function mkcase(id,sig)
+-- returns one case as str; accumulates unique idx => aggr-sig in aggrs
+-- (sequentially) and aggr-sig => {body,name} in seen_aggrs (depth first for
+-- nested aggrs, so sub-aggrs conveniently precede parents)
+function mkcase(id, sig, aggrs, seen_aggrs)
   local sig = trim(sig)
   local fsig = put_sig_rtype_first(sig)
   local h = { "/* ",id,":",sig," */ " }
@@ -35,7 +27,7 @@
   local n_nest = 0
   local aggr = { }
   local aggr_sig = { }
-  aggr[0] = { }     -- non-sequential [0] collects all non-aggr types
+  aggr[0] = { }     -- non-sequential [0] collects all non-aggr types (not used, though)
   aggr_sig[0] = ''
   for i = 1, #fsig do
     local name = "a"..pos
@@ -55,12 +47,13 @@
     if ch:match('[%[%]0123456789]') ~= nil then
       aggr[n_nest][#aggr[n_nest]] = aggr[n_nest][#aggr[n_nest]]..ch
     else
-
+      -- register (sub)aggrs on closing char
       if ch == '}' or ch == '>' then
-        -- register yet unseen aggregates, key is sig, val is body and name
+        -- only add unseen aggregates, key is aggr sig, val is body and name
         if seen_aggrs[aggr_sig[n_nest]] == nil then
           aggrs[#aggrs+1] = aggr_sig[n_nest]
-          ch = ch..#aggrs
+          if ch == '}' then ch = 'struct ' else ch = 'union ' end
+		  ch = ch..'A'..#aggrs
           seen_aggrs[aggr_sig[n_nest]] = { aggr[n_nest], ch }
         end
         ch = seen_aggrs[aggr_sig[n_nest]][2]
@@ -69,20 +62,21 @@
         aggr_sig[n_nest] = aggr_sig[n_nest]..aggr_sig[n_nest+1]
       end
 
+      -- add member type and var name to aggr
       if ch ~= '{' and ch ~= '}' and ch ~= '<' and ch ~= '>' then
-        aggr[n_nest][#aggr[n_nest]+1] = canon_type(ch)
+        aggr[n_nest][#aggr[n_nest]+1] = ch
         aggr[n_nest][#aggr[n_nest]+1] = 'm'..(#aggr[n_nest] >> 1)
       end
 
       -- no nesting (= actual func args), generate case code
       if n_nest == 0 then
-        h[#h+1] = canon_type(ch)
-        -- aggregate types have more than one
+        h[#h+1] = ch
+        -- aggregate types have more than one char
         if #h[#h] > 1 then
           if aggrcpsimple then
             t[#t+1] = '*('..h[#h]..'*)V_a['..pos.."]="..name..";"
           else
-            t[#t+1] = 'f_cp'..h[#h]:sub(8)..'(V_a['..pos.."],&"..name..");"
+            t[#t+1] = 'f_cp'..h[#h]:match('A.*')..'(V_a['..pos.."],&"..name..");"
           end
           if aggrmutabletest then
             t[#t] = t[#t]..'memset(&'..name..',0,sizeof('..name..'));'
@@ -115,85 +109,64 @@
   return table.concat(h,"")..table.concat(t,"")
 end
 
-function split_array_decl(s)
-  local name = s
-  local n = nil  -- not an array
-  local array_i = s:find('%[')
-  if array_i ~= nil then
-    name = name:sub(1, array_i-1)
-    n = tonumber(s:sub(array_i):match('[0123456789]+'))
-  end
-  return { name, n }
-end
 
-function mkall()
-  local lineno = 0
-  local sigtab = { }
-  local cases = ''
+function mkaggrdefs(aggrs, seen_aggrs)
+  local agg_defs  = { }
+  local agg_sizes = { }
+  local agg_sigs  = { }
+  local agg_names = { }
 
-  for line in io.lines() do
-    local sig = trim(line)
-    cases = cases..mkcase(lineno,sig)
-    sigtab[#sigtab+1] = sig
-    lineno = lineno + 1
-  end
-
-  agg_sizes = {}
-  agg_sigs  = {}
-  agg_names = {}
   for a = 1, #aggrs do
     local k = aggrs[a]
     local v = seen_aggrs[k]
-    local at = canon_type(v[2])  -- aggregate type
-    local am = v[1]              -- aggregate members
-
-    agg_sizes[#agg_sizes + 1] = 'sizeof('..at..')'
-    agg_sigs [#agg_sigs  + 1] = k
-    agg_names[#agg_names + 1] = at:sub(8)
+    local am = v[1]            -- aggregate members
+    local at = v[2]            -- aggregate type
+    local an = at:match('A.*') -- aggregate name (w/o struct or union)
 
     -- aggregate def
-    io.write('/* '..k..' */\n')
+    aggr_def = '/* '..k..' */\n'
     if aggrpacking ~= 0 then
       local pack = aggrpacking
       if pack < 0 then
         pack = math.floor(math.pow(2,math.floor(math.log(math.random(math.abs(pack)),2))))
       end
-      io.write('#pragma pack(push,'..pack..')\n')
+      aggr_def = aggr_def..'#pragma pack(push,'..pack..')\n'
     end
 
-    io.write(at..' { ')
+    aggr_def = aggr_def..at..' { '
     for i = 1, #am, 2 do
-      io.write(am[i]..' '..am[i+1]..'; ')
+      aggr_def = aggr_def..am[i]..' '..am[i+1]..'; '
     end
-    io.write("};\n")
+    aggr_def = aggr_def..'};\n'
 
     if aggrpacking ~= 0 then
-      io.write('#pragma pack(pop)\n')
+      aggr_def = aggr_def..'#pragma pack(pop)\n'
     end
 
     -- aggregate cp and cmp funcs
     s = {
-      'void f_cp'..at:sub(8)..'('..at..' *x, const '..at..' *y) { ',
-      'int f_cmp'..at:sub(8)..'(const '..at..' *x, const '..at..' *y) { return '
+      'void f_cp'..an..'('..at..' *x, const '..at..' *y) { ',
+      'int f_cmp'..an..'(const '..at..' *x, const '..at..' *y) { return '
     }
     o = { '=', '==', 'f_cp', 'f_cmp', '; ', ' && ', '', '1' }
     for t = 1, 2 do
       if t ~= 1 or aggrcpsimple == false then
-        io.write(s[t])
+        aggr_def = aggr_def..s[t]
         local b = {}
         for i = 1, #am, 2 do
-          local m = split_array_decl(am[i+1])
+          local mn, mc = split_array_decl(am[i+1]) -- aggr member name and (array) count
           local fmt = ''
-          if m[2] ~= nil then -- need array suffixes?
+          if mc ~= nil then -- need array suffixes?
             fmt = '[%d]'
           else
-            m[2] = 1
+            mc = 1
           end
        
-          for j = 1, m[2] do
-            name = m[1]..string.format(fmt, j-1)
-            if string.match(am[i], ' ') then -- aggregate canonical types contain at least one space
-              b[#b+1] = o[t+2]..am[i]:sub(8)..'(&x->'..name..', &y->'..name..')'
+          for j = 1, mc do
+            name = mn..fmt:format(j-1)
+			amn = am[i]:match('A.*')
+            if amn then -- is aggr?
+              b[#b+1] = o[t+2]..amn..'(&x->'..name..', &y->'..name..')'
             else
               b[#b+1] = 'x->'..name..' '..o[t]..' y->'..name
             end
@@ -202,33 +175,60 @@
         if #b == 0 then  -- to handle empty aggregates
           b[1] = o[t+6]
         end
-        io.write(table.concat(b,o[t+4]).."; };\n")
+        aggr_def = aggr_def..table.concat(b,o[t+4])..'; };\n'
+      end
+    end
+
+    -- write convenient dcNewAggr() helper/wrapper funcs
+    aggr_def = aggr_def..'DCaggr* f_touchdcst'..an..'() {\n\tstatic DCaggr* a = NULL;\n\tif(!a) {\n\t\ta = dcNewAggr('..(#am>>1)..', sizeof('..at..'));\n\t\t'
+    for i = 1, #am, 2 do
+      local mn, mc = split_array_decl(am[i+1])
+      if mc == nil then
+        mc = 1
+      end
+      amn = am[i]:match('A.*')
+      if amn then -- is aggr?
+        --aggr_def = aggr_def..'dcAggrField(at, DC_SIGCHAR_AGGREGATE, offsetof('..at..', '..mn..'), '..mc..', f_touchdcst'..amn..'());\n\t\t'
+        aggr_def = aggr_def.."AFa("..at..','..mn..','..mc..','..amn..')\n\t\t'
+      else
+        --aggr_def = aggr_def.."dcAggrField(at, '"..am[i].."', offsetof("..at..', '..mn..'), '..mc..');\n\t\t'
+        aggr_def = aggr_def.."AF('"..am[i].."',"..at..','..mn..','..mc..')\n\t\t'
       end
     end
 
-    -- convenient dcnewstruct helper funcs
-    io.write('DCaggr* f_touchdcst'..at:sub(8)..'() {\n\tstatic DCaggr* at = NULL;\n\tif(!at) {\n\t\tat = dcNewAggr('..(#am>>1)..', sizeof('..at..'));\n\t\t')
-    for i = 1, #am, 2 do
-      local m = split_array_decl(am[i+1])
-      if m[2] == nil then -- need array suffixes?
-        m[2] = 1
-      end
-      if string.match(am[i], ' ') then -- aggregate canonical types contain at least one space
-        --io.write('dcAggrField(at, DC_SIGCHAR_AGGREGATE, offsetof('..at..', '..m[1]..'), '..m[2]..', f_touchdcst'..am[i]:sub(8)..'());\n\t\t')
-        io.write("AFa("..at..','..m[1]..','..m[2]..','..am[i]:sub(8)..')\n\t\t')
-      else
-        --io.write("dcAggrField(at, '"..am[i].."', offsetof("..at..', '..m[1]..'), '..m[2]..');\n\t\t')
-        io.write("AF('"..am[i].."',"..at..','..m[1]..','..m[2]..')\n\t\t')
-      end
-    end
-    io.write("dcCloseAggr(at);\n\t}\n\treturn at;\n};\n")
+    agg_defs [#agg_defs  + 1] = aggr_def..'dcCloseAggr(a);\n\t}\n\treturn a;\n};'
+    agg_sizes[#agg_sizes + 1] = 'sizeof('..at..')'
+    agg_sigs [#agg_sigs  + 1] = k
+    agg_names[#agg_names + 1] = an
   end
 
+  return agg_defs, agg_sizes, agg_sigs, agg_names
+end
+
+
+function mkall()
+  local lineno = 0
+  local sigtab = { }
+  local cases = ''
+  local aggrs = { }
+  local seen_aggrs = { }
+
+
+  for line in io.lines() do
+    local sig = trim(line)
+    cases = cases..mkcase(lineno, sig, aggrs, seen_aggrs)
+    sigtab[#sigtab+1] = sig
+    lineno = lineno + 1
+  end
+
+  local agg_defs, agg_sizes, agg_sigs, agg_names = mkaggrdefs(aggrs, seen_aggrs)
+
   -- make table.concat work
   if #agg_names > 0 then
     table.insert(agg_names, 1, '')
   end
 
+  io.write(table.concat(agg_defs,'\n')..'\n')
   io.write(cases)
   io.write(mkfuntab(lineno, 'f', 'funptr', 'G_funtab', true))
   io.write(mksigtab(sigtab, '', 'G_sigtab'))