comparison 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
comparison
equal deleted inserted replaced
518:a0ff5dff090b 519:99819b874bac
6 require"mk-cases" 6 require"mk-cases"
7 7
8 8
9 local max_numargs = 0 9 local max_numargs = 0
10 10
11 local aggrs = { } 11
12 local seen_aggrs = { }
13
14
15 function canon_type(t)
16 -- aggregate types start with special (closing) char
17 c = ({ ['}'] = 'struct ', ['>'] = 'union ' })[t:sub(1,1)]
18 if c ~= nil then
19 return c..'A'..t:sub(2)
20 end
21 return t
22 end
23 12
24 function put_sig_rtype_first(sig) 13 function put_sig_rtype_first(sig)
25 return sig:sub(sig:find(')')+1,-1)..sig:sub(1,sig:find(')')-1) 14 return sig:sub(sig:find(')')+1,-1)..sig:sub(1,sig:find(')')-1)
26 end 15 end
27 16
28 17
29 function mkcase(id,sig) 18 -- returns one case as str; accumulates unique idx => aggr-sig in aggrs
19 -- (sequentially) and aggr-sig => {body,name} in seen_aggrs (depth first for
20 -- nested aggrs, so sub-aggrs conveniently precede parents)
21 function mkcase(id, sig, aggrs, seen_aggrs)
30 local sig = trim(sig) 22 local sig = trim(sig)
31 local fsig = put_sig_rtype_first(sig) 23 local fsig = put_sig_rtype_first(sig)
32 local h = { "/* ",id,":",sig," */ " } 24 local h = { "/* ",id,":",sig," */ " }
33 local t = { "" } 25 local t = { "" }
34 local pos = -1 26 local pos = -1
35 local n_nest = 0 27 local n_nest = 0
36 local aggr = { } 28 local aggr = { }
37 local aggr_sig = { } 29 local aggr_sig = { }
38 aggr[0] = { } -- non-sequential [0] collects all non-aggr types 30 aggr[0] = { } -- non-sequential [0] collects all non-aggr types (not used, though)
39 aggr_sig[0] = '' 31 aggr_sig[0] = ''
40 for i = 1, #fsig do 32 for i = 1, #fsig do
41 local name = "a"..pos 33 local name = "a"..pos
42 local ch = fsig:sub(i,i) 34 local ch = fsig:sub(i,i)
43 35
53 45
54 -- array? Just append to name of member var from prev loop 46 -- array? Just append to name of member var from prev loop
55 if ch:match('[%[%]0123456789]') ~= nil then 47 if ch:match('[%[%]0123456789]') ~= nil then
56 aggr[n_nest][#aggr[n_nest]] = aggr[n_nest][#aggr[n_nest]]..ch 48 aggr[n_nest][#aggr[n_nest]] = aggr[n_nest][#aggr[n_nest]]..ch
57 else 49 else
58 50 -- register (sub)aggrs on closing char
59 if ch == '}' or ch == '>' then 51 if ch == '}' or ch == '>' then
60 -- register yet unseen aggregates, key is sig, val is body and name 52 -- only add unseen aggregates, key is aggr sig, val is body and name
61 if seen_aggrs[aggr_sig[n_nest]] == nil then 53 if seen_aggrs[aggr_sig[n_nest]] == nil then
62 aggrs[#aggrs+1] = aggr_sig[n_nest] 54 aggrs[#aggrs+1] = aggr_sig[n_nest]
63 ch = ch..#aggrs 55 if ch == '}' then ch = 'struct ' else ch = 'union ' end
56 ch = ch..'A'..#aggrs
64 seen_aggrs[aggr_sig[n_nest]] = { aggr[n_nest], ch } 57 seen_aggrs[aggr_sig[n_nest]] = { aggr[n_nest], ch }
65 end 58 end
66 ch = seen_aggrs[aggr_sig[n_nest]][2] 59 ch = seen_aggrs[aggr_sig[n_nest]][2]
67 60
68 n_nest = n_nest - 1 61 n_nest = n_nest - 1
69 aggr_sig[n_nest] = aggr_sig[n_nest]..aggr_sig[n_nest+1] 62 aggr_sig[n_nest] = aggr_sig[n_nest]..aggr_sig[n_nest+1]
70 end 63 end
71 64
65 -- add member type and var name to aggr
72 if ch ~= '{' and ch ~= '}' and ch ~= '<' and ch ~= '>' then 66 if ch ~= '{' and ch ~= '}' and ch ~= '<' and ch ~= '>' then
73 aggr[n_nest][#aggr[n_nest]+1] = canon_type(ch) 67 aggr[n_nest][#aggr[n_nest]+1] = ch
74 aggr[n_nest][#aggr[n_nest]+1] = 'm'..(#aggr[n_nest] >> 1) 68 aggr[n_nest][#aggr[n_nest]+1] = 'm'..(#aggr[n_nest] >> 1)
75 end 69 end
76 70
77 -- no nesting (= actual func args), generate case code 71 -- no nesting (= actual func args), generate case code
78 if n_nest == 0 then 72 if n_nest == 0 then
79 h[#h+1] = canon_type(ch) 73 h[#h+1] = ch
80 -- aggregate types have more than one 74 -- aggregate types have more than one char
81 if #h[#h] > 1 then 75 if #h[#h] > 1 then
82 if aggrcpsimple then 76 if aggrcpsimple then
83 t[#t+1] = '*('..h[#h]..'*)V_a['..pos.."]="..name..";" 77 t[#t+1] = '*('..h[#h]..'*)V_a['..pos.."]="..name..";"
84 else 78 else
85 t[#t+1] = 'f_cp'..h[#h]:sub(8)..'(V_a['..pos.."],&"..name..");" 79 t[#t+1] = 'f_cp'..h[#h]:match('A.*')..'(V_a['..pos.."],&"..name..");"
86 end 80 end
87 if aggrmutabletest then 81 if aggrmutabletest then
88 t[#t] = t[#t]..'memset(&'..name..',0,sizeof('..name..'));' 82 t[#t] = t[#t]..'memset(&'..name..',0,sizeof('..name..'));'
89 end 83 end
90 else 84 else
113 t[#t+1] = "ret_a("..pos..","..h[6]..")}\n" 107 t[#t+1] = "ret_a("..pos..","..h[6]..")}\n"
114 end 108 end
115 return table.concat(h,"")..table.concat(t,"") 109 return table.concat(h,"")..table.concat(t,"")
116 end 110 end
117 111
118 function split_array_decl(s) 112
119 local name = s 113 function mkaggrdefs(aggrs, seen_aggrs)
120 local n = nil -- not an array 114 local agg_defs = { }
121 local array_i = s:find('%[') 115 local agg_sizes = { }
122 if array_i ~= nil then 116 local agg_sigs = { }
123 name = name:sub(1, array_i-1) 117 local agg_names = { }
124 n = tonumber(s:sub(array_i):match('[0123456789]+')) 118
125 end 119 for a = 1, #aggrs do
126 return { name, n } 120 local k = aggrs[a]
127 end 121 local v = seen_aggrs[k]
122 local am = v[1] -- aggregate members
123 local at = v[2] -- aggregate type
124 local an = at:match('A.*') -- aggregate name (w/o struct or union)
125
126 -- aggregate def
127 aggr_def = '/* '..k..' */\n'
128 if aggrpacking ~= 0 then
129 local pack = aggrpacking
130 if pack < 0 then
131 pack = math.floor(math.pow(2,math.floor(math.log(math.random(math.abs(pack)),2))))
132 end
133 aggr_def = aggr_def..'#pragma pack(push,'..pack..')\n'
134 end
135
136 aggr_def = aggr_def..at..' { '
137 for i = 1, #am, 2 do
138 aggr_def = aggr_def..am[i]..' '..am[i+1]..'; '
139 end
140 aggr_def = aggr_def..'};\n'
141
142 if aggrpacking ~= 0 then
143 aggr_def = aggr_def..'#pragma pack(pop)\n'
144 end
145
146 -- aggregate cp and cmp funcs
147 s = {
148 'void f_cp'..an..'('..at..' *x, const '..at..' *y) { ',
149 'int f_cmp'..an..'(const '..at..' *x, const '..at..' *y) { return '
150 }
151 o = { '=', '==', 'f_cp', 'f_cmp', '; ', ' && ', '', '1' }
152 for t = 1, 2 do
153 if t ~= 1 or aggrcpsimple == false then
154 aggr_def = aggr_def..s[t]
155 local b = {}
156 for i = 1, #am, 2 do
157 local mn, mc = split_array_decl(am[i+1]) -- aggr member name and (array) count
158 local fmt = ''
159 if mc ~= nil then -- need array suffixes?
160 fmt = '[%d]'
161 else
162 mc = 1
163 end
164
165 for j = 1, mc do
166 name = mn..fmt:format(j-1)
167 amn = am[i]:match('A.*')
168 if amn then -- is aggr?
169 b[#b+1] = o[t+2]..amn..'(&x->'..name..', &y->'..name..')'
170 else
171 b[#b+1] = 'x->'..name..' '..o[t]..' y->'..name
172 end
173 end
174 end
175 if #b == 0 then -- to handle empty aggregates
176 b[1] = o[t+6]
177 end
178 aggr_def = aggr_def..table.concat(b,o[t+4])..'; };\n'
179 end
180 end
181
182 -- write convenient dcNewAggr() helper/wrapper funcs
183 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'
184 for i = 1, #am, 2 do
185 local mn, mc = split_array_decl(am[i+1])
186 if mc == nil then
187 mc = 1
188 end
189 amn = am[i]:match('A.*')
190 if amn then -- is aggr?
191 --aggr_def = aggr_def..'dcAggrField(at, DC_SIGCHAR_AGGREGATE, offsetof('..at..', '..mn..'), '..mc..', f_touchdcst'..amn..'());\n\t\t'
192 aggr_def = aggr_def.."AFa("..at..','..mn..','..mc..','..amn..')\n\t\t'
193 else
194 --aggr_def = aggr_def.."dcAggrField(at, '"..am[i].."', offsetof("..at..', '..mn..'), '..mc..');\n\t\t'
195 aggr_def = aggr_def.."AF('"..am[i].."',"..at..','..mn..','..mc..')\n\t\t'
196 end
197 end
198
199 agg_defs [#agg_defs + 1] = aggr_def..'dcCloseAggr(a);\n\t}\n\treturn a;\n};'
200 agg_sizes[#agg_sizes + 1] = 'sizeof('..at..')'
201 agg_sigs [#agg_sigs + 1] = k
202 agg_names[#agg_names + 1] = an
203 end
204
205 return agg_defs, agg_sizes, agg_sigs, agg_names
206 end
207
128 208
129 function mkall() 209 function mkall()
130 local lineno = 0 210 local lineno = 0
131 local sigtab = { } 211 local sigtab = { }
132 local cases = '' 212 local cases = ''
213 local aggrs = { }
214 local seen_aggrs = { }
215
133 216
134 for line in io.lines() do 217 for line in io.lines() do
135 local sig = trim(line) 218 local sig = trim(line)
136 cases = cases..mkcase(lineno,sig) 219 cases = cases..mkcase(lineno, sig, aggrs, seen_aggrs)
137 sigtab[#sigtab+1] = sig 220 sigtab[#sigtab+1] = sig
138 lineno = lineno + 1 221 lineno = lineno + 1
139 end 222 end
140 223
141 agg_sizes = {} 224 local agg_defs, agg_sizes, agg_sigs, agg_names = mkaggrdefs(aggrs, seen_aggrs)
142 agg_sigs = {}
143 agg_names = {}
144 for a = 1, #aggrs do
145 local k = aggrs[a]
146 local v = seen_aggrs[k]
147 local at = canon_type(v[2]) -- aggregate type
148 local am = v[1] -- aggregate members
149
150 agg_sizes[#agg_sizes + 1] = 'sizeof('..at..')'
151 agg_sigs [#agg_sigs + 1] = k
152 agg_names[#agg_names + 1] = at:sub(8)
153
154 -- aggregate def
155 io.write('/* '..k..' */\n')
156 if aggrpacking ~= 0 then
157 local pack = aggrpacking
158 if pack < 0 then
159 pack = math.floor(math.pow(2,math.floor(math.log(math.random(math.abs(pack)),2))))
160 end
161 io.write('#pragma pack(push,'..pack..')\n')
162 end
163
164 io.write(at..' { ')
165 for i = 1, #am, 2 do
166 io.write(am[i]..' '..am[i+1]..'; ')
167 end
168 io.write("};\n")
169
170 if aggrpacking ~= 0 then
171 io.write('#pragma pack(pop)\n')
172 end
173
174 -- aggregate cp and cmp funcs
175 s = {
176 'void f_cp'..at:sub(8)..'('..at..' *x, const '..at..' *y) { ',
177 'int f_cmp'..at:sub(8)..'(const '..at..' *x, const '..at..' *y) { return '
178 }
179 o = { '=', '==', 'f_cp', 'f_cmp', '; ', ' && ', '', '1' }
180 for t = 1, 2 do
181 if t ~= 1 or aggrcpsimple == false then
182 io.write(s[t])
183 local b = {}
184 for i = 1, #am, 2 do
185 local m = split_array_decl(am[i+1])
186 local fmt = ''
187 if m[2] ~= nil then -- need array suffixes?
188 fmt = '[%d]'
189 else
190 m[2] = 1
191 end
192
193 for j = 1, m[2] do
194 name = m[1]..string.format(fmt, j-1)
195 if string.match(am[i], ' ') then -- aggregate canonical types contain at least one space
196 b[#b+1] = o[t+2]..am[i]:sub(8)..'(&x->'..name..', &y->'..name..')'
197 else
198 b[#b+1] = 'x->'..name..' '..o[t]..' y->'..name
199 end
200 end
201 end
202 if #b == 0 then -- to handle empty aggregates
203 b[1] = o[t+6]
204 end
205 io.write(table.concat(b,o[t+4]).."; };\n")
206 end
207 end
208
209 -- convenient dcnewstruct helper funcs
210 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')
211 for i = 1, #am, 2 do
212 local m = split_array_decl(am[i+1])
213 if m[2] == nil then -- need array suffixes?
214 m[2] = 1
215 end
216 if string.match(am[i], ' ') then -- aggregate canonical types contain at least one space
217 --io.write('dcAggrField(at, DC_SIGCHAR_AGGREGATE, offsetof('..at..', '..m[1]..'), '..m[2]..', f_touchdcst'..am[i]:sub(8)..'());\n\t\t')
218 io.write("AFa("..at..','..m[1]..','..m[2]..','..am[i]:sub(8)..')\n\t\t')
219 else
220 --io.write("dcAggrField(at, '"..am[i].."', offsetof("..at..', '..m[1]..'), '..m[2]..');\n\t\t')
221 io.write("AF('"..am[i].."',"..at..','..m[1]..','..m[2]..')\n\t\t')
222 end
223 end
224 io.write("dcCloseAggr(at);\n\t}\n\treturn at;\n};\n")
225 end
226 225
227 -- make table.concat work 226 -- make table.concat work
228 if #agg_names > 0 then 227 if #agg_names > 0 then
229 table.insert(agg_names, 1, '') 228 table.insert(agg_names, 1, '')
230 end 229 end
231 230
231 io.write(table.concat(agg_defs,'\n')..'\n')
232 io.write(cases) 232 io.write(cases)
233 io.write(mkfuntab(lineno, 'f', 'funptr', 'G_funtab', true)) 233 io.write(mkfuntab(lineno, 'f', 'funptr', 'G_funtab', true))
234 io.write(mksigtab(sigtab, '', 'G_sigtab')) 234 io.write(mksigtab(sigtab, '', 'G_sigtab'))
235 io.write('const char* G_agg_sigs[] = {\n\t"'..table.concat(agg_sigs, '",\n\t"')..'"\n};\n') 235 io.write('const char* G_agg_sigs[] = {\n\t"'..table.concat(agg_sigs, '",\n\t"')..'"\n};\n')
236 io.write('int G_agg_sizes[] = {\n\t'..table.concat(agg_sizes, ',\n\t')..'\n};\n') 236 io.write('int G_agg_sizes[] = {\n\t'..table.concat(agg_sizes, ',\n\t')..'\n};\n')