1 #ifndef XVFUNCS_H
2 #define XVFUNCS_H
3 
4 // ================================================================
5 // Functions on extended values, namely, scalars and maps.
6 //
7 // NOTE ON EPHEMERALITY OF MAPS:
8 //
9 // Most functions here free their inputs. E.g. for string concatenation, the
10 // output which is returned is the concatenation of the two inputs which are
11 // freed. This is true for functions on scalars as well as functions on maps
12 // (the latter in this header file).
13 //
14 // However, maps are treated differently from scalars in that some maps are
15 // referenced, rather than copied, within the concrete syntax tree.  E.g. in
16 // 'mapsum({3:4},@v)', the map literal {3:4} is ephemeral to the expression and
17 // must be freed during evaluation, but the @v part is referenced to the @v data
18 // structure and is only copied on write.  The boxed_xval_t's is_ephemeral flag
19 // tracks the difference between the two cases.
20 // ================================================================
21 
22 #include "../lib/mlrutil.h"
23 #include "../containers/mlhmmv.h"
24 #include "../containers/boxed_xval.h"
25 
26 // ----------------------------------------------------------------
27 typedef boxed_xval_t xv_variadic_func_t(
28 	boxed_xval_t* pbxvals,
29 	int           nxvals);
30 
31 typedef boxed_xval_t xv_zary_func_t();
32 
33 typedef boxed_xval_t xv_unary_func_t(
34 	boxed_xval_t* pbxval1);
35 
36 typedef boxed_xval_t xv_binary_func_t(
37 	boxed_xval_t* pbxval1,
38 	boxed_xval_t* pbxval2);
39 
40 typedef boxed_xval_t xv_ternary_func_t(
41 	boxed_xval_t* pbxval1,
42 	boxed_xval_t* pbxval2,
43 	boxed_xval_t* pbxval3);
44 
45 // ----------------------------------------------------------------
46 // Most functions here free their inputs. E.g. for string concatenation, the
47 // output which is returned is the concatenation of the two inputs which are
48 // freed. For another example, is_string frees its input and returns the boolean
49 // value of the result. These functions, by contrast, only return a boolean for
50 // the outcome of the test but do not free the inputs. The intended usage is for
51 // type-assertion checks.  E.g. in '$b = asserting_string($a)', if $a is a
52 // string it is assigned to $b, else an error is thrown.
53 
b_x_is_present_no_free_xfunc(boxed_xval_t * pbxval1)54 static inline boxed_xval_t b_x_is_present_no_free_xfunc(boxed_xval_t* pbxval1) {
55 	return box_ephemeral_val(
56 		mv_from_bool(
57 			!pbxval1->xval.is_terminal || mv_is_present(&pbxval1->xval.terminal_mlrval)
58 		)
59 	);
60 }
61 
b_x_is_absent_no_free_xfunc(boxed_xval_t * pbxval1)62 static inline boxed_xval_t b_x_is_absent_no_free_xfunc(boxed_xval_t* pbxval1) {
63 	return box_ephemeral_val(
64 		mv_from_bool(
65 			pbxval1->xval.is_terminal && mv_is_absent(&pbxval1->xval.terminal_mlrval)
66 		)
67 	);
68 }
69 
b_x_is_map_no_free_xfunc(boxed_xval_t * pbxval1)70 static inline boxed_xval_t b_x_is_map_no_free_xfunc(boxed_xval_t* pbxval1) {
71 	return box_ephemeral_val(
72 		mv_from_bool(
73 			!pbxval1->xval.is_terminal
74 		)
75 	);
76 }
77 
b_x_is_not_map_no_free_xfunc(boxed_xval_t * pbxval1)78 static inline boxed_xval_t b_x_is_not_map_no_free_xfunc(boxed_xval_t* pbxval1) {
79 	return box_ephemeral_val(
80 		mv_from_bool(
81 			pbxval1->xval.is_terminal
82 		)
83 	);
84 }
85 
b_x_is_numeric_no_free_xfunc(boxed_xval_t * pbxval1)86 static inline boxed_xval_t b_x_is_numeric_no_free_xfunc(boxed_xval_t* pbxval1) {
87 	return box_ephemeral_val(
88 		mv_from_bool(
89 			pbxval1->xval.is_terminal && mv_is_numeric(&pbxval1->xval.terminal_mlrval)
90 		)
91 	);
92 }
93 
b_x_is_int_no_free_xfunc(boxed_xval_t * pbxval1)94 static inline boxed_xval_t b_x_is_int_no_free_xfunc(boxed_xval_t* pbxval1) {
95 	return box_ephemeral_val(
96 		mv_from_bool(
97 			pbxval1->xval.is_terminal && mv_is_int(&pbxval1->xval.terminal_mlrval)
98 		)
99 	);
100 }
101 
b_x_is_float_no_free_xfunc(boxed_xval_t * pbxval1)102 static inline boxed_xval_t b_x_is_float_no_free_xfunc(boxed_xval_t* pbxval1) {
103 	return box_ephemeral_val(
104 		mv_from_bool(
105 			pbxval1->xval.is_terminal && mv_is_float(&pbxval1->xval.terminal_mlrval)
106 		)
107 	);
108 }
109 
b_x_is_boolean_no_free_xfunc(boxed_xval_t * pbxval1)110 static inline boxed_xval_t b_x_is_boolean_no_free_xfunc(boxed_xval_t* pbxval1) {
111 	return box_ephemeral_val(
112 		mv_from_bool(
113 			pbxval1->xval.is_terminal && mv_is_boolean(&pbxval1->xval.terminal_mlrval)
114 		)
115 	);
116 }
117 
b_x_is_string_no_free_xfunc(boxed_xval_t * pbxval1)118 static inline boxed_xval_t b_x_is_string_no_free_xfunc(boxed_xval_t* pbxval1) {
119 	return box_ephemeral_val(
120 		mv_from_bool(
121 			pbxval1->xval.is_terminal && mv_is_string(&pbxval1->xval.terminal_mlrval)
122 		)
123 	);
124 }
125 
b_x_is_null_no_free_xfunc(boxed_xval_t * pbxval1)126 static inline boxed_xval_t b_x_is_null_no_free_xfunc(boxed_xval_t* pbxval1) {
127 	return box_ephemeral_val(
128 		mv_from_bool(
129 			pbxval1->xval.is_terminal && mv_is_null(&pbxval1->xval.terminal_mlrval)
130 		)
131 	);
132 }
133 
b_x_is_not_null_no_free_xfunc(boxed_xval_t * pbxval1)134 static inline boxed_xval_t b_x_is_not_null_no_free_xfunc(boxed_xval_t* pbxval1) {
135 	return box_ephemeral_val(
136 		mv_from_bool(
137 			!(pbxval1->xval.is_terminal && mv_is_null(&pbxval1->xval.terminal_mlrval))
138 		)
139 	);
140 }
141 
b_x_is_empty_no_free_xfunc(boxed_xval_t * pbxval1)142 static inline boxed_xval_t b_x_is_empty_no_free_xfunc(boxed_xval_t* pbxval1) {
143 	return box_ephemeral_val(
144 		mv_from_bool(
145 			pbxval1->xval.is_terminal && mv_is_empty(&pbxval1->xval.terminal_mlrval)
146 		)
147 	);
148 }
149 
b_x_is_not_empty_no_free_xfunc(boxed_xval_t * pbxval1)150 static inline boxed_xval_t b_x_is_not_empty_no_free_xfunc(boxed_xval_t* pbxval1) {
151 	return box_ephemeral_val(
152 		mv_from_bool(
153 			!(pbxval1->xval.is_terminal && mv_is_empty(&pbxval1->xval.terminal_mlrval))
154 		)
155 	);
156 }
157 
b_x_is_empty_map_no_free_xfunc(boxed_xval_t * pbxval1)158 static inline boxed_xval_t b_x_is_empty_map_no_free_xfunc(boxed_xval_t* pbxval1) {
159 	return box_ephemeral_val(
160 		mv_from_bool(
161 			!pbxval1->xval.is_terminal && pbxval1->xval.pnext_level->num_occupied == 0
162 		)
163 	);
164 }
165 
b_x_is_nonempty_map_no_free_xfunc(boxed_xval_t * pbxval1)166 static inline boxed_xval_t b_x_is_nonempty_map_no_free_xfunc(boxed_xval_t* pbxval1) {
167 	return box_ephemeral_val(
168 		mv_from_bool(
169 			!pbxval1->xval.is_terminal && pbxval1->xval.pnext_level->num_occupied != 0
170 		)
171 	);
172 }
173 
s_x_typeof_no_free_xfunc(boxed_xval_t * pbxval1)174 static inline boxed_xval_t s_x_typeof_no_free_xfunc(boxed_xval_t* pbxval1) {
175 	return box_ephemeral_val(
176 	    mv_from_string(
177 			mlhmmv_xvalue_describe_type_simple(&pbxval1->xval), NO_FREE
178 		)
179 	);
180 }
181 
182 // ----------------------------------------------------------------
b_x_is_present_xfunc(boxed_xval_t * pbxval1)183 static inline boxed_xval_t b_x_is_present_xfunc(boxed_xval_t* pbxval1) {
184 	boxed_xval_t rv = b_x_is_present_no_free_xfunc(pbxval1);
185 	if (pbxval1->is_ephemeral)
186 	  mlhmmv_xvalue_free(&pbxval1->xval);
187 	return rv;
188 }
189 
b_x_is_absent_xfunc(boxed_xval_t * pbxval1)190 static inline boxed_xval_t b_x_is_absent_xfunc(boxed_xval_t* pbxval1) {
191 	boxed_xval_t rv = b_x_is_absent_no_free_xfunc(pbxval1);
192 	if (pbxval1->is_ephemeral)
193 	  mlhmmv_xvalue_free(&pbxval1->xval);
194 	return rv;
195 }
196 
b_x_is_map_xfunc(boxed_xval_t * pbxval1)197 static inline boxed_xval_t b_x_is_map_xfunc(boxed_xval_t* pbxval1) {
198 	boxed_xval_t rv = b_x_is_map_no_free_xfunc(pbxval1);
199 	if (pbxval1->is_ephemeral)
200 	  mlhmmv_xvalue_free(&pbxval1->xval);
201 	return rv;
202 }
203 
b_x_is_not_map_xfunc(boxed_xval_t * pbxval1)204 static inline boxed_xval_t b_x_is_not_map_xfunc(boxed_xval_t* pbxval1) {
205 	boxed_xval_t rv = b_x_is_not_map_no_free_xfunc(pbxval1);
206 	if (pbxval1->is_ephemeral)
207 	  mlhmmv_xvalue_free(&pbxval1->xval);
208 	return rv;
209 }
210 
b_x_is_numeric_xfunc(boxed_xval_t * pbxval1)211 static inline boxed_xval_t b_x_is_numeric_xfunc(boxed_xval_t* pbxval1) {
212 	boxed_xval_t rv = b_x_is_numeric_no_free_xfunc(pbxval1);
213 	if (pbxval1->is_ephemeral)
214 	  mlhmmv_xvalue_free(&pbxval1->xval);
215 	return rv;
216 }
217 
b_x_is_int_xfunc(boxed_xval_t * pbxval1)218 static inline boxed_xval_t b_x_is_int_xfunc(boxed_xval_t* pbxval1) {
219 	boxed_xval_t rv = b_x_is_int_no_free_xfunc(pbxval1);
220 	if (pbxval1->is_ephemeral)
221 	  mlhmmv_xvalue_free(&pbxval1->xval);
222 	return rv;
223 }
224 
b_x_is_float_xfunc(boxed_xval_t * pbxval1)225 static inline boxed_xval_t b_x_is_float_xfunc(boxed_xval_t* pbxval1) {
226 	boxed_xval_t rv = b_x_is_float_no_free_xfunc(pbxval1);
227 	if (pbxval1->is_ephemeral)
228 	  mlhmmv_xvalue_free(&pbxval1->xval);
229 	return rv;
230 }
231 
b_x_is_boolean_xfunc(boxed_xval_t * pbxval1)232 static inline boxed_xval_t b_x_is_boolean_xfunc(boxed_xval_t* pbxval1) {
233 	boxed_xval_t rv = b_x_is_boolean_no_free_xfunc(pbxval1);
234 	if (pbxval1->is_ephemeral)
235 	  mlhmmv_xvalue_free(&pbxval1->xval);
236 	return rv;
237 }
238 
b_x_is_string_xfunc(boxed_xval_t * pbxval1)239 static inline boxed_xval_t b_x_is_string_xfunc(boxed_xval_t* pbxval1) {
240 	boxed_xval_t rv = b_x_is_string_no_free_xfunc(pbxval1);
241 	if (pbxval1->is_ephemeral)
242 	  mlhmmv_xvalue_free(&pbxval1->xval);
243 	return rv;
244 }
245 
b_x_is_null_xfunc(boxed_xval_t * pbxval1)246 static inline boxed_xval_t b_x_is_null_xfunc(boxed_xval_t* pbxval1) {
247 	boxed_xval_t rv = b_x_is_null_no_free_xfunc(pbxval1);
248 	if (pbxval1->is_ephemeral)
249 	  mlhmmv_xvalue_free(&pbxval1->xval);
250 	return rv;
251 }
252 
b_x_is_not_null_xfunc(boxed_xval_t * pbxval1)253 static inline boxed_xval_t b_x_is_not_null_xfunc(boxed_xval_t* pbxval1) {
254 	boxed_xval_t rv = b_x_is_not_null_no_free_xfunc(pbxval1);
255 	if (pbxval1->is_ephemeral)
256 	  mlhmmv_xvalue_free(&pbxval1->xval);
257 	return rv;
258 }
259 
b_x_is_empty_xfunc(boxed_xval_t * pbxval1)260 static inline boxed_xval_t b_x_is_empty_xfunc(boxed_xval_t* pbxval1) {
261 	boxed_xval_t rv = b_x_is_empty_no_free_xfunc(pbxval1);
262 	if (pbxval1->is_ephemeral)
263 	  mlhmmv_xvalue_free(&pbxval1->xval);
264 	return rv;
265 }
266 
b_x_is_not_empty_xfunc(boxed_xval_t * pbxval1)267 static inline boxed_xval_t b_x_is_not_empty_xfunc(boxed_xval_t* pbxval1) {
268 	boxed_xval_t rv = b_x_is_not_empty_no_free_xfunc(pbxval1);
269 	if (pbxval1->is_ephemeral)
270 	  mlhmmv_xvalue_free(&pbxval1->xval);
271 	return rv;
272 }
273 
b_x_is_empty_map_xfunc(boxed_xval_t * pbxval1)274 static inline boxed_xval_t b_x_is_empty_map_xfunc(boxed_xval_t* pbxval1) {
275 	boxed_xval_t rv = b_x_is_empty_map_no_free_xfunc(pbxval1);
276 	if (pbxval1->is_ephemeral)
277 	  mlhmmv_xvalue_free(&pbxval1->xval);
278 	return rv;
279 }
280 
b_x_is_nonempty_map_xfunc(boxed_xval_t * pbxval1)281 static inline boxed_xval_t b_x_is_nonempty_map_xfunc(boxed_xval_t* pbxval1) {
282 	boxed_xval_t rv = b_x_is_nonempty_map_no_free_xfunc(pbxval1);
283 	if (pbxval1->is_ephemeral)
284 	  mlhmmv_xvalue_free(&pbxval1->xval);
285 	return rv;
286 }
287 
s_x_typeof_xfunc(boxed_xval_t * pbxval1)288 static inline boxed_xval_t s_x_typeof_xfunc(boxed_xval_t* pbxval1) {
289 	boxed_xval_t rv = s_x_typeof_no_free_xfunc(pbxval1);
290 	if (pbxval1->is_ephemeral)
291 	  mlhmmv_xvalue_free(&pbxval1->xval);
292 	return rv;
293 }
294 
295 // ----------------------------------------------------------------
296 boxed_xval_t b_xx_haskey_xfunc(
297 	boxed_xval_t* pmapval,
298 	boxed_xval_t* pkeyval);
299 
300 boxed_xval_t i_x_length_xfunc(
301 	boxed_xval_t* pbxval1);
302 
303 boxed_xval_t i_x_depth_xfunc(
304 	boxed_xval_t* pbxval1);
305 
306 boxed_xval_t i_x_leafcount_xfunc(
307 	boxed_xval_t* pbxval1);
308 
309 boxed_xval_t variadic_mapsum_xfunc(
310 	boxed_xval_t* pbxvals, int nxvals);
311 
312 boxed_xval_t variadic_mapdiff_xfunc(
313 	boxed_xval_t* pbxvals, int nxvals);
314 
315 boxed_xval_t variadic_mapexcept_xfunc(
316 	boxed_xval_t* pbxvals, int nxvals);
317 
318 boxed_xval_t variadic_mapselect_xfunc(
319 	boxed_xval_t* pbxvals, int nxvals);
320 
321 boxed_xval_t m_ss_splitnv_xfunc(
322 	boxed_xval_t* pstringval,
323 	boxed_xval_t* psepval);
324 
325 boxed_xval_t m_ss_splitnvx_xfunc(
326 	boxed_xval_t* pstringval,
327 	boxed_xval_t* psepval);
328 
329 boxed_xval_t m_sss_splitkv_xfunc(
330 	boxed_xval_t* pstringval,
331 	boxed_xval_t* ppairsepval,
332 	boxed_xval_t* plistsepval);
333 
334 boxed_xval_t m_sss_splitkvx_xfunc(
335 	boxed_xval_t* pstringval,
336 	boxed_xval_t* ppairsepval,
337 	boxed_xval_t* plistsepval);
338 
339 boxed_xval_t s_ms_joink_xfunc(
340 	boxed_xval_t* pmapval,
341 	boxed_xval_t* psepval);
342 
343 boxed_xval_t s_ms_joinv_xfunc(
344 	boxed_xval_t* pmapval,
345 	boxed_xval_t* psepval);
346 
347 boxed_xval_t s_mss_joinkv_xfunc(
348 	boxed_xval_t* pmapval,
349 	boxed_xval_t* ppairsepval,
350 	boxed_xval_t* plistsepval);
351 
352 #endif // XVFUNCS_H
353