Mercurial > pub > dyncall > dyncall
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') |