Line data Source code
1 : /*
2 : * SPDX-License-Identifier: MPL-2.0
3 : *
4 : * This Source Code Form is subject to the terms of the Mozilla Public
5 : * License, v. 2.0. If a copy of the MPL was not distributed with this
6 : * file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 : *
8 : * Copyright 2024 MonetDB Foundation;
9 : * Copyright August 2008 - 2023 MonetDB B.V.;
10 : * Copyright 1997 - July 2008 CWI.
11 : */
12 :
13 : /*
14 : * (author) M. Kersten 2015
15 : */
16 :
17 : #include "monetdb_config.h"
18 : #include "mal_instruction.h"
19 : #include "mal_function.h" /* for getPC() */
20 : #include "mal_utils.h"
21 : #include "mal_exception.h"
22 : #include "mal_listing.h"
23 :
24 : /*
25 : * Since MAL programs can be created on the fly by linked-in query
26 : * compilers, or transformed by optimizers, it becomes
27 : * mandatory to be able to produce textual correct MAL programs
28 : * from its internal representation for several purposes.
29 : *
30 : * Whenever there is an overriding property it is applied.
31 : *
32 : * The hiddenInstruction operator assumes a sufficiently large block
33 : * to leave information on the signature behind.
34 : *
35 : * The protection against overflow is not tight.
36 : */
37 : #define advance(X,B,L) while(*(X) && B+L>X)(X)++;
38 :
39 : /* Copy string in src to *dstp which has *lenp space available and
40 : * terminate with a NULL byte. *dstp and *lenp are adjusted for the
41 : * used space. If there is not enough space to copy all of src,
42 : * return false, otherwise return true. The resulting string is
43 : * always NULL-terminated. */
44 : static inline bool
45 3949204 : copystring(char **dstp, const char *src, size_t *lenp)
46 : {
47 3949204 : size_t len = *lenp;
48 3949204 : char *dst = *dstp;
49 :
50 3949204 : if (src == NULL)
51 : return true;
52 3949204 : if (len > 0) {
53 19204394 : while (*src && len > 1) {
54 15255162 : *dst++ = *src++;
55 15255162 : len--;
56 : }
57 3949232 : *dst = 0;
58 3949232 : *dstp = dst;
59 3949232 : *lenp = len;
60 : }
61 3949204 : return *src == 0;
62 : }
63 :
64 : static str
65 40543 : renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg)
66 : {
67 40543 : char *buf = 0;
68 40543 : int nameused = 0;
69 40543 : size_t len = 0, maxlen = BUFSIZ;
70 40543 : ValRecord *val = 0;
71 40543 : char *cv = 0;//, *c;
72 40543 : str tpe;
73 40543 : int showtype = 0, closequote = 0;
74 40543 : int varid = getArg(p, idx);
75 :
76 40543 : buf = GDKzalloc(maxlen);
77 40550 : if (buf == NULL) {
78 0 : addMalException(mb, "renderTerm:Failed to allocate");
79 0 : return NULL;
80 : }
81 : // show the name when required or is used
82 40550 : if ((flg & LIST_MAL_NAME) && !isVarConstant(mb, varid)
83 19660 : && !isVarTypedef(mb, varid)) {
84 19653 : char *nme = getVarNameIntoBuffer(mb, varid, buf);
85 19647 : len += strlen(nme);
86 19647 : nameused = 1;
87 : }
88 : // show the value when required or being a constant
89 40544 : if (((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb, varid)) {
90 22917 : if (nameused) {
91 2034 : strcat(buf + len, "=");
92 2034 : len++;
93 : }
94 :
95 : // locate value record
96 22917 : if (isVarConstant(mb, varid)) {
97 20881 : val = &getVarConstant(mb, varid);
98 20881 : showtype = getVarType(mb, varid) != TYPE_str
99 20881 : && getVarType(mb, varid) != TYPE_bit;
100 2036 : } else if (stk)
101 2036 : val = &stk->stk[varid];
102 :
103 22917 : if ((cv = VALformat(val)) == NULL) {
104 0 : addMalException(mb, "renderTerm:Failed to allocate");
105 0 : GDKfree(buf);
106 0 : return NULL;
107 : }
108 22909 : if (len + strlen(cv) >= maxlen) {
109 0 : char *nbuf = GDKrealloc(buf, maxlen = len + strlen(cv) + BUFSIZ);
110 :
111 0 : if (nbuf == 0) {
112 0 : GDKfree(buf);
113 0 : GDKfree(cv);
114 0 : addMalException(mb, "renderTerm:Failed to allocate");
115 0 : return NULL;
116 : }
117 : buf = nbuf;
118 : }
119 :
120 22909 : if (!val->bat && strcmp(cv, "nil") == 0) {
121 213 : strcat(buf + len, cv);
122 213 : len += strlen(buf + len);
123 213 : GDKfree(cv);
124 214 : showtype = showtype
125 9 : || (getBatType(getVarType(mb, varid)) >= TYPE_date
126 9 : && getBatType(getVarType(mb, varid)) != TYPE_str)
127 8 : || ((isVarTypedef(mb, varid)) && isVarConstant(mb, varid))
128 222 : || isaBatType(getVarType(mb, varid));
129 : } else {
130 22696 : if (!isaBatType(getVarType(mb, varid))
131 20626 : && getBatType(getVarType(mb, varid)) >= TYPE_date
132 11086 : && getBatType(getVarType(mb, varid)) != TYPE_str) {
133 280 : closequote = 1;
134 280 : strcat(buf + len, "\"");
135 280 : len++;
136 : }
137 : /*
138 : if (isaBatType(getVarType(mb, varid)) && !is_bat_nil(val->val.bval)) {
139 : c = strchr(cv, '>');
140 : strcat(buf + len, c + 1);
141 : len += strlen(buf + len);
142 : } else {
143 : */
144 22696 : strcat(buf + len, cv);
145 22696 : len += strlen(buf + len);
146 : //}
147 22696 : GDKfree(cv);
148 :
149 22705 : if (closequote) {
150 280 : strcat(buf + len, "\"");
151 280 : len++;
152 : }
153 45410 : showtype = showtype || closequote > TYPE_str
154 13913 : ||
155 13913 : ((isVarTypedef(mb, varid)
156 13911 : || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE)))
157 13903 : && isVarConstant(mb, varid))
158 24752 : || (isaBatType(getVarType(mb, varid)) && idx < p->retc);
159 :
160 22705 : if (stk && isaBatType(getVarType(mb, varid))
161 1893 : && stk->stk[varid].val.bval) {
162 1890 : BAT *d = BBPquickdesc(stk->stk[varid].val.bval);
163 1886 : if (d)
164 1707 : len += snprintf(buf + len, maxlen - len, "[" BUNFMT "]",
165 : BATcount(d));
166 : }
167 : }
168 : }
169 :
170 : // show the type when required or frozen by the user
171 : // special care should be taken with constants, they may have been casted
172 40542 : if ((flg & LIST_MAL_TYPE) || (idx < p->retc) || isVarTypedef(mb, varid)
173 16 : || showtype) {
174 40526 : strcat(buf + len, ":");
175 40526 : len++;
176 40526 : tpe = getTypeName(getVarType(mb, varid));
177 40524 : len += snprintf(buf + len, maxlen - len, "%s", tpe);
178 40524 : GDKfree(tpe);
179 : }
180 :
181 40548 : if (len >= maxlen)
182 0 : addMalException(mb, "renderTerm:Value representation too large");
183 : return buf;
184 : }
185 :
186 : /*
187 : It receives the space to store the definition
188 : The MAL profiler dumps some performance data at the
189 : beginning of each line.
190 : */
191 :
192 : str
193 163083 : cfcnDefinition(Symbol s, str t, int flg, str base, size_t len)
194 : {
195 163083 : unsigned int i;
196 163083 : str arg, tpe;
197 163083 : mel_func *f = s->func;
198 :
199 163083 : len -= t - base;
200 163083 : if (!flg && !copystring(&t, "#", &len))
201 : return base;
202 163083 : if (f->unsafe && !copystring(&t, "unsafe ", &len))
203 : return base;
204 326166 : if (!copystring(&t, operatorName(s->kind), &len) ||
205 326166 : !copystring(&t, " ", &len) ||
206 489249 : !copystring(&t, f->mod ? f->mod : "user", &len) ||
207 326166 : !copystring(&t, ".", &len) ||
208 326166 : !copystring(&t, f->fcn, &len) || !copystring(&t, "(", &len))
209 0 : return base;
210 :
211 163083 : char var[16];
212 618486 : for (i = f->retc; i < f->argc; i++) {
213 455403 : if (snprintf(var, 16, "X_%d:", i-f->retc) >= 16 || !copystring(&t, var, &len))
214 0 : return base;
215 714683 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
216 : return base;
217 455403 : arg = f->args[i].type;
218 455403 : if (arg[0] && !copystring(&t, arg, &len))
219 : return base;
220 455403 : if (!arg[0]) {
221 17314 : if (f->args[i].nr) {
222 15920 : if (snprintf(var, 16, "any_%d", f->args[i].nr ) >= 16 || !copystring(&t, var, &len))
223 0 : return base;
224 1394 : } else if (!copystring(&t, "any", &len))
225 : return base;
226 : }
227 455403 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
228 : return base;
229 455403 : if (i+1 < f->argc && !copystring(&t, ", ", &len))
230 : return base;
231 : }
232 :
233 163083 : advance(t, base, len);
234 163083 : if (f->vargs && !copystring(&t, "...", &len))
235 : return base;
236 :
237 163083 : if (f->retc == 0) {
238 1522 : if (!copystring(&t, "):void", &len))
239 : return base;
240 161561 : } else if (f->retc == 1) {
241 158137 : if (!copystring(&t, "):", &len))
242 : return base;
243 266731 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, (f->args[0].opt == 1)?"bat?[:":"bat[:", &len))
244 : return base;
245 158137 : tpe = f->args[0].type;
246 158137 : if (tpe[0] && !copystring(&t, tpe, &len))
247 : return base;
248 158137 : if (!tpe[0]) {
249 2649 : if (f->args[0].nr) {
250 2466 : if (snprintf(var, 16, "any_%d", f->args[0].nr ) >= 16 || !copystring(&t, var, &len))
251 0 : return base;
252 183 : } else if (!copystring(&t, "any", &len))
253 : return base;
254 : }
255 158137 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, "]", &len))
256 : return base;
257 158137 : if (f->vrets && !copystring(&t, "...", &len))
258 : return base;
259 : } else {
260 3424 : if (!copystring(&t, ") (", &len))
261 : return base;
262 13952 : for (i = 0; i < f->retc; i++) {
263 10528 : if (snprintf(var, 16, "X_%d:", i+(f->argc-f->retc)) >= 16 || !copystring(&t, var, &len))
264 0 : return base;
265 19584 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
266 : return base;
267 10528 : arg = f->args[i].type;
268 10528 : if (arg[0] && !copystring(&t, arg, &len))
269 : return base;
270 10528 : if (!arg[0]) {
271 352 : if (f->args[i].nr) {
272 304 : if (snprintf(var, 16, "any_%d", f->args[i].nr ) >= 16 || !copystring(&t, var, &len))
273 0 : return base;
274 48 : } else if (!copystring(&t, "any", &len))
275 : return base;
276 : }
277 10528 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
278 : return base;
279 10528 : if (i+1 < f->retc && !copystring(&t, ", ", &len))
280 : return base;
281 : }
282 3424 : if (f->vrets && !copystring(&t, "...", &len))
283 : return base;
284 3424 : if (!copystring(&t, ")", &len))
285 : return base;
286 : }
287 :
288 163083 : if (f->cname) {
289 326166 : if (!copystring(&t, " address ", &len) ||
290 163083 : !copystring(&t, f->cname, &len))
291 0 : return base;
292 : }
293 163083 : (void) copystring(&t, ";", &len);
294 163083 : return base;
295 : }
296 :
297 : str
298 191 : fcnDefinition(MalBlkPtr mb, InstrPtr p, str t, int flg, str base, size_t len)
299 : {
300 191 : int i, j;
301 191 : str arg, tpe;
302 :
303 191 : len -= t - base;
304 191 : if (!flg && !copystring(&t, "#", &len))
305 : return base;
306 191 : if (mb->inlineProp && !copystring(&t, "inline ", &len))
307 : return base;
308 191 : if (mb->unsafeProp && !copystring(&t, "unsafe ", &len))
309 : return base;
310 382 : if (!copystring(&t, operatorName(p->token), &len) ||
311 382 : !copystring(&t, " ", &len) ||
312 573 : !copystring(&t, getModuleId(p) ? getModuleId(p) : "user", &len) ||
313 382 : !copystring(&t, ".", &len) ||
314 382 : !copystring(&t, getFunctionId(p), &len) || !copystring(&t, "(", &len))
315 0 : return base;
316 :
317 195 : for (i = p->retc; i < p->argc; i++) {
318 4 : arg = renderTerm(mb, 0, p, i,
319 : (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS));
320 4 : if (arg && !copystring(&t, arg, &len)) {
321 0 : GDKfree(arg);
322 0 : return base;
323 : }
324 4 : GDKfree(arg);
325 4 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
326 : return base;
327 : }
328 :
329 191 : advance(t, base, len);
330 191 : if (p->varargs & VARARGS && !copystring(&t, "...", &len))
331 : return base;
332 :
333 191 : if (p->retc == 1) {
334 191 : if (!copystring(&t, "):", &len))
335 : return base;
336 191 : tpe = getTypeName(getVarType(mb, getArg(p, 0)));
337 191 : if (!copystring(&t, tpe, &len)) {
338 0 : GDKfree(tpe);
339 0 : return base;
340 : }
341 191 : GDKfree(tpe);
342 191 : if (p->varargs & VARRETS && !copystring(&t, "...", &len))
343 : return base;
344 : } else {
345 0 : if (!copystring(&t, ") (", &len))
346 : return base;
347 0 : for (i = 0; i < p->retc; i++) {
348 0 : arg = renderTerm(mb, 0, p, i,
349 : (LIST_MAL_NAME | LIST_MAL_TYPE | LIST_MAL_PROPS));
350 0 : if (arg && !copystring(&t, arg, &len)) {
351 0 : GDKfree(arg);
352 0 : return base;
353 : }
354 0 : GDKfree(arg);
355 0 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
356 : return base;
357 : }
358 0 : if (p->varargs & VARRETS && !copystring(&t, "...", &len))
359 : return base;
360 0 : if (!copystring(&t, ")", &len))
361 : return base;
362 : }
363 :
364 191 : if (mb->binding[0]) {
365 0 : if (!copystring(&t, " address ", &len) ||
366 0 : !copystring(&t, mb->binding, &len))
367 0 : return base;
368 : }
369 191 : (void) copystring(&t, ";", &len);
370 : /* add the extra properties for debugging */
371 191 : if (flg & LIST_MAL_PROPS) {
372 1 : char extra[256];
373 1 : if (p->token == REMsymbol) {
374 : } else {
375 0 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", getPC(mb, p),
376 1 : getRowCnt(mb, getArg(p, 0)),
377 1 : (p->blk ? p->blk->binding : ""));
378 1 : if (!copystring(&t, extra, &len))
379 0 : return base;
380 2 : for (j = 0; j < p->retc; j++) {
381 1 : snprintf(extra, 256, "%d ", getArg(p, j));
382 1 : if (!copystring(&t, extra, &len))
383 : return base;
384 : }
385 1 : if (p->argc - p->retc > 0) {
386 0 : if (!copystring(&t, "<- ", &len))
387 : return base;
388 : }
389 1 : for (; j < p->argc; j++) {
390 0 : snprintf(extra, 256, "%d ", getArg(p, j));
391 0 : if (!copystring(&t, extra, &len))
392 : return base;
393 : }
394 1 : if (!p->typeresolved) {
395 0 : if (!copystring(&t, " type check needed", &len))
396 : return base;
397 : }
398 : }
399 : }
400 : return base;
401 : }
402 :
403 : static str
404 3380 : fmtRemark(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, str t, int flg, str base,
405 : size_t len)
406 : {
407 3380 : char aux[128];
408 :
409 3380 : if (!copystring(&t, "# ", &len))
410 : return base;
411 :
412 3380 : if (pci->argc == 3) {
413 3376 : if (getFunctionId(pci)) {
414 3376 : char *arg1 = renderTerm(mb, stk, pci, 1, flg);
415 3376 : char *arg2 = renderTerm(mb, stk, pci, 2, flg);
416 3376 : if (arg1 && arg2) {
417 3376 : const char *f = getFunctionId(pci);
418 3376 : if (strcmp(f, "total") == 0)
419 128 : snprintf(aux, 128, "%d optimizers %ld usecs", atoi(arg1), atol(arg2));
420 : else
421 3248 : snprintf(aux, 128, "%-36s %d actions %ld usecs", f, atoi(arg1), atol(arg2));
422 3376 : (void) copystring(&t, aux, &len);
423 : }
424 3376 : GDKfree(arg1);
425 3376 : GDKfree(arg2);
426 : }
427 4 : } else if (pci->argc == 1) {
428 4 : if (getFunctionId(pci)) {
429 4 : if (!copystring(&t, getFunctionId(pci), &len))
430 : return base;
431 : }
432 0 : } else if (getVar(mb, getArg(pci, 0))->value.val.sval &&
433 0 : getVar(mb, getArg(pci, 0))->value.len > 0 &&
434 0 : !copystring(&t, getVar(mb, getArg(pci, 0))->value.val.sval,
435 : &len))
436 : return base;
437 :
438 : return base;
439 : }
440 :
441 : str
442 163383 : operatorName(int i)
443 : {
444 163383 : switch (i) {
445 : case ASSIGNsymbol:
446 : return ":=";
447 20 : case BARRIERsymbol:
448 20 : return "barrier";
449 0 : case REDOsymbol:
450 0 : return "redo";
451 0 : case LEAVEsymbol:
452 0 : return "leave";
453 12 : case EXITsymbol:
454 12 : return "exit";
455 0 : case RETURNsymbol:
456 0 : return "return";
457 0 : case CATCHsymbol:
458 0 : return "catch";
459 0 : case RAISEsymbol:
460 0 : return "raise";
461 36 : case ENDsymbol:
462 36 : return "end";
463 232 : case FUNCTIONsymbol:
464 232 : return "function";
465 26097 : case COMMANDsymbol:
466 26097 : return "command";
467 136986 : case PATTERNsymbol:
468 136986 : return "pattern";
469 :
470 : /* internal symbols */
471 : case FCNcall:
472 0 : assert(0);
473 : return "FCNcall";
474 : case CMDcall:
475 0 : assert(0);
476 : return "CMDcall";
477 : case PATcall:
478 0 : assert(0);
479 : return "PATcall";
480 : }
481 0 : return "";
482 : }
483 :
484 : str
485 11136 : instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
486 : {
487 11136 : int i, j;
488 11136 : str base, t;
489 11136 : size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */
490 11136 : str arg;
491 :
492 11136 : t = base = GDKmalloc(len);
493 11146 : if (base == NULL)
494 : return NULL;
495 11146 : if (!flg) {
496 1 : *t++ = '#';
497 1 : len--;
498 1 : if (!p->typeresolved) {
499 0 : *t++ = '!'; /* error */
500 0 : len--;
501 : }
502 : }
503 11146 : *t = 0;
504 11146 : if (p->token == REMsymbol
505 3388 : && !(getModuleId(p) && strcmp(getModuleId(p), "querylog") == 0
506 0 : && getFunctionId(p) && strcmp(getFunctionId(p), "define") == 0)) {
507 : /* do nothing */
508 7758 : } else if (p->barrier) {
509 28 : if (p->barrier == LEAVEsymbol ||
510 28 : p->barrier == REDOsymbol ||
511 : p->barrier == RETURNsymbol || p->barrier == RAISEsymbol) {
512 0 : if (!copystring(&t, " ", &len))
513 : return base;
514 : }
515 28 : arg = operatorName(p->barrier);
516 28 : if (!copystring(&t, arg, &len) || !copystring(&t, " ", &len))
517 0 : return base;
518 7730 : } else if (functionStart(p) && flg != LIST_MAL_CALL) {
519 170 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
520 7560 : } else if (!functionExit(p) && flg != LIST_MAL_CALL) {
521 : // beautify with tabs
522 7386 : if (!copystring(&t, " ", &len))
523 : return base;
524 : }
525 10974 : switch (p->token < 0 ? -p->token : p->token) {
526 7415 : case FCNcall:
527 : case PATcall:
528 : case CMDcall:
529 : case ASSIGNsymbol:
530 : // is any variable explicit or used
531 : /* this code was meant to make it easy to detect functions whose
532 : * result variable was not used anywhere.
533 : * It is not essential
534 : for (i = 0; i < p->retc; i++)
535 : if ( !isTmpVar(mb,getArg(p,i)) || isVarUsed(mb, getArg(p, i)))
536 : break;
537 :
538 : if (i == p->retc)
539 : break;
540 : */
541 :
542 : /* display multi-assignment list */
543 7415 : if (p->retc > 1 && !copystring(&t, "(", &len))
544 : return base;
545 :
546 14968 : for (i = 0; i < p->retc; i++) {
547 7553 : arg = renderTerm(mb, stk, p, i, flg);
548 7552 : if (arg) {
549 7552 : if (!copystring(&t, arg, &len)) {
550 0 : GDKfree(arg);
551 0 : return base;
552 : }
553 7551 : GDKfree(arg);
554 : }
555 7553 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
556 : return base;
557 : }
558 7415 : if (p->retc > 1 && !copystring(&t, ")", &len))
559 : return base;
560 :
561 7415 : if (p->argc > p->retc || getFunctionId(p)) {
562 7403 : if (!copystring(&t, " := ", &len))
563 : return base;
564 : }
565 : break;
566 169 : case ENDsymbol:
567 338 : if (!copystring(&t, "end ", &len) ||
568 338 : !copystring(&t, getModuleId(getInstrPtr(mb, 0)), &len) ||
569 338 : !copystring(&t, ".", &len) ||
570 169 : !copystring(&t, getFunctionId(getInstrPtr(mb, 0)), &len))
571 0 : return base;
572 : break;
573 5 : case COMMANDsymbol:
574 : case FUNCTIONsymbol:
575 : case PATTERNsymbol:
576 5 : if (flg & LIST_MAL_VALUE) {
577 10 : if (!copystring(&t, operatorName(p->token), &len) ||
578 5 : !copystring(&t, " ", &len))
579 0 : return base;
580 : }
581 5 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
582 3380 : case REMsymbol:
583 3380 : return fmtRemark(mb, stk, p, t, flg, base, len);
584 5 : default:
585 5 : i = snprintf(t, len, " unknown symbol ?%d? ", p->token);
586 5 : if (i < 0 || (size_t) i >= len)
587 : return base;
588 5 : len -= (size_t) i;
589 5 : t += i;
590 5 : break;
591 : }
592 :
593 7584 : if (getModuleId(p)) {
594 7330 : if (!copystring(&t, getModuleId(p), &len) || !copystring(&t, ".", &len))
595 0 : return base;
596 : }
597 7584 : if (getFunctionId(p)) {
598 14666 : if (!copystring(&t, getFunctionId(p), &len) ||
599 7334 : !copystring(&t, "(", &len))
600 0 : return base;
601 249 : } else if (p->argc > p->retc + 1) {
602 0 : if (!copystring(&t, "(", &len))
603 : return base;
604 : }
605 33815 : for (i = p->retc; i < p->argc; i++) {
606 26234 : arg = renderTerm(mb, stk, p, i, flg);
607 26239 : if (arg) {
608 26239 : if (!copystring(&t, arg, &len)) {
609 1 : GDKfree(arg);
610 1 : return base;
611 : }
612 26238 : GDKfree(arg);
613 : }
614 :
615 26235 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
616 : return base;
617 : }
618 7581 : if (getFunctionId(p) || p->argc > p->retc + 1) {
619 7332 : if (!copystring(&t, ")", &len))
620 : return base;
621 : }
622 7581 : if (p->token != REMsymbol) {
623 7582 : if (!copystring(&t, ";", &len))
624 : return base;
625 : }
626 : /* add the extra properties for debugging */
627 7579 : if (flg & LIST_MAL_PROPS) {
628 4193 : char extra[256];
629 4193 : if (p->token == REMsymbol) {
630 : } else {
631 1 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", p->pc,
632 4193 : getRowCnt(mb, getArg(p, 0)),
633 4193 : (p->blk ? p->blk->binding : ""));
634 4193 : if (!copystring(&t, extra, &len))
635 0 : return base;
636 8420 : for (j = 0; j < p->retc; j++) {
637 4227 : snprintf(extra, 256, "%d ", getArg(p, j));
638 4227 : if (!copystring(&t, extra, &len))
639 : return base;
640 : }
641 4193 : if (p->argc - p->retc > 0) {
642 4190 : if (!copystring(&t, "<- ", &len))
643 : return base;
644 : }
645 20887 : for (; j < p->argc; j++) {
646 16694 : snprintf(extra, 256, "%d ", getArg(p, j));
647 16694 : if (!copystring(&t, extra, &len))
648 : return base;
649 : }
650 4193 : if (!p->typeresolved) {
651 0 : if (!copystring(&t, " type check needed", &len))
652 : return base;
653 : }
654 : }
655 : }
656 7579 : if (flg & LIST_MAL_ALGO) {
657 902 : const char *algo = MT_thread_getalgorithm();
658 905 : if (algo) {
659 144 : if (!copystring(&t, " # ", &len))
660 : return base;
661 144 : if (!copystring(&t, algo, &len))
662 : return base;
663 : }
664 : }
665 : return base;
666 : }
667 :
668 : /* the MAL beautifier is meant to simplify correlation of MAL variables and
669 : * the columns in the underlying database.
670 : * If the status is set, then we consider the instruction DONE and the result variables
671 : * should be shown as well.
672 : */
673 :
674 : /* Remote execution of MAL calls for more type/property information to be exchanged */
675 : str
676 0 : mal2str(MalBlkPtr mb, int first, int last)
677 : {
678 0 : str ps = NULL, *txt;
679 0 : int i, j;
680 0 : size_t *len, totlen = 0;
681 :
682 0 : txt = GDKmalloc(sizeof(str) * mb->stop);
683 0 : len = GDKmalloc(sizeof(size_t) * mb->stop);
684 :
685 0 : if (txt == NULL || len == NULL) {
686 0 : addMalException(mb, "mal2str: " MAL_MALLOC_FAIL);
687 0 : GDKfree(txt);
688 0 : GDKfree(len);
689 0 : return NULL;
690 : }
691 0 : for (i = first; i < last; i++) {
692 0 : if (i == 0)
693 0 : txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i),
694 : LIST_MAL_NAME | LIST_MAL_TYPE |
695 : LIST_MAL_PROPS);
696 : else
697 0 : txt[i] = instruction2str(mb, 0, getInstrPtr(mb, i),
698 : LIST_MAL_CALL | LIST_MAL_PROPS |
699 : LIST_MAL_REMOTE);
700 :
701 0 : if (txt[i])
702 0 : totlen += len[i] = strlen(txt[i]);
703 : else {
704 0 : addMalException(mb, "mal2str: " MAL_MALLOC_FAIL);
705 0 : GDKfree(len);
706 0 : for (j = first; j < i; j++)
707 0 : GDKfree(txt[j]);
708 0 : GDKfree(txt);
709 0 : return NULL;
710 : }
711 : }
712 0 : ps = GDKmalloc(totlen + mb->stop + 1);
713 0 : if (ps == NULL) {
714 0 : addMalException(mb, "mal2str: " MAL_MALLOC_FAIL);
715 0 : GDKfree(len);
716 0 : for (i = first; i < last; i++)
717 0 : GDKfree(txt[i]);
718 0 : GDKfree(txt);
719 0 : return NULL;
720 : }
721 :
722 : totlen = 0;
723 0 : for (i = first; i < last; i++) {
724 0 : if (txt[i]) {
725 0 : strncpy(ps + totlen, txt[i], len[i]);
726 0 : ps[totlen + len[i]] = '\n';
727 0 : ps[totlen + len[i] + 1] = 0;
728 0 : totlen += len[i] + 1;
729 0 : GDKfree(txt[i]);
730 : }
731 : }
732 0 : GDKfree(len);
733 0 : GDKfree(txt);
734 0 : return ps;
735 : }
736 :
737 : void
738 3011 : printInstruction(stream *fd, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
739 : {
740 3011 : str ps;
741 :
742 3011 : if (fd == 0)
743 : return;
744 3011 : ps = instruction2str(mb, stk, p, flg);
745 : /* ps[strlen(ps)-1] = 0; remove '\n' */
746 3011 : if (ps) {
747 3051 : mnstr_printf(fd, "%s%s", (flg & LIST_MAL_MAPI ? "=" : ""), ps);
748 3011 : GDKfree(ps);
749 : } else {
750 0 : mnstr_printf(fd, "#failed instruction2str()");
751 : }
752 3011 : mnstr_printf(fd, "\n");
753 : }
754 :
755 : void
756 99978653 : traceInstruction(component_t comp, MalBlkPtr mb, MalStkPtr stk, InstrPtr p,
757 : int flg)
758 : {
759 99978653 : str ps;
760 99978653 : TRC_DEBUG_IF(comp) {
761 0 : ps = instruction2str(mb, stk, p, flg);
762 : /* ps[strlen(ps)-1] = 0; remove '\n' */
763 0 : if (ps) {
764 0 : TRC_DEBUG_ENDIF(comp, "%s%s\n", (flg & LIST_MAL_MAPI ? "=" : ""),
765 : ps);
766 0 : GDKfree(ps);
767 : } else {
768 0 : TRC_DEBUG_ENDIF(comp, "Failed instruction2str()\n");
769 : }
770 : }
771 99978653 : }
772 :
773 : void
774 0 : printSignature(stream *fd, Symbol s, int flg)
775 : {
776 0 : InstrPtr p;
777 0 : str txt;
778 :
779 0 : if (s->def == 0) {
780 0 : mnstr_printf(fd, "missing definition of %s\n", s->name);
781 0 : return;
782 : }
783 0 : txt = GDKzalloc(MAXLISTING); /* some slack for large blocks */
784 0 : if (txt) {
785 0 : p = getSignature(s);
786 0 : (void) fcnDefinition(s->def, p, txt, flg, txt, MAXLISTING);
787 0 : mnstr_printf(fd, "%s\n", txt);
788 0 : GDKfree(txt);
789 : } else
790 0 : mnstr_printf(fd, "printSignature: " MAL_MALLOC_FAIL);
791 : }
|