LCOV - code coverage report
Current view: top level - monetdb5/mal - mal_parser.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 827 1044 79.2 %
Date: 2021-09-14 22:17:06 Functions: 35 35 100.0 %

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

Generated by: LCOV version 1.14