LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_parser.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 987 1242 79.5 %
Date: 2024-04-25 20:03:45 Functions: 35 35 100.0 %

          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             : /* (c): M. L. Kersten
      14             : */
      15             : 
      16             : #include "monetdb_config.h"
      17             : #include "mal_parser.h"
      18             : #include "mal_resolve.h"
      19             : #include "mal_linker.h"
      20             : #include "mal_atom.h"                 /* for malAtomDefinition(), malAtomProperty() */
      21             : #include "mal_interpreter.h"  /* for showErrors() */
      22             : #include "mal_instruction.h"  /* for pushEndInstruction(), findVariableLength() */
      23             : #include "mal_namespace.h"
      24             : #include "mal_utils.h"
      25             : #include "mal_builder.h"
      26             : #include "mal_type.h"
      27             : #include "mal_session.h"
      28             : #include "mal_private.h"
      29             : 
      30             : #define FATALINPUT (MAXERRORS+1)
      31             : #define NL(X) ((X)=='\n' || (X)=='\r')
      32             : 
      33             : static str idCopy(Client cntxt, int len);
      34             : static str strCopy(Client cntxt, int len);
      35             : 
      36             : /*
      37             :  * For error reporting we may have to find the start of the previous line,
      38             :  * which, ofcourse, is easy given the client buffer.
      39             :  * The remaining functions are self-explanatory.
      40             : */
      41             : static str
      42         142 : lastline(Client cntxt)
      43             : {
      44         142 :         str s = CURRENT(cntxt);
      45         142 :         if (NL(*s))
      46           4 :                 s++;
      47         592 :         while (s > cntxt->fdin->buf && !NL(*s))
      48         450 :                 s--;
      49         142 :         if (NL(*s))
      50         128 :                 s++;
      51         142 :         return s;
      52             : }
      53             : 
      54             : static ssize_t
      55          71 : position(Client cntxt)
      56             : {
      57          71 :         str s = lastline(cntxt);
      58          71 :         return (ssize_t) (CURRENT(cntxt) - s);
      59             : }
      60             : 
      61             : /*
      62             :  * Upon encountering an error we skip to the nearest semicolon,
      63             :  * or comment terminated by a new line
      64             :  */
      65             : static inline void
      66        9499 : skipToEnd(Client cntxt)
      67             : {
      68        9499 :         char c;
      69        9869 :         while ((c = *CURRENT(cntxt)) != ';' && c && c != '\n')
      70         370 :                 nextChar(cntxt);
      71        9499 :         if (c && c != '\n')
      72        9413 :                 nextChar(cntxt);
      73        9499 : }
      74             : 
      75             : /*
      76             :  * Keep on syntax error for reflection and correction.
      77             :  */
      78             : static void
      79          71 : parseError(Client cntxt, str msg)
      80             : {
      81          71 :         MalBlkPtr mb;
      82          71 :         char *old, *new;
      83          71 :         char buf[1028] = { 0 };
      84          71 :         char *s = buf, *t, *line = "", *marker = "";
      85          71 :         char *l = lastline(cntxt);
      86          71 :         ssize_t i;
      87             : 
      88          71 :         if (cntxt->backup) {
      89           5 :                 freeSymbol(cntxt->curprg);
      90           5 :                 cntxt->curprg = cntxt->backup;
      91           5 :                 cntxt->backup = 0;
      92             :         }
      93             : 
      94          71 :         mb = cntxt->curprg->def;
      95          71 :         s = buf;
      96         680 :         for (t = l; *t && *t != '\n' && s < buf + sizeof(buf) - 4; t++) {
      97         609 :                 *s++ = *t;
      98             :         }
      99          71 :         *s++ = '\n';
     100          71 :         *s = 0;
     101          71 :         line = createException(SYNTAX, "parseError", "%s", buf);
     102             : 
     103             :         /* produce the position marker */
     104          71 :         s = buf;
     105          71 :         i = position(cntxt);
     106         232 :         for (; i > 0 && s < buf + sizeof(buf) - 4; i--) {
     107         165 :                 *s++ = ((l && *(l + 1) && *l++ != '\t')) ? ' ' : '\t';
     108             :         }
     109          71 :         *s++ = '^';
     110          71 :         *s = 0;
     111          71 :         marker = createException(SYNTAX, "parseError", "%s%s", buf, msg);
     112             : 
     113          71 :         old = mb->errors;
     114          71 :         new = GDKzalloc((old ? strlen(old) : 0) + strlen(line) + strlen(marker) +
     115             :                                         64);
     116          71 :         if (new == NULL) {
     117           0 :                 freeException(line);
     118           0 :                 freeException(marker);
     119           0 :                 skipToEnd(cntxt);
     120           0 :                 return;                                 // just stick to old error message
     121             :         }
     122          71 :         if (old) {
     123          24 :                 strcpy(new, old);
     124          24 :                 GDKfree(old);
     125             :         }
     126          71 :         strcat(new, line);
     127          71 :         strcat(new, marker);
     128             : 
     129          71 :         mb->errors = new;
     130          71 :         freeException(line);
     131          71 :         freeException(marker);
     132          71 :         skipToEnd(cntxt);
     133             : }
     134             : 
     135             : /* Before a line is parsed we check for a request to echo it.
     136             :  * This command should be executed at the beginning of a parse
     137             :  * request and each time we encounter EOL.
     138             : */
     139             : static void
     140       24322 : echoInput(Client cntxt)
     141             : {
     142       24322 :         char *c = CURRENT(cntxt);
     143       24322 :         if (cntxt->listing == 1 && *c && !NL(*c)) {
     144           0 :                 mnstr_printf(cntxt->fdout, "#");
     145           0 :                 while (*c && !NL(*c)) {
     146           0 :                         mnstr_printf(cntxt->fdout, "%c", *c++);
     147             :                 }
     148           0 :                 mnstr_printf(cntxt->fdout, "\n");
     149             :         }
     150       24322 : }
     151             : 
     152             : static inline void
     153      216463 : skipSpace(Client cntxt)
     154             : {
     155      216463 :         char *s = &currChar(cntxt);
     156      254523 :         for (;;) {
     157      235493 :                 switch (*s++) {
     158       19030 :                 case ' ':
     159             :                 case '\t':
     160             :                 case '\n':
     161             :                 case '\r':
     162       19030 :                         nextChar(cntxt);
     163       19030 :                         break;
     164             :                 default:
     165      216463 :                         return;
     166             :                 }
     167             :         }
     168             : }
     169             : 
     170             : static inline void
     171       86828 : advance(Client cntxt, size_t length)
     172             : {
     173       86828 :         cntxt->yycur += length;
     174       86828 :         skipSpace(cntxt);
     175       27754 : }
     176             : 
     177             : /*
     178             :  * The most recurring situation is to recognize identifiers.
     179             :  * This process is split into a few steps to simplify subsequent
     180             :  * construction and comparison.
     181             :  * IdLength searches the end of an identifier without changing
     182             :  * the cursor into the input pool.
     183             :  * IdCopy subsequently prepares a GDK string for inclusion in the
     184             :  * instruction datastructures.
     185             : */
     186             : 
     187             : static const bool opCharacter[256] = {
     188             :         ['$'] = true,
     189             :         ['!'] = true,
     190             :         ['%'] = true,
     191             :         ['&'] = true,
     192             :         ['*'] = true,
     193             :         ['+'] = true,
     194             :         ['-'] = true,
     195             :         ['/'] = true,
     196             :         [':'] = true,
     197             :         ['<'] = true,
     198             :         ['='] = true,
     199             :         ['>'] = true,
     200             :         ['\\'] = true,
     201             :         ['^'] = true,
     202             :         ['|'] = true,
     203             :         ['~'] = true,
     204             : };
     205             : 
     206             : static const bool idCharacter[256] = {
     207             :         ['a'] = true,
     208             :         ['b'] = true,
     209             :         ['c'] = true,
     210             :         ['d'] = true,
     211             :         ['e'] = true,
     212             :         ['f'] = true,
     213             :         ['g'] = true,
     214             :         ['h'] = true,
     215             :         ['i'] = true,
     216             :         ['j'] = true,
     217             :         ['k'] = true,
     218             :         ['l'] = true,
     219             :         ['m'] = true,
     220             :         ['n'] = true,
     221             :         ['o'] = true,
     222             :         ['p'] = true,
     223             :         ['q'] = true,
     224             :         ['r'] = true,
     225             :         ['s'] = true,
     226             :         ['t'] = true,
     227             :         ['u'] = true,
     228             :         ['v'] = true,
     229             :         ['w'] = true,
     230             :         ['x'] = true,
     231             :         ['y'] = true,
     232             :         ['z'] = true,
     233             :         ['A'] = true,
     234             :         ['B'] = true,
     235             :         ['C'] = true,
     236             :         ['D'] = true,
     237             :         ['E'] = true,
     238             :         ['F'] = true,
     239             :         ['G'] = true,
     240             :         ['H'] = true,
     241             :         ['I'] = true,
     242             :         ['J'] = true,
     243             :         ['K'] = true,
     244             :         ['L'] = true,
     245             :         ['M'] = true,
     246             :         ['N'] = true,
     247             :         ['O'] = true,
     248             :         ['P'] = true,
     249             :         ['Q'] = true,
     250             :         ['R'] = true,
     251             :         ['S'] = true,
     252             :         ['T'] = true,
     253             :         ['U'] = true,
     254             :         ['V'] = true,
     255             :         ['W'] = true,
     256             :         ['X'] = true,
     257             :         ['Y'] = true,
     258             :         ['Z'] = true,
     259             :         [TMPMARKER] = true,
     260             : };
     261             : 
     262             : static const bool idCharacter2[256] = {
     263             :         ['a'] = true,
     264             :         ['b'] = true,
     265             :         ['c'] = true,
     266             :         ['d'] = true,
     267             :         ['e'] = true,
     268             :         ['f'] = true,
     269             :         ['g'] = true,
     270             :         ['h'] = true,
     271             :         ['i'] = true,
     272             :         ['j'] = true,
     273             :         ['k'] = true,
     274             :         ['l'] = true,
     275             :         ['m'] = true,
     276             :         ['n'] = true,
     277             :         ['o'] = true,
     278             :         ['p'] = true,
     279             :         ['q'] = true,
     280             :         ['r'] = true,
     281             :         ['s'] = true,
     282             :         ['t'] = true,
     283             :         ['u'] = true,
     284             :         ['v'] = true,
     285             :         ['w'] = true,
     286             :         ['x'] = true,
     287             :         ['y'] = true,
     288             :         ['z'] = true,
     289             :         ['A'] = true,
     290             :         ['B'] = true,
     291             :         ['C'] = true,
     292             :         ['D'] = true,
     293             :         ['E'] = true,
     294             :         ['F'] = true,
     295             :         ['G'] = true,
     296             :         ['H'] = true,
     297             :         ['I'] = true,
     298             :         ['J'] = true,
     299             :         ['K'] = true,
     300             :         ['L'] = true,
     301             :         ['M'] = true,
     302             :         ['N'] = true,
     303             :         ['O'] = true,
     304             :         ['P'] = true,
     305             :         ['Q'] = true,
     306             :         ['R'] = true,
     307             :         ['S'] = true,
     308             :         ['T'] = true,
     309             :         ['U'] = true,
     310             :         ['V'] = true,
     311             :         ['W'] = true,
     312             :         ['X'] = true,
     313             :         ['Y'] = true,
     314             :         ['Z'] = true,
     315             :         ['0'] = true,
     316             :         ['1'] = true,
     317             :         ['2'] = true,
     318             :         ['3'] = true,
     319             :         ['4'] = true,
     320             :         ['5'] = true,
     321             :         ['6'] = true,
     322             :         ['7'] = true,
     323             :         ['8'] = true,
     324             :         ['9'] = true,
     325             :         [TMPMARKER] = true,
     326             :         ['@'] = true,
     327             : };
     328             : 
     329             : static int
     330       53248 : idLength(Client cntxt)
     331             : {
     332       53248 :         str s, t;
     333       53248 :         int len = 0;
     334             : 
     335       53248 :         skipSpace(cntxt);
     336       53248 :         s = CURRENT(cntxt);
     337       53248 :         t = s;
     338             : 
     339       53248 :         if (!idCharacter[(unsigned char) (*s)])
     340             :                 return 0;
     341             :         /* avoid a clash with old temporaries */
     342       48350 :         if (s[0] == TMPMARKER)
     343          65 :                 s[0] = REFMARKER;
     344             :         /* prepare escape of temporary names */
     345       48350 :         s++;
     346      322665 :         while (len < IDLENGTH && idCharacter2[(unsigned char) (*s)]) {
     347      274315 :                 s++;
     348      274315 :                 len++;
     349             :         }
     350       48350 :         if (len == IDLENGTH)
     351             :                 // skip remainder
     352           0 :                 while (idCharacter2[(unsigned char) (*s)])
     353           0 :                         s++;
     354       48350 :         return (int) (s - t);
     355             : }
     356             : 
     357             : /* Simple type identifiers can not be marked with a type variable. */
     358             : static size_t
     359        5271 : typeidLength(Client cntxt)
     360             : {
     361        5271 :         size_t l;
     362        5271 :         char id[IDLENGTH], *t = id;
     363        5271 :         str s;
     364        5271 :         skipSpace(cntxt);
     365        5271 :         s = CURRENT(cntxt);
     366             : 
     367        5271 :         if (!idCharacter[(unsigned char) (*s)])
     368             :                 return 0;
     369        5271 :         l = 1;
     370        5271 :         *t++ = *s++;
     371        5271 :         while (l < IDLENGTH
     372       15982 :                    && (idCharacter[(unsigned char) (*s)]
     373        5310 :                            || isdigit((unsigned char) *s))) {
     374       10711 :                 *t++ = *s++;
     375       10711 :                 l++;
     376             :         }
     377             :         /* recognize the special type variables {any, any_<nr>} */
     378        5271 :         if (strncmp(id, "any", 3) == 0)
     379             :                 return 3;
     380        5231 :         if (strncmp(id, "any_", 4) == 0)
     381           0 :                 return 4;
     382             :         return l;
     383             : }
     384             : 
     385             : static str
     386           1 : idCopy(Client cntxt, int length)
     387             : {
     388           1 :         str s = GDKmalloc(length + 1);
     389           1 :         if (s == NULL)
     390             :                 return NULL;
     391           1 :         memcpy(s, CURRENT(cntxt), (size_t) length);
     392           1 :         s[length] = 0;
     393             :         /* avoid a clash with old temporaries */
     394           1 :         advance(cntxt, length);
     395           1 :         return s;
     396             : }
     397             : 
     398             : static int
     399       24927 : MALlookahead(Client cntxt, str kw, int length)
     400             : {
     401       24927 :         int i;
     402             : 
     403             :         /* avoid double test or use lowercase only. */
     404       24927 :         if (currChar(cntxt) == *kw &&
     405       24204 :                 strncmp(CURRENT(cntxt), kw, length) == 0 &&
     406        1070 :                 !idCharacter[(unsigned char) (CURRENT(cntxt)[length])] &&
     407        1070 :                 !isdigit((unsigned char) (CURRENT(cntxt)[length]))) {
     408             :                 return 1;
     409             :         }
     410             :         /* check for captialized versions */
     411       51036 :         for (i = 0; i < length; i++)
     412       51036 :                 if (tolower(CURRENT(cntxt)[i]) != kw[i])
     413             :                         return 0;
     414           0 :         if (!idCharacter[(unsigned char) (CURRENT(cntxt)[length])] &&
     415           0 :                 !isdigit((unsigned char) (CURRENT(cntxt)[length]))) {
     416           0 :                 return 1;
     417             :         }
     418             :         return 0;
     419             : }
     420             : 
     421             : static inline int
     422       24928 : MALkeyword(Client cntxt, str kw, int length)
     423             : {
     424       24928 :         skipSpace(cntxt);
     425       24928 :         if (MALlookahead(cntxt, kw, length)) {
     426        1070 :                 advance(cntxt, length);
     427        1070 :                 return 1;
     428             :         }
     429             :         return 0;
     430             : }
     431             : 
     432             : /*
     433             :  * Keyphrase testing is limited to a few characters only
     434             :  * (check manually). To speed this up we use a pipelined and inline macros.
     435             : */
     436             : 
     437             : static inline int
     438        1531 : keyphrase1(Client cntxt, str kw)
     439             : {
     440        1531 :         skipSpace(cntxt);
     441        1531 :         if (currChar(cntxt) == *kw) {
     442        1415 :                 advance(cntxt, 1);
     443        1415 :                 return 1;
     444             :         }
     445             :         return 0;
     446             : }
     447             : 
     448             : static inline int
     449        7359 : keyphrase2(Client cntxt, str kw)
     450             : {
     451        7359 :         skipSpace(cntxt);
     452        7359 :         if (CURRENT(cntxt)[0] == kw[0] && CURRENT(cntxt)[1] == kw[1]) {
     453        7033 :                 advance(cntxt, 2);
     454        7033 :                 return 1;
     455             :         }
     456             :         return 0;
     457             : }
     458             : 
     459             : /*
     460             :  * A similar approach is used for string literals.
     461             :  * Beware, string lengths returned include the
     462             :  * brackets and escapes. They are eaten away in strCopy.
     463             :  * We should provide the C-method to split strings and
     464             :  * concatenate them upon retrieval[todo]
     465             : */
     466             : static int
     467        2782 : stringLength(Client cntxt)
     468             : {
     469        2782 :         int l = 0;
     470        2782 :         int quote = 0;
     471        2782 :         str s;
     472        2782 :         skipSpace(cntxt);
     473        2782 :         s = CURRENT(cntxt);
     474             : 
     475        2782 :         if (*s != '"')
     476             :                 return 0;
     477      167146 :         for (s++; *s; l++, s++) {
     478      167146 :                 if (quote) {
     479             :                         quote = 0;
     480             :                 } else {
     481      144783 :                         if (*s == '"')
     482             :                                 break;
     483      142001 :                         quote = *s == '\\';
     484             :                 }
     485             :         }
     486        2782 :         return l + 2;
     487             : }
     488             : 
     489             : /*Beware, the idcmp routine uses a short cast to compare multiple bytes
     490             :  * at once. This may cause problems when the net string length is zero.
     491             : */
     492             : 
     493             : str
     494        2782 : strCopy(Client cntxt, int length)
     495             : {
     496        2782 :         str s;
     497        2782 :         int i;
     498             : 
     499        2782 :         i = length < 4 ? 4 : length;
     500        2782 :         s = GDKmalloc(i);
     501        2782 :         if (s == 0)
     502             :                 return NULL;
     503        2782 :         memcpy(s, CURRENT(cntxt) + 1, (size_t) (length - 2));
     504        2782 :         s[length - 2] = 0;
     505        2782 :         mal_unquote(s);
     506        2782 :         return s;
     507             : }
     508             : 
     509             : /*
     510             :  * And a similar approach is used for operator names.
     511             :  * A lookup table is considered, because it generally is
     512             :  * faster then a non-dense switch.
     513             : */
     514             : static int
     515        2785 : operatorLength(Client cntxt)
     516             : {
     517        2785 :         int l = 0;
     518        2785 :         str s;
     519             : 
     520        2785 :         skipSpace(cntxt);
     521        3012 :         for (s = CURRENT(cntxt); *s; s++) {
     522        2992 :                 if (opCharacter[(unsigned char) (*s)])
     523         227 :                         l++;
     524             :                 else
     525        2765 :                         return l;
     526             :         }
     527             :         return l;
     528             : }
     529             : 
     530             : /*
     531             :  * The lexical analyser for constants is a little more complex.
     532             :  * Aside from getting its length, we need an indication of its type.
     533             :  * The constant structure is initialized for later use.
     534             :  */
     535             : static int
     536       31255 : cstToken(Client cntxt, ValPtr cst)
     537             : {
     538       31255 :         int i = 0;
     539       31255 :         str s = CURRENT(cntxt);
     540             : 
     541       31255 :         cst->vtype = TYPE_int;
     542       31255 :         cst->val.lval = 0;
     543       31255 :         switch (*s) {
     544             :         case '{':
     545             :         case '[':
     546             :                 /* JSON Literal */
     547             :                 break;
     548        2780 :         case '"':
     549        2780 :                 i = stringLength(cntxt);
     550        2780 :                 VALset(cst, TYPE_str, strCopy(cntxt, i));
     551        2780 :                 return i;
     552          21 :         case '-':
     553          21 :                 i++;
     554          21 :                 s++;
     555             :                 /* fall through */
     556        1586 :         case '0':
     557        1586 :                 if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X')) {
     558             :                         /* deal with hex */
     559           0 :                         i += 2;
     560           0 :                         s += 2;
     561           0 :                         while (isxdigit((unsigned char) *s)) {
     562           0 :                                 i++;
     563           0 :                                 s++;
     564             :                         }
     565           0 :                         goto handleInts;
     566             :                 }
     567             :                 /* fall through */
     568             :         case '1':
     569             :         case '2':
     570             :         case '3':
     571             :         case '4':
     572             :         case '5':
     573             :         case '6':
     574             :         case '7':
     575             :         case '8':
     576             :         case '9':
     577        9927 :                 while (isdigit((unsigned char) *s)) {
     578        6066 :                         i++;
     579        6066 :                         s++;
     580             :                 }
     581             : 
     582             :                 /* fall through */
     583             :         case '.':
     584        3861 :                 if (*s == '.' && isdigit((unsigned char) *(s + 1))) {
     585          83 :                         i++;
     586          83 :                         s++;
     587         227 :                         while (isdigit((unsigned char) *s)) {
     588         144 :                                 i++;
     589         144 :                                 s++;
     590             :                         }
     591          83 :                         cst->vtype = TYPE_dbl;
     592             :                 }
     593        3861 :                 if (*s == 'e' || *s == 'E') {
     594           4 :                         i++;
     595           4 :                         s++;
     596           4 :                         if (*s == '-' || *s == '+') {
     597           2 :                                 i++;
     598           2 :                                 s++;
     599             :                         }
     600           4 :                         cst->vtype = TYPE_dbl;
     601           8 :                         while (isdigit((unsigned char) *s)) {
     602           4 :                                 i++;
     603           4 :                                 s++;
     604             :                         }
     605             :                 }
     606        3861 :                 if (cst->vtype == TYPE_flt) {
     607           0 :                         size_t len = sizeof(flt);
     608           0 :                         float *pval = &cst->val.fval;
     609           0 :                         if (fltFromStr(CURRENT(cntxt), &len, &pval, false) < 0) {
     610           0 :                                 parseError(cntxt, GDKerrbuf);
     611           0 :                                 return i;
     612             :                         }
     613             :                 }
     614        3861 :                 if (cst->vtype == TYPE_dbl) {
     615          83 :                         size_t len = sizeof(dbl);
     616          83 :                         double *pval = &cst->val.dval;
     617          83 :                         if (dblFromStr(CURRENT(cntxt), &len, &pval, false) < 0) {
     618           0 :                                 parseError(cntxt, GDKerrbuf);
     619           0 :                                 return i;
     620             :                         }
     621             :                 }
     622        3861 :                 if (*s == '@') {
     623          77 :                         size_t len = sizeof(lng);
     624          77 :                         lng l, *pval = &l;
     625          77 :                         if (lngFromStr(CURRENT(cntxt), &len, &pval, false) < 0) {
     626           0 :                                 parseError(cntxt, GDKerrbuf);
     627           0 :                                 return i;
     628             :                         }
     629          77 :                         if (is_lng_nil(l) || l < 0
     630             : #if SIZEOF_OID < SIZEOF_LNG
     631             :                                 || l > GDK_oid_max
     632             : #endif
     633             :                                         )
     634           0 :                                 cst->val.oval = oid_nil;
     635             :                         else
     636          77 :                                 cst->val.oval = (oid) l;
     637          77 :                         cst->vtype = TYPE_oid;
     638          77 :                         i++;
     639          77 :                         s++;
     640         154 :                         while (isdigit((unsigned char) *s)) {
     641          77 :                                 i++;
     642          77 :                                 s++;
     643             :                         }
     644          77 :                         return i;
     645             :                 }
     646        3784 :                 if (*s == 'L') {
     647           4 :                         if (cst->vtype == TYPE_int)
     648           4 :                                 cst->vtype = TYPE_lng;
     649           4 :                         if (cst->vtype == TYPE_flt)
     650           0 :                                 cst->vtype = TYPE_dbl;
     651           4 :                         i++;
     652           4 :                         s++;
     653           4 :                         if (*s == 'L') {
     654           0 :                                 i++;
     655           0 :                                 s++;
     656             :                         }
     657           4 :                         if (cst->vtype == TYPE_dbl) {
     658           0 :                                 size_t len = sizeof(dbl);
     659           0 :                                 dbl *pval = &cst->val.dval;
     660           0 :                                 if (dblFromStr(CURRENT(cntxt), &len, &pval, false) < 0) {
     661           0 :                                         parseError(cntxt, GDKerrbuf);
     662           0 :                                         return i;
     663             :                                 }
     664             :                         } else {
     665           4 :                                 size_t len = sizeof(lng);
     666           4 :                                 lng *pval = &cst->val.lval;
     667           4 :                                 if (lngFromStr(CURRENT(cntxt), &len, &pval, false) < 0) {
     668           0 :                                         parseError(cntxt, GDKerrbuf);
     669           0 :                                         return i;
     670             :                                 }
     671             :                         }
     672           4 :                         return i;
     673             :                 }
     674             : #ifdef HAVE_HGE
     675        3780 :                 if (*s == 'H' && cst->vtype == TYPE_int) {
     676           2 :                         size_t len = sizeof(hge);
     677           2 :                         hge *pval = &cst->val.hval;
     678           2 :                         cst->vtype = TYPE_hge;
     679           2 :                         i++;
     680           2 :                         s++;
     681           2 :                         if (*s == 'H') {
     682           0 :                                 i++;
     683           0 :                                 s++;
     684             :                         }
     685           2 :                         if (hgeFromStr(CURRENT(cntxt), &len, &pval, false) < 0) {
     686           0 :                                 parseError(cntxt, GDKerrbuf);
     687           0 :                                 return i;
     688             :                         }
     689             :                         return i;
     690             :                 }
     691             : #endif
     692        3778 :   handleInts:
     693        3778 :                 assert(cst->vtype != TYPE_lng);
     694             : #ifdef HAVE_HGE
     695        3778 :                 assert(cst->vtype != TYPE_hge);
     696             : #endif
     697        3778 :                 if (cst->vtype == TYPE_int) {
     698             : #ifdef HAVE_HGE
     699        3695 :                         size_t len = sizeof(hge);
     700        3695 :                         hge l, *pval = &l;
     701        3695 :                         if (hgeFromStr(CURRENT(cntxt), &len, &pval, false) < 0)
     702           0 :                                 l = hge_nil;
     703             : 
     704        3695 :                         if ((hge) GDK_int_min <= l && l <= (hge) GDK_int_max) {
     705        3688 :                                 cst->vtype = TYPE_int;
     706        3688 :                                 cst->val.ival = (int) l;
     707           7 :                         } else if ((hge) GDK_lng_min <= l && l <= (hge) GDK_lng_max) {
     708           3 :                                 cst->vtype = TYPE_lng;
     709           3 :                                 cst->val.lval = (lng) l;
     710             :                         } else {
     711           4 :                                 cst->vtype = TYPE_hge;
     712           4 :                                 cst->val.hval = l;
     713             :                         }
     714             : #else
     715             :                         size_t len = sizeof(lng);
     716             :                         lng l, *pval = &l;
     717             :                         if (lngFromStr(CURRENT(cntxt), &len, &pval, false) < 0)
     718             :                                 l = lng_nil;
     719             : 
     720             :                         if ((lng) GDK_int_min <= l && l <= (lng) GDK_int_max) {
     721             :                                 cst->vtype = TYPE_int;
     722             :                                 cst->val.ival = (int) l;
     723             :                         } else {
     724             :                                 cst->vtype = TYPE_lng;
     725             :                                 cst->val.lval = l;
     726             :                         }
     727             : #endif
     728             :                 }
     729             :                 return i;
     730             : 
     731        1260 :         case 'f':
     732        1260 :                 if (strncmp(s, "false", 5) == 0 && !isalnum((unsigned char) *(s + 5)) &&
     733             :                         *(s + 5) != '_') {
     734         984 :                         cst->vtype = TYPE_bit;
     735         984 :                         cst->val.btval = 0;
     736         984 :                         cst->len = 1;
     737         984 :                         return 5;
     738             :                 }
     739             :                 return 0;
     740         983 :         case 't':
     741         983 :                 if (strncmp(s, "true", 4) == 0 && !isalnum((unsigned char) *(s + 4)) &&
     742             :                         *(s + 4) != '_') {
     743         716 :                         cst->vtype = TYPE_bit;
     744         716 :                         cst->val.btval = 1;
     745         716 :                         cst->len = 1;
     746         716 :                         return 4;
     747             :                 }
     748             :                 return 0;
     749        2157 :         case 'n':
     750        2157 :                 if (strncmp(s, "nil", 3) == 0 && !isalnum((unsigned char) *(s + 3)) &&
     751             :                         *(s + 3) != '_') {
     752        2090 :                         cst->vtype = TYPE_void;
     753        2090 :                         cst->len = 0;
     754        2090 :                         cst->val.oval = oid_nil;
     755        2090 :                         return 3;
     756             :                 }
     757             :         }
     758             :         return 0;
     759             : }
     760             : 
     761             : #define cstCopy(C,I)  idCopy(C,I)
     762             : 
     763             : /* Type qualifier
     764             :  * Types are recognized as identifiers preceded by a colon.
     765             :  *
     766             :  * The type ANY matches any type specifier.
     767             :  * Appending it with an alias turns it into a type variable.
     768             :  * The type alias is \$DIGIT (1-9) and can be used to relate types
     769             :  * by type equality.
     770             :  * The type variable are defined within the context of a function
     771             :  * scope.
     772             :  * Additional information, such as a repetition factor,
     773             :  * encoding tables, or type dependency should be modeled as properties.
     774             :  *
     775             :  * It would make more sense for tpe parameter to be an int, but simpleTypeId returns a size_t
     776             :  */
     777             : static int
     778        5271 : typeAlias(Client cntxt, int tpe)
     779             : {
     780        5271 :         int t;
     781             : 
     782        5271 :         if (tpe != TYPE_any)
     783             :                 return -1;
     784          40 :         if (currChar(cntxt) == TMPMARKER) {
     785          37 :                 nextChar(cntxt);
     786          37 :                 t = currChar(cntxt) - '0';
     787          37 :                 if (t <= 0 || t > 9)
     788           0 :                         parseError(cntxt, "[1-9] expected\n");
     789             :                 else
     790          37 :                         nextChar(cntxt);
     791          37 :                 return t;
     792             :         }
     793             :         return -1;
     794             : }
     795             : 
     796             : /*
     797             :  * The simple type analysis currently assumes a proper type identifier.
     798             :  * We should change getMALtype to return a failure instead.
     799             :  */
     800             : static int
     801        5271 : simpleTypeId(Client cntxt)
     802             : {
     803        5271 :         int tpe;
     804        5271 :         size_t l;
     805             : 
     806        5271 :         nextChar(cntxt);
     807        5271 :         l = typeidLength(cntxt);
     808        5271 :         if (l == 0) {
     809           0 :                 parseError(cntxt, "Type identifier expected\n");
     810           0 :                 cntxt->yycur--;                      /* keep it */
     811           0 :                 return -1;
     812             :         }
     813        5271 :         tpe = getAtomIndex(CURRENT(cntxt), l, -1);
     814        5271 :         if (tpe < 0) {
     815           0 :                 parseError(cntxt, "Type identifier expected\n");
     816           0 :                 cntxt->yycur -= l;           /* keep it */
     817           0 :                 return TYPE_void;
     818             :         }
     819        5271 :         advance(cntxt, l);
     820        5271 :         return tpe;
     821             : }
     822             : 
     823             : static int
     824        5271 : parseTypeId(Client cntxt)
     825             : {
     826        5271 :         int i = TYPE_any, kt = 0;
     827        5271 :         char *s = CURRENT(cntxt);
     828        5271 :         int tt;
     829             : 
     830        5271 :         if (strncmp(s, ":bat[", 5) == 0 || strncmp(s, ":BAT[", 5) == 0) {
     831             :                 /* parse :bat[:type] */
     832         421 :                 advance(cntxt, 5);
     833         421 :                 if (currChar(cntxt) == ':') {
     834         421 :                         tt = simpleTypeId(cntxt);
     835         421 :                         kt = typeAlias(cntxt, tt);
     836             :                 } else {
     837           0 :                         parseError(cntxt, "':bat[:any]' expected\n");
     838           0 :                         return -1;
     839             :                 }
     840             : 
     841         421 :                 i = newBatType(tt);
     842         421 :                 if (kt > 0)
     843          22 :                         setTypeIndex(i, kt);
     844             : 
     845         421 :                 if (currChar(cntxt) != ']')
     846           0 :                         parseError(cntxt, "']' expected\n");
     847         421 :                 nextChar(cntxt);                // skip ']'
     848         421 :                 skipSpace(cntxt);
     849         421 :                 return i;
     850             :         }
     851        4850 :         if (currChar(cntxt) == ':') {
     852        4850 :                 tt = simpleTypeId(cntxt);
     853        4850 :                 kt = typeAlias(cntxt, tt);
     854        4850 :                 if (kt > 0)
     855          15 :                         setTypeIndex(tt, kt);
     856        4850 :                 return tt;
     857             :         }
     858           0 :         parseError(cntxt, "<type identifier> expected\n");
     859           0 :         return -1;
     860             : }
     861             : 
     862             : static inline int
     863        9645 : typeElm(Client cntxt, int def)
     864             : {
     865        9645 :         if (currChar(cntxt) != ':')
     866             :                 return def;                             /* no type qualifier */
     867        5266 :         return parseTypeId(cntxt);
     868             : }
     869             : 
     870             :  /*
     871             :   * The Parser
     872             :   * The client is responsible to collect the
     873             :   * input for parsing in a single string before calling the parser.
     874             :   * Once the input is available parsing runs in a critial section for
     875             :   * a single client thread.
     876             :   *
     877             :   * The parser uses the rigid structure of the language to speedup
     878             :   * analysis. In particular, each input line is translated into
     879             :   * a MAL instruction record as quickly as possible. Its context is
     880             :   * manipulated during the parsing process, by keeping the  curPrg,
     881             :   * curBlk, and curInstr variables.
     882             :   *
     883             :   * The language statements of the parser are gradually introduced, with
     884             :   * the overall integration framework last.
     885             :   * The convention is to return a zero when an error has been
     886             :   * reported or when the structure can not be recognized.
     887             :   * Furthermore, we assume that blancs have been skipped before entering
     888             :   * recognition of a new token.
     889             :   *
     890             :   * Module statement.
     891             :   * The module and import commands have immediate effect.
     892             :   * The module statement switches the location for symbol table update
     893             :   * to a specific named area. The effect is that all definitions may become
     894             :   * globally known (?) and symbol table should be temporarilly locked
     895             :   * for updates by concurrent users.
     896             :   *
     897             :   * @multitable @columnfractions 0.15 0.8
     898             :   * @item moduleStmt
     899             :   * @tab :  @sc{atom} ident [':'ident]
     900             :   * @item
     901             :   * @tab | @sc{module} ident
     902             :   * @end multitable
     903             :   *
     904             :   * An atom statement does not introduce a new module.
     905             :   */
     906             : static void
     907         219 : helpInfo(Client cntxt, str *help)
     908             : {
     909         219 :         int l = 0;
     910         219 :         char c, *e, *s;
     911             : 
     912         219 :         if (MALkeyword(cntxt, "comment", 7)) {
     913           2 :                 skipSpace(cntxt);
     914             :                 // The comment is either a quoted string or all characters up to the next semicolon
     915           2 :                 c = currChar(cntxt);
     916           2 :                 if (c != '"') {
     917             :                         e = s = CURRENT(cntxt);
     918           0 :                         for (; *e; l++, e++)
     919           0 :                                 if (*e == ';')
     920             :                                         break;
     921           0 :                         *help = strCopy(cntxt, l);
     922           0 :                         skipToEnd(cntxt);
     923             :                 } else {
     924           2 :                         if ((l = stringLength(cntxt))) {
     925           2 :                                 GDKfree(*help);
     926           2 :                                 *help = strCopy(cntxt, l);
     927           2 :                                 if (*help)
     928           2 :                                         advance(cntxt, l - 1);
     929           2 :                                 skipToEnd(cntxt);
     930             :                         } else {
     931           0 :                                 parseError(cntxt, "<string> expected\n");
     932             :                         }
     933             :                 }
     934         217 :         } else if (currChar(cntxt) != ';')
     935           0 :                 parseError(cntxt, "';' expected\n");
     936         219 : }
     937             : 
     938             : static InstrPtr
     939         186 : binding(Client cntxt, MalBlkPtr curBlk, InstrPtr curInstr, int flag)
     940             : {
     941         186 :         int l, varid = -1;
     942         186 :         malType type;
     943             : 
     944         186 :         l = idLength(cntxt);
     945         186 :         if (l > 0) {
     946         145 :                 varid = findVariableLength(curBlk, CURRENT(cntxt), l);
     947         145 :                 if (varid < 0) {
     948         145 :                         varid = newVariable(curBlk, CURRENT(cntxt), l, TYPE_any);
     949         145 :                         advance(cntxt, l);
     950         145 :                         if (varid < 0)
     951             :                                 return curInstr;
     952         145 :                         type = typeElm(cntxt, TYPE_any);
     953         145 :                         if (isPolymorphic(type))
     954          30 :                                 setPolymorphic(curInstr, type, TRUE);
     955         145 :                         setVarType(curBlk, varid, type);
     956           0 :                 } else if (flag) {
     957           0 :                         parseError(cntxt, "Argument defined twice\n");
     958           0 :                         typeElm(cntxt, getVarType(curBlk, varid));
     959             :                 } else {
     960           0 :                         advance(cntxt, l);
     961           0 :                         type = typeElm(cntxt, getVarType(curBlk, varid));
     962           0 :                         if (type != getVarType(curBlk, varid))
     963           0 :                                 parseError(cntxt, "Incompatible argument type\n");
     964           0 :                         if (isPolymorphic(type))
     965           0 :                                 setPolymorphic(curInstr, type, TRUE);
     966           0 :                         setVarType(curBlk, varid, type);
     967             :                 }
     968          41 :         } else if (currChar(cntxt) == ':') {
     969          41 :                 type = typeElm(cntxt, TYPE_any);
     970          41 :                 varid = newTmpVariable(curBlk, type);
     971          41 :                 if (varid < 0)
     972             :                         return curInstr;
     973          41 :                 if (isPolymorphic(type))
     974           2 :                         setPolymorphic(curInstr, type, TRUE);
     975          41 :                 setVarType(curBlk, varid, type);
     976             :         } else {
     977           0 :                 parseError(cntxt, "argument expected\n");
     978           0 :                 return curInstr;
     979             :         }
     980         186 :         if (varid >= 0)
     981         186 :                 curInstr = pushArgument(curBlk, curInstr, varid);
     982         186 :         return curInstr;
     983             : }
     984             : 
     985             : /*
     986             :  * At this stage the LHS part has been parsed and the destination
     987             :  * variables have been set. Next step is to parse the expression,
     988             :  * which starts with an operand.
     989             :  * This code is used in both positions of the expression
     990             :  */
     991             : static int
     992       18118 : term(Client cntxt, MalBlkPtr curBlk, InstrPtr *curInstr, int ret)
     993             : {
     994       18118 :         int i, idx, free = 1;
     995       18118 :         ValRecord cst;
     996       18118 :         int cstidx = -1;
     997       18118 :         malType tpe = TYPE_any;
     998             : 
     999       18118 :         if ((i = cstToken(cntxt, &cst))) {
    1000       10428 :                 advance(cntxt, i);
    1001       10428 :                 if (currChar(cntxt) != ':' && cst.vtype == TYPE_dbl
    1002          47 :                         && cst.val.dval > FLT_MIN && cst.val.dval <= FLT_MAX) {
    1003          46 :                         float dummy = (flt) cst.val.dval;
    1004          46 :                         cst.vtype = TYPE_flt;
    1005          46 :                         cst.val.fval = dummy;
    1006             :                 }
    1007       10428 :                 cstidx = fndConstant(curBlk, &cst, MAL_VAR_WINDOW);
    1008       10428 :                 if (cstidx >= 0) {
    1009             : 
    1010        1529 :                         if (currChar(cntxt) == ':') {
    1011           6 :                                 tpe = typeElm(cntxt, getVarType(curBlk, cstidx));
    1012           6 :                                 if (tpe < 0)
    1013             :                                         return 3;
    1014           6 :                                 if (tpe != getVarType(curBlk, cstidx)) {
    1015           1 :                                         cstidx = defConstant(curBlk, tpe, &cst);
    1016           1 :                                         if (cstidx < 0)
    1017             :                                                 return 3;
    1018           1 :                                         setPolymorphic(*curInstr, tpe, FALSE);
    1019           1 :                                         free = 0;
    1020             :                                 }
    1021        1523 :                         } else if (cst.vtype != getVarType(curBlk, cstidx)) {
    1022           0 :                                 cstidx = defConstant(curBlk, cst.vtype, &cst);
    1023           0 :                                 if (cstidx < 0)
    1024             :                                         return 3;
    1025           0 :                                 setPolymorphic(*curInstr, cst.vtype, FALSE);
    1026           0 :                                 free = 0;
    1027             :                         }
    1028             :                         /* protect against leaks coming from constant reuse */
    1029        1529 :                         if (free && ATOMextern(cst.vtype) && cst.val.pval)
    1030          45 :                                 VALclear(&cst);
    1031        1529 :                         *curInstr = pushArgument(curBlk, *curInstr, cstidx);
    1032        1529 :                         return ret;
    1033             :                 } else {
    1034             :                         /* add a new constant literal, the :type could be erroneously be a coltype */
    1035        8899 :                         tpe = typeElm(cntxt, cst.vtype);
    1036        8899 :                         if (tpe < 0)
    1037             :                                 return 3;
    1038        8899 :                         cstidx = defConstant(curBlk, tpe, &cst);
    1039        8899 :                         if (cstidx < 0)
    1040             :                                 return 3;
    1041        8895 :                         setPolymorphic(*curInstr, tpe, FALSE);
    1042        8895 :                         *curInstr = pushArgument(curBlk, *curInstr, cstidx);
    1043        8895 :                         return ret;
    1044             :                 }
    1045        7690 :         } else if ((i = idLength(cntxt))) {
    1046        7414 :                 if ((idx = findVariableLength(curBlk, CURRENT(cntxt), i)) == -1) {
    1047           5 :                         idx = newVariable(curBlk, CURRENT(cntxt), i, TYPE_any);
    1048           5 :                         advance(cntxt, i);
    1049           5 :                         if (idx < 0)
    1050             :                                 return 0;
    1051             :                 } else {
    1052        7409 :                         advance(cntxt, i);
    1053             :                 }
    1054        7414 :                 if (currChar(cntxt) == ':') {
    1055             :                         /* skip the type description */
    1056           2 :                         tpe = typeElm(cntxt, TYPE_any);
    1057           2 :                         if (getVarType(curBlk, idx) == TYPE_any)
    1058           1 :                                 setVarType(curBlk, idx, tpe);
    1059           1 :                         else if (getVarType(curBlk, idx) != tpe) {
    1060             :                                 /* non-matching types */
    1061             :                                 return 4;
    1062             :                         }
    1063             :                 }
    1064        7414 :                 *curInstr = pushArgument(curBlk, *curInstr, idx);
    1065         276 :         } else if (currChar(cntxt) == ':') {
    1066         274 :                 tpe = typeElm(cntxt, TYPE_any);
    1067         274 :                 if (tpe < 0)
    1068             :                         return 3;
    1069         274 :                 setPolymorphic(*curInstr, tpe, FALSE);
    1070         274 :                 idx = newTypeVariable(curBlk, tpe);
    1071         274 :                 *curInstr = pushArgument(curBlk, *curInstr, idx);
    1072         274 :                 return ret;
    1073             :         }
    1074             :         return 0;
    1075             : }
    1076             : 
    1077             : static int
    1078           5 : parseAtom(Client cntxt)
    1079             : {
    1080           5 :         const char *modnme = 0;
    1081           5 :         int l, tpe;
    1082           5 :         char *nxt = CURRENT(cntxt);
    1083             : 
    1084           5 :         if ((l = idLength(cntxt)) <= 0) {
    1085           0 :                 parseError(cntxt, "atom name expected\n");
    1086           0 :                 return -1;
    1087             :         }
    1088             : 
    1089             :         /* parse: ATOM id:type */
    1090           5 :         modnme = putNameLen(nxt, l);
    1091           5 :         if (modnme == NULL) {
    1092           0 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1093           0 :                 return -1;
    1094             :         }
    1095           5 :         advance(cntxt, l);
    1096           5 :         if (currChar(cntxt) != ':')
    1097             :                 tpe = TYPE_void;                /* no type qualifier */
    1098             :         else
    1099           5 :                 tpe = parseTypeId(cntxt);
    1100           5 :         if (ATOMindex(modnme) < 0) {
    1101           4 :                 if (cntxt->curprg->def->errors)
    1102           0 :                         freeException(cntxt->curprg->def->errors);
    1103           4 :                 cntxt->curprg->def->errors = malAtomDefinition(modnme, tpe);
    1104             :         }
    1105           5 :         if (strcmp(modnme, "user"))
    1106           5 :                 cntxt->curmodule = fixModule(modnme);
    1107             :         else
    1108           0 :                 cntxt->curmodule = cntxt->usermodule;
    1109           5 :         cntxt->usermodule->isAtomModule = TRUE;
    1110           5 :         skipSpace(cntxt);
    1111           5 :         helpInfo(cntxt, &cntxt->usermodule->help);
    1112           5 :         return 0;
    1113             : }
    1114             : 
    1115             : /*
    1116             :  * All modules, except 'user', should be global
    1117             :  */
    1118             : static int
    1119           3 : parseModule(Client cntxt)
    1120             : {
    1121           3 :         const char *modnme = 0;
    1122           3 :         int l;
    1123           3 :         char *nxt;
    1124             : 
    1125           3 :         nxt = CURRENT(cntxt);
    1126           3 :         if ((l = idLength(cntxt)) <= 0) {
    1127           0 :                 parseError(cntxt, "<module path> expected\n");
    1128           0 :                 return -1;
    1129             :         }
    1130           3 :         modnme = putNameLen(nxt, l);
    1131           3 :         if (modnme == NULL) {
    1132           0 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1133           0 :                 return -1;
    1134             :         }
    1135           3 :         advance(cntxt, l);
    1136           3 :         if (strcmp(modnme, cntxt->usermodule->name) == 0) {
    1137             :                 // ignore this module definition
    1138           3 :         } else if (getModule(modnme) == NULL) {
    1139           3 :                 if (globalModule(modnme) == NULL)
    1140           0 :                         parseError(cntxt, "<module> could not be created");
    1141             :         }
    1142           3 :         if (strcmp(modnme, "user"))
    1143           3 :                 cntxt->curmodule = fixModule(modnme);
    1144             :         else
    1145           0 :                 cntxt->curmodule = cntxt->usermodule;
    1146           3 :         skipSpace(cntxt);
    1147           3 :         helpInfo(cntxt, &cntxt->usermodule->help);
    1148           3 :         return 0;
    1149             : }
    1150             : 
    1151             : /*
    1152             :  * Include files should be handled in line with parsing. This way we
    1153             :  * are ensured that any possible signature definition will be known
    1154             :  * afterwards. The effect is that errors in the include sequence are
    1155             :  * marked as warnings.
    1156             :  */
    1157             : static int
    1158           2 : parseInclude(Client cntxt)
    1159             : {
    1160           2 :         const char *modnme = 0;
    1161           2 :         char *s;
    1162           2 :         int x;
    1163           2 :         char *nxt;
    1164             : 
    1165           2 :         nxt = CURRENT(cntxt);
    1166             : 
    1167           2 :         if ((x = idLength(cntxt)) > 0) {
    1168           2 :                 modnme = putNameLen(nxt, x);
    1169           2 :                 advance(cntxt, x);
    1170           0 :         } else if ((x = stringLength(cntxt)) > 0) {
    1171           0 :                 modnme = putNameLen(nxt + 1, x - 1);
    1172           0 :                 advance(cntxt, x);
    1173             :         } else {
    1174           0 :                 parseError(cntxt, "<module name> expected\n");
    1175           0 :                 return -1;
    1176             :         }
    1177           2 :         if (modnme == NULL) {
    1178           0 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1179           0 :                 return -1;
    1180             :         }
    1181             : 
    1182           2 :         if (currChar(cntxt) != ';') {
    1183           0 :                 parseError(cntxt, "';' expected\n");
    1184           0 :                 return 0;
    1185             :         }
    1186           2 :         skipToEnd(cntxt);
    1187             : 
    1188           2 :         if (!malLibraryEnabled(modnme)) {
    1189             :                 return 0;
    1190             :         }
    1191             : 
    1192           2 :         if (getModule(modnme) == NULL) {
    1193           1 :                 s = loadLibrary(modnme, FALSE);
    1194           1 :                 if (s) {
    1195           1 :                         parseError(cntxt, s);
    1196           1 :                         freeException(s);
    1197           1 :                         return 0;
    1198             :                 }
    1199             :         }
    1200           1 :         if ((s = malInclude(cntxt, modnme, 0))) {
    1201           0 :                 parseError(cntxt, s);
    1202           0 :                 freeException(s);
    1203           0 :                 return 0;
    1204             :         }
    1205             :         return 0;
    1206             : }
    1207             : 
    1208             : /* return the combined count of the number of arguments and the number
    1209             :  * of return values so that we can allocate enough space in the
    1210             :  * instruction; returns -1 on error (missing closing parenthesis) */
    1211             : static int
    1212         212 : cntArgsReturns(Client cntxt)
    1213             : {
    1214         212 :         size_t yycur = cntxt->yycur;
    1215         212 :         int cnt = 0;
    1216         212 :         char ch;
    1217             : 
    1218         212 :         ch = currChar(cntxt);
    1219         212 :         if (ch != ')') {
    1220             :                 cnt++;
    1221        1129 :                 while (ch != ')' && ch && !NL(ch)) {
    1222        1038 :                         if (ch == ',')
    1223          43 :                                 cnt++;
    1224        1038 :                         nextChar(cntxt);
    1225        1038 :                         ch = currChar(cntxt);
    1226             :                 }
    1227             :         }
    1228          91 :         if (ch != ')') {
    1229           0 :                 parseError(cntxt, "')' expected\n");
    1230           0 :                 cntxt->yycur = yycur;
    1231           0 :                 return -1;
    1232             :         }
    1233         212 :         advance(cntxt, 1);
    1234         212 :         ch = currChar(cntxt);
    1235         212 :         if (ch == '(') {
    1236          13 :                 advance(cntxt, 1);
    1237          13 :                 ch = currChar(cntxt);
    1238          13 :                 cnt++;
    1239         304 :                 while (ch != ')' && ch && !NL(ch)) {
    1240         291 :                         if (ch == ',')
    1241          39 :                                 cnt++;
    1242         291 :                         nextChar(cntxt);
    1243         291 :                         ch = currChar(cntxt);
    1244             :                 }
    1245          13 :                 if (ch != ')') {
    1246           0 :                         parseError(cntxt, "')' expected\n");
    1247           0 :                         cntxt->yycur = yycur;
    1248           0 :                         return -1;
    1249             :                 }
    1250             :         } else {
    1251         199 :                 cnt++;
    1252             :         }
    1253         212 :         cntxt->yycur = yycur;
    1254         212 :         return cnt;
    1255             : }
    1256             : 
    1257             : /*
    1258             :  * Definition
    1259             :  * The definition statements share a lot in common, which calls for factoring
    1260             :  * out the code in a few text macros. Upon encountering a definition, we
    1261             :  * initialize a MAL instruction container. We should also check for
    1262             :  * non-terminated definitions.
    1263             :  *
    1264             :  * Beware, a function signature f(a1..an):(b1..bn) is parsed in such a way that
    1265             :  * the symbol table and stackframe contains the sequence
    1266             :  * f,a1..an,b1..bn. This slightly complicates the implementation
    1267             :  * of the return statement.
    1268             :  *
    1269             :  * Note, the function name could be mod.fcn, which calls for storing
    1270             :  * the function definition in a particular module instead of the current one.
    1271             :  */
    1272             : static MalBlkPtr
    1273         212 : fcnHeader(Client cntxt, int kind)
    1274             : {
    1275         212 :         int l;
    1276         212 :         malType tpe;
    1277         212 :         const char *fnme;
    1278         212 :         const char *modnme = NULL;
    1279         212 :         char ch;
    1280         212 :         Symbol curPrg;
    1281         212 :         MalBlkPtr curBlk = 0;
    1282         212 :         InstrPtr curInstr;
    1283             : 
    1284         212 :         l = operatorLength(cntxt);
    1285         212 :         if (l == 0)
    1286         211 :                 l = idLength(cntxt);
    1287         211 :         if (l == 0) {
    1288           0 :                 parseError(cntxt, "<identifier> | <operator> expected\n");
    1289           0 :                 return 0;
    1290             :         }
    1291             : 
    1292         212 :         fnme = putNameLen(((char *) CURRENT(cntxt)), l);
    1293         212 :         if (fnme == NULL) {
    1294           0 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1295           0 :                 return NULL;
    1296             :         }
    1297         212 :         advance(cntxt, l);
    1298             : 
    1299         212 :         if (currChar(cntxt) == '.') {
    1300           8 :                 nextChar(cntxt);                /* skip '.' */
    1301           8 :                 modnme = fnme;
    1302           8 :                 if (strcmp(modnme, "user") && getModule(modnme) == NULL) {
    1303           1 :                         if (globalModule(modnme) == NULL) {
    1304           0 :                                 parseError(cntxt, "<module> name not defined\n");
    1305           0 :                                 return 0;
    1306             :                         }
    1307             :                 }
    1308           8 :                 l = operatorLength(cntxt);
    1309           8 :                 if (l == 0)
    1310           8 :                         l = idLength(cntxt);
    1311           8 :                 if (l == 0) {
    1312           0 :                         parseError(cntxt, "<identifier> | <operator> expected\n");
    1313           0 :                         return 0;
    1314             :                 }
    1315           8 :                 fnme = putNameLen(((char *) CURRENT(cntxt)), l);
    1316           8 :                 if (fnme == NULL) {
    1317           0 :                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1318           0 :                         return NULL;
    1319             :                 }
    1320           8 :                 advance(cntxt, l);
    1321             :         } else
    1322         204 :                 modnme = cntxt->curmodule->name;
    1323             : 
    1324             :         /* temporary suspend capturing statements in main block */
    1325         212 :         if (cntxt->backup) {
    1326           0 :                 parseError(cntxt, "mal_parser: unexpected recursion\n");
    1327           0 :                 return 0;
    1328             :         }
    1329         212 :         if (currChar(cntxt) != '(') {
    1330           0 :                 parseError(cntxt, "function header '(' expected\n");
    1331           0 :                 return curBlk;
    1332             :         }
    1333         212 :         advance(cntxt, 1);
    1334             : 
    1335         212 :         assert(!cntxt->backup);
    1336         212 :         cntxt->backup = cntxt->curprg;
    1337         212 :         int nargs = cntArgsReturns(cntxt);
    1338         212 :         if (nargs < 0)
    1339             :                 return 0;
    1340             :         /* one extra for argument/return manipulation */
    1341         212 :         cntxt->curprg = newFunctionArgs(modnme, fnme, kind, nargs + 1);
    1342         212 :         if (cntxt->curprg == NULL) {
    1343             :                 /* reinstate curprg to have a place for the error */
    1344           0 :                 cntxt->curprg = cntxt->backup;
    1345           0 :                 cntxt->backup = NULL;
    1346           0 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1347           0 :                 return 0;
    1348             :         }
    1349         212 :         cntxt->curprg->def->errors = cntxt->backup->def->errors;
    1350         212 :         cntxt->backup->def->errors = 0;
    1351         212 :         curPrg = cntxt->curprg;
    1352         212 :         curBlk = curPrg->def;
    1353         212 :         curInstr = getInstrPtr(curBlk, 0);
    1354             : 
    1355             :         /* get calling parameters */
    1356         212 :         ch = currChar(cntxt);
    1357         255 :         while (ch != ')' && ch && !NL(ch)) {
    1358         134 :                 curInstr = binding(cntxt, curBlk, curInstr, 1);
    1359             :                 /* the last argument may be variable length */
    1360         134 :                 if (MALkeyword(cntxt, "...", 3)) {
    1361           7 :                         curInstr->varargs |= VARARGS;
    1362           7 :                         setPolymorphic(curInstr, TYPE_any, TRUE);
    1363           7 :                         break;
    1364             :                 }
    1365         127 :                 if ((ch = currChar(cntxt)) != ',') {
    1366          84 :                         if (ch == ')')
    1367             :                                 break;
    1368           0 :                         if (cntxt->backup)
    1369           0 :                                 curBlk = NULL;
    1370           0 :                         parseError(cntxt, "',' expected\n");
    1371           0 :                         return curBlk;
    1372             :                 } else
    1373          43 :                         nextChar(cntxt);        /* skip ',' */
    1374          43 :                 skipSpace(cntxt);
    1375          43 :                 ch = currChar(cntxt);
    1376             :         }
    1377         212 :         if (currChar(cntxt) != ')') {
    1378           0 :                 freeInstruction(curInstr);
    1379           0 :                 if (cntxt->backup)
    1380           0 :                         curBlk = NULL;
    1381           0 :                 parseError(cntxt, "')' expected\n");
    1382           0 :                 return curBlk;
    1383             :         }
    1384         212 :         advance(cntxt, 1);                      /* skip ')' */
    1385             : /*
    1386             :    The return type is either a single type or multiple return type structure.
    1387             :    We simply keep track of the number of arguments added and
    1388             :    during the final phase reshuffle the return values to the beginning (?)
    1389             :  */
    1390         212 :         if (currChar(cntxt) == ':') {
    1391          83 :                 tpe = typeElm(cntxt, TYPE_void);
    1392          83 :                 setPolymorphic(curInstr, tpe, TRUE);
    1393          83 :                 setVarType(curBlk, curInstr->argv[0], tpe);
    1394             :                 /* we may be confronted by a variable target type list */
    1395          83 :                 if (MALkeyword(cntxt, "...", 3)) {
    1396           3 :                         curInstr->varargs |= VARRETS;
    1397           3 :                         setPolymorphic(curInstr, TYPE_any, TRUE);
    1398             :                 }
    1399             : 
    1400         129 :         } else if (keyphrase1(cntxt, "(")) {  /* deal with compound return */
    1401          13 :                 int retc = curInstr->argc, i1, i2 = 0;
    1402          13 :                 int max;
    1403          13 :                 short *newarg;
    1404             :                 /* parse multi-target result */
    1405             :                 /* skipSpace(cntxt); */
    1406          13 :                 ch = currChar(cntxt);
    1407          52 :                 while (ch != ')' && ch && !NL(ch)) {
    1408          52 :                         curInstr = binding(cntxt, curBlk, curInstr, 0);
    1409             :                         /* we may be confronted by a variable target type list */
    1410          52 :                         if (MALkeyword(cntxt, "...", 3)) {
    1411           3 :                                 curInstr->varargs |= VARRETS;
    1412           3 :                                 setPolymorphic(curInstr, TYPE_any, TRUE);
    1413             :                         }
    1414          52 :                         if ((ch = currChar(cntxt)) != ',') {
    1415          13 :                                 if (ch == ')')
    1416             :                                         break;
    1417           0 :                                 if (cntxt->backup)
    1418           0 :                                         curBlk = NULL;
    1419           0 :                                 parseError(cntxt, "',' expected\n");
    1420           0 :                                 return curBlk;
    1421             :                         } else {
    1422          39 :                                 nextChar(cntxt);        /* skip ',' */
    1423             :                         }
    1424          39 :                         skipSpace(cntxt);
    1425          39 :                         ch = currChar(cntxt);
    1426             :                 }
    1427             :                 /* re-arrange the parameters, results first */
    1428          13 :                 max = curInstr->maxarg;
    1429          13 :                 newarg = (short *) GDKmalloc(max * sizeof(curInstr->argv[0]));
    1430          13 :                 if (newarg == NULL) {
    1431           0 :                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1432           0 :                         if (cntxt->backup)
    1433           0 :                                 curBlk = NULL;
    1434           0 :                         return curBlk;
    1435             :                 }
    1436          65 :                 for (i1 = retc; i1 < curInstr->argc; i1++)
    1437          52 :                         newarg[i2++] = curInstr->argv[i1];
    1438          13 :                 curInstr->retc = curInstr->argc - retc;
    1439          31 :                 for (i1 = 1; i1 < retc; i1++)
    1440          18 :                         newarg[i2++] = curInstr->argv[i1];
    1441          13 :                 curInstr->argc = i2;
    1442          26 :                 for (; i2 < max; i2++)
    1443          13 :                         newarg[i2] = 0;
    1444          96 :                 for (i1 = 0; i1 < max; i1++)
    1445          83 :                         curInstr->argv[i1] = newarg[i1];
    1446          13 :                 GDKfree(newarg);
    1447          13 :                 if (currChar(cntxt) != ')') {
    1448           0 :                         freeInstruction(curInstr);
    1449           0 :                         if (cntxt->backup)
    1450           0 :                                 curBlk = NULL;
    1451           0 :                         parseError(cntxt, "')' expected\n");
    1452           0 :                         return curBlk;
    1453             :                 }
    1454          13 :                 nextChar(cntxt);                /* skip ')' */
    1455             :         } else {                                        /* default */
    1456         116 :                 setVarType(curBlk, 0, TYPE_void);
    1457             :         }
    1458         212 :         if (curInstr != getInstrPtr(curBlk, 0)) {
    1459           0 :                 freeInstruction(getInstrPtr(curBlk, 0));
    1460           0 :                 putInstrPtr(curBlk, 0, curInstr);
    1461             :         }
    1462             :         return curBlk;
    1463             : }
    1464             : 
    1465             : static MalBlkPtr
    1466          13 : parseCommandPattern(Client cntxt, int kind, MALfcn address)
    1467             : {
    1468          13 :         MalBlkPtr curBlk = 0;
    1469          13 :         Symbol curPrg = 0;
    1470          13 :         InstrPtr curInstr = 0;
    1471          13 :         const char *modnme = NULL;
    1472          13 :         size_t l = 0;
    1473          13 :         str msg = MAL_SUCCEED;
    1474             : 
    1475          13 :         curBlk = fcnHeader(cntxt, kind);
    1476          13 :         if (curBlk == NULL) {
    1477           0 :                 cntxt->blkmode = 0;
    1478           0 :                 return curBlk;
    1479             :         }
    1480          13 :         getInstrPtr(curBlk, 0)->token = kind;
    1481          13 :         curPrg = cntxt->curprg;
    1482          13 :         curPrg->kind = kind;
    1483          13 :         curInstr = getInstrPtr(curBlk, 0);
    1484             : 
    1485          13 :         modnme = getModuleId(getInstrPtr(curBlk, 0));
    1486          13 :         if (modnme && (getModule(modnme) == FALSE && strcmp(modnme, "user"))) {
    1487             :                 // introduce the module
    1488           0 :                 if (globalModule(modnme) == NULL) {
    1489           0 :                         parseError(cntxt, "<module> could not be defined\n");
    1490           0 :                         return 0;
    1491             :                 }
    1492             :         }
    1493           0 :         modnme = modnme ? modnme : cntxt->usermodule->name;
    1494             : 
    1495          13 :         l = strlen(modnme);
    1496          13 :         modnme = putNameLen(modnme, l);
    1497          13 :         if (modnme == NULL) {
    1498           0 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1499           0 :                 return NULL;
    1500             :         }
    1501          13 :         if (strcmp(modnme, "user") == 0 || getModule(modnme)) {
    1502          13 :                 if (strcmp(modnme, "user") == 0)
    1503          10 :                         insertSymbol(cntxt->usermodule, curPrg);
    1504             :                 else
    1505           3 :                         insertSymbol(getModule(modnme), curPrg);
    1506          13 :                 if (!cntxt->curprg->def->errors)
    1507          13 :                         msg = chkProgram(cntxt->usermodule, curBlk);
    1508          13 :                 if (msg && !cntxt->curprg->def->errors)
    1509           0 :                         cntxt->curprg->def->errors = msg;
    1510          13 :                 if (cntxt->curprg->def->errors)
    1511           0 :                         freeException(cntxt->curprg->def->errors);
    1512          13 :                 cntxt->curprg->def->errors = cntxt->backup->def->errors;
    1513          13 :                 cntxt->backup->def->errors = 0;
    1514          13 :                 cntxt->curprg = cntxt->backup;
    1515          13 :                 cntxt->backup = 0;
    1516             :         } else {
    1517           0 :                 parseError(cntxt, "<module> not found\n");
    1518           0 :                 return 0;
    1519             :         }
    1520             : /*
    1521             :  * Short-cut function calls
    1522             :  * Most functions are (dynamically) linked with the kernel as
    1523             :  * commands or pattern definitions.  This enables for fast execution.
    1524             :  *
    1525             :  * In addition we allow functions to be bound to both
    1526             :  * a linked C-function and a MAL specification block.
    1527             :  * It the function address is not available, the interpreter
    1528             :  * will use the MAL block instead.
    1529             :  * This scheme is intended for just-in-time compilation.
    1530             :  *
    1531             :  * [note, command and patterns do not have a MAL block]
    1532             :  */
    1533          13 :         if (MALkeyword(cntxt, "address", 7)) {
    1534             :                 /* TO BE DEPRECATED */
    1535          13 :                 int i;
    1536          13 :                 i = idLength(cntxt);
    1537          13 :                 if (i == 0) {
    1538           0 :                         parseError(cntxt, "address <identifier> expected\n");
    1539           0 :                         return 0;
    1540             :                 }
    1541          13 :                 cntxt->blkmode = 0;
    1542          13 :                 if (getModuleId(curInstr))
    1543          13 :                         setModuleId(curInstr, NULL);
    1544          13 :                 setModuleScope(curInstr, findModule(cntxt->usermodule, modnme));
    1545             : 
    1546          13 :                 memcpy(curBlk->binding, CURRENT(cntxt),
    1547          13 :                            (size_t) (i < IDLENGTH ? i : IDLENGTH - 1));
    1548          13 :                 curBlk->binding[(i < IDLENGTH ? i : IDLENGTH - 1)] = 0;
    1549             :                 /* avoid a clash with old temporaries */
    1550          13 :                 advance(cntxt, i);
    1551          13 :                 curInstr->fcn = getAddress(getModuleId(curInstr), curBlk->binding);
    1552             : 
    1553          13 :                 if (cntxt->usermodule->isAtomModule) {
    1554           3 :                         if (curInstr->fcn == NULL) {
    1555           0 :                                 parseError(cntxt, "<address> not found\n");
    1556           0 :                                 return 0;
    1557             :                         }
    1558           3 :                         malAtomProperty(curBlk, curInstr);
    1559             :                 }
    1560          13 :                 skipSpace(cntxt);
    1561           0 :         } else if (address) {
    1562           0 :                 setModuleScope(curInstr, findModule(cntxt->usermodule, modnme));
    1563           0 :                 setModuleId(curInstr, modnme);
    1564           0 :                 curInstr->fcn = address;
    1565             :         }
    1566          13 :         helpInfo(cntxt, &curBlk->help);
    1567          13 :         return curBlk;
    1568             : }
    1569             : 
    1570             : static MalBlkPtr
    1571         199 : parseFunction(Client cntxt, int kind)
    1572             : {
    1573         199 :         MalBlkPtr curBlk = 0;
    1574             : 
    1575         199 :         curBlk = fcnHeader(cntxt, kind);
    1576         199 :         if (curBlk == NULL)
    1577             :                 return curBlk;
    1578         199 :         if (MALkeyword(cntxt, "address", 7)) {
    1579             :                 /* TO BE DEPRECATED */
    1580           1 :                 str nme;
    1581           1 :                 int i;
    1582           1 :                 InstrPtr curInstr = getInstrPtr(curBlk, 0);
    1583           1 :                 i = idLength(cntxt);
    1584           1 :                 if (i == 0) {
    1585           0 :                         parseError(cntxt, "<identifier> expected\n");
    1586           0 :                         return 0;
    1587             :                 }
    1588           1 :                 nme = idCopy(cntxt, i);
    1589           1 :                 if (nme == NULL) {
    1590           0 :                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1591           0 :                         return 0;
    1592             :                 }
    1593           1 :                 curInstr->fcn = getAddress(getModuleId(curInstr), nme);
    1594           1 :                 GDKfree(nme);
    1595           1 :                 if (curInstr->fcn == NULL) {
    1596           1 :                         parseError(cntxt, "<address> not found\n");
    1597           1 :                         return 0;
    1598             :                 }
    1599           0 :                 skipSpace(cntxt);
    1600             :         }
    1601             :         /* block is terminated at the END statement */
    1602         198 :         helpInfo(cntxt, &curBlk->help);
    1603         198 :         return curBlk;
    1604             : }
    1605             : 
    1606             : /*
    1607             :  * Functions and  factories end with a labeled end-statement.
    1608             :  * The routine below checks for misalignment of the closing statements.
    1609             :  * Any instruction parsed after the function block is considered an error.
    1610             :  */
    1611             : static int
    1612         292 : parseEnd(Client cntxt)
    1613             : {
    1614         292 :         Symbol curPrg = 0;
    1615         292 :         size_t l;
    1616         292 :         InstrPtr sig;
    1617         292 :         str errors = MAL_SUCCEED, msg = MAL_SUCCEED;
    1618             : 
    1619         292 :         if (MALkeyword(cntxt, "end", 3)) {
    1620         204 :                 curPrg = cntxt->curprg;
    1621         204 :                 l = idLength(cntxt);
    1622         204 :                 if (l == 0)
    1623          37 :                         l = operatorLength(cntxt);
    1624         204 :                 sig = getInstrPtr(cntxt->curprg->def, 0);
    1625         204 :                 if (strncmp(CURRENT(cntxt), getModuleId(sig), l) == 0) {
    1626          37 :                         advance(cntxt, l);
    1627          37 :                         skipSpace(cntxt);
    1628          37 :                         if (currChar(cntxt) == '.')
    1629           0 :                                 nextChar(cntxt);
    1630          37 :                         skipSpace(cntxt);
    1631          37 :                         l = idLength(cntxt);
    1632          37 :                         if (l == 0)
    1633          37 :                                 l = operatorLength(cntxt);
    1634             :                 }
    1635             :                 /* parse fcn */
    1636         204 :                 if ((l == strlen(curPrg->name) &&
    1637         204 :                          strncmp(CURRENT(cntxt), curPrg->name, l) == 0) || l == 0)
    1638         195 :                         advance(cntxt, l);
    1639             :                 else
    1640           9 :                         parseError(cntxt, "non matching end label\n");
    1641         204 :                 pushEndInstruction(cntxt->curprg->def);
    1642         204 :                 cntxt->blkmode = 0;
    1643         204 :                 if (strcmp(getModuleId(sig), "user") == 0)
    1644         199 :                         insertSymbol(cntxt->usermodule, cntxt->curprg);
    1645             :                 else
    1646           5 :                         insertSymbol(getModule(getModuleId(sig)), cntxt->curprg);
    1647             : 
    1648         204 :                 if (cntxt->curprg->def->errors) {
    1649          11 :                         errors = cntxt->curprg->def->errors;
    1650          11 :                         cntxt->curprg->def->errors = 0;
    1651             :                 }
    1652             :                 // check for newly identified errors
    1653         204 :                 msg = chkProgram(cntxt->usermodule, cntxt->curprg->def);
    1654         204 :                 if (errors == NULL)
    1655             :                         errors = msg;
    1656             :                 else
    1657          11 :                         freeException(msg);
    1658         204 :                 if (errors == NULL) {
    1659         169 :                         errors = cntxt->curprg->def->errors;
    1660         169 :                         cntxt->curprg->def->errors = 0;
    1661          35 :                 } else if (cntxt->curprg->def->errors) {
    1662             :                         //collect all errors for reporting
    1663           0 :                         str new = GDKmalloc(strlen(errors) +
    1664             :                                                                 strlen(cntxt->curprg->def->errors) + 16);
    1665           0 :                         if (new) {
    1666           0 :                                 strcpy(new, errors);
    1667           0 :                                 if (new[strlen(new) - 1] != '\n')
    1668           0 :                                         strcat(new, "\n");
    1669           0 :                                 strcat(new, "!");
    1670           0 :                                 strcat(new, cntxt->curprg->def->errors);
    1671             : 
    1672           0 :                                 freeException(errors);
    1673           0 :                                 freeException(cntxt->curprg->def->errors);
    1674             : 
    1675           0 :                                 cntxt->curprg->def->errors = 0;
    1676           0 :                                 errors = new;
    1677             :                         }
    1678             :                 }
    1679             : 
    1680         204 :                 if (cntxt->backup) {
    1681         194 :                         cntxt->curprg = cntxt->backup;
    1682         194 :                         cntxt->backup = 0;
    1683             :                 } else {
    1684          10 :                         str msg;
    1685          10 :                         if ((msg = MSinitClientPrg(cntxt, cntxt->curmodule->name,
    1686             :                                                                            "main")) != MAL_SUCCEED) {
    1687           0 :                                 if (errors) {
    1688           0 :                                         str new = GDKmalloc(strlen(errors) + strlen(msg) + 3);
    1689           0 :                                         if (new) {
    1690           0 :                                                 strcpy(new, msg);
    1691           0 :                                                 if (new[strlen(new) - 1] != '\n')
    1692           0 :                                                         strcat(new, "\n");
    1693           0 :                                                 strcat(new, errors);
    1694           0 :                                                 freeException(errors);
    1695           0 :                                                 cntxt->curprg->def->errors = new;
    1696             :                                         } else {
    1697           0 :                                                 cntxt->curprg->def->errors = errors;
    1698             :                                         }
    1699           0 :                                         freeException(msg);
    1700             :                                 } else {
    1701           0 :                                         cntxt->curprg->def->errors = msg;
    1702             :                                 }
    1703           0 :                                 return 1;
    1704             :                         }
    1705             :                 }
    1706             :                 // pass collected errors to context
    1707         204 :                 assert(cntxt->curprg->def->errors == NULL);
    1708         204 :                 cntxt->curprg->def->errors = errors;
    1709         204 :                 return 1;
    1710             :         }
    1711             :         return 0;
    1712             : }
    1713             : 
    1714             : /*
    1715             :  * Most instructions are simple assignments, possibly
    1716             :  * modified with a barrier/catch tag.
    1717             :  *
    1718             :  * The basic types are also predefined as a variable.
    1719             :  * This makes it easier to communicate types to MAL patterns.
    1720             :  */
    1721             : 
    1722             : #define GETvariable(FREE)                                                                                               \
    1723             :         if ((varid = findVariableLength(curBlk, CURRENT(cntxt), l)) == -1) { \
    1724             :                 varid = newVariable(curBlk, CURRENT(cntxt),l, TYPE_any);                \
    1725             :                 advance(cntxt, l);                                                                                              \
    1726             :                 if(varid <  0) { FREE; return; }                                                             \
    1727             :         } else                                                                                                                          \
    1728             :                 advance(cntxt, l);
    1729             : 
    1730             : /* The parameter of parseArguments is the return value of the enclosing function. */
    1731             : static int
    1732        8974 : parseArguments(Client cntxt, MalBlkPtr curBlk, InstrPtr *curInstr)
    1733             : {
    1734       24597 :         while (currChar(cntxt) != ')') {
    1735       15624 :                 switch (term(cntxt, curBlk, curInstr, 0)) {
    1736             :                 case 0:
    1737       15623 :                         break;
    1738             :                 case 2:
    1739             :                         return 2;
    1740             :                 case 3:
    1741             :                         return 3;
    1742           0 :                 case 4:
    1743           0 :                         parseError(cntxt, "Argument type overwrites previous definition\n");
    1744           0 :                         return 0;
    1745           0 :                 default:
    1746           0 :                         parseError(cntxt, "<factor> expected\n");
    1747           0 :                         return 1;
    1748             :                 }
    1749       15623 :                 if (currChar(cntxt) == ',')
    1750        7312 :                         advance(cntxt, 1);
    1751        8311 :                 else if (currChar(cntxt) != ')') {
    1752           0 :                         parseError(cntxt, "',' expected\n");
    1753           0 :                         cntxt->yycur--;              /* keep it */
    1754           0 :                         break;
    1755             :                 }
    1756             :         }
    1757        8973 :         if (currChar(cntxt) == ')')
    1758        8973 :                 advance(cntxt, 1);
    1759             :         return 0;
    1760             : }
    1761             : 
    1762             : static void
    1763       11748 : parseAssign(Client cntxt, int cntrl)
    1764             : {
    1765       11748 :         InstrPtr curInstr;
    1766       11748 :         MalBlkPtr curBlk;
    1767       11748 :         Symbol curPrg;
    1768       11748 :         int i = 0, l, type = TYPE_any, varid = -1;
    1769       11748 :         const char *arg = 0;
    1770       11748 :         ValRecord cst;
    1771             : 
    1772       11748 :         curPrg = cntxt->curprg;
    1773       11748 :         curBlk = curPrg->def;
    1774       11748 :         if ((curInstr = newInstruction(curBlk, NULL, NULL)) == NULL) {
    1775          13 :                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1776        2376 :                 return;
    1777             :         }
    1778             : 
    1779       11735 :         if (cntrl) {
    1780         592 :                 curInstr->token = ASSIGNsymbol;
    1781         592 :                 curInstr->barrier = cntrl;
    1782             :         }
    1783             : 
    1784             :         /* start the parsing by recognition of the lhs of an assignment */
    1785       11735 :         if (currChar(cntxt) == '(') {
    1786             :                 /* parsing multi-assignment */
    1787         218 :                 advance(cntxt, 1);
    1788         218 :                 curInstr->argc = 0;          /*reset to handle pushArg correctly !! */
    1789         218 :                 curInstr->retc = 0;
    1790        1838 :                 while (currChar(cntxt) != ')' && currChar(cntxt)) {
    1791        1620 :                         l = idLength(cntxt);
    1792        1620 :                         i = cstToken(cntxt, &cst);
    1793        1620 :                         if (l == 0 || i) {
    1794           1 :                                 parseError(cntxt, "<identifier> or <literal> expected\n");
    1795           1 :                                 freeInstruction(curInstr);
    1796           1 :                                 return;
    1797             :                         }
    1798        1619 :                         GETvariable(freeInstruction(curInstr));
    1799        1619 :                         if (currChar(cntxt) == ':') {
    1800          31 :                                 type = typeElm(cntxt, getVarType(curBlk, varid));
    1801          31 :                                 if (type < 0)
    1802           0 :                                         goto part3;
    1803          31 :                                 setPolymorphic(curInstr, type, FALSE);
    1804          31 :                                 setVarType(curBlk, varid, type);
    1805             :                         }
    1806        1619 :                         curInstr = pushArgument(curBlk, curInstr, varid);
    1807        1619 :                         curInstr->retc++;
    1808        1619 :                         if (currChar(cntxt) == ')')
    1809             :                                 break;
    1810        1402 :                         if (currChar(cntxt) == ',')
    1811        1402 :                                 keyphrase1(cntxt, ",");
    1812             :                 }
    1813         217 :                 advance(cntxt, 1);              /* skip ')' */
    1814         217 :                 if (curInstr->retc == 0) {
    1815             :                         /* add dummy variable */
    1816           0 :                         curInstr = pushArgument(curBlk, curInstr,
    1817             :                                                                         newTmpVariable(curBlk, TYPE_any));
    1818           0 :                         curInstr->retc++;
    1819             :                 }
    1820             :         } else {
    1821             :                 /* are we dealing with a simple assignment? */
    1822       11517 :                 l = idLength(cntxt);
    1823       11517 :                 i = cstToken(cntxt, &cst);
    1824       11517 :                 if (l == 0 || i) {
    1825             :                         /* we haven't seen a target variable */
    1826             :                         /* flow of control statements may end here. */
    1827             :                         /* shouldn't allow for nameless controls todo */
    1828           6 :                         if (i && cst.vtype == TYPE_str)
    1829           0 :                                 GDKfree(cst.val.sval);
    1830           6 :                         if (cntrl == LEAVEsymbol || cntrl == REDOsymbol ||
    1831           6 :                                 cntrl == RETURNsymbol || cntrl == EXITsymbol) {
    1832           4 :                                 curInstr->argv[0] = getBarrierEnvelop(curBlk);
    1833           4 :                                 if (currChar(cntxt) != ';') {
    1834           0 :                                         freeInstruction(curInstr);
    1835           0 :                                         parseError(cntxt,
    1836             :                                                            "<identifier> or <literal> expected in control statement\n");
    1837           0 :                                         return;
    1838             :                                 }
    1839           4 :                                 pushInstruction(curBlk, curInstr);
    1840           4 :                                 return;
    1841             :                         }
    1842           2 :                         getArg(curInstr, 0) = newTmpVariable(curBlk, TYPE_any);
    1843           2 :                         freeInstruction(curInstr);
    1844           2 :                         parseError(cntxt, "<identifier> or <literal> expected\n");
    1845           2 :                         return;
    1846             :                 }
    1847             :                 /* Check if we are dealing with module.fcn call */
    1848       11511 :                 if (CURRENT(cntxt)[l] == '.' || CURRENT(cntxt)[l] == '(') {
    1849        4368 :                         curInstr->argv[0] = newTmpVariable(curBlk, TYPE_any);
    1850        4368 :                         goto FCNcallparse;
    1851             :                 }
    1852             : 
    1853             :                 /* Get target variable details */
    1854        7143 :                 GETvariable(freeInstruction(curInstr));
    1855        7143 :                 if (!(currChar(cntxt) == ':' && CURRENT(cntxt)[1] == '=')) {
    1856         449 :                         curInstr->argv[0] = varid;
    1857         449 :                         if (currChar(cntxt) == ':') {
    1858         164 :                                 type = typeElm(cntxt, getVarType(curBlk, varid));
    1859         164 :                                 if (type < 0)
    1860           0 :                                         goto part3;
    1861         164 :                                 setPolymorphic(curInstr, type, FALSE);
    1862         164 :                                 setVarType(curBlk, varid, type);
    1863             :                         }
    1864             :                 }
    1865        7143 :                 curInstr->argv[0] = varid;
    1866             :         }
    1867             :         /* look for assignment operator */
    1868        7360 :         if (!keyphrase2(cntxt, ":=")) {
    1869             :                 /* no assignment !! a control variable is allowed */
    1870             :                 /* for the case RETURN X, we normalize it to include the function arguments */
    1871         326 :                 if (cntrl == RETURNsymbol) {
    1872          31 :                         int e;
    1873          31 :                         InstrPtr sig = getInstrPtr(curBlk, 0);
    1874          31 :                         curInstr->retc = 0;
    1875          64 :                         for (e = 0; e < sig->retc; e++)
    1876          33 :                                 curInstr = pushReturn(curBlk, curInstr, getArg(sig, e));
    1877             :                 }
    1878             : 
    1879         326 :                 goto part3;
    1880             :         }
    1881        7034 :         if (currChar(cntxt) == '(') {
    1882             :                 /* parse multi assignment */
    1883           9 :                 advance(cntxt, 1);
    1884           9 :                 switch (parseArguments(cntxt, curBlk, &curInstr)) {
    1885           0 :                 case 2:
    1886           0 :                         goto part2;
    1887           9 :                 default:
    1888             :                 case 3:
    1889           9 :                         goto part3;
    1890             :                 }
    1891             :                 /* unreachable */
    1892             :         }
    1893             : /*
    1894             :  * We have so far the LHS part of an assignment. The remainder is
    1895             :  * either a simple term expression, a multi assignent, or the start
    1896             :  * of a function call.
    1897             :  */
    1898        7025 :   FCNcallparse:
    1899       11393 :         if ((l = idLength(cntxt)) && CURRENT(cntxt)[l] == '(') {
    1900             :                 /*  parseError(cntxt,"<module> expected\n"); */
    1901          62 :                 setModuleId(curInstr, cntxt->curmodule->name);
    1902          62 :                 i = l;
    1903          62 :                 goto FCNcallparse2;
    1904       11331 :         } else if ((l = idLength(cntxt)) && CURRENT(cntxt)[l] == '.') {
    1905             :                 /* continue with parseing a function/operator call */
    1906        8905 :                 arg = putNameLen(CURRENT(cntxt), l);
    1907        8905 :                 if (arg == NULL) {
    1908           0 :                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1909           0 :                         freeInstruction(curInstr);
    1910           0 :                         return;
    1911             :                 }
    1912        8905 :                 advance(cntxt, l + 1);  /* skip '.' too */
    1913        8905 :                 setModuleId(curInstr, arg);
    1914        8905 :                 i = idLength(cntxt);
    1915        8905 :                 if (i == 0)
    1916          68 :                         i = operatorLength(cntxt);
    1917        8837 :   FCNcallparse2:
    1918         130 :                 if (i) {
    1919        8967 :                         setFunctionId(curInstr, putNameLen(((char *) CURRENT(cntxt)), i));
    1920        8967 :                         if (getFunctionId(curInstr) == NULL) {
    1921           0 :                                 parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1922           0 :                                 freeInstruction(curInstr);
    1923           0 :                                 return;
    1924             :                         }
    1925        8967 :                         advance(cntxt, i);
    1926             :                 } else {
    1927           0 :                         parseError(cntxt, "<functionname> expected\n");
    1928           0 :                         freeInstruction(curInstr);
    1929           0 :                         return;
    1930             :                 }
    1931        8967 :                 skipSpace(cntxt);
    1932        8967 :                 if (currChar(cntxt) != '(') {
    1933           2 :                         parseError(cntxt, "'(' expected\n");
    1934           2 :                         freeInstruction(curInstr);
    1935           2 :                         return;
    1936             :                 }
    1937        8965 :                 advance(cntxt, 1);
    1938        8965 :                 switch (parseArguments(cntxt, curBlk, &curInstr)) {
    1939           0 :                 case 2:
    1940           0 :                         goto part2;
    1941        8965 :                 default:
    1942             :                 case 3:
    1943        8965 :                         goto part3;
    1944             :                 }
    1945             :                 /* unreachable */
    1946             :         }
    1947             :         /* Handle the ordinary assignments and expressions */
    1948        2426 :         switch (term(cntxt, curBlk, &curInstr, 2)) {
    1949        2254 :         case 2:
    1950        2254 :                 goto part2;
    1951           3 :         case 3:
    1952           3 :                 goto part3;
    1953             :         }
    1954             :   part2:                                                /* consume <operator><term> part of expression */
    1955        2423 :         if ((i = operatorLength(cntxt))) {
    1956             :                 /* simple arithmetic operator expression */
    1957         122 :                 setFunctionId(curInstr, putNameLen(((char *) CURRENT(cntxt)), i));
    1958         122 :                 if (getFunctionId(curInstr) == NULL) {
    1959           0 :                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1960           0 :                         freeInstruction(curInstr);
    1961           0 :                         return;
    1962             :                 }
    1963         122 :                 advance(cntxt, i);
    1964         122 :                 curInstr->modname = putName("calc");
    1965         122 :                 if (curInstr->modname == NULL) {
    1966           0 :                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    1967           0 :                         freeInstruction(curInstr);
    1968           0 :                         return;
    1969             :                 }
    1970         122 :                 if ((l = idLength(cntxt))
    1971          54 :                         && !(l == 3 && strncmp(CURRENT(cntxt), "nil", 3) == 0)) {
    1972          54 :                         GETvariable(freeInstruction(curInstr));
    1973          54 :                         curInstr = pushArgument(curBlk, curInstr, varid);
    1974          54 :                         goto part3;
    1975             :                 }
    1976          68 :                 switch (term(cntxt, curBlk, &curInstr, 3)) {
    1977           0 :                 case 2:
    1978           0 :                         goto part2;
    1979          67 :                 case 3:
    1980          67 :                         goto part3;
    1981             :                 }
    1982           1 :                 parseError(cntxt, "<term> expected\n");
    1983           1 :                 freeInstruction(curInstr);
    1984           1 :                 return;
    1985             :         } else {
    1986        2301 :                 skipSpace(cntxt);
    1987        2301 :                 if (currChar(cntxt) == '(') {
    1988           0 :                         parseError(cntxt, "module name missing\n");
    1989           0 :                         freeInstruction(curInstr);
    1990           0 :                         return;
    1991        2301 :                 } else if (currChar(cntxt) != ';' && currChar(cntxt) != '#') {
    1992           1 :                         parseError(cntxt, "operator expected\n");
    1993           1 :                         freeInstruction(curInstr);
    1994           1 :                         return;
    1995             :                 }
    1996        2300 :                 pushInstruction(curBlk, curInstr);
    1997        2300 :                 return;
    1998             :         }
    1999        9424 :   part3:
    2000        9424 :         skipSpace(cntxt);
    2001        9424 :         if (currChar(cntxt) != ';') {
    2002          39 :                 parseError(cntxt, "';' expected\n");
    2003          39 :                 skipToEnd(cntxt);
    2004          39 :                 freeInstruction(curInstr);
    2005          39 :                 return;
    2006             :         }
    2007        9385 :         skipToEnd(cntxt);
    2008        9385 :         if (cntrl == RETURNsymbol
    2009          36 :                 && !(curInstr->token == ASSIGNsymbol || getModuleId(curInstr) != 0)) {
    2010           0 :                 parseError(cntxt, "return assignment expected\n");
    2011           0 :                 freeInstruction(curInstr);
    2012           0 :                 return;
    2013             :         }
    2014        9385 :         pushInstruction(curBlk, curInstr);
    2015             : }
    2016             : 
    2017             : void
    2018       10461 : parseMAL(Client cntxt, Symbol curPrg, int skipcomments, int lines,
    2019             :                  MALfcn address)
    2020             : {
    2021       10461 :         int cntrl = 0;
    2022             :         /*Symbol curPrg= cntxt->curprg; */
    2023       10461 :         char c;
    2024       10461 :         int inlineProp = 0, unsafeProp = 0;
    2025             : 
    2026       10461 :         (void) curPrg;
    2027       10461 :         echoInput(cntxt);
    2028             :         /* here the work takes place */
    2029       41858 :         while ((c = currChar(cntxt)) && lines > 0) {
    2030       31397 :                 switch (c) {
    2031       13851 :                 case '\n':
    2032             :                 case '\r':
    2033             :                 case '\f':
    2034       13851 :                         lines -= c == '\n';
    2035       13851 :                         nextChar(cntxt);
    2036       13851 :                         echoInput(cntxt);
    2037       13851 :                         continue;
    2038        5337 :                 case ';':
    2039             :                 case '\t':
    2040             :                 case ' ':
    2041        5337 :                         nextChar(cntxt);
    2042        5337 :                         continue;
    2043          13 :                 case '#':
    2044             :                 {                                               /* keep the full line comments */
    2045          13 :                         char start[256], *e = start, c;
    2046          13 :                         MalBlkPtr curBlk = cntxt->curprg->def;
    2047          13 :                         InstrPtr curInstr;
    2048             : 
    2049          13 :                         *e = 0;
    2050          13 :                         nextChar(cntxt);
    2051         228 :                         while ((c = currChar(cntxt))) {
    2052         228 :                                 if (e < start + 256 - 1)
    2053         228 :                                         *e++ = c;
    2054         228 :                                 nextChar(cntxt);
    2055         228 :                                 if (c == '\n' || c == '\r') {
    2056          13 :                                         *e = 0;
    2057          13 :                                         if (e > start)
    2058          13 :                                                 e--;
    2059             :                                         /* prevChar(cntxt); */
    2060             :                                         break;
    2061             :                                 }
    2062             :                         }
    2063          13 :                         if (e > start)
    2064          13 :                                 *e = 0;
    2065          13 :                         if (!skipcomments && e > start && curBlk->stop > 0) {
    2066          13 :                                 ValRecord cst;
    2067          13 :                                 if ((curInstr = newInstruction(curBlk, NULL, NULL)) == NULL) {
    2068           1 :                                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2069           1 :                                         continue;
    2070             :                                 }
    2071          12 :                                 curInstr->token = REMsymbol;
    2072          12 :                                 curInstr->barrier = 0;
    2073          12 :                                 if (VALinit(&cst, TYPE_str, start) == NULL) {
    2074           0 :                                         parseError(cntxt, SQLSTATE(HY013) MAL_MALLOC_FAIL);
    2075           0 :                                         freeInstruction(curInstr);
    2076           0 :                                         continue;
    2077             :                                 }
    2078          12 :                                 int cstidx = defConstant(curBlk, TYPE_str, &cst);
    2079          12 :                                 if (cstidx < 0) {
    2080           0 :                                         freeInstruction(curInstr);
    2081           0 :                                         continue;
    2082             :                                 }
    2083          12 :                                 getArg(curInstr, 0) = cstidx;
    2084          12 :                                 setVarDisabled(curBlk, getArg(curInstr, 0));
    2085          12 :                                 pushInstruction(curBlk, curInstr);
    2086             :                         }
    2087          12 :                         echoInput(cntxt);
    2088             :                 }
    2089          12 :                         continue;
    2090          97 :                 case 'A':
    2091             :                 case 'a':
    2092          97 :                         if (MALkeyword(cntxt, "atom", 4) && parseAtom(cntxt) == 0)
    2093             :                                 break;
    2094          92 :                         goto allLeft;
    2095        1213 :                 case 'b':
    2096             :                 case 'B':
    2097        1213 :                         if (MALkeyword(cntxt, "barrier", 7)) {
    2098         165 :                                 cntxt->blkmode++;
    2099         165 :                                 cntrl = BARRIERsymbol;
    2100             :                         }
    2101        1213 :                         goto allLeft;
    2102         469 :                 case 'C':
    2103             :                 case 'c':
    2104         469 :                         if (MALkeyword(cntxt, "command", 7)) {
    2105           5 :                                 MalBlkPtr p = parseCommandPattern(cntxt, COMMANDsymbol, address);
    2106           5 :                                 if (p) {
    2107           5 :                                         p->unsafeProp = unsafeProp;
    2108             :                                 }
    2109           5 :                                 cntxt->curprg->def->unsafeProp = unsafeProp;
    2110           5 :                                 if (inlineProp)
    2111           0 :                                         parseError(cntxt, "<identifier> expected\n");
    2112           5 :                                 inlineProp = 0;
    2113           5 :                                 unsafeProp = 0;
    2114           5 :                                 continue;
    2115             :                         }
    2116         464 :                         if (MALkeyword(cntxt, "catch", 5)) {
    2117          24 :                                 cntxt->blkmode++;
    2118          24 :                                 cntrl = CATCHsymbol;
    2119          24 :                                 goto allLeft;
    2120             :                         }
    2121         440 :                         goto allLeft;
    2122         487 :                 case 'E':
    2123             :                 case 'e':
    2124         487 :                         if (MALkeyword(cntxt, "exit", 4)) {
    2125         195 :                                 if (cntxt->blkmode > 0)
    2126         189 :                                         cntxt->blkmode--;
    2127             :                                 cntrl = EXITsymbol;
    2128         292 :                         } else if (parseEnd(cntxt)) {
    2129             :                                 break;
    2130             :                         }
    2131         283 :                         goto allLeft;
    2132         333 :                 case 'F':
    2133             :                 case 'f':
    2134         333 :                         if (MALkeyword(cntxt, "function", 8)) {
    2135         199 :                                 MalBlkPtr p;
    2136         199 :                                 cntxt->blkmode++;
    2137         199 :                                 if ((p = parseFunction(cntxt, FUNCTIONsymbol))) {
    2138         198 :                                         p->unsafeProp = unsafeProp;
    2139         198 :                                         cntxt->curprg->def->inlineProp = inlineProp;
    2140         198 :                                         cntxt->curprg->def->unsafeProp = unsafeProp;
    2141         198 :                                         inlineProp = 0;
    2142         198 :                                         unsafeProp = 0;
    2143         198 :                                         break;
    2144             :                                 }
    2145             :                         }
    2146         135 :                         goto allLeft;
    2147        1796 :                 case 'I':
    2148             :                 case 'i':
    2149        1796 :                         if (MALkeyword(cntxt, "inline", 6)) {
    2150          23 :                                 inlineProp = 1;
    2151          23 :                                 skipSpace(cntxt);
    2152          23 :                                 continue;
    2153        1773 :                         } else if (MALkeyword(cntxt, "include", 7)) {
    2154           2 :                                 parseInclude(cntxt);
    2155           2 :                                 break;
    2156             :                         }
    2157        1771 :                         goto allLeft;
    2158          81 :                 case 'L':
    2159             :                 case 'l':
    2160          81 :                         if (MALkeyword(cntxt, "leave", 5))
    2161          40 :                                 cntrl = LEAVEsymbol;
    2162          81 :                         goto allLeft;
    2163          79 :                 case 'M':
    2164             :                 case 'm':
    2165          79 :                         if (MALkeyword(cntxt, "module", 6) && parseModule(cntxt) == 0)
    2166             :                                 break;
    2167          76 :                         goto allLeft;
    2168          63 :                 case 'P':
    2169             :                 case 'p':
    2170          63 :                         if (MALkeyword(cntxt, "pattern", 7)) {
    2171           8 :                                 MalBlkPtr p;
    2172           8 :                                 if (inlineProp)
    2173           0 :                                         parseError(cntxt, "parseError:INLINE ignored\n");
    2174           8 :                                 p = parseCommandPattern(cntxt, PATTERNsymbol, address);
    2175           8 :                                 if (p) {
    2176           8 :                                         p->unsafeProp = unsafeProp;
    2177             :                                 }
    2178           8 :                                 cntxt->curprg->def->unsafeProp = unsafeProp;
    2179           8 :                                 inlineProp = 0;
    2180           8 :                                 unsafeProp = 0;
    2181           8 :                                 continue;
    2182             :                         }
    2183          55 :                         goto allLeft;
    2184        5736 :                 case 'R':
    2185             :                 case 'r':
    2186        5736 :                         if (MALkeyword(cntxt, "redo", 4)) {
    2187          85 :                                 cntrl = REDOsymbol;
    2188          85 :                                 goto allLeft;
    2189             :                         }
    2190        5651 :                         if (MALkeyword(cntxt, "raise", 5)) {
    2191           7 :                                 cntrl = RAISEsymbol;
    2192           7 :                                 goto allLeft;
    2193             :                         }
    2194        5644 :                         if (MALkeyword(cntxt, "return", 6)) {
    2195          76 :                                 cntrl = RETURNsymbol;
    2196             :                         }
    2197        5644 :                         goto allLeft;
    2198          51 :                 case 'U':
    2199             :                 case 'u':
    2200          51 :                         if (MALkeyword(cntxt, "unsafe", 6)) {
    2201           0 :                                 unsafeProp = 1;
    2202           0 :                                 skipSpace(cntxt);
    2203           0 :                                 continue;
    2204             :                         }
    2205             :                         /* fall through */
    2206             :                 default:
    2207          51 :   allLeft:
    2208       11748 :                         parseAssign(cntxt, cntrl);
    2209       11748 :                         cntrl = 0;
    2210             :                 }
    2211             :         }
    2212       10461 :         skipSpace(cntxt);
    2213       10461 : }

Generated by: LCOV version 1.14