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

Generated by: LCOV version 1.14