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 2917095 : copystring(char **dstp, const char *src, size_t *lenp)
46 : {
47 2917095 : size_t len = *lenp;
48 2917095 : char *dst = *dstp;
49 :
50 2917095 : if (src == NULL)
51 : return true;
52 2917095 : if (len > 0) {
53 14145146 : while (*src && len > 1) {
54 11228000 : *dst++ = *src++;
55 11228000 : len--;
56 : }
57 2917146 : *dst = 0;
58 2917146 : *dstp = dst;
59 2917146 : *lenp = len;
60 : }
61 2917095 : return *src == 0;
62 : }
63 :
64 : static str
65 23234 : renderTerm(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int idx, int flg)
66 : {
67 23234 : char *buf = 0;
68 23234 : int nameused = 0;
69 23234 : size_t len = 0, maxlen = BUFSIZ;
70 23234 : ValRecord *val = 0;
71 23234 : char *cv = 0;//, *c;
72 23234 : str tpe;
73 23234 : int showtype = 0, closequote = 0;
74 23234 : int varid = getArg(p, idx);
75 :
76 23234 : buf = GDKzalloc(maxlen);
77 23244 : 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 23244 : if ((flg & LIST_MAL_NAME) && !isVarConstant(mb, varid)
83 9335 : && !isVarTypedef(mb, varid)) {
84 9329 : char *nme = getVarNameIntoBuffer(mb, varid, buf);
85 9327 : len += strlen(nme);
86 9327 : nameused = 1;
87 : }
88 : // show the value when required or being a constant
89 23242 : if (((flg & LIST_MAL_VALUE) && stk != 0) || isVarConstant(mb, varid)) {
90 16003 : if (nameused) {
91 2098 : strcat(buf + len, "=");
92 2098 : len++;
93 : }
94 :
95 : // locate value record
96 16003 : if (isVarConstant(mb, varid)) {
97 13902 : val = &getVarConstant(mb, varid);
98 13902 : showtype = getVarType(mb, varid) != TYPE_str
99 13902 : && getVarType(mb, varid) != TYPE_bit;
100 2101 : } else if (stk)
101 2101 : val = &stk->stk[varid];
102 :
103 16003 : if ((cv = VALformat(val)) == NULL) {
104 0 : addMalException(mb, "renderTerm:Failed to allocate");
105 0 : GDKfree(buf);
106 0 : return NULL;
107 : }
108 15995 : 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 15995 : if (!val->bat && strcmp(cv, "nil") == 0) {
121 213 : strcat(buf + len, cv);
122 213 : len += strlen(buf + len);
123 213 : GDKfree(cv);
124 213 : 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 221 : || isaBatType(getVarType(mb, varid));
129 : } else {
130 15782 : if (!isaBatType(getVarType(mb, varid))
131 13628 : && getBatType(getVarType(mb, varid)) >= TYPE_date
132 4210 : && getBatType(getVarType(mb, varid)) != TYPE_str) {
133 276 : closequote = 1;
134 276 : strcat(buf + len, "\"");
135 276 : 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 15782 : strcat(buf + len, cv);
145 15782 : len += strlen(buf + len);
146 : //}
147 15782 : GDKfree(cv);
148 :
149 15785 : if (closequote) {
150 276 : strcat(buf + len, "\"");
151 276 : len++;
152 : }
153 31570 : showtype = showtype || closequote > TYPE_str
154 7102 : ||
155 7102 : ((isVarTypedef(mb, varid)
156 7100 : || (flg & (LIST_MAL_REMOTE | LIST_MAL_TYPE)))
157 7094 : && isVarConstant(mb, varid))
158 17893 : || (isaBatType(getVarType(mb, varid)) && idx < p->retc);
159 :
160 15785 : if (stk && isaBatType(getVarType(mb, varid))
161 1973 : && stk->stk[varid].val.bval) {
162 1970 : BAT *d = BBPquickdesc(stk->stk[varid].val.bval);
163 1967 : if (d)
164 1781 : 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 23234 : if ((flg & LIST_MAL_TYPE) || (idx < p->retc) || isVarTypedef(mb, varid)
173 16 : || showtype) {
174 23218 : strcat(buf + len, ":");
175 23218 : len++;
176 23218 : tpe = getTypeName(getVarType(mb, varid));
177 23224 : len += snprintf(buf + len, maxlen - len, "%s", tpe);
178 23224 : GDKfree(tpe);
179 : }
180 :
181 23240 : 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 122187 : cfcnDefinition(Symbol s, str t, int flg, str base, size_t len)
194 : {
195 122187 : unsigned int i;
196 122187 : str arg, tpe;
197 122187 : mel_func *f = s->func;
198 :
199 122187 : len -= t - base;
200 122187 : if (!flg && !copystring(&t, "#", &len))
201 : return base;
202 122187 : if (f->unsafe && !copystring(&t, "unsafe ", &len))
203 : return base;
204 244374 : if (!copystring(&t, operatorName(s->kind), &len) ||
205 244374 : !copystring(&t, " ", &len) ||
206 366561 : !copystring(&t, f->mod ? f->mod : "user", &len) ||
207 244374 : !copystring(&t, ".", &len) ||
208 244374 : !copystring(&t, f->fcn, &len) || !copystring(&t, "(", &len))
209 0 : return base;
210 :
211 122187 : char var[16];
212 463302 : for (i = f->retc; i < f->argc; i++) {
213 341115 : if (snprintf(var, 16, "X_%d:", i-f->retc) >= 16 || !copystring(&t, var, &len))
214 0 : return base;
215 535455 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
216 : return base;
217 341115 : arg = f->args[i].type;
218 341115 : if (arg[0] && !copystring(&t, arg, &len))
219 : return base;
220 341115 : if (!arg[0]) {
221 12990 : if (f->args[i].nr) {
222 11940 : if (snprintf(var, 16, "any_%d", f->args[i].nr ) >= 16 || !copystring(&t, var, &len))
223 0 : return base;
224 1050 : } else if (!copystring(&t, "any", &len))
225 : return base;
226 : }
227 341115 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
228 : return base;
229 341115 : if (i+1 < f->argc && !copystring(&t, ", ", &len))
230 : return base;
231 : }
232 :
233 122187 : advance(t, base, len);
234 122187 : if (f->vargs && !copystring(&t, "...", &len))
235 : return base;
236 :
237 122187 : if (f->retc == 0) {
238 1142 : if (!copystring(&t, "):void", &len))
239 : return base;
240 121045 : } else if (f->retc == 1) {
241 118477 : if (!copystring(&t, "):", &len))
242 : return base;
243 199803 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, (f->args[0].opt == 1)?"bat?[:":"bat[:", &len))
244 : return base;
245 118477 : tpe = f->args[0].type;
246 118477 : if (tpe[0] && !copystring(&t, tpe, &len))
247 : return base;
248 118477 : if (!tpe[0]) {
249 1993 : if (f->args[0].nr) {
250 1850 : if (snprintf(var, 16, "any_%d", f->args[0].nr ) >= 16 || !copystring(&t, var, &len))
251 0 : return base;
252 143 : } else if (!copystring(&t, "any", &len))
253 : return base;
254 : }
255 118477 : if ((f->args[0].isbat || f->args[0].opt == 1) && !copystring(&t, "]", &len))
256 : return base;
257 118477 : if (f->vrets && !copystring(&t, "...", &len))
258 : return base;
259 : } else {
260 2568 : if (!copystring(&t, ") (", &len))
261 : return base;
262 10380 : for (i = 0; i < f->retc; i++) {
263 7812 : if (snprintf(var, 16, "X_%d:", i+(f->argc-f->retc)) >= 16 || !copystring(&t, var, &len))
264 0 : return base;
265 14520 : if ((f->args[i].isbat || (f->args[i].opt == 1)) && !copystring(&t, (f->args[i].opt == 1)?"bat?[:":"bat[:", &len))
266 : return base;
267 7812 : arg = f->args[i].type;
268 7812 : if (arg[0] && !copystring(&t, arg, &len))
269 : return base;
270 7812 : if (!arg[0]) {
271 264 : if (f->args[i].nr) {
272 228 : if (snprintf(var, 16, "any_%d", f->args[i].nr ) >= 16 || !copystring(&t, var, &len))
273 0 : return base;
274 36 : } else if (!copystring(&t, "any", &len))
275 : return base;
276 : }
277 7812 : if ((f->args[i].isbat || f->args[i].opt == 1) && !copystring(&t, "]", &len))
278 : return base;
279 7812 : if (i+1 < f->retc && !copystring(&t, ", ", &len))
280 : return base;
281 : }
282 2568 : if (f->vrets && !copystring(&t, "...", &len))
283 : return base;
284 2568 : if (!copystring(&t, ")", &len))
285 : return base;
286 : }
287 :
288 122187 : if (f->cname) {
289 244374 : if (!copystring(&t, " address ", &len) ||
290 122187 : !copystring(&t, f->cname, &len))
291 0 : return base;
292 : }
293 122187 : (void) copystring(&t, ";", &len);
294 122187 : return base;
295 : }
296 :
297 : str
298 185 : fcnDefinition(MalBlkPtr mb, InstrPtr p, str t, int flg, str base, size_t len)
299 : {
300 185 : int i, j;
301 185 : str arg, tpe;
302 :
303 185 : len -= t - base;
304 185 : if (!flg && !copystring(&t, "#", &len))
305 : return base;
306 185 : if (mb->inlineProp && !copystring(&t, "inline ", &len))
307 : return base;
308 185 : if (mb->unsafeProp && !copystring(&t, "unsafe ", &len))
309 : return base;
310 370 : if (!copystring(&t, operatorName(p->token), &len) ||
311 370 : !copystring(&t, " ", &len) ||
312 555 : !copystring(&t, getModuleId(p) ? getModuleId(p) : "user", &len) ||
313 370 : !copystring(&t, ".", &len) ||
314 370 : !copystring(&t, getFunctionId(p), &len) || !copystring(&t, "(", &len))
315 0 : return base;
316 :
317 189 : 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 185 : advance(t, base, len);
330 185 : if (p->varargs & VARARGS && !copystring(&t, "...", &len))
331 : return base;
332 :
333 185 : if (p->retc == 1) {
334 185 : if (!copystring(&t, "):", &len))
335 : return base;
336 185 : tpe = getTypeName(getVarType(mb, getArg(p, 0)));
337 185 : if (!copystring(&t, tpe, &len)) {
338 0 : GDKfree(tpe);
339 0 : return base;
340 : }
341 185 : GDKfree(tpe);
342 185 : 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 185 : if (mb->binding[0]) {
365 0 : if (!copystring(&t, " address ", &len) ||
366 0 : !copystring(&t, mb->binding, &len))
367 0 : return base;
368 : }
369 185 : (void) copystring(&t, ";", &len);
370 : /* add the extra properties for debugging */
371 185 : 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 3322 : fmtRemark(MalBlkPtr mb, MalStkPtr stk, InstrPtr pci, str t, int flg, str base,
405 : size_t len)
406 : {
407 3322 : char aux[128];
408 :
409 3322 : if (!copystring(&t, "# ", &len))
410 : return base;
411 :
412 3322 : if (pci->argc == 3) {
413 3318 : if (getFunctionId(pci)) {
414 3318 : char *arg1 = renderTerm(mb, stk, pci, 1, flg);
415 3318 : char *arg2 = renderTerm(mb, stk, pci, 2, flg);
416 3318 : if (arg1 && arg2) {
417 3318 : const char *f = getFunctionId(pci);
418 3318 : if (strcmp(f, "total") == 0)
419 126 : snprintf(aux, 128, "%d optimizers %ld usecs", atoi(arg1), atol(arg2));
420 : else
421 3192 : snprintf(aux, 128, "%-36s %d actions %ld usecs", f, atoi(arg1), atol(arg2));
422 3318 : (void) copystring(&t, aux, &len);
423 : }
424 3318 : GDKfree(arg1);
425 3318 : 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 122481 : operatorName(int i)
443 : {
444 122481 : 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 226 : case FUNCTIONsymbol:
464 226 : return "function";
465 19585 : case COMMANDsymbol:
466 19585 : return "command";
467 102602 : case PATTERNsymbol:
468 102602 : 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 7625 : instruction2str(MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
486 : {
487 7625 : int i, j;
488 7625 : str base, t;
489 7625 : size_t len = 512 + (p->argc * 128); /* max realistic line length estimate */
490 7625 : str arg;
491 :
492 7625 : t = base = GDKmalloc(len);
493 7648 : if (base == NULL)
494 : return NULL;
495 7648 : if (!flg) {
496 1 : *t++ = '#';
497 1 : len--;
498 1 : if (!p->typeresolved) {
499 0 : *t++ = '!'; /* error */
500 0 : len--;
501 : }
502 : }
503 7648 : *t = 0;
504 7648 : if (p->token == REMsymbol
505 3341 : && !(getModuleId(p) && strcmp(getModuleId(p), "querylog") == 0
506 0 : && getFunctionId(p) && strcmp(getFunctionId(p), "define") == 0)) {
507 : /* do nothing */
508 4307 : } 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 4279 : } else if (functionStart(p) && flg != LIST_MAL_CALL) {
519 168 : return fcnDefinition(mb, p, t, flg, base, len + (t - base));
520 4111 : } else if (!functionExit(p) && flg != LIST_MAL_CALL) {
521 : // beautify with tabs
522 3939 : if (!copystring(&t, " ", &len))
523 : return base;
524 : }
525 7477 : switch (p->token < 0 ? -p->token : p->token) {
526 3971 : 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 3971 : if (p->retc > 1 && !copystring(&t, "(", &len))
544 : return base;
545 :
546 8092 : for (i = 0; i < p->retc; i++) {
547 4120 : arg = renderTerm(mb, stk, p, i, flg);
548 4119 : if (arg) {
549 4119 : if (!copystring(&t, arg, &len)) {
550 0 : GDKfree(arg);
551 0 : return base;
552 : }
553 4122 : GDKfree(arg);
554 : }
555 4121 : if (i < p->retc - 1 && !copystring(&t, ", ", &len))
556 : return base;
557 : }
558 3972 : if (p->retc > 1 && !copystring(&t, ")", &len))
559 : return base;
560 :
561 3971 : if (p->argc > p->retc || getFunctionId(p)) {
562 3959 : if (!copystring(&t, " := ", &len))
563 : return base;
564 : }
565 : break;
566 167 : case ENDsymbol:
567 334 : if (!copystring(&t, "end ", &len) ||
568 334 : !copystring(&t, getModuleId(getInstrPtr(mb, 0)), &len) ||
569 334 : !copystring(&t, ".", &len) ||
570 167 : !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 3322 : case REMsymbol:
583 3322 : return fmtRemark(mb, stk, p, t, flg, base, len);
584 12 : default:
585 12 : i = snprintf(t, len, " unknown symbol ?%d? ", p->token);
586 12 : if (i < 0 || (size_t) i >= len)
587 : return base;
588 12 : len -= (size_t) i;
589 12 : t += i;
590 12 : break;
591 : }
592 :
593 4140 : if (getModuleId(p)) {
594 3886 : if (!copystring(&t, getModuleId(p), &len) || !copystring(&t, ".", &len))
595 0 : return base;
596 : }
597 4139 : if (getFunctionId(p)) {
598 7772 : if (!copystring(&t, getFunctionId(p), &len) ||
599 3888 : !copystring(&t, "(", &len))
600 0 : return base;
601 247 : } else if (p->argc > p->retc + 1) {
602 0 : if (!copystring(&t, "(", &len))
603 : return base;
604 : }
605 16610 : for (i = p->retc; i < p->argc; i++) {
606 12471 : arg = renderTerm(mb, stk, p, i, flg);
607 12477 : if (arg) {
608 12477 : if (!copystring(&t, arg, &len)) {
609 1 : GDKfree(arg);
610 1 : return base;
611 : }
612 12477 : GDKfree(arg);
613 : }
614 :
615 12483 : if (i < p->argc - 1 && !copystring(&t, ", ", &len))
616 : return base;
617 : }
618 4139 : if (getFunctionId(p) || p->argc > p->retc + 1) {
619 3892 : if (!copystring(&t, ")", &len))
620 : return base;
621 : }
622 4138 : if (p->token != REMsymbol) {
623 4139 : if (!copystring(&t, ";", &len))
624 : return base;
625 : }
626 : /* add the extra properties for debugging */
627 4136 : if (flg & LIST_MAL_PROPS) {
628 793 : char extra[256];
629 793 : if (p->token == REMsymbol) {
630 : } else {
631 1 : snprintf(extra, 256, "\t#[%d] (" BUNFMT ") %s ", p->pc,
632 793 : getRowCnt(mb, getArg(p, 0)),
633 793 : (p->blk ? p->blk->binding : ""));
634 793 : if (!copystring(&t, extra, &len))
635 0 : return base;
636 1620 : for (j = 0; j < p->retc; j++) {
637 827 : snprintf(extra, 256, "%d ", getArg(p, j));
638 827 : if (!copystring(&t, extra, &len))
639 : return base;
640 : }
641 793 : if (p->argc - p->retc > 0) {
642 790 : if (!copystring(&t, "<- ", &len))
643 : return base;
644 : }
645 3823 : for (; j < p->argc; j++) {
646 3030 : snprintf(extra, 256, "%d ", getArg(p, j));
647 3030 : if (!copystring(&t, extra, &len))
648 : return base;
649 : }
650 793 : if (!p->typeresolved) {
651 0 : if (!copystring(&t, " type check needed", &len))
652 : return base;
653 : }
654 : }
655 : }
656 4136 : if (flg & LIST_MAL_ALGO) {
657 926 : const char *algo = MT_thread_getalgorithm();
658 925 : if (algo) {
659 159 : if (!copystring(&t, " # ", &len))
660 : return base;
661 159 : 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 2944 : printInstruction(stream *fd, MalBlkPtr mb, MalStkPtr stk, InstrPtr p, int flg)
739 : {
740 2944 : str ps;
741 :
742 2944 : if (fd == 0)
743 : return;
744 2944 : ps = instruction2str(mb, stk, p, flg);
745 : /* ps[strlen(ps)-1] = 0; remove '\n' */
746 2944 : if (ps) {
747 2984 : mnstr_printf(fd, "%s%s", (flg & LIST_MAL_MAPI ? "=" : ""), ps);
748 2944 : GDKfree(ps);
749 : } else {
750 0 : mnstr_printf(fd, "#failed instruction2str()");
751 : }
752 2944 : mnstr_printf(fd, "\n");
753 : }
754 :
755 : void
756 90580319 : traceInstruction(component_t comp, MalBlkPtr mb, MalStkPtr stk, InstrPtr p,
757 : int flg)
758 : {
759 90580319 : str ps;
760 90580319 : 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 90580319 : }
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 : }
|