36dcc59871b9d3c32a43919d2d6d26fef10e3d78 kent Tue Aug 6 11:50:28 2019 -0700 Making rql interpreter handle string additions, which the parser was just merrily putting in leading to internalErrs during the eval phase. To support this adding a new rqlEvalCoerceToString function. diff --git src/lib/rqlEval.c src/lib/rqlEval.c index 84feb57..e0d86bb 100644 --- src/lib/rqlEval.c +++ src/lib/rqlEval.c @@ -31,30 +31,58 @@ case rqlTypeInt: r.val.b = (r.val.i != 0); break; case rqlTypeDouble: r.val.b = (r.val.x != 0.0); break; default: internalErr(); r.val.b = FALSE; break; } r.type = rqlTypeBoolean; return r; } +struct rqlEval rqlEvalCoerceToString(struct rqlEval r, char *buf, int bufSize) +/* Return a version of r with .val.s filled in with something reasonable even + * if r input is not a string */ +{ +assert(bufSize >= 32); +switch (r.type) + { + case rqlTypeBoolean: + r.val.s = (r.val.b ? "true" : "false"); + case rqlTypeString: + break; /* It's already done. */ + case rqlTypeInt: + safef(buf, bufSize, "%lld", r.val.i); + r.val.s = buf; + break; + case rqlTypeDouble: + safef(buf, bufSize, "%g", r.val.x); + r.val.s = buf; + break; + default: + internalErr(); + r.val.s = NULL; + break; + } +r.type = rqlTypeString; +return r; +} + static struct rqlEval rqlEvalEq(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Return true if two children are equal regardless of children type * (which are just gauranteed to be the same). */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next; struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm); struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm); struct rqlEval res; res.type = rqlTypeBoolean; assert(lv.type == rv.type); switch (lv.type) { case rqlTypeBoolean: @@ -146,30 +174,45 @@ /* Return a + b. */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next; struct rqlEval lv = rqlLocalEval(lp, record, lookup, lm); struct rqlEval rv = rqlLocalEval(rp, record, lookup, lm); struct rqlEval res; switch (lv.type) { case rqlTypeInt: res.val.i = (lv.val.i + rv.val.i); break; case rqlTypeDouble: res.val.x = (lv.val.x + rv.val.x); break; + case rqlTypeString: + { + char numBuf[32]; + if (rv.type != rqlTypeString) // Perhaps later could coerce to string + { + rv = rqlEvalCoerceToString(rv, numBuf, sizeof(numBuf)); + } + int lLen = strlen(lv.val.s); + int rLen = strlen(rv.val.s); + char *s = lmAlloc(lm, lLen + rLen + 1); + memcpy(s, lv.val.s, lLen); + memcpy(s+lLen, rv.val.s, rLen); + res.val.s = s; + break; + } default: internalErr(); res.val.b = FALSE; break; } res.type = lv.type; return res; } static struct rqlEval rqlEvalSubtract(struct rqlParse *p, void *record, RqlEvalLookup lookup, struct lm *lm) /* Return a - b. */ { struct rqlParse *lp = p->children; struct rqlParse *rp = lp->next;