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 3906295 : copystring(char **dstp, const char *src, size_t *lenp)
46 : {
47 3906295 : size_t len = *lenp;
48 3906295 : char *dst = *dstp;
49 :
50 3906295 : if (src == NULL)
51 : return true;
52 3906295 : if (len > 0) {
53 18915902 : while (*src && len > 1) {
54 15009605 : *dst++ = *src++;
55 15009605 : len--;
56 : }
57 3906297 : *dst = 0;
58 3906297 : *dstp = dst;
59 3906297 : *lenp = len;
60 : }
61 3906295 : return *src == 0;
62 : }
63 :
64 : static str
65 31177 : renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg)
66 : {
67 31177 : char *buf = 0;
68 31177 : int nameused = 0;
69 31177 : size_t len = 0, maxlen = BUFSIZ;
70 31177 : ValRecord *val = 0;
71 31177 : char *cv = 0;//, *c;
72 31177 : str tpe;
73 31177 : int showtype = 0, closequote = 0;
74 31177 : int varid = getArg(p, idx);
75 :
76 31177 : buf = GDKzalloc(maxlen);
77 31179 : 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 31179 : if ((flg & LIST_MAL_NAME) && !isVarConstant(mb, varid)
83 14114 : && !isVarTypedef(mb, varid)) {
84 14107 : char *nme = getVarNameIntoBuffer(mb, varid, buf);
85 14107 : len += strlen(nme);
86 14107 : nameused = 1;
87 : }
88 : // show the value when required or being a constant
89 31179 : if (((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb, varid)) {
90 18837 : if (nameused) {
91 1779 : strcat(buf + len, "=");
92 1779 : len++;
93 : }
94 :
95 : // locate value record
96 18837 : if (isVarConstant(mb, varid)) {
97 17058 : val = &getVarConstant(mb, varid);
98 17058 : showtype = getVarType(mb, varid) != TYPE_str
99 17058 : && getVarType(mb, varid) != TYPE_bit;
100 1779 : } else if (stk)
101 1779 : val = &stk->stk[varid];
102 :
103 18837 : if ((cv = VALformat(val)) == NULL) {
104 0 : addMalException(mb, "renderTerm:Failed to allocate");
105 0 : GDKfree(buf);
106 0 : return NULL;
107 : }
108 18837 : 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 18837 : if (!val->bat && strcmp(cv, "nil") == 0) {
121 206 : strcat(buf + len, cv);
122 206 : len += strlen(buf + len);
123 206 : GDKfree(cv);
124 206 : 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 214 : || isaBatType(getVarType(mb, varid));
129 : } else {
130 18631 : if (!isaBatType(getVarType(mb, varid))
131 16786 : && getBatType(getVarType(mb, varid)) >= TYPE_date
132 7378 : && 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 18631 : strcat(buf + len, cv);
145 18631 : len += strlen(buf + len);
146 : //}
147 18631 : GDKfree(cv);
148 :
149 18630 : if (closequote) {
150 280 : strcat(buf + len, "\"");
151 280 : len++;
152 : }
153 37260 : showtype = showtype || closequote > TYPE_str
154 9900 : ||
155 9900 : ((isVarTypedef(mb, varid)
156 9900 : || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE)))
157 9890 : && isVarConstant(mb, varid))
158 20418 : || (isaBatType(getVarType(mb, varid)) && idx < p->retc);
159 :
160 18630 : if (stk && isaBatType(getVarType(mb, varid))
161 1665 : && stk->stk[varid].val.bval) {
162 1663 : BAT *d = BBPquickdesc(stk->stk[varid].val.bval);
163 1663 : if (d)
164 1500 : 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 31178 : if ((flg & LIST_MAL_TYPE) || (idx < p->retc) || isVarTypedef(mb, varid)
173 16 : || showtype) {
174 31162 : strcat(buf + len, ":");
175 31162 : len++;
176 31162 : tpe = getTypeName(getVarType(mb, varid));
177 31162 : len += snprintf(buf + len, maxlen - len, "%s", tpe);
178 31162 : GDKfree(tpe);
179 : }
180 :
181 31178 : 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 9216 : instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
486 : {
487 9216 : int i, j;
488 9216 : str base, t;
489 9216 : size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */
490 9216 : str arg;
491 :
492 9216 : t = base = GDKmalloc(len);
493 9218 : if (base == NULL)
494 : return NULL;
495 9218 : if (!flg) {
496 1 : *t++ = '#';
497 1 : len--;
498 1 : if (!p->typeresolved) {
499 0 : *t++ = '!'; /* error */
500 0 : len--;
501 : }
502 : }
503 9218 : *t = 0;
504 9218 : if (p->token == REMsymbol
505 3382 : && !(getModuleId(p) && strcmp(getModuleId(p), "querylog") == 0
506 0 : && getFunctionId(p) && strcmp(getFunctionId(p), "define") == 0)) {
507 : /* do nothing */
508 5836 : } 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 5808 : } else if (functionStart(p) && flg != LIST_MAL_CALL) {
519 170 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
520 5638 : } else if (!functionExit(p) && flg != LIST_MAL_CALL) {
521 : // beautify with tabs
522 5464 : if (!copystring(&t, " ", &len))
523 : return base;
524 : }
525 9048 : switch (p->token < 0 ? -p->token : p->token) {
526 5492 : 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 5492 : if (p->retc > 1 && !copystring(&t, "(", &len))
544 : return base;
545 :
546 11114 : for (i = 0; i < p->retc; i++) {
547 5622 : arg = renderTerm(mb, stk, p, i, flg);
548 5622 : if (arg) {
549 5622 : if (!copystring(&t, arg, &len)) {
550 0 : GDKfree(arg);
551 0 : return base;
552 : }
553 5622 : GDKfree(arg);
554 : }
555 5622 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
556 : return base;
557 : }
558 5492 : if (p->retc > 1 && !copystring(&t, ")", &len))
559 : return base;
560 :
561 5492 : if (p->argc > p->retc || getFunctionId(p)) {
562 5480 : 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 2 : default:
585 2 : i = snprintf(t, len, " unknown symbol ?%d? ", p->token);
586 2 : if (i < 0 || (size_t) i >= len)
587 : return base;
588 2 : len -= (size_t) i;
589 2 : t += i;
590 2 : break;
591 : }
592 :
593 5662 : if (getModuleId(p)) {
594 5412 : if (!copystring(&t, getModuleId(p), &len) || !copystring(&t, ".", &len))
595 0 : return base;
596 : }
597 5661 : if (getFunctionId(p)) {
598 10823 : if (!copystring(&t, getFunctionId(p), &len) ||
599 5412 : !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 24459 : for (i = p->retc; i < p->argc; i++) {
606 18799 : arg = renderTerm(mb, stk, p, i, flg);
607 18800 : if (arg) {
608 18800 : if (!copystring(&t, arg, &len)) {
609 1 : GDKfree(arg);
610 1 : return base;
611 : }
612 18799 : GDKfree(arg);
613 : }
614 :
615 18799 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
616 : return base;
617 : }
618 5660 : if (getFunctionId(p) || p->argc > p->retc + 1) {
619 5411 : if (!copystring(&t, ")", &len))
620 : return base;
621 : }
622 5660 : if (p->token != REMsymbol) {
623 5660 : if (!copystring(&t, ";", &len))
624 : return base;
625 : }
626 : /* add the extra properties for debugging */
627 5660 : if (flg & LIST_MAL_PROPS) {
628 2370 : char extra[256];
629 2370 : if (p->token == REMsymbol) {
630 : } else {
631 1 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", p->pc,
632 2370 : getRowCnt(mb, getArg(p, 0)),
633 2370 : (p->blk ? p->blk->binding : ""));
634 2370 : if (!copystring(&t, extra, &len))
635 0 : return base;
636 4774 : for (j = 0; j < p->retc; j++) {
637 2404 : snprintf(extra, 256, "%d ", getArg(p, j));
638 2404 : if (!copystring(&t, extra, &len))
639 : return base;
640 : }
641 2370 : if (p->argc - p->retc > 0) {
642 2367 : if (!copystring(&t, "<- ", &len))
643 : return base;
644 : }
645 11913 : for (; j < p->argc; j++) {
646 9543 : snprintf(extra, 256, "%d ", getArg(p, j));
647 9543 : if (!copystring(&t, extra, &len))
648 : return base;
649 : }
650 2370 : if (!p->typeresolved) {
651 0 : if (!copystring(&t, " type check needed", &len))
652 : return base;
653 : }
654 : }
655 : }
656 5660 : if (flg & LIST_MAL_ALGO) {
657 806 : const char *algo = MT_thread_getalgorithm();
658 806 : if (algo) {
659 122 : if (!copystring(&t, " # ", &len))
660 : return base;
661 122 : 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 43138521 : traceInstruction(component_t comp, MalBlkPtr mb, MalStkPtr stk, InstrPtr p,
757 : int flg)
758 : {
759 43138521 : str ps;
760 43138521 : 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 43138521 : }
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 : }
|