10a280e3c8255ef35d6e08053893557b38c6701c kent Sat Aug 17 10:57:51 2019 -0700 Refactoring code so that symbol table and lookup and local memory store is all combined into a strexRuntime structure, and passed as a single parameter rather than three in the evaluation chain. Then added warnHandler and abortHandler passed in to strexEvalAsString to it. All this is in preparation for implementing warn and error builtins. diff --git src/lib/strex.c src/lib/strex.c index 81c4c37..04481bc 100644 --- src/lib/strex.c +++ src/lib/strex.c @@ -19,30 +19,31 @@ * available in the same directory as this file as strex.doc when you read this. * * The subscript operator treats the string it is applied to as a comma separated value array. * It really is not very efficient alas. */ #include "common.h" #include "linefile.h" #include "hash.h" #include "dystring.h" #include "sqlNum.h" #include "localmem.h" #include "csv.h" #include "tokenizer.h" #include "hmac.h" +#include "errAbort.h" #include "strex.h" enum strexType /* A type within parse tree or built in function specification. */ { strexTypeBoolean = 1, strexTypeString = 2, strexTypeInt = 3, strexTypeDouble = 4, }; enum strexBuiltInFunc /* One of these for each builtIn. We'll just do a switch to implement * Each built in function needs a value here, to keep it simple there's @@ -1118,32 +1119,78 @@ struct strexParse *strexParseFile(char *fileName, void *symbols, StrexLookup lookup) /* Parse string expression out of a file */ { struct lineFile *lf = lineFileOpen(fileName, TRUE); struct strexIn *si = strexInNew(lf, symbols, lookup); si->tkz->uncommentShell = TRUE; // Yay to comments. struct strexParse *parseTree = strexParseExpression(si); ensureAtEnd(si); strexInFree(&si); return parseTree; } /************ The parsing section is done, now for the evaluation section. **************/ -static struct strexEval strexLocalEval(struct strexParse *p, void *record, StrexLookup lookup, - struct lm *lm); +struct strexRun +/* What we need to run a strex expression evaluation */ + { + void *symbols; /* Pointer to symbol table */ + StrexLookup lookup; /* Something that can look up things in symbol table */ + struct lm *lm; /* Local memory for evaluation */ + void (*warnHandler)(char *warning); /* Send warning messages here */ + void (*abortHandler)(); /* Call this guy to abort */ + }; + +static void strexDefaultWarn(char *warning) +/* Default warning handler */ +{ +warn("%s", warning); +} + +static void strexDefaultAbort() +/* Default abort handler */ +{ +noWarnAbort(); +} + +static struct strexRun *strexRunNew(void *symbols, StrexLookup lookup, + void (*warnHandler)(char *warning), void (*abortHandler)() ) +/* Return new strexRun structure */ +{ +struct strexRun *run; +AllocVar(run); +run->lm = lmInit(0); +run->symbols = symbols; +run->lookup = lookup; +run->warnHandler = (warnHandler != NULL ? warnHandler : strexDefaultWarn); +run->abortHandler = (abortHandler != NULL ? abortHandler : strexDefaultAbort); +return run; +} + +static void strexRunFree(struct strexRun **pRun) +/* Free up strex run structure */ +{ +struct strexRun *run = *pRun; +if (run != NULL) + { + lmCleanup(&run->lm); + freez(pRun); + } +} + +static struct strexEval strexLocalEval(struct strexParse *p, struct strexRun *run); /* Evaluate self on parse tree, allocating memory if needed from lm. */ static struct strexEval strexEvalCoerceToString(struct strexEval 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 strexTypeBoolean: r.val.s = (r.val.b ? "true" : "false"); break; case strexTypeString: break; /* It's already done. */ @@ -1152,113 +1199,110 @@ r.val.s = buf; break; case strexTypeDouble: safef(buf, bufSize, "%g", r.val.x); r.val.s = buf; break; default: internalErr(); r.val.s = NULL; break; } r.type = strexTypeString; return r; } -static struct strexEval strexEvalAdd(struct strexParse *p, void *record, StrexLookup lookup, - struct lm *lm) +static struct strexEval strexEvalAdd(struct strexParse *p, struct strexRun *run) /* Return a + b. */ { struct strexParse *lp = p->children; struct strexParse *rp = lp->next; -struct strexEval lv = strexLocalEval(lp, record, lookup, lm); -struct strexEval rv = strexLocalEval(rp, record, lookup, lm); +struct strexEval lv = strexLocalEval(lp, run); +struct strexEval rv = strexLocalEval(rp, run); struct strexEval res; assert(lv.type == rv.type); // Is our type automatic casting working? switch (lv.type) { case strexTypeInt: res.val.i = (lv.val.i + rv.val.i); break; case strexTypeDouble: res.val.x = (lv.val.x + rv.val.x); break; case strexTypeString: { char numBuf[32]; if (rv.type != strexTypeString) // Perhaps later could coerce to string { rv = strexEvalCoerceToString(rv, numBuf, sizeof(numBuf)); } int lLen = strlen(lv.val.s); int rLen = strlen(rv.val.s); - char *s = lmAlloc(lm, lLen + rLen + 1); + char *s = lmAlloc(run->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 strexEval strexEvalOr(struct strexParse *p, void *record, StrexLookup lookup, - struct lm *lm) +static struct strexEval strexEvalOr(struct strexParse *p, struct strexRun *run) /* Return a or b. */ { struct strexParse *lp = p->children; struct strexParse *rp = lp->next; -struct strexEval lv = strexLocalEval(lp, record, lookup, lm); -struct strexEval rv = strexLocalEval(rp, record, lookup, lm); +struct strexEval lv = strexLocalEval(lp, run); +struct strexEval rv = strexLocalEval(rp, run); struct strexEval res; assert(lv.type == rv.type); // Is our type automatic casting working? switch (lv.type) { case strexTypeBoolean: res.val.b = (lv.val.b || rv.val.b); break; case strexTypeInt: res.val.i = (lv.val.i ? lv.val.i : rv.val.i); break; case strexTypeDouble: res.val.x = (lv.val.x != 0.0 ? lv.val.x : rv.val.x); break; case strexTypeString: res.val.s = (lv.val.s[0] ? lv.val.s : rv.val.s); break; default: internalErr(); res.val.b = FALSE; break; } res.type = lv.type; return res; } -static struct strexEval strexEvalAnd(struct strexParse *p, void *record, StrexLookup lookup, - struct lm *lm) +static struct strexEval strexEvalAnd(struct strexParse *p, struct strexRun *run) /* Return a and b. */ { struct strexParse *lp = p->children; struct strexParse *rp = lp->next; -struct strexEval lv = strexLocalEval(lp, record, lookup, lm); -struct strexEval rv = strexLocalEval(rp, record, lookup, lm); +struct strexEval lv = strexLocalEval(lp, run); +struct strexEval rv = strexLocalEval(rp, run); struct strexEval res; assert(lv.type == rv.type); // Is our type automatic casting working? switch (lv.type) { case strexTypeBoolean: res.val.b = (lv.val.b && rv.val.b); break; case strexTypeInt: res.val.i = (lv.val.i ? rv.val.i : lv.val.i); break; case strexTypeDouble: res.val.x = (lv.val.x != 0.0 ? rv.val.x : lv.val.x); break; case strexTypeString: res.val.s = (lv.val.s[0] ? rv.val.s : lv.val.s); @@ -1274,73 +1318,71 @@ static char *csvParseOneOut(char *csvIn, int ix, struct dyString *scratch) /* Return csv value of given index or NULL if at end */ { char *pos = csvIn; int i; for (i=0; ichildren; struct strexParse *index = array->next; -struct strexEval arrayVal = strexLocalEval(array, record, lookup, lm); -struct strexEval indexVal = strexLocalEval(index, record, lookup, lm); +struct strexEval arrayVal = strexLocalEval(array, run); +struct strexEval indexVal = strexLocalEval(index, run); int ix = indexVal.val.i; if (ix < 0) ix = strlen(arrayVal.val.s) + ix; struct strexEval res; -res.val.s = lmCloneStringZ(lm, arrayVal.val.s + ix, 1); +res.val.s = lmCloneStringZ(run->lm, arrayVal.val.s + ix, 1); res.type = strexTypeString; return res; } -static struct strexEval strexEvalArrayRange(struct strexParse *p, - void *record, StrexLookup lookup, struct lm *lm) +static struct strexEval strexEvalArrayRange(struct strexParse *p, struct strexRun *run) /* Handle parse tree generated by array range expression, which by now * has just been turned into two integer values. */ { struct strexParse *array = p->children; struct strexParse *index1 = array->next; struct strexParse *index2 = index1->next; -struct strexEval arrayVal = strexLocalEval(array, record, lookup, lm); -struct strexEval rangeStart = strexLocalEval(index1, record, lookup, lm); -struct strexEval rangeEnd = strexLocalEval(index2, record, lookup, lm); +struct strexEval arrayVal = strexLocalEval(array, run); +struct strexEval rangeStart = strexLocalEval(index1, run); +struct strexEval rangeEnd = strexLocalEval(index2, run); char *arraySource = arrayVal.val.s; int start = rangeStart.val.i; int end = rangeEnd.val.i; int len = strlen(arraySource); if (start < 0) start = strlen(arraySource) + start; if (end < 0) end = strlen(arraySource) + end; if (start < 0) start = 0; if (end > len) end = len; if (end < start) end = start; // errors apparently just get truncated in this language. hmm struct strexEval res; -res.val.s = lmCloneStringZ(lm, arrayVal.val.s + start, end-start); +res.val.s = lmCloneStringZ(run->lm, arrayVal.val.s + start, end-start); res.type = strexTypeString; return res; } static char *splitString(char *words, int ix, struct lm *lm) /* Return the space-delimited word of index ix as clone into lm */ { if (ix < 0) // Negative index. We got to count, dang { int wordCount = chopByWhite(words, NULL, 0); ix = wordCount + ix; if (ix < 0) return ""; } char *s = words; @@ -1454,193 +1496,193 @@ out += strlen(hexBuf); } } *out++ = 0; int len = strlen(result) - prefixSize; if (len > 32) { char *md5 = hmacMd5("", original); strcpy(result + prefixSize, md5); freeMem(md5); } return result; } -static struct strexEval strexEvalCallBuiltIn(struct strexParse *p, - void *record, StrexLookup lookup, struct lm *lm) +static struct strexEval strexEvalCallBuiltIn(struct strexParse *p, struct strexRun *run) /* Handle parse tree generated by call to a built in function. */ { struct strexBuiltIn *builtIn = p->val.builtIn; struct strexEval res; res.type = builtIn->returnType; +struct lm *lm = run->lm; switch (builtIn->func) { case strexBuiltInTrim: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); res.val.s = trimSpaces(a.val.s); break; } case strexBuiltInBetween: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); - struct strexEval c = strexLocalEval(p->children->next->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); + struct strexEval c = strexLocalEval(p->children->next->next, run); char *between = stringBetween(a.val.s, c.val.s, b.val.s); res.val.s = emptyForNull(lmCloneString(lm, between)); freeMem(between); break; } case strexBuiltInSplit: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); res.val.s = splitString(a.val.s, b.val.i, lm); break; } case strexBuiltInNow: { time_t now; time(&now); char buf[64]; // strftime(buf, sizeof buf, "%FT%TZ", gmtime(&now)); strftime(buf, sizeof buf, "%FT%T%z", localtime(&now)); res.val.s = lmCloneString(lm, buf); eraseTrailingSpaces(res.val.s); break; } case strexBuiltInMd5: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); char *md5 = hmacMd5("", a.val.s); res.val.s = lmCloneString(lm, md5); freez(&md5); break; } case strexBuiltInSeparate: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); - struct strexEval c = strexLocalEval(p->children->next->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); + struct strexEval c = strexLocalEval(p->children->next->next, run); res.val.s = separateString(a.val.s, b.val.s, c.val.i, lm); break; } case strexBuiltInUncsv: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); res.val.s = uncsvString(a.val.s, b.val.i, lm); break; } case strexBuiltInUntsv: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); res.val.s = untsvString(a.val.s, b.val.i, lm); break; } case strexBuiltInReplace: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); - struct strexEval c = strexLocalEval(p->children->next->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); + struct strexEval c = strexLocalEval(p->children->next->next, run); res.val.s = replaceString(a.val.s, b.val.s, c.val.s, lm); break; } case strexBuiltInFix: { - struct strexEval string = strexLocalEval(p->children, record, lookup, lm); - struct strexEval oldVal = strexLocalEval(p->children->next, record, lookup, lm); - struct strexEval newVal = strexLocalEval(p->children->next->next, record, lookup, lm); + struct strexEval string = strexLocalEval(p->children, run); + struct strexEval oldVal = strexLocalEval(p->children->next, run); + struct strexEval newVal = strexLocalEval(p->children->next->next, run); if (sameString(string.val.s, oldVal.val.s)) { res.val.s = newVal.val.s; } else res.val.s = string.val.s; break; } case strexBuiltInStrip: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); res.val.s = stripAll(a.val.s, b.val.s, lm); break; } case strexBuiltInLen: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); res.val.i = strlen(a.val.s); break; } case strexBuiltInSymbol: // Convert string to something could use as a C language symbol { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); res.val.s = symbolify(a.val.s, b.val.s, lm); break; } case strexBuiltInLower: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); res.val.s = lmCloneString(lm, a.val.s); tolowers(res.val.s); break; } case strexBuiltInUpper: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); res.val.s = lmCloneString(lm, a.val.s); touppers(res.val.s); break; } case strexBuiltInIn: { - struct strexEval string = strexLocalEval(p->children, record, lookup, lm); - struct strexEval query = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval string = strexLocalEval(p->children, run); + struct strexEval query = strexLocalEval(p->children->next, run); res.val.b = (strstr(string.val.s, query.val.s) != NULL); break; } case strexBuiltInStarts: { - struct strexEval starts = strexLocalEval(p->children, record, lookup, lm); - struct strexEval string = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval starts = strexLocalEval(p->children, run); + struct strexEval string = strexLocalEval(p->children->next, run); res.val.b = startsWith(starts.val.s, string.val.s); break; } case strexBuiltInEnds: { - struct strexEval string = strexLocalEval(p->children, record, lookup, lm); - struct strexEval end = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval string = strexLocalEval(p->children, run); + struct strexEval end = strexLocalEval(p->children->next, run); res.val.b = endsWith(string.val.s, end.val.s); break; } case strexBuiltInSame: { - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); res.val.b = (strcmp(a.val.s, b.val.s) == 0); break; } case strexBuiltInTidy: { /* Get parameters */ - struct strexEval a = strexLocalEval(p->children, record, lookup, lm); - struct strexEval b = strexLocalEval(p->children->next, record, lookup, lm); - struct strexEval c = strexLocalEval(p->children->next->next, record, lookup, lm); + struct strexEval a = strexLocalEval(p->children, run); + struct strexEval b = strexLocalEval(p->children->next, run); + struct strexEval c = strexLocalEval(p->children->next->next, run); char *before = a.val.s; char *orig = b.val.s; char *after = c.val.s; /* Figure out start position - start of string if before string is empty or doesn't match * otherwise right after the place where before matches. */ char *ourStart = NULL; if (!isEmpty(before)) { ourStart = strstr(orig, before); if (ourStart != NULL) ourStart += strlen(before); } if (ourStart == NULL) ourStart = orig; @@ -1651,236 +1693,242 @@ if (!isEmpty(after)) { ourEnd = strstr(ourStart, after); } if (ourEnd == NULL) ourEnd = defaultEnd; int size = ourEnd - ourStart; assert(size >= 0); res.val.s = lmCloneStringZ(lm, ourStart, size); } } return res; } -static struct strexEval strexEvalPick(struct strexParse *pick, void *record, StrexLookup lookup, - struct lm *lm) +static struct strexEval strexEvalPick(struct strexParse *pick, struct strexRun *run) /* Evaluate a pick operator. */ { /* Evaluate the keyValue */ struct strexParse *p = pick->children; -struct strexEval keyVal = strexLocalEval(p, record, lookup, lm); +struct strexEval keyVal = strexLocalEval(p, run); p = p->next; /* Get pointer to default expression but don't evaluate it yet */ struct strexParse *defaultExp = p; p = p->next; /* Loop through all the key/val pairs until find first that matches. */ boolean gotMatch = FALSE; while (p != NULL) { - struct strexEval key = strexLocalEval(p, record, lookup, lm); + struct strexEval key = strexLocalEval(p, run); p = p->next; // Parser guarantees this non-null struct strexParse *valExp = p; p = p->next; switch (key.type) { case strexTypeInt: gotMatch = (keyVal.val.i == key.val.i); break; case strexTypeDouble: gotMatch = (keyVal.val.x == key.val.x); break; case strexTypeBoolean: gotMatch = (keyVal.val.b = key.val.b); break; case strexTypeString: gotMatch = sameString(keyVal.val.s, key.val.s); break; } if (gotMatch) { - return strexLocalEval(valExp, record, lookup, lm); + return strexLocalEval(valExp, run); } } -return strexLocalEval(defaultExp, record, lookup, lm); +return strexLocalEval(defaultExp, run); } -static struct strexEval strexEvalConditional(struct strexParse *conditional, - void *record, StrexLookup lookup, struct lm *lm) -/* Evaluate a conditional trinary ? : operator. */ +static struct strexEval strexEvalConditional(struct strexParse *conditional, struct strexRun *run) { struct strexParse *child = conditional->children; -struct strexEval b = strexLocalEval(child, record, lookup, lm); +struct strexEval b = strexLocalEval(child, run); struct strexEval res; if (b.val.b) - res = strexLocalEval(child->next, record, lookup, lm); + res = strexLocalEval(child->next, run); else - res = strexLocalEval(child->next->next, record, lookup, lm); + res = strexLocalEval(child->next->next, run); return res; } -static struct strexEval strexLocalEval(struct strexParse *p, void *record, StrexLookup lookup, - struct lm *lm) +static struct strexEval strexLocalEval(struct strexParse *p, struct strexRun *run) /* Evaluate self on parse tree, allocating memory if needed from lm. */ { struct strexEval res; switch (p->op) { case strexOpLiteral: res.val = p->val; res.type = p->type; break; case strexOpSymbol: res.type = strexTypeString; - char *s = lookup(record, p->val.s); + char *s = run->lookup(run->symbols, p->val.s); if (s == NULL) res.val.s = ""; else res.val.s = s; break; /* Type casts. */ case strexOpStringToBoolean: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeBoolean; res.val.b = (res.val.s[0] != 0); break; case strexOpIntToBoolean: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeBoolean; res.val.b = (res.val.i != 0); break; case strexOpDoubleToBoolean: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeBoolean; res.val.b = (res.val.x != 0.0); break; case strexOpStringToInt: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeInt; res.val.i = atoll(res.val.s); break; case strexOpDoubleToInt: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeInt; res.val.i = res.val.x; break; case strexOpStringToDouble: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeDouble; res.val.x = atof(res.val.s); break; case strexOpBooleanToInt: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeInt; res.val.i = res.val.b; break; case strexOpBooleanToDouble: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeDouble; res.val.x = res.val.b; break; case strexOpIntToDouble: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeDouble; res.val.x = res.val.b; break; case strexOpIntToString: { - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeString; char buf[32]; safef(buf, sizeof(buf), "%lld", res.val.i); - res.val.s = lmCloneString(lm, buf); + res.val.s = lmCloneString(run->lm, buf); break; } case strexOpDoubleToString: { - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeString; char buf[32]; safef(buf, sizeof(buf), "%g", res.val.x); - res.val.s = lmCloneString(lm, buf); + res.val.s = lmCloneString(run->lm, buf); break; } case strexOpBooleanToString: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeString; res.val.s = (res.val.b ? "true" : "false"); break; /* Arithmetical negation. */ case strexOpUnaryMinusInt: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.val.i = -res.val.i; break; case strexOpUnaryMinusDouble: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.val.x = -res.val.x; break; case strexOpArrayIx: - res = strexEvalArrayIx(p, record, lookup, lm); + res = strexEvalArrayIx(p, run); break; case strexOpArrayRange: - res = strexEvalArrayRange(p, record, lookup, lm); + res = strexEvalArrayRange(p, run); break; case strexOpStrlen: - res = strexLocalEval(p->children, record, lookup, lm); + res = strexLocalEval(p->children, run); res.type = strexTypeInt; res.val.i = strlen(res.val.s); break; /* More complicated ops. */ case strexOpBuiltInCall: - res = strexEvalCallBuiltIn(p, record, lookup, lm); + res = strexEvalCallBuiltIn(p, run); break; case strexOpPick: - res = strexEvalPick(p, record, lookup, lm); + res = strexEvalPick(p, run); break; case strexOpConditional: - res = strexEvalConditional(p, record, lookup, lm); + res = strexEvalConditional(p, run); break; /* Mathematical ops, simple binary type */ case strexOpAdd: - res = strexEvalAdd(p, record, lookup, lm); + res = strexEvalAdd(p, run); break; /* Logical ops, simple binary type */ case strexOpOr: - res = strexEvalOr(p, record, lookup, lm); + res = strexEvalOr(p, run); break; case strexOpAnd: - res = strexEvalAnd(p, record, lookup, lm); + res = strexEvalAnd(p, run); break; default: errAbort("Unknown op %s\n", strexOpToString(p->op)); res.type = strexTypeInt; // Keep compiler from complaining. res.val.i = 0; // Keep compiler from complaining. break; } return res; } -char *strexEvalAsString(struct strexParse *p, void *record, StrexLookup lookup) -/* Evaluating a strex expression on a symbol table with a lookup function for variables and - * return result as a string value. */ +/* ---- And the one public evaluation function ---- */ + +char *strexEvalAsString(struct strexParse *p, void *symbols, StrexLookup lookup, + void (*warnHandler)(char *warning), void (*abortHandler)() ) +/* Return result as a string value. The warnHandler and abortHandler are optional, + * and can be used to wrap your own warnings and abort processing onto what strex + * provides. For default behavior just pass in NULL. */ + { -struct lm *lm = lmInit(0); -struct strexEval res = strexLocalEval(p, record, lookup, lm); +/* Set up run time environment for strex and evaluate.*/ +struct strexRun *run = strexRunNew(symbols, lookup, warnHandler, abortHandler); +struct strexEval res = strexLocalEval(p,run); + +/* Convert result to string and copy to memory that'll survive loss of run time environment */ char numBuf[32]; struct strexEval strRes = strexEvalCoerceToString(res, numBuf, sizeof(numBuf)); char *ret = cloneString(strRes.val.s); -lmCleanup(&lm); + +/* Clean up and go home */ +strexRunFree(&run); return ret; }