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 3944509 : copystring(char **dstp, const char *src, size_t *lenp)
46 : {
47 3944509 : size_t len = *lenp;
48 3944509 : char *dst = *dstp;
49 :
50 3944509 : if (src == NULL)
51 : return true;
52 3944509 : if (len > 0) {
53 19173839 : while (*src && len > 1) {
54 15229293 : *dst++ = *src++;
55 15229293 : len--;
56 : }
57 3944546 : *dst = 0;
58 3944546 : *dstp = dst;
59 3944546 : *lenp = len;
60 : }
61 3944509 : return *src == 0;
62 : }
63 :
64 : static str
65 39603 : renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg)
66 : {
67 39603 : char *buf = 0;
68 39603 : int nameused = 0;
69 39603 : size_t len = 0, maxlen = BUFSIZ;
70 39603 : ValRecord *val = 0;
71 39603 : char *cv = 0;//, *c;
72 39603 : str tpe;
73 39603 : int showtype = 0, closequote = 0;
74 39603 : int varid = getArg(p, idx);
75 :
76 39603 : buf = GDKzalloc(maxlen);
77 39619 : 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 39619 : if ((flg & LIST_MAL_NAME) && !isVarConstant(mb, varid)
83 19065 : && !isVarTypedef(mb, varid)) {
84 19058 : char *nme = getVarNameIntoBuffer(mb, varid, buf);
85 19054 : len += strlen(nme);
86 19054 : nameused = 1;
87 : }
88 : // show the value when required or being a constant
89 39615 : if (((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb, varid)) {
90 22582 : if (nameused) {
91 2033 : strcat(buf + len, "=");
92 2033 : len++;
93 : }
94 :
95 : // locate value record
96 22582 : if (isVarConstant(mb, varid)) {
97 20543 : val = &getVarConstant(mb, varid);
98 20543 : showtype = getVarType(mb, varid) != TYPE_str
99 20543 : && getVarType(mb, varid) != TYPE_bit;
100 2039 : } else if (stk)
101 2039 : val = &stk->stk[varid];
102 :
103 22582 : if ((cv = VALformat(val)) == NULL) {
104 0 : addMalException(mb, "renderTerm:Failed to allocate");
105 0 : GDKfree(buf);
106 0 : return NULL;
107 : }
108 22570 : 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 22570 : if (!val->bat && strcmp(cv, "nil") == 0) {
121 212 : strcat(buf + len, cv);
122 212 : len += strlen(buf + len);
123 212 : GDKfree(cv);
124 212 : 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 220 : || isaBatType(getVarType(mb, varid));
129 : } else {
130 22358 : if (!isaBatType(getVarType(mb, varid))
131 20290 : && getBatType(getVarType(mb, varid)) >= TYPE_date
132 10638 : && 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 22358 : strcat(buf + len, cv);
145 22358 : len += strlen(buf + len);
146 : //}
147 22358 : GDKfree(cv);
148 :
149 22367 : if (closequote) {
150 280 : strcat(buf + len, "\"");
151 280 : len++;
152 : }
153 44734 : showtype = showtype || closequote > TYPE_str
154 13455 : ||
155 13455 : ((isVarTypedef(mb, varid)
156 13453 : || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE)))
157 13446 : && isVarConstant(mb, varid))
158 24410 : || (isaBatType(getVarType(mb, varid)) && idx < p->retc);
159 :
160 22367 : if (stk && isaBatType(getVarType(mb, varid))
161 1890 : && stk->stk[varid].val.bval) {
162 1890 : BAT *d = BBPquickdesc(stk->stk[varid].val.bval);
163 1889 : if (d)
164 1710 : 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 39611 : if ((flg & LIST_MAL_TYPE) || (idx < p->retc) || isVarTypedef(mb, varid)
173 16 : || showtype) {
174 39595 : strcat(buf + len, ":");
175 39595 : len++;
176 39595 : tpe = getTypeName(getVarType(mb, varid));
177 39591 : len += snprintf(buf + len, maxlen - len, "%s", tpe);
178 39591 : GDKfree(tpe);
179 : }
180 :
181 39613 : 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 162955 : cfcnDefinition(Symbol s, str t, int flg, str base, size_t len)
194 : {
195 162955 : unsigned int i;
196 162955 : str arg, tpe;
197 162955 : mel_func *f = s->func;
198 :
199 162955 : len -= t - base;
200 162955 : if (!flg && !copystring(&t, "#", &len))
201 : return base;
202 162955 : if (f->unsafe && !copystring(&t, "unsafe ", &len))
203 : return base;
204 325910 : if (!copystring(&t, operatorName(s->kind), &len) ||
205 325910 : !copystring(&t, " ", &len) ||
206 488865 : !copystring(&t, f->mod ? f->mod : "user", &len) ||
207 325910 : !copystring(&t, ".", &len) ||
208 325910 : !copystring(&t, f->fcn, &len) || !copystring(&t, "(", &len))
209 0 : return base;
210 :
211 162955 : char var[16];
212 618790 : for (i = f->retc; i < f->argc; i++) {
213 455835 : if (snprintf(var, 16, "X_%d:", i-f->retc) >= 16 || !copystring(&t, var, &len))
214 0 : return base;
215 715067 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
216 : return base;
217 455835 : arg = f->args[i].type;
218 455835 : if (arg[0] && !copystring(&t, arg, &len))
219 : return base;
220 455835 : if (!arg[0]) {
221 17298 : if (f->args[i].nr) {
222 15904 : 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 455835 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
228 : return base;
229 455835 : if (i+1 < f->argc && !copystring(&t, ", ", &len))
230 : return base;
231 : }
232 :
233 162955 : advance(t, base, len);
234 162955 : if (f->vargs && !copystring(&t, "...", &len))
235 : return base;
236 :
237 162955 : if (f->retc == 0) {
238 1554 : if (!copystring(&t, "):void", &len))
239 : return base;
240 161401 : } else if (f->retc == 1) {
241 157961 : if (!copystring(&t, "):", &len))
242 : return base;
243 266555 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, (f->args[0].opt == 1)?"bat?[:":"bat[:", &len))
244 : return base;
245 157961 : tpe = f->args[0].type;
246 157961 : if (tpe[0] && !copystring(&t, tpe, &len))
247 : return base;
248 157961 : 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 157961 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, "]", &len))
256 : return base;
257 157961 : if (f->vrets && !copystring(&t, "...", &len))
258 : return base;
259 : } else {
260 3440 : if (!copystring(&t, ") (", &len))
261 : return base;
262 14000 : for (i = 0; i < f->retc; i++) {
263 10560 : if (snprintf(var, 16, "X_%d:", i+(f->argc-f->retc)) >= 16 || !copystring(&t, var, &len))
264 0 : return base;
265 19648 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
266 : return base;
267 10560 : arg = f->args[i].type;
268 10560 : if (arg[0] && !copystring(&t, arg, &len))
269 : return base;
270 10560 : 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 10560 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
278 : return base;
279 10560 : if (i+1 < f->retc && !copystring(&t, ", ", &len))
280 : return base;
281 : }
282 3440 : if (f->vrets && !copystring(&t, "...", &len))
283 : return base;
284 3440 : if (!copystring(&t, ")", &len))
285 : return base;
286 : }
287 :
288 162955 : if (f->cname) {
289 325910 : if (!copystring(&t, " address ", &len) ||
290 162955 : !copystring(&t, f->cname, &len))
291 0 : return base;
292 : }
293 162955 : (void) copystring(&t, ";", &len);
294 162955 : return base;
295 : }
296 :
297 : str
298 193 : fcnDefinition(MalBlkPtr mb, InstrPtr p, str t, int flg, str base, size_t len)
299 : {
300 193 : int i, j;
301 193 : str arg, tpe;
302 :
303 193 : len -= t - base;
304 193 : if (!flg && !copystring(&t, "#", &len))
305 : return base;
306 193 : if (mb->inlineProp && !copystring(&t, "inline ", &len))
307 : return base;
308 193 : if (mb->unsafeProp && !copystring(&t, "unsafe ", &len))
309 : return base;
310 386 : if (!copystring(&t, operatorName(p->token), &len) ||
311 386 : !copystring(&t, " ", &len) ||
312 579 : !copystring(&t, getModuleId(p) ? getModuleId(p) : "user", &len) ||
313 386 : !copystring(&t, ".", &len) ||
314 386 : !copystring(&t, getFunctionId(p), &len) || !copystring(&t, "(", &len))
315 0 : return base;
316 :
317 197 : 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 193 : advance(t, base, len);
330 193 : if (p->varargs & VARARGS && !copystring(&t, "...", &len))
331 : return base;
332 :
333 193 : if (p->retc == 1) {
334 193 : if (!copystring(&t, "):", &len))
335 : return base;
336 193 : tpe = getTypeName(getVarType(mb, getArg(p, 0)));
337 193 : if (!copystring(&t, tpe, &len)) {
338 0 : GDKfree(tpe);
339 0 : return base;
340 : }
341 193 : GDKfree(tpe);
342 193 : 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 193 : if (mb->binding[0]) {
365 0 : if (!copystring(&t, " address ", &len) ||
366 0 : !copystring(&t, mb->binding, &len))
367 0 : return base;
368 : }
369 193 : (void) copystring(&t, ";", &len);
370 : /* add the extra properties for debugging */
371 193 : 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 3438 : fmtRemark(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, str t, int flg, str base,
405 : size_t len)
406 : {
407 3438 : char aux[128];
408 :
409 3438 : if (!copystring(&t, "# ", &len))
410 : return base;
411 :
412 3438 : if (pci->argc == 3) {
413 3434 : if (getFunctionId(pci)) {
414 3434 : char *arg1 = renderTerm(mb, stk, pci, 1, flg);
415 3434 : char *arg2 = renderTerm(mb, stk, pci, 2, flg);
416 3434 : if (arg1 && arg2) {
417 3434 : const char *f = getFunctionId(pci);
418 3434 : if (strcmp(f, "total") == 0)
419 130 : snprintf(aux, 128, "%d optimizers %ld usecs", atoi(arg1), atol(arg2));
420 : else
421 3304 : snprintf(aux, 128, "%-36s %d actions %ld usecs", f, atoi(arg1), atol(arg2));
422 3434 : (void) copystring(&t, aux, &len);
423 : }
424 3434 : GDKfree(arg1);
425 3434 : 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 163257 : operatorName(int i)
443 : {
444 163257 : 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 234 : case FUNCTIONsymbol:
464 234 : return "function";
465 25889 : case COMMANDsymbol:
466 25889 : return "command";
467 137066 : case PATTERNsymbol:
468 137066 : 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 10984 : instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
486 : {
487 10984 : int i, j;
488 10984 : str base, t;
489 10984 : size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */
490 10984 : str arg;
491 :
492 10984 : t = base = GDKmalloc(len);
493 10998 : if (base == NULL)
494 : return NULL;
495 10998 : if (!flg) {
496 1 : *t++ = '#';
497 1 : len--;
498 1 : if (!p->typeresolved) {
499 0 : *t++ = '!'; /* error */
500 0 : len--;
501 : }
502 : }
503 10998 : *t = 0;
504 10998 : if (p->token == REMsymbol
505 3448 : && !(getModuleId(p) && strcmp(getModuleId(p), "querylog") == 0
506 0 : && getFunctionId(p) && strcmp(getFunctionId(p), "define") == 0)) {
507 : /* do nothing */
508 7550 : } 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 7522 : } else if (functionStart(p) && flg != LIST_MAL_CALL) {
519 172 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
520 7350 : } else if (!functionExit(p) && flg != LIST_MAL_CALL) {
521 : // beautify with tabs
522 7174 : if (!copystring(&t, " ", &len))
523 : return base;
524 : }
525 10824 : switch (p->token < 0 ? -p->token : p->token) {
526 7203 : 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 7203 : if (p->retc > 1 && !copystring(&t, "(", &len))
544 : return base;
545 :
546 14548 : for (i = 0; i < p->retc; i++) {
547 7344 : arg = renderTerm(mb, stk, p, i, flg);
548 7342 : if (arg) {
549 7342 : if (!copystring(&t, arg, &len)) {
550 0 : GDKfree(arg);
551 0 : return base;
552 : }
553 7342 : GDKfree(arg);
554 : }
555 7345 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
556 : return base;
557 : }
558 7204 : if (p->retc > 1 && !copystring(&t, ")", &len))
559 : return base;
560 :
561 7204 : if (p->argc > p->retc || getFunctionId(p)) {
562 7192 : if (!copystring(&t, " := ", &len))
563 : return base;
564 : }
565 : break;
566 171 : case ENDsymbol:
567 342 : if (!copystring(&t, "end ", &len) ||
568 342 : !copystring(&t, getModuleId(getInstrPtr(mb, 0)), &len) ||
569 342 : !copystring(&t, ".", &len) ||
570 171 : !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 3438 : case REMsymbol:
583 3438 : return fmtRemark(mb, stk, p, t, flg, base, len);
584 7 : default:
585 7 : i = snprintf(t, len, " unknown symbol ?%d? ", p->token);
586 7 : if (i < 0 || (size_t) i >= len)
587 : return base;
588 7 : len -= (size_t) i;
589 7 : t += i;
590 7 : break;
591 : }
592 :
593 7378 : if (getModuleId(p)) {
594 7122 : if (!copystring(&t, getModuleId(p), &len) || !copystring(&t, ".", &len))
595 0 : return base;
596 : }
597 7376 : if (getFunctionId(p)) {
598 14245 : if (!copystring(&t, getFunctionId(p), &len) ||
599 7125 : !copystring(&t, "(", &len))
600 0 : return base;
601 251 : } else if (p->argc > p->retc + 1) {
602 0 : if (!copystring(&t, "(", &len))
603 : return base;
604 : }
605 32767 : for (i = p->retc; i < p->argc; i++) {
606 25393 : arg = renderTerm(mb, stk, p, i, flg);
607 25395 : if (arg) {
608 25395 : if (!copystring(&t, arg, &len)) {
609 1 : GDKfree(arg);
610 1 : return base;
611 : }
612 25396 : GDKfree(arg);
613 : }
614 :
615 25396 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
616 : return base;
617 : }
618 7374 : if (getFunctionId(p) || p->argc > p->retc + 1) {
619 7123 : if (!copystring(&t, ")", &len))
620 : return base;
621 : }
622 7374 : if (p->token != REMsymbol) {
623 7375 : if (!copystring(&t, ";", &len))
624 : return base;
625 : }
626 : /* add the extra properties for debugging */
627 7374 : if (flg & LIST_MAL_PROPS) {
628 3965 : char extra[256];
629 3965 : if (p->token == REMsymbol) {
630 : } else {
631 1 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", p->pc,
632 3965 : getRowCnt(mb, getArg(p, 0)),
633 3965 : (p->blk ? p->blk->binding : ""));
634 3965 : if (!copystring(&t, extra, &len))
635 0 : return base;
636 7964 : for (j = 0; j < p->retc; j++) {
637 3999 : snprintf(extra, 256, "%d ", getArg(p, j));
638 3999 : if (!copystring(&t, extra, &len))
639 : return base;
640 : }
641 3965 : if (p->argc - p->retc > 0) {
642 3962 : if (!copystring(&t, "<- ", &len))
643 : return base;
644 : }
645 19765 : for (; j < p->argc; j++) {
646 15800 : snprintf(extra, 256, "%d ", getArg(p, j));
647 15800 : if (!copystring(&t, extra, &len))
648 : return base;
649 : }
650 3965 : if (!p->typeresolved) {
651 0 : if (!copystring(&t, " type check needed", &len))
652 : return base;
653 : }
654 : }
655 : }
656 7374 : if (flg & LIST_MAL_ALGO) {
657 905 : const char *algo = MT_thread_getalgorithm();
658 902 : 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 3054 : printInstruction(stream *fd, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
739 : {
740 3054 : str ps;
741 :
742 3054 : if (fd == 0)
743 : return;
744 3054 : ps = instruction2str(mb, stk, p, flg);
745 : /* ps[strlen(ps)-1] = 0; remove '\n' */
746 3054 : if (ps) {
747 3094 : mnstr_printf(fd, "%s%s", (flg & LIST_MAL_MAPI ? "=" : ""), ps);
748 3054 : GDKfree(ps);
749 : } else {
750 0 : mnstr_printf(fd, "#failed instruction2str()");
751 : }
752 3054 : mnstr_printf(fd, "\n");
753 : }
754 :
755 : void
756 96329870 : traceInstruction(component_t comp, MalBlkPtr mb, MalStkPtr stk, InstrPtr p,
757 : int flg)
758 : {
759 96329870 : str ps;
760 96329870 : 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 96329870 : }
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 : }
|