/*====================================================
* rapl_expr.js "A Tcl like language implementation in Javascript named WebRAPL
* (Web Rapid Application Programming Language)"
*
* RAPL expr implementation
*
* Released under BSD license.
* (BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
*
* Arnulf Wiedemann 2011
*/
RP.add("rapl-expr", function(R, name) {
function Expr(interp) {
R.log('constructor called', '2.life', 'Expr', true);
// kweight
var exp = this;
exp.interp = interp;
var constructor = exp.constructor;
Expr.superclass.constructor.apply(exp, arguments);
R.Base.expr_oid++;
exp.oid = R.Base.expr_oid;
R.log('constructor end', '2.life', 'Expr', true);
}
R.extend(Expr, R.Token, {
my_name: "Expr",
/* ==================== exprPush ================================== */
exprPush: function(e, obj_ptr) {
var exp = this;
obj_ptr.incrRefCount();
e.stack[e.stacklen++] = obj_ptr;
},
/* ==================== exprPop ================================== */
exprPop: function(e) {
return e.stack[--e.stacklen];
},
/* ==================== exprOpNumUnary ================================== */
exprOpNumUnary: function(e) {
var exp = this;
var intresult = 0;
var rc = exp.OK;
var A = exp.exprPop(e);
var dA = new Array();
var dC = 0;
var wA = new Array();
var wC = 0;
if ((A.obj_type != exp.interp.double_obj_type || A.bytes) && exp.interp.int_obj_type.getWideNoErr(A, wA) == exp.OK) {
intresult = 1;
switch (e.opcode) {
case exp.TOKEN_EXPROP_FUNC_INT:
wC = wA[0];
break;
case exp.TOKEN_EXPROP_FUNC_ROUND:
wC = wA[0];
break;
case exp.TOKEN_EXPROP_FUNC_DOUBLE:
dC = wA[0];
intresult = 0;
break;
case exp.TOKEN_EXPROP_FUNC_ABS:
wC = wA >= 0 ? wA[0] : -wA[0];
break;
case exp.TOKEN_EXPROP_UNARYMINUS:
wC = -wA[0];
break;
case exp.TOKEN_EXPROP_UNARYPLUS:
wC = wA[0];
break;
case exp.TOKEN_EXPROP_NOT:
wC = !wA[0];
break;
default:
abort();
}
} else {
if ((rc = exp.getDouble(A, dA)) == exp.OK) {
switch (e.opcode) {
case exp.TOKEN_EXPROP_FUNC_INT:
wC = dA[0];
intresult = 1;
break;
case exp.TOKEN_EXPROP_FUNC_ROUND:
wC = dA[0] < 0 ? (dA[0] - 0.5) : (dA[0] + 0.5);
intresult = 1;
break;
case exp.TOKEN_EXPROP_FUNC_DOUBLE:
dC = dA[0];
break;
case exp.TOKEN_EXPROP_FUNC_ABS:
dC = dA[0] >= 0 ? dA[0] : -dA[0];
break;
case exp.TOKEN_EXPROP_UNARYMINUS:
dC = -dA[0];
break;
case exp.TOKEN_EXPROP_UNARYPLUS:
dC = dA[0];
break;
case exp.TOKEN_EXPROP_NOT:
wC = !dA[0];
intresult = 1;
break;
default:
abort();
}
}
}
if (rc == exp.OK) {
if (intresult) {
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(wC));
} else {
ExprPush(e, exp.interp.double_obj_type.newDoubleObj(dC));
}
}
A.decrRefCount();
return rc;
},
/* ==================== randDouble ================================== */
randDouble: function() {
var x;
x = exp.randomBytes(64);
return x / ~0;
},
/* ==================== exprOpIntUnary ================================== */
exprOpIntUnary: function(e) {
var exp = this;
var A = exp.exprPop(e);
var wA = new Array();
var rc;
rc = exp.getWide(A, wA);
if (rc == exp.OK) {
switch (e.opcode) {
case exp.TOKEN_EXPROP_BITNOT:
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(~wA));
break;
case exp.TOKEN_EXPROP_FUNC_SRAND:
exp.prngSeed(wA, 64);
exp.exprPush(e, exp.interp.double_obj_type.newDoubleObj(exp.randDouble()));
break;
default:
abort();
}
}
A.decrRefCount();
return rc;
},
/* ==================== exprOpNone ================================== */
exprOpNone: function(e) {
var exp = this;
exp.panic(e.opcode != exp.TOKEN_EXPROP_FUNC_RAND, "JimExprOpNone only support rand()");
exp.exprPush(e, exp.interp.double_obj_type.newDoubleObj(exp.randDouble()));
return exp.OK;
},
/* ==================== exprOpDoubleUnary ================================== */
exprOpDoubleUnary: function(e) {
var exp = this;
var rc;
var A = exp.exprPop(e);
var dA = new Array();
var dC;
rc = exp.getDouble(A, dA);
if (rc == exp.OK) {
switch (e.opcode) {
case exp.TOKEN_EXPROP_FUNC_SIN:
dC = sin(dA);
break;
case exp.TOKEN_EXPROP_FUNC_COS:
dC = cos(dA);
break;
case exp.TOKEN_EXPROP_FUNC_TAN:
dC = tan(dA);
break;
case exp.TOKEN_EXPROP_FUNC_ASIN:
dC = asin(dA);
break;
case exp.TOKEN_EXPROP_FUNC_ACOS:
dC = acos(dA);
break;
case exp.TOKEN_EXPROP_FUNC_ATAN:
dC = atan(dA);
break;
case exp.TOKEN_EXPROP_FUNC_SINH:
dC = sinh(dA);
break;
case exp.TOKEN_EXPROP_FUNC_COSH:
dC = cosh(dA);
break;
case exp.TOKEN_EXPROP_FUNC_TANH:
dC = tanh(dA);
break;
case exp.TOKEN_EXPROP_FUNC_CEIL:
dC = ceil(dA);
break;
case exp.TOKEN_EXPROP_FUNC_FLOOR:
dC = floor(dA);
break;
case exp.TOKEN_EXPROP_FUNC_EXP:
dC = exp(dA);
break;
case exp.TOKEN_EXPROP_FUNC_LOG:
dC = log(dA);
break;
case exp.TOKEN_EXPROP_FUNC_LOG10:
dC = log10(dA);
break;
case exp.TOKEN_EXPROP_FUNC_SQRT:
dC = sqrt(dA);
break;
default:
abort();
}
exp.exprPush(e, exp.interp.double_obj_type.newDoubleObj(dC));
}
A.decrRefCount();
return rc;
},
/* A binary operation on two ints */
/* ==================== exprOpIntBin ================================== */
exprOpIntBin: function(e) {
var exp = this;
var B = exp.exprPop(e);
var A = exp.exprPop(e);
var wA = new Array();
var wB = new Array();
var rc = exp.ERROR;
if (exp.getWide(A, wA) == exp.OK && exp.getWide(B, wB) == exp.OK) {
var wC;
rc = exp.OK;
switch (e.opcode) {
case exp.TOKEN_EXPROP_LSHIFT:
wC = wA << wB;
break;
case exp.TOKEN_EXPROP_RSHIFT:
wC = wA >> wB;
break;
case exp.TOKEN_EXPROP_BITAND:
wC = wA & wB;
break;
case exp.TOKEN_EXPROP_BITXOR:
wC = wA ^ wB;
break;
case exp.TOKEN_EXPROP_BITOR:
wC = wA | wB;
break;
case exp.TOKEN_EXPROP_MOD:
if (wB == 0) {
wC = 0;
exp.interp.setResultString("Division by zero", -1);
rc = exp.ERROR;
} else {
/*
* From Tcl 8.x
*
* This code is tricky: C doesn't guarantee much
* about the quotient or remainder, but Tcl does.
* The remainder always has the same sign as the
* divisor and a smaller absolute value.
*/
var negative = 0;
if (wB < 0) {
wB = -wB;
wA = -wA;
negative = 1;
}
wC = wA % wB;
if (wC < 0) {
wC += wB;
}
if (negative) {
wC = -wC;
}
}
break;
case exp.TOKEN_EXPROP_ROTL:
case exp.TOKEN_EXPROP_ROTR:
/* uint32_t would be better. But not everyone has inttypes.h? */
var uA = wA;
var uB = wB;
S = 8 * 8;
/* Shift left by the word size or more is undefined. */
uB %= S;
if (e.opcode == exp.TOKEN_EXPROP_ROTR) {
uB = S - uB;
}
wC = (uA << uB) | (uA >> (S - uB));
break;
default:
abort();
}
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(wC));
}
A.decrRefCount();
B.decrRefCount();
return rc;
},
/* A binary operation on two ints or two doubles (or two strings for some ops) */
/* ==================== exprOpBin ================================== */
exprOpBin: function(e) {
var exp = this;
var intresult = 0;
var rc = exp.OK;
var dA;
var dB;
var dC = 0;
var wA = new Array();
var wB = new Array();
var wC = 0;
var B = exp.exprPop(e);
var A = exp.exprPop(e);
if ((A.obj_type != exp.interp.double_obj_type || A.bytes) &&
(B.obj_type != exp.interp.double_obj_type || B.bytes) &&
exp.interp.int_obj_type.getWideNoErr(A, wA) == exp.OK && exp.interp.int_obj_type.getWideNoErr(B, wB) == exp.OK) {
wA = parseInt(wA[0]);
wB = parseInt(wB[0]);
/* Both are ints */
intresult = 1;
switch (e.opcode) {
case exp.TOKEN_EXPROP_POW:
case exp.TOKEN_EXPROP_FUNC_POW:
wC = exp.powWide(wA, wB);
break;
case exp.TOKEN_EXPROP_ADD:
wC = wA + wB;
break;
case exp.TOKEN_EXPROP_SUB:
wC = wA - wB;
break;
case exp.TOKEN_EXPROP_MUL:
wC = wA * wB;
break;
case exp.TOKEN_EXPROP_DIV:
if (wB == 0) {
exp.interp.setResultString("Division by zero", -1);
rc = exp.ERROR;
} else {
/*
* From Tcl 8.x
*
* This code is tricky: C doesn't guarantee much
* about the quotient or remainder, but Tcl does.
* The remainder always has the same sign as the
* divisor and a smaller absolute value.
*/
if (wB < 0) {
wB = -wB;
wA = -wA;
}
wC = wA / wB;
if (wA % wB < 0) {
wC--;
}
}
break;
case exp.TOKEN_EXPROP_LT:
wC = wA < wB;
break;
case exp.TOKEN_EXPROP_GT:
wC = wA > wB;
break;
case exp.TOKEN_EXPROP_LTE:
wC = wA <= wB;
break;
case exp.TOKEN_EXPROP_GTE:
wC = wA >= wB;
break;
case exp.TOKEN_EXPROP_NUMEQ:
wC = wA == wB;
break;
case exp.TOKEN_EXPROP_NUMNE:
wC = wA != wB;
break;
default:
abort();
}
} else {
if (exp.getDouble(A, dA) == exp.OK && exp.getDouble(B, dB) == exp.OK) {
switch (e.opcode) {
case exp.TOKEN_EXPROP_POW:
case exp.TOKEN_EXPROP_FUNC_POW:
if (exp.interp.HAVE_MATH_FUNCTIONS) {
dC = pow(dA, dB);
} else {
exp.interp.setResultString("unsupported", -1);
rc = exp.ERROR;
}
break;
case exp.TOKEN_EXPROP_ADD:
dC = dA + dB;
break;
case exp.TOKEN_EXPROP_SUB:
dC = dA - dB;
break;
case exp.TOKEN_EXPROP_MUL:
dC = dA * dB;
break;
case exp.TOKEN_EXPROP_DIV:
if (dB == 0) {
if (exp.interp.HAVE_INFINITY) {
dC = dA < 0 ? -INFINITY : INFINITY;
} else {
dC = (dA < 0 ? -1.0 : 1.0) * strtod("Inf", null);
}
} else {
dC = dA / dB;
}
break;
case exp.TOKEN_EXPROP_LT:
wC = dA < dB;
intresult = 1;
break;
case exp.TOKEN_EXPROP_GT:
wC = dA > dB;
intresult = 1;
break;
case exp.TOKEN_EXPROP_LTE:
wC = dA <= dB;
intresult = 1;
break;
case exp.TOKEN_EXPROP_GTE:
wC = dA >= dB;
intresult = 1;
break;
case exp.TOKEN_EXPROP_NUMEQ:
wC = dA == dB;
intresult = 1;
break;
case exp.TOKEN_EXPROP_NUMNE:
wC = dA != dB;
intresult = 1;
break;
default:
abort();
}
} else {
/* Handle the string case */
/* REVISIT: Could optimise the eq/ne case by checking lengths */
var i = exp.stringCompareObj(A, B, 0);
intresult = 1;
switch (e.opcode) {
case exp.TOKEN_EXPROP_LT:
wC = i < 0;
break;
case exp.TOKEN_EXPROP_GT:
wC = i > 0;
break;
case exp.TOKEN_EXPROP_LTE:
wC = i <= 0;
break;
case exp.TOKEN_EXPROP_GTE:
wC = i >= 0;
break;
case exp.TOKEN_EXPROP_NUMEQ:
wC = i == 0;
break;
case exp.TOKEN_EXPROP_NUMNE:
wC = i != 0;
break;
default:
rc = exp.ERROR;
break;
}
}
}
if (rc == exp.OK) {
if (intresult) {
/* javascript returns true or false for comparisions, we need 1 or 0 for Tcl */
if (wC == true) {
wC = 1;
} else {
if (wC == false) {
wC = 0;
}
}
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(wC));
} else {
exp.exprPush(e, exp.interp.double_obj_type.newDoubleObj(dC));
}
}
A.decrRefCount();
B.decrRefCount();
return rc;
},
/* ==================== searchList ================================== */
searchList: function(list_obj_ptr, val_obj) {
var listlen;
var i;
listlen = exp.listLength(list_obj_ptr);
for (i = 0; i < listlen; i++) {
var obj_ptr = new Array();
exp.listIndex(list_obj_ptr, i, obj_ptr, exp.FUNCTION_FLAGS_NONE);
if (exp.stringEqObj(obj_ptr, val_obj)) {
return 1;
}
}
return 0;
},
/* ==================== exprOpStrBin ================================== */
exprOpStrBin: function(e) {
var exp = this;
var obj_ptr = exp.interp.default_obj;
var B = exp.exprPop(e);
var A = exp.exprPop(e);
var wC;
switch (e.opcode) {
case exp.TOKEN_EXPROP_STREQ:
case exp.TOKEN_EXPROP_STRNE:
var Alen = new Array();
var Blen = new Array();
var sA = obj_ptr.getString(A, Alen);
var sB = obj_ptr.getString(B, Blen);
if (e.opcode == exp.TOKEN_EXPROP_STREQ) {
wC = (Alen == Blen && sA == sB);
} else {
wC = (Alen != Blen || sA == sB);
}
break;
case exp.TOKEN_EXPROP_STRIN:
wC = exp.searchList(B, A);
break;
case exp.TOKEN_EXPROP_STRNI:
wC = !exp.searchList(interp, B, A);
break;
default:
abort();
}
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(wC));
A.decrRefCount();
B.decrRefCount();
return exp.OK;
},
/* ==================== exprBool ================================== */
exprBool: function(obj) {
var l = new Array();
var d = new Array();
if (exp.getLong(interp, obj, l) == exp.OK) {
return l != 0;
}
if (exp.getDouble(d) == exp.OK) {
return d != 0;
}
return -1;
},
/* ==================== exprOpAndLeft ================================== */
exprOpAndLeft: function(e) {
var exp = this;
var skip = exp.exprPop(e);
var A = exp.exprPop(e);
var rc = exp.OK;
switch (exp.exprBool(A)) {
case 0:
/* false, so skip RHS opcodes with a 0 result */
e.skip = exp.wideValue(skip);
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(0));
break;
case 1:
/* true so continue */
break;
case -1:
/* Invalid */
rc = exp.ERROR;
}
A.decrRefCount();
skip.decrRefCount();
return rc;
},
/* ==================== exprOpOrLeft ================================== */
exprOpOrLeft: function(e) {
var exp = this;
var skip = exp.exprPop(e);
var A = exp.exprPop(e);
var rc = exp.OK;
switch (exp.exprBool(A)) {
case 0:
/* false, so do nothing */
break;
case 1:
/* true so skip RHS opcodes with a 1 result */
e.skip = exp.wideValue(skip);
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(1));
break;
case -1:
/* Invalid */
rc = exp.ERROR;
break;
}
A.decrRefCount();
skip.decrRefCount();
return rc;
},
/* ==================== exprOpAndOrRight ================================== */
exprOpAndOrRight: function(e) {
var exp = this;
var A = exp.exprPop(e);
var rc = exp.OK;
switch (exp.exprBool(A)) {
case 0:
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(0));
break;
case 1:
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(1));
break;
case -1:
/* Invalid */
rc = exp.ERROR;
break;
}
A.decrRefCount();
return rc;
},
/* ==================== exprOpTernaryLeft ================================== */
exprOpTernaryLeft: function(e) {
var exp = this;
var skip = exp.exprPop(e);
var A = exp.exprPop(e);
var rc = expOK;
/* Repush A */
exp.exprPush(e, A);
switch (exp.exprBool(A)) {
case 0:
/* false, skip RHS opcodes */
e.skip = exp.wideValue(skip);
/* Push a dummy value */
exp.exprPush(e, exp.interp.int_obj_type.newIntObj(0));
break;
case 1:
/* true so do nothing */
break;
case -1:
/* Invalid */
rc = exp.ERROR;
break;
}
A.decrRefCount();
skip.decrRefCount();
return rc;
},
/* ==================== exprOpColonLeft ================================== */
exprOpColonLeft: function(e) {
var exp = this;
var skip = exp.exprPop(e);
var B = exp.exprPop(e);
var A = exp.exprPop(e);
/* No need to check for A as non-boolean */
if (exp.exprBool(A)) {
/* true, so skip RHS opcodes */
e.skip = exp.wideValue(skip);
/* Repush B as the answer */
exp.exprPush(e, B);
}
skip.decrRefCount();
A.decrRefCount();
B.decrRefCount();
return exp.OK;
},
/* ==================== exprOpNull ================================== */
exprOpNull: function(e) {
return exp.OK;
},
/* ==================== exprOperatorInfoByOpcode ================================== */
exprOperatorInfoByOpcode: function(opcode) {
var exp = this;
var dummy_op = {
name: null,
precedence: 0,
arity: 0,
opcode: "",
lazy: 0
};
if (opcode < exp.TOKEN_EXPR_OP) {
return dummy_op;
}
return exp.exprOperators[opcode - exp.TOKEN_EXPR_OP];
},
/* ==================== tt_name ================================== */
tt_name: function(token) {
var exp = this;
var tt_names = [ "NIL", "STR", "ESC", "VAR", "ARY", "CMD", "SEP", "EOL", "EOF", "LIN", "WRD", "(((", ")))", ",,,", "INT", "DBL", "$()" ];
if (token < exp.TOKEN_EXPR_OP) {
return tt_names[token];
} else {
op = exp.exprOperatorInfoByOpcode(token);
if (op.name) {
return op.name;
}
return "("+token+")";
}
},
/* ==================== getWideNoErr ================================== */
old_getWideNoErr: function(obj_ptr, wide_ptr) {
var exp = this;
if (obj_ptr.obj_type != exp.interp.int_obj_type && exp.interp.int_obj_type.setFromAny(obj_ptr, exp.FUNCTION_FLAGS_NONE) == exp.ERROR) {
return exp.ERROR;
}
wide_ptr[0] = obj_ptr.wideValue();
return exp.OK;
},
/* -----------------------------------------------------------------------------
* Expression Object
* ---------------------------------------------------------------------------*/
/* ==================== exprFreeByteCode ================================== */
exprFreeByteCode: function(expr) {
var exp = this;
var obj_ptr = exp.interp.default_obj;
var i;
for (i = 0; i < expr.len; i++) {
expr.token_list[i].obj_ptr.decrRefCount();
}
// obj_ptr.free(expr.token_list);
// obj_ptr.free(expr);
},
/* ==================== exprFreeInternalRep ================================== */
freeExprInternalRep: function(obj_ptr) {
var expr = obj_ptr.ptr();
if (expr) {
if (--expr.inUse != 0) {
return;
}
exp.exprFreeByteCode(expr);
}
},
/* ==================== dupExprInternalRep ================================== */
dupExprInternalRep: function(src_ptr, dup_ptr) {
/* Just returns an simple string. */
dupPtr.obj_type = null;
},
/* ==================== exprCheckCorrectness ================================== */
/* Check if an expr program looks correct. */
exprCheckCorrectness: function(expr) {
var exp = this;
var i;
var stacklen = 0;
var ternary = 0;
/* Try to check if there are stack underflows,
* and make sure at the end of the program there is
* a single result on the stack. */
for (i = 0; i < expr.len; i++) {
var t = expr.token_list[i];
var op = exp.exprOperatorInfoByOpcode(t.token);
stacklen -= op.arity;
if (stacklen < 0) {
break;
}
if (t.token == exp.TOKEN_EXPROP_TERNARY || t.token == exp.TOKEN_EXPROP_TERNARY_LEFT) {
ternary++;
} else {
if (t.token == exp.TOKEN_EXPROP_COLON || t.token == exp.TOKEN_EXPROP_COLON_LEFT) {
ternary--;
}
}
/* All operations and operands add one to the stack */
stacklen++;
}
if (stacklen != 1 || ternary != 0) {
return exp.ERROR;
}
return exp.OK;
},
/* This procedure converts every occurrence of || and && opereators
* in lazy unary versions.
*
* a b || is converted into:
*
* a <offset> |L b |R
*
* a b && is converted into:
*
* a <offset> &L b &R
*
* "|L" checks if 'a' is true:
* 1) if it is true pushes 1 and skips <offset> instructions to reach
* the opcode just after |R.
* 2) if it is false does nothing.
* "|R" checks if 'b' is true:
* 1) if it is true pushes 1, otherwise pushes 0.
*
* "&L" checks if 'a' is true:
* 1) if it is true does nothing.
* 2) If it is false pushes 0 and skips <offset> instructions to reach
* the opcode just after &R
* "&R" checks if 'a' is true:
* if it is true pushes 1, otherwise pushes 0.
*/
/* ==================== exprAddLazyOperator ================================== */
exprAddLazyOperator: function(expr, t) {
var exp = this;
var obj_ptr = exp.interp.default_obj;
var i;
var leftindex;
var arity;
var offset;
/* Search for the end of the first operator */
leftindex = expr.len - 1;
arity = 1;
while (arity) {
var tt = expr.token_list[leftindex];
if (tt.token >= exp.TOKEN_EXPR_OP) {
arity += exp.exprOperatorInfoByOpcode(tt.token).arity;
}
arity--;
if (--leftindex < 0) {
return exp.ERROR;
}
}
leftindex++;
/* Move them up */
for (var j = leftindex + 2; j > expr.len -leftindex; j--) {
expr.token_list[j], expr.token_list[j - 2];
}
expr.len += 2;
offset = (expr.len - leftindex) - 1;
/* Now we rely on the fact the the left and right version have opcodes
* 1 and 2 after the main opcode respectively
*/
expr.token_list[leftindex + 1].token = t.token + 1;
expr.token_list[leftindex + 1].obj_ptr = exp.interp.empty_obj;
expr.token_list[leftindex].token = exp.TOKEN_EXPR_INT;
expr.token_list[leftindex].obj_ptr = exp.interp.int_obj_type.newIntObj(offset);
/* Now add the 'R' operator */
expr.token_list[expr.len].obj_ptr = exp.interp.empty_obj;
expr.token_list[expr.len].token = t.token + 2;
expr.len++;
/* Do we need to adjust the skip count for any &L, |L, ?L or :L in the left operand? */
for (i = leftindex - 1; i > 0; i--) {
var op = exp.exprOperatorInfoByOpcode(expr.token_list[i].token);
if (op.lazy == exp.EXPR_TYPE_LAZY_LEFT) {
if (exp.wideValue(expr.token_list[i - 1].obj_ptr) + i - 1 >= leftindex) {
exp.wideValue(expr.token_list[i - 1].obj_ptr) += 2;
}
}
}
return exp.OK;
},
/* ==================== exprAddOperator ================================== */
exprAddOperator: function(expr, t) {
var exp = this;
var token = {
token: 0,
obj_ptr: null
};
var op = exp.exprOperatorInfoByOpcode(t.token);
if (op.lazy == exp.EXPR_TYPE_LAZY_OP) {
if (exp.exprAddLazyOperator(expr, t) != exp.OK) {
exp.interp.setResultFormatted("Expression has bad operands to %s", op.name);
return exp.ERROR;
}
} else {
token.obj_ptr = exp.interp.empty_obj;
token.token = t.token;
expr.token_list[expr.len] = token;
expr.len++;
}
return exp.OK;
},
/**
* Returns the index of the COLON_LEFT to the left of 'right_index'
* taking into account nesting.
*
* The expression *must* be well formed, thus a COLON_LEFT will always be found.
*/
/* ==================== exprTernaryGetColonLeftIndex ================================== */
exprTernaryGetColonLeftIndex: function(expr, right_index) {
var exp = this;
var ternary_count = 1;
right_index--;
while (right_index > 1) {
if (expr.token_list[right_index].token == exp.TOKEN_EXPROP_TERNARY_LEFT) {
ternary_count--;
} else {
if (expr.token_list[right_index].token == exp.TOKEN_EXPROP_COLON_RIGHT) {
ternary_count++;
} else {
if (expr.token_list[right_index].token == exp.TOKEN_EXPROP_COLON_LEFT && ternary_count == 1) {
return right_index;
}
}
}
right_index--;
}
/*notreached*/
return -1;
},
/* ==================== exprTernaryGetMoveIndices ================================== */
/**
* Find the left/right indices for the ternary expression to the left of 'right_index'.
*
* Returns 1 if found, and fills in *prev_right_index and *prev_left_index.
* Otherwise returns 0.
*/
exprTernaryGetMoveIndices: function(expr, right_index, prev_right_index, prev_left_index) {
var exp = this;
var i = right_index - 1;
var ternary_count = 1;
while (i > 1) {
if (expr.token_list[i].token == exp.TOKEN_EXPROP_TERNARY_LEFT) {
if (--ternary_count == 0 && expr.token_list[i - 2].token == exp.TOKEN_EXPROP_COLON_RIGHT) {
prev_right_index[0] = i - 2;
prev_left_index[0] = exp.exprTernaryGetColonLeftIndex(expr, prev_right_index);
return 1;
}
} else {
if (expr.token_list[i].token == exp.TOKEN_EXPROP_COLON_RIGHT) {
if (ternary_count == 0) {
return 0;
}
ternary_count++;
}
}
i--;
}
return 0;
},
/* ==================== exprTernaryReorderExpression ================================== */
/*
* ExprTernaryReorderExpression description
* ========================================
*
* ?: is right-to-left associative which doesn't work with the stack-based
* expression engine. The fix is to reorder the bytecode.
*
* The expression:
*
* expr 1?2:0?3:4
*
* Has initial bytecode:
*
* '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '0' (44=COLON_RIGHT)
* '2' (40=TERNARY_LEFT) '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT)
*
* The fix involves simulating this expression instead:
*
* expr 1?2:(0?3:4)
*
* With the following bytecode:
*
* '1' '2' (40=TERNARY_LEFT) '2' (41=TERNARY_RIGHT) '10' (43=COLON_LEFT) '0'
* '2' (40=TERNARY_LEFT)
* '3' (41=TERNARY_RIGHT) '2' (43=COLON_LEFT) '4' (44=COLON_RIGHT) (44=COLON_RIGHT)
*
* i.e. The token COLON_RIGHT at index 8 is moved towards the end of the stack,
* all tokens above 8
* are shifted down and the skip count of the token TOKEN_EXPROP_COLON_LEFT at
* index 5 is
* incremented by the amount tokens shifted down. The token TOKEN_EXPROP_COLON_RIGHT
* that is moved
* is identified as immediately preceeding a token TOKEN_EXPROP_TERNARY_LEFT
*
* ExprTernaryReorderExpression works thus as follows :
* - start from the end of the stack
* - while walking towards the beginning of the stack
* if token=TOKEN_EXPROP_COLON_RIGHT then
* find the associated token TOKEN_EXPROP_TERNARY_LEFT, which allows to
* find the associated token previous(TOKEN_EXPROP_COLON_RIGHT)
* find the associated token previous(TOKEN_EXPROP_LEFT_RIGHT)
* if all found then
* perform the rotation
* update the skip count of the token previous(TOKEN_EXPROP_LEFT_RIGHT)
* end if
* end if
*
* Note: care has to be taken for nested ternary constructs!!!
*/
exprTernaryReorderExpression: function(expr) {
var exp = this;
var i;
for (i = expr.len - 1; i > 1; i--) {
var prev_right_index = new Array();
var prev_left_index = new Array();
var j;
var tmp;
if (expr.token_list[i].token != exp.TOKEN_EXPROP_COLON_RIGHT) {
continue;
}
/* COLON_RIGHT found: get the indexes needed to move the tokens in the stack (if any) */
if (exp.exprTernaryGetMoveIndices(expr, i, prev_right_index, prev_left_index) == 0) {
continue;
}
/*
** rotate tokens down
**
** +-> [i] : TOKEN_EXPROP_COLON_RIGHT
** | | |
** | V V
** | [...] : ...
** | | |
** | V V
** | [...] : ...
** | | |
** | V V
** +- [prev_right_index] : TOKEN_EXPROP_COLON_RIGHT
*/
tmp = expr.token_list[prev_right_index];
for (j = prev_right_index; j < i; j++) {
expr.token_list[j] = expr.token_list[j + 1];
}
expr.token_list[i] = tmp;
/* Increment the 'skip' count associated to the previous TOKEN_EXPROP_COLON_LEFT token
*
* This is 'colon left increment' = i - prev_right_index
*
* [prev_left_index] : TOKEN_EXPROP_LEFT_RIGHT
* [prev_left_index-1] : skip_count
*
*/
exp.wideValue(expr.token_list[prev_left_index-1].obj_ptr) += (i - prev_right_index);
/* Adjust for i-- in the loop */
i++;
}
},
/* ==================== exprCreateByteCode ================================== */
exprCreateByteCode: function(script, file_name_obj) {
var exp = this;
var token_list = script.parse_token_list;
var obj_ptr = exp.interp.default_obj;
var stack = new Array();
var expr;
var ok = 1;
var i;
var prev_token = exp.TOKEN_NONE;
var have_ternary = 0;
/* -1 for EOL */
var count = token_list.length - 1;
var expr = {
len: 0,
token_list: null,
in_use: 1
};
var stack = {
len: 0,
maxlen: 0,
vector: null
}
exp.initStack(stack);
/* Need extra bytecodes for lazy operators.
* Also check for the ternary operator
*/
for (i = 0; i < token_list.length - 1; i++) {
var t = token_list[i];
var op = exp.exprOperatorInfoByOpcode(t.token);
if (op.lazy == exp.EXPR_TYPE_LAZY_OP) {
count += 2;
/* Ternary is a lazy op but also needs reordering */
if (t.token == exp.TOKEN_EXPROP_TERNARY) {
have_ternary = 1;
}
}
}
expr.token_list = new Array()
for (i = 0; i < token_list.length && ok; i++) {
var t = token_list[i];
var token = {
token: 0,
obj_ptr: null
};
if (t.token == exp.TOKEN_EOL) {
break;
}
switch (t.token) {
case exp.TOKEN_STR:
case exp.TOKEN_ESC:
case exp.TOKEN_VAR:
case exp.TOKEN_VAR_ARRAY_NAME:
case exp.TOKEN_EXPRSUGAR:
case exp.TOKEN_CMD:
token.obj_ptr = exp.interp.string_obj_type.newStringObj(script.getText(t.start, t.len), t.len);
token.token = t.token;
if (t.token == exp.TOKEN_CMD) {
/* Only commands need source info */
exp.interp.source_obj_type.setSourceInfo(token.obj_ptr, file_name_obj, t.line);
}
expr.token_list[expr.len] = token;
expr.len++;
break;
case exp.TOKEN_EXPR_INT:
token.obj_ptr = exp.interp.int_obj_type.newIntObj(script.getText(t.start, t.len));
token.token = t.token;
expr.token_list[expr.len] = token;
expr.len++;
break;
case exp.TOKEN_EXPR_DOUBLE:
token.obj_ptr = exp.interp.double_obj_type.newDoubleObj(script.getText(t.start, t.len));
token.token = t.token;
expr.token_list[expr.len] = token;
expr.len++;
break;
case exp.TOKEN_SUBEXPR_START:
exp.stackPush(stack, t);
prevtt = exp.TOKEN_NONE;
continue;
case exp.TOKEN_SUBEXPR_COMMA:
/* Simple approach. Comma is simply ignored */
continue;
case exp.TOKEN_SUBEXPR_END:
ok = 0;
while (stack.len) {
var tt = exp.stackPop(stack);
if (tt.token == exp.TOKEN_SUBEXPR_START) {
ok = 1;
break;
}
if (exp.exprAddOperator(expr, tt) != exp.OK) {
/* Free the stack used for the compilation. */
exp.freeStack(stack);
for (i = 0; i < expr.len; i++) {
expr.token_list[i].obj_ptr.incrRefCount();
}
if (!ok) {
exp.exprFreeByteCode(expr);
return null;
}
return expr;
}
}
if (!ok) {
exp.interp.setResultString("Unexpected close parenthesis", -1);
/* Free the stack used for the compilation. */
exp.freeStack(stack);
for (i = 0; i < expr.len; i++) {
expr.token_list[i].obj_ptr.incrRefCount();
}
if (!ok) {
exp.exprFreeByteCode(expr);
return null;
}
return expr;
}
break;
default:
/* Must be an operator */
var op;
var tt;
/* Convert -/+ to unary minus or unary plus if necessary */
if (prevtt == exp.TOKEN_NONE || prevtt >= exp.TOKEN_EXPR_OP) {
if (t.token == exp.TOKEN_EXPROP_SUB) {
t.token = exp.TOKEN_EXPROP_UNARYMINUS;
} else {
if (t.token == exp.TOKEN_EXPROP_ADD) {
t.token = exp.TOKEN_EXPROP_UNARYPLUS;
}
}
}
op = exp.exprOperatorInfoByOpcode(t.token);
/* Now handle precedence */
while ((tt = exp.stackPeek(stack)) != null) {
var tt_op = exp.exprOperatorInfoByOpcode(tt.token);
/* Note that right-to-left associativity of ?: operator is handled later */
if (op.arity != 1 && tt_op.precedence >= op.precedence) {
if (exp.exprAddOperator(expr, tt) != exp.OK) {
ok = 0;
/* Free the stack used for the compilation. */
exp.freeStack(stack);
for (i = 0; i < expr.len; i++) {
expr.token_list[i].obj_ptr.incrRefCount();
}
if (!ok) {
exp.exprFreeByteCode(expr);
return null;
}
return expr;
}
exp.stackPop(stack);
} else {
break;
}
}
exp.stackPush(stack, t);
break;
}
prevtt = t.token;
}
/* Reduce any remaining subexpr */
while (stack.len) {
var tt = exp.stackPop(stack);
if (tt.token == exp.TOKEN_SUBEXPR_START) {
ok = 0;
exp.interp.setResultString("Missing close parenthesis", -1);
/* Free the stack used for the compilation. */
exp.freeStack(stack);
for (i = 0; i < expr.len; i++) {
expr.token_list[i].obj_ptr.incrRefCount();
}
if (!ok) {
exp.exprFreeByteCode(expr);
return null;
}
return expr;
}
if (exp.exprAddOperator(expr, tt) != exp.OK) {
ok = 0;
}
}
if (ok && have_ternary) {
exp.exprTernaryReorderExpression(expr);
}
/* Free the stack used for the compilation. */
exp.freeStack(stack);
for (i = 0; i < expr.len; i++) {
expr.token_list[i].obj_ptr.incrRefCount();
}
if (!ok) {
exp.exprFreeByteCode(expr);
return null;
}
return expr;
},
/* ==================== initStack ================================== */
initStack: function(stack) {
stack.len = 0;
stack.vector = new Array();
},
/* ==================== freeStack ================================== */
freeStack: function(stack) {
stack.len = 0;
stack.vector = null;
},
/* ==================== stackPeek ================================== */
stackPeek: function(stack) {
if (stack.len == 0) {
return null;
}
return stack.vector[stack.len - 1];
},
/* ==================== stackPush ================================== */
stackPush: function(stack, val) {
stack.len++;
stack.vector.push(val);
},
/* ==================== stackPop ================================== */
stackPop: function(stack) {
stack.len--;
return stack.vector.pop();
},
/* ==================== setExprFromAny ================================== */
/* This method takes the string representation of an expression
* and generates a program for the Expr's stack-based VM.
*/
setExprFromAny: function(obj_ptr) {
var exp = this;
var parser = new R.Parser();
var expr;
var tokenlist;
var line;
var file_name_obj;
var script = new R.RaplScript(exp.interp);
var rc = exp.ERROR;
var debug_info = 0;
script.text = script.interp.string_obj_type.getString(obj_ptr);
script.text_len = script.interp.string_obj_type.getStringLength(obj_ptr);
/* Try to get information about filename / line number */
if (obj_ptr.obj_type == exp.interp.source_obj_type) {
file_name_obj = obj_ptr.sourceValue.fileNameObj();
line = obj_ptr.sourceValue.lineNumber();
} else {
file_name_obj = exp.interp.empty_obj;
line = 1;
}
file_name_obj.incrRefCount();
/* Initially tokenise the expression into tokenlist */
script.scriptTokenListInit();
parser.parserInit(script.text, script.text_len, line);
while (!parser.parse_info.eof) {
if (parser.parseExpression() != exp.OK) {
script.scriptTokenListFree();
exp.interp.setResultFormatted("syntax error in expression: \"%#s\"", obj_ptr);
expr = null;
/* Free the old internal rep and set the new one. */
file_name_obj.decrRefCount();
obj_ptr.freeIntRep();
obj_ptr.setIntRepPtr(expr);
obj_ptr.obj_type = exp.interp.expr_obj_type;
return rc;
}
script.scriptAddToken(parser.parse_info.start, parser.parse_info.end - parser.parse_info.start + 1, parser.parse_info.token, parser.parse_info.line);
}
if (debug_info) {
print("==== Expr Tokens ====");
for (var i = 0; i < script.parse_token_list.length; i++) {
parse_token = script.parse_token_list[i];
print("["+i+"]@"+parse_token.line+" "+script.getTokenString(parse_token.token)+" '"+script.text.substring(parse_token.start, parse_token.start + parse_token.len)+"'");
}
print("==== Expr Tokens END ====");
}
/* Now create the expression bytecode from the tokenlist */
expr = exp.exprCreateByteCode(script, file_name_obj);
/* No longer need the token list */
script.scriptTokenListFree(script.parse_token_list);
if (!expr) {
/* Free the old internal rep and set the new one. */
file_name_obj.decrRefCount();
obj_ptr.freeIntRep();
obj_ptr.setIntRepPtr(expr);
obj_ptr.obj_type = exp.interp.expr_obj_type;
return rc;
}
if (debug_info) {
print("==== Expr ====");
for (var i = 0; i < expr.len; i++) {
var t = expr.token_list[i];
print("["+i+"]"+exp.getTokenString(t.token)+" '"+t.obj_ptr.getString()+"'");
}
print("==== Expr END ====");
}
/* Check program correctness. */
if (exp.exprCheckCorrectness(expr) != exp.OK) {
exp.exprFreeByteCode(expr);
exp.interp.setResultFormatted("syntax error in expression: \"%#s\"", obj_ptr);
expr = null;
/* Free the old internal rep and set the new one. */
file_name_obj.decrRefCount();
obj_ptr.freeIntRep();
obj_ptr.setIntRepPtr(expr);
obj_ptr.obj_type = exp.interp.expr_obj_type;
return rc;
}
rc = exp.OK;
/* Free the old internal rep and set the new one. */
file_name_obj.decrRefCount();
obj_ptr.freeIntRep();
obj_ptr.setIntRepPtr(expr);
obj_ptr.obj_type = exp.interp.expr_obj_type;
return rc;
},
/* ==================== getExpression ================================== */
getExpression: function(obj_ptr) {
var exp = this;
if (obj_ptr.obj_type != exp.interp.expr_obj_type) {
if (exp.setExprFromAny(obj_ptr) != exp.OK) {
return null;
}
}
return obj_ptr.getIntRepPtr();
},
/* ==================== evalExpression ================================== */
/* -----------------------------------------------------------------------------
* Expressions evaluation.
* RAPL uses a specialized stack-based virtual machine for expressions,
* that takes advantage of the fact that expr's operators
* can't be redefined.
*
* evalExpression() uses the bytecode compiled by
* setExprFromAny() method of the "expression" object.
*
* On success a Tcl Object containing the result of the evaluation
* is stored into expResultPtrPtr (having refcount of 1), and exp.OK is
* returned.
* On error the function returns a retcode != to exp.OK and set a suitable
* error on the interp.
* ---------------------------------------------------------------------------*/
evalExpression: function(expr_obj_ptr, exprResultPtrPtr) {
var exp = this;
var expr;
var staticStack = new Array();
var i;
var retcode = exp.OK;
var fcn;
var e = {
stack: null,
stacklen: 0,
opcode: 0,
skip: 0
};
expr = exp.getExpression(expr_obj_ptr);
if (!expr) {
return exp.ERROR; /* error in expression. */
}
/* Check for one of the following common expressions used by while/for
*
* CONST
* $a
* !$a
* $a < CONST, $a < $b
* $a <= CONST, $a <= $b
* $a > CONST, $a > $b
* $a >= CONST, $a >= $b
* $a != CONST, $a != $b
* $a == CONST, $a == $b
*/
{
var obj_ptr;
/* STEP 1 -- Check if there are the conditions to run the specialized
* version of while */
switch (expr.len) {
case 1:
if (expr.token_list[0].token == exp.TPOKEN_EXPR_INT) {
exprResultPtrPtr[0] = expr.token_list[0].obj_ptr;
exprResultPtrPtr[0].incrRefCount();
return exp.OK;
}
if (expr.token_list[0].token == exp.TOKEN_VAR) {
obj_ptr = exp.interp.variable_obj_type.getVariable(expr.token_list[0].obj_ptr, FUNCTION_FLAGS_LEAVE_ERR_MSG);
if (obj_ptr) {
exprResultPtrPtr[0] = obj_ptr;
exprResultPtrPtr[0].incrRefCount();
return exp.OK;
}
}
break;
case 2:
if (expr.token_list[1].token == exp.TOKEN_EXPROP_NOT && expr.token_list[0].token == exp.TOKEN_VAR) {
var wideValue;
obj_ptr = exp.interp.variable_obj_type.getVariable(expr.token_list[0].obj_ptr, exp.FUNCTION_FLAGS_NONE);
if (obj_ptr && exp.isWide(obj_ptr) && exp.getWide(obj_ptr, wideValue) == exp.OK) {
exprResultPtrPtr[0] = wideValue ? exp.interp.false_obj : exp.interp.true_obj;
exprResultPtrPtr[0].incrRefCount();
return exp.OK;
}
}
break;
case 3:
if (expr.token_list[0].token == exp.TOKEN_VAR && (expr.token_list[1].token == exp_TOKEN_EXPR_INT || expr.token_list[1].token == exp.TOKEN_VAR)) {
switch (expr.token_list[2].token) {
case exp.TOKEN_EXPROP_LT:
case exp.TOKEN_EXPROP_LTE:
case exp.TOKEN_EXPROP_GT:
case exp.TOKEN_EXPROP_GTE:
case exp.TOKEN_EXPROP_NUMEQ:
case exp.TOKEN_EXPROP_NUMNE:
/* optimise ok */
var wideValueA;
var wideValueB;
obj_ptr = exp.interp.variable_obj_type.getVariable(expr.token_list[0].obj_ptr, exp_FUNCTION_FLAGS_NONE);
if (obj_ptr && exp.isWide(obj_ptr) && exp.getWide(obj_ptr, wideValueA) == exp.OK) {
if (expr.token_list[1].token == exp.TOKEN_VAR) {
obj_ptr = exp.interp.variable_obj_type.getVariable(expr.token_list[1].obj_ptr, exp_FUNCTION_FLAGS_NONE);
} else {
obj_tr = expr.token_list[1].obj_ptr;
}
if (obj_ptr && exp.isWide(obj_ptr) && exp.getWide(obj_ptr, wideValueB) == exp.OK) {
var cmpRes;
switch (expr.token_list[2].token) {
case exp.TOKEN_EXPROP_LT:
cmpRes = wideValueA < wideValueB;
break;
case exp.TOKEN_EXPROP_LTE:
cmpRes = wideValueA <= wideValueB;
break;
case exp.TOKEN_EXPROP_GT:
cmpRes = wideValueA > wideValueB;
break;
case exp.TOKEN_EXPROP_GTE:
cmpRes = wideValueA >= wideValueB;
break;
case exp.TOKEN_EXPROP_NUMEQ:
cmpRes = wideValueA == wideValueB;
break;
case exp.TOKEN_EXPROP_NUMNE:
cmpRes = wideValueA != wideValueB;
break;
default: /*notreached */
cmpRes = 0;
}
exprResultPtrPtr[0] = cmpRes ? exp.interp.true_obj : exp.interp.false_obj;
exprResultPtrPtr[0].incrRefCount();
return exp.OK;
}
}
}
}
break;
}
}
/* In order to avoid that the internal repr gets freed due to
* shimmering of the exprObjPtr's object, we make the internal rep
* shared.
* */
expr.inUse++;
/* The stack-based expr VM itself */
/* Stack allocation. Expr programs have the feature that
* a program of length N can't require a stack longer than
* N.
* */
e.stack = new Array();
e.stacklen = 0;
/* Execute every instruction */
for (i = 0; i < expr.len && retcode == exp.OK; i++) {
var obj_ptr;
//print("evalExpr!"+exp.getTokenString(expr.token_list[i].token)+"!");
switch (expr.token_list[i].token) {
case exp.TOKEN_EXPR_INT:
case exp.TOKEN_EXPR_DOUBLE:
case exp.TOKEN_STR:
exp.exprPush(e, expr.token_list[i].obj_ptr);
break;
case exp.TOKEN_VAR:
obj_ptr = exp.interp.variable_obj_type.getVariable(expr.token_list[i].obj_ptr, exp.FUNCTION_FLAGS_LEAVE_ERR_MSG);
if (obj_ptr) {
exp.exprPush(e, obj_ptr);
} else {
retcode = exp.ERROR;
}
break;
case exp.TOKEN_VAR_ARRAY_NAME:
obj_ptr = exp.expandDictSugar(expr.token_list[i].obj_ptr);
if (obj_ptr) {
exp.exprPush(e, obj_ptr);
} else {
retcode = exp.ERROR;
}
break;
case exp.TOKEN_ESC:
retcode = exp.substObj(expr.token_list[i].obj_ptr, obj_ptr, exp.FUNTION_FLAGS_NONE);
if (retcode == expOK) {
exp.exprPush(e, obj_ptr);
}
break;
case exp.TOKEN_CMD:
retcode = exp.interp.eval_statement.evalObj(expr.token_list[i].obj_ptr);
if (retcode == exp.OK) {
exp.exprPush(e, exp.interp.getResult());
}
break;
default:
/* Find and execute the operation */
e.skip = 0;
e.opcode = expr.token_list[i].token;
fcn = exp.exprOperatorInfoByOpcode(e.opcode).funcop;
//print("fcn!"+fcn+"!");
retcode = eval ("exp."+fcn+"(e)");
/* Skip some opcodes if necessary */
i += e.skip;
continue;
}
}
expr.inUse--;
if (retcode == exp.OK) {
exprResultPtrPtr[0] = exp.exprPop(e);
} else {
for (i = 0; i < e.stacklen; i++) {
e.stack[i].decrRefCount();
}
}
return retcode;
},
/* ==================== getBoolFromExpr ================================== */
getBoolFromExpr: function(expr_obj_ptr, bool_ptr) {
var exp = this;
var retcode;
var wide_value = new Array();
var double_value = new Array();
var expr_result_ptr = new Array();
retcode = exp.evalExpression(expr_obj_ptr, expr_result_ptr);
if (retcode != exp.OK) {
return retcode;
}
expr_result_ptr = expr_result_ptr[0];
if (exp.interp.int_obj_type.getWideNoErr(expr_result_ptr, wide_value) != exp.OK) {
if (exp.getDouble(expr_result_ptr, double_value) != exp.OK) {
expr_result_ptr.decrRefCount();
return exp.ERROR;
} else {
double_value = double_value[0]
expr_result_ptr.decrRefCount();
boolPtr[0] = double_value != 0 ? 1 : 0;
return exp.OK;
}
}
wide_value = wide_value[0];
bool_ptr[0] = wide_value != 0;
expr_result_ptr.decrRefCount();
return exp.OK;
},
});
Expr.prototype.constructor = Expr;
R.Expr = Expr;
}, "0.0.1", {});