/*====================================================
* rapl_eval_statement.js "A Tcl like language implementation in Javascript named WebRAPL
* (Web Rapid Application Programming Language)"
*
* evaluate a statement for RAPL also eval execution traces, if necessary
*
* Released under the same terms as Tcl itself.
* (BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
*
* Based on Picol by Salvatore Sanfilippo (<http://antirez.com/page/picol>)
* (c) Stéphane Arnold 2007
* Richard Suchenwirth 2007: cleanup, additions
* Arnulf Wiedemann 2011: a lot of additions for Tcl 8.6 syntax, itcl support
*/
RP.add("rapl-eval-statement", function(R, name) {
/* =============================== EvalStatement ================================== */
function EvalStatement(interp) {
R.log('constructor called', '2.life', 'EvalStatement', true);
// kweight
var stmt = this;
var constructor = stmt.constructor;
EvalStatement.superclass.constructor.apply(stmt, arguments);
R.Base.eval_statment_oid++;
stmt.oid = R.Base.eval_statement_oid;
stmt.interp = interp;
stmt.call_level = 0;
stmt.eval_level = 0;
stmt.expr_eval_level = 0;
stmt.level_infos = new Array();
stmt.enterstep_traces = new Array();
stmt.leavestep_traces = new Array();
stmt.inLoop = false;
stmt.level = 0;
stmt.no_trace = false;
stmt.call_debug = 0;
stmt.eval_stmt_debug = 0;
stmt.eval_expr_debug = 0;
stmt.eval_ipol_debug = 0;
stmt.eval_obj_debug = 0;
stmt.eval_subst_debug = 0;
stmt.ignore_var_not_found = false;
stmt.code = stmt.OK;
stmt.file_name = null;
stmt.in_quoted_string = false;
stmt.in_brace = false;
stmt.cmd_name = "";
stmt.last_token = 0;
stmt.intv = null;
stmt.in_quotes = false;
stmt.had_macro_cmd = false;
R.log('constructor end', '2.life', 'EvalStatement', true);
}
R.extend(EvalStatement, R.Token, {
my_name: "RaplEvalStatement",
/* ==================== substOneToken ===================================== */
substOneToken: function (script, idx, result_ptr) {
var stmt = this;
var obj_ptr;
var token = script.script_object.tokens[idx];
var result_var_ptr = new Array();
if (stmt.eval_subst_debug) {
script.dumpToken(idx);
print("substOneToken!"+token.token+"!"+stmt.getTokenString(token.token)+"!"+token.obj_ptr.mySelf()+"!"+token.obj_ptr.getString()+"!");
}
result_ptr[0] = null;
switch (token.token) {
case stmt.TOKEN_QUOTE_ESC:
stmt.in_quotes = true;
/* fall through */
case stmt.TOKEN_STR:
case stmt.TOKEN_ESC:
obj_ptr = token.obj_ptr;
break;
case stmt.TOKEN_VAR_ARRAY_NAME:
case stmt.TOKEN_VAR:
result_var_ptr[0] = null;
obj_ptr = stmt.interp.variable_obj_type.getVariable(token.obj_ptr, stmt.FUNCTION_FLAGS_LEAVE_ERR_MSG, result_var_ptr);
result_var_ptr = result_var_ptr[0];
/* special case for ::itcl::type type variable !! */
if (obj_ptr == null && result_var_ptr != null && token.obj_ptr.getString() == "type") {
obj_ptr = stmt.interp.string_obj_type.newStringObj(result_var_ptr.namespace.full_name, -1, "EVAL_STATEMENT_1");
obj_ptr.incrRefCount("I_EVAL_STATEMENT_1");
}
if (stmt.interp.frame_ptr.type == stmt.CALL_TYPE_MACROEXPAND) {
/* if we are expanding a macro and we find a not escaped variable not in the
* parameter/argument list, for the macro, we ignore that and return the variable
* as "$var_name" instead
*/
if (obj_ptr == null) {
obj_ptr = stmt.interp.string_obj_type.newStringObj("$"+token.obj_ptr.getString(), -1, "EVAL_STATEMENT_2");
stmt.interp.setResult(stmt.interp.empty_string_obj);
} else {
/* if we are expanding a macro and the variable is a list put it into {} to be safe */
if (obj_ptr.obj_type = stmt.interp.list_obj_type) {
obj_ptr = stmt.interp.string_obj_type.newStringObj("{"+obj_ptr.getString()+"}", -1, "EVAL_STATEMENT_3");
}
}
} else {
if (stmt.had_macro_cmd) {
obj_ptr = stmt.interp.string_obj_type.newStringObj("$"+token.obj_ptr.getString(), -1, "EVAL_STATEMENT_4");
}
}
break;
case stmt.TOKEN_ARRAY_NAME_VAR:
obj_ptr = JimExpandDictSugar(stmt.interp, token.obj_ptr);
break;
case stmt.TOKEN_EXPRSUGAR:
obj_ptr = stmt.interp.expr_obj_type.expandExprSugar(token.obj_ptr);
break;
case stmt.TOKEN_BRACE:
if (!stmt.in_quotes) {
obj_ptr = token.obj_ptr;
} else {
if (token.obj_ptr.len == 0) {
/* we have a single pair of {} within quotes,
* so make a corresponding string object
*/
obj_ptr = stmt.interp.string_obj_type.newStringObj("{}", -1, "EVAL_STATEMENT_5");
} else {
switch (stmt.interp.script_obj_type.substObj(token.obj_ptr, result_ptr, stmt.FUNCTION_FLAGS_LEAVE_ERR_MSG)) {
case stmt.OK:
obj_ptr = result_ptr[0];
/* special handling for expand in quotes !! */
if (obj_ptr.len == 1 && obj_ptr.bytes.substring(0,1) == "*") {
obj_ptr.len = 3;
obj_ptr.bytes = "{*}"+"\0";
}
break;
default:
return stmt.ERROR;
}
}
}
break;
case stmt.TOKEN_CMD:
if (stmt.interp.frame_ptr.type == stmt.CALL_TYPE_MACROEXPAND) {
stmt.had_macro_cmd = true;
stmt.macro_cmd_level = stmt.eval_level;
}
switch (stmt.evalObj(token.obj_ptr)) {
case stmt.OK:
case stmt.RETURN:
obj_ptr = stmt.interp.result;
break;
case stmt.BREAK:
/* Stop substituting */
return stmt.BREAK;
case stmt.CONTINUE:
/* just skip this one */
return stmt.CONTINUE;
default:
return stmt.ERROR;
}
break;
case stmt.TOKEN_NONE:
print("TOKEN_NONE");
//FIXME !!!
break;
default:
stmt.panic(1, "default token type ("+token.token+") "+stmt.getTokenString(token.token)+" reached in substOneToken().");
obj_ptr = null;
break;
}
if (obj_ptr) {
result_ptr[0] = obj_ptr;
return stmt.OK;
}
print("SUBST3 ERROR!"+stmt.interp.getResult()+"!"+stmt.interp.frame_ptr.ns_ptr.toDebugString()+"!");
script.dumpToken(idx);
return stmt.ERROR;
},
/* ==================== interpolateTokens ===================================== */
/* Interpolate the given tokens into a unique RaplObject returned by reference
* via obj_ptr. This function is only called by evalObj() and substObj()
* The returned object has refcount = 0.
*/
interpolateTokens: function (script, idx, word_tokens, flags) {
var stmt = this;
var total_len = 0;
var i;
var j;
var obj_ptr = null;
var str;
var intv2;
var token = script.script_object.tokens;
var result_ptr;
var retcode;
var my_in_quotes = stmt.in_quotes;
stmt.in_quotes = false;
intv2 = new Array();
/* Compute every token forming the argument
* in the intv2 objects vector.
*/
j = 0;
for (i = 0; i < word_tokens; i++) {
if (stmt.eval_ipol_debug) {
print("IPOL!"+i+"!"+idx+"!");
script.dumpToken(i+idx);
}
if (script.script_object.tokens[i + idx].token == stmt.TOKEN_COMMENT) {
continue;
}
result_ptr = new Array();
retcode = stmt.substOneToken(script, idx + i, result_ptr);
intv2[j] = result_ptr[0];
if (stmt.eval_ipol_debug > 1) {
print("RES!"+result_ptr[0]+"!"+intv2+"!"+retcode+"!");
script.dumpToken(i+idx);
}
if (intv2[j] != null) {
intv2[j].incrRefCount("I_EVAL_STATEMENT_2");
}
switch(retcode) {
case stmt.OK:
case stmt.RETURN:
break;
case stmt.BREAK:
if (flags & stmt.SUBST_FLAG) {
/* Stop here */
tokens = i;
continue;
}
/* XXX: Should probably set an error about break outside loop */
/* fall through to error */
case stmt.CONTINUE:
if (flags & stmt.SUBST_FLAG) {
intv2[i] = null;
continue;
}
/* XXX: Ditto continue outside loop */
/* fall through to error */
default:
while (j--) {
if (intv2[j] != null) {
intv2[j].decrRefCount("D_EVAL_STATEMENT_1");
}
}
intv2 = null;
stmt.in_quotes = my_in_quotes;
return null;
}
total_len += intv2[j].toString().length;
j++;
}
/* Fast path return for a single token */
if (word_tokens == 1 && intv2[0]) {
intv2[0].decrRefCount("D_EVAL_STATEMENT_2");
stmt.in_quotes = my_in_quotes;
return intv2[0];
}
/* Concatenate every token in an unique
* object.
*/
obj_ptr = stmt.interp.string_obj_type.newStringObjNoAlloc(null, 0, "EVAL_STATEMENT_6");
if (word_tokens == 4 && token.length > i + idx + 2 && token[i + idx + 0].token == stmt.TOKEN_ESC && token[i + idx + 1].token == stmt.TOKEN_ESC
&& token[i + idx + 2].token == stmt.TOKEN_VAR) {
/* May be able to do fast interpolated object -> array */
obj_ptr.obj_type = obj_ptr.interpolatedObjType;
obj_ptr.twoPtrValue.ptr1(token);
obj_ptr.twoPtrValue.ptr2(intv2[idx + 2]);
intv2[idx + 2].incrRefCount("I_EVAL_STATEMENT_3");
}
obj_ptr.bytes = "";
obj_ptr.length = total_len;
for (i = 0; i < j; i++) {
if (intv2[i]) {
obj_ptr.bytes += intv2[i].toString();
intv2[i].decrRefCount("D_EVAL_STATEMENT_3");
}
}
// obj_ptr.bytes[total_len] = '\0';
obj_ptr.len = total_len;
/* Free the intv2 vector. */
intv2 = null;
if (stmt.eval_ipol_debug > 1) {
print("interpolateTokens END!"+obj_ptr.toDebugString()+"!");
}
stmt.in_quotes = my_in_quotes;
return obj_ptr;
},
/* ==================== evalObj ===================================== */
evalObj: function (script_obj_ptr) {
var stmt = this;
var i;
var script;
var token;
var retcode = stmt.OK;
var sargv = null;
var line_no = 0;
var had_comment = false;
stmt.eval_level++;
if (stmt.eval_stmt_debug) {
print("EVALOBJ level!"+stmt.eval_level+"!"+script_obj_ptr+"!");
if (stmt.eval_stmt_debug > 1) {
print("EVALOBJ level!"+stmt.eval_level+"!"+script_obj_ptr.mySelf()+"!");
}
}
stmt.interp.error_flag = 0;
/* If the object is of type "list", with no string rep we can call
* a specialized version of evalObj() */
if (script_obj_ptr.isListObj() && script_obj_ptr.bytes == null) {
retcode = stmt.evalObjList(script_obj_ptr, stmt.interp.empty_obj, 1);
if (stmt.macro_cmd_level == stmt.eval_level) {
stmt.had_macro_cmd = false;
}
stmt.eval_level--;
return retcode;
}
script_obj_ptr.incrRefCount("I_EVAL_STATEMENT_4"); /* Make sure it's shared. */
script = script_obj_ptr.interp.script_obj_type.getScript(script_obj_ptr);
if (script == null) {
stmt.interp.setResultString("error in parsing script: \""+script_obj_ptr+"\"");
if (stmt.macro_cmd_level == stmt.eval_level) {
stmt.had_macro_cmd = false;
}
stmt.eval_level--;
return stmt.ERROR;
}
/* Reset the interpreter result. This is useful to
* return the empty result in the case of empty program. */
script_obj_ptr.interp.setEmptyResult();
/* Check for one of the following common scripts used by for, while
*
* {}
* incr a
*/
if (script.len == 0) {
script_obj_ptr.decrRefCount("D_EVAL_STATEMENT_4");
if (stmt.macro_cmd_level == stmt.eval_level) {
stmt.had_macro_cmd = false;
}
stmt.eval_level--;
return stmt.OK;
}
if (script.len == 3
&& script.script_object.tokens[1].obj_ptr.obj_type.type_name == "command"
&& script.script_object.tokens[1].obj_ptr.cmdValue.cmdPtr().is_proc == false
&& script.script_object.tokens[1].obj_ptr.cmdValue.cmdPtr().u.native_fcn.cmd_proc == script.interp.incrCoreCommand
&& script.script_object.tokens[2].obj_ptr.obj_typ.type_name == "variable") {
var obj_ptr = stmt.interp.getVariable(script.script_object.tokens[2].obj_ptr, stmt.TOKENNONE);
if (obj_ptr && !obj_ptr.isShared() && obj_ptrobj_type.name == "int") {
// JimWideValue(obj_ptr)++;
obj_ptr.invalidateStringRep();
script_obj_ptr.decrRefCount("D_EVAL_STATEMENT_5");
stmt.interp.setResult(obj_ptr);
if (stmt.macro_cmd_level == stmt.eval_level) {
stmt.had_macro_cmd = false;
}
stmt.eval_level--;
return stmt.OK;
}
}
/* Now we have to make sure the internal repr will not be
* freed on shimmering.
*
* Think for example to this:
*
* set x {llength $x; ... some more code ...}; eval $x
*
* In order to preserve the internal rep, we increment the
* inUse field of the script internal rep structure.
*/
script.ref_count++;
token = script.script_object.tokens;
/* Execute every command sequentially until the end of the script
* or an error occurs.
*/
for (i = 0; i < script.len && retcode == stmt.OK; ) {
var argc;
var argv = new Array();
var j;
var cmd;
var num_comments = 0;
/* First token of the line is always TOKEN_LINE */
argc = token[i].obj_ptr.scriptLineValue.argc();
//print("I!"+i+"!"+argc+"!"+script.getTokenString(token[i].token)+"!"+token[i].obj_ptr.toDebugString()+"!");
linenr = token[i].obj_ptr.scriptLineValue.line();
/* Skip the TOKEN_LINE token */
i++;
/* Populate the arguments objects.
* If an error occurs, retcode will be set and
* 'j' will be set to the number of args expanded
*/
had_comment = false;
for (j = 0; j < argc; j++) {
//print("J!"+j+"!"+argc+"!"+argv+"!");
var word_tokens = 1;
var expand = 0;
var word_obj_ptr = null;
if (stmt.eval_stmt_debug) {
print("J!"+j+"!"+script.getTokenString(token[i].token)+"!"+token[i].obj_ptr.toDebugString()+"!");
}
if (token[i].token == stmt.TOKEN_WORD) {
//script.dumpToken(i);
word_tokens = token[i++].obj_ptr.wideValue();
if (word_tokens < 0) {
expand = 1;
word_tokens = -word_tokens;
}
}
had_comment = false;
if (word_tokens == 1) {
/* Fast path if the token does not
* need interpolation
*/
//print("word_tokens 1!");
if (stmt.eval_stmt_debug) {
script.dumpToken(i);
}
switch (token[i].token) {
case stmt.TOKEN_COMMENT:
had_comment = true;
num_comments++;
break;
case stmt.TOKEN_QUOTE_ESC:
/* fall through */
case stmt.TOKEN_ESC:
case stmt.TOKEN_STR:
word_obj_ptr = token[i].obj_ptr;
break;
case stmt.TOKEN_VAR_ARRAY_NAME:
word_obj_ptr = stmt.interp.array_obj_type.expandArray(token[i].obj_ptr);
break;
case stmt.TOKEN_VAR:
var result_var_ptr = new Array();
result_var_ptr[0] = null;
word_obj_ptr = stmt.interp.variable_obj_type.getVariable(token[i].obj_ptr, stmt.FUNCTION_FLAGS_LEAVE_ERR_MSG, result_var_ptr);
result_var_ptr = result_var_ptr[0];
/* special case for ::itcl::type type variable !! */
if (word_obj_ptr == null && result_var_ptr != null && token[i].obj_ptr.getString() == "type") {
word_obj_ptr = stmt.interp.string_obj_type.newStringObj(result_var_ptr.namespace.full_name, -1, "EVAL_STATEMENT_7");
word_obj_ptr.incrRefCount("I_EVAL_STATEMENT_5");
}
break;
case stmt.TOKEN_EXPRSUGAR:
word_obj_ptr = stmt.expandExprSugar(token[i].obj_ptr);
break;
case stmt.TOKEN_ARRAY_NAME_VAR:
word_obj_ptr = stmt.expandDictSugar(token[i].obj_ptr);
break;
case stmt.TOKEN_BRACE:
if (!stmt.in_quotes) {
word_obj_ptr = token[i].obj_ptr;
} else {
var result_ptr = new Array();
retcode = stmt.interp.script_obj_type.substObj(token[i].obj_ptr, result_ptr, stmt.FUNCTION_FLAGS_LEAVE_ERR_MSG);
if (retcode == stmt.OK) {
word_obj_ptr = result_ptr[0];
}
}
break;
case stmt.TOKEN_CMD:
retcode = stmt.evalObj(token[i].obj_ptr);
if (retcode == stmt.OK) {
word_obj_ptr = stmt.interp.result;
}
break;
default:
stmt.panic(1, "default token type reached in evalObj(): "+stmt.getTokenString(token[i].token));
}
} else {
/* For interpolation we call a helper
* function to do the work for us.
*/
//print("interpolate!");
//script.dumpToken(i);
word_obj_ptr = stmt.interpolateTokens(script, i, word_tokens, stmt.TOKEN_NONE);
//print("interpolate!"+word_obj_ptr.toDebugString()+"!");
if (word_obj_ptr != null && word_obj_ptr.len == 0) {
/* we had only comment tokens, nothing to do */
had_comment = true;
}
}
i += word_tokens;
if (!had_comment) {
if (!word_obj_ptr) {
if (retcode == stmt.OK) {
retcode = stmt.ERROR;
}
break;
}
word_obj_ptr.incrRefCount("I_EVAL_STATEMENT_6");
if (!expand) {
if (!had_comment) {
argv.push(word_obj_ptr);
}
} else {
/* Need to expand word_obj_ptr into multiple args from argv[j] ... */
var len = stmt.interp.list_obj_type.listLength(word_obj_ptr);
var newargc = argc + len - 1;
var k;
//print("EXPAND!"+argc+"!"+len+"!"+newargc+"!"+word_obj_ptr.toDebugString()+"!");
/* Now copy in the expanded version */
for (k = 0; k < len; k++) {
argv.push(word_obj_ptr.listValue.elem()[k]);
j++;
word_obj_ptr.listValue.elem()[k].incrRefCount("I_EVAL_STATEMENT_7");
}
/* The original object reference is no longer needed,
* after the expansion it is no longer present on
* the argument vector, but the single elements are
* in its place.
*/
word_obj_ptr.decrRefCount("D_EVAL_STATEMENT_6");
/* And update the indexes */
j--;
argc += len - 1;
}
}
}
if (had_comment) {
continue
}
argc -= num_comments;
if (retcode == stmt.OK && argc) {
/* Lookup the command to call */
// cmd = stmt.interp.command_obj_type.getCommand(argv[0], stmt.FUNCTION_FLAGS_LEAVE_ERR_MSG);
cmd = stmt.interp.getCommand(argv[0]);
if (cmd == null && argc == 1) {
/* check if the argument looks like a list and the expand it (old style!!) */
var len = stmt.interp.list_obj_type.listLength(argv[0]);
var result_ptr = new Array();
var ret = stmt.interp.script_obj_type.substObj(argv[0], result_ptr, stmt.FUNCTION_FLAGS_NONE)
if (ret == stmt.OK) {
result_ptr = result_ptr[0];
len = stmt.interp.list_obj_type.listLength(result_ptr);
if (len > 1) {
var my_argc = new Array();
var my_argv = new Array();
if (len > 1) {
stmt.interp.list_obj_type.listGetElements(result_ptr, my_argc, my_argv);
argc = my_argc[0];
argv = my_argv[0];
cmd = stmt.interp.getCommand(argv[0]);
}
}
}
}
if (cmd != null) {
/* Call it -- Make sure result is an empty object. */
cmd.incrCmdRefCount();
stmt.interp.setEmptyResult();
//print("CMDT!"+argv[0]+"!"+cmd.getCommandTypeString(cmd.command_type)+"!");
//print("argv!"+argc+"!"+argv+"!"+argv.length+"!");
if (cmd.is_proc) {
retcode = cmd.u.proc.cmd_proc(cmd, script.script_object.file_name_obj, line_no, argc, argv);
} else {
/* Check if there are too nested calls */
//print("FR!"+intp.frame_ptr.toDebugString()+"!"+intp.max_nesting_depth+"!");
stmt.interp.cmd_priv_data = cmd.u.native_fcn.privdata;
retcode = cmd.u.native_fcn.cmd_proc(stmt.interp, argv, cmd);
}
cmd.decrCmdRefCount();
} else {
if (! (argc == 1 && argv == "")) {
print("UNK!"+argv[0]+"!"+argv[0].toDebugString()+"!");
//print("RETC!"+retcode+"!"+argc+"!"+argv+"!");
/* Call [unknown] */
retcode = stmt.interp.unknownFcn(argc, argv, script.script_object.file_name_obj, line_no);
} else {
/* we do not call unknown, if we had only the empty string as command and no arguments */
}
}
}
// /* Finished with the command, so decrement ref counts of each argument */
for (j = 0; j < argv.length; j++) {
argv[j].decrRefCount("D_EVAL_STATEMENT_7");
}
argv = new Array();
}
/* Possibly add to the error stack trace */
stmt.addErrorToStack(retcode, script.script_object.file_name_obj, line_no);
/* Note that we don't have to decrement ref_count, because the
* following code transfers our use of the reference again to
* the script object. */
script_obj_ptr.freeIntRep();
script_obj_ptr.obj_type = stmt.interp.script_obj_type;
script_obj_ptr.setIntRepPtr(script);
script_obj_ptr.decrRefCount("D_EVAL_STATEMENT_8");
//print("EVALOBJ end level!"+stmt.eval_level+"!"+retcode+"!");
if (stmt.macro_cmd_level == stmt.eval_level) {
stmt.had_macro_cmd = false;
}
stmt.eval_level--;
return retcode;
},
/* ==================== _evalObjVector ===================================== */
/* Eval the object vector 'objv' composed of 'objc' elements.
* Every element is used as single argument.
* evalObj() will call this function every time its object
* argument is of "list" type, with no string representation.
*
* This is possible because the string representation of a
* list object generated by the list_obj_type.UpdateString is made
* in a way that ensures that every list element is a different
* command argument.
*/
_evalObjVector: function(objc, objv, file_name_obj, line_no) {
var stmt = this;
var i;
var retcode;
var cmd_ptr;
/* Incr refcount of arguments. */
for (i = 0; i < objc; i++) {
objv[i].incrRefCount("I_EVAL_STATEMENT_8");
}
/* Command lookup */
cmd_ptr = stmt.interp.getCommand(objv[0], stmt.interp.FUNCTION_FLAGS_LEAVE_ERR_MSG);
//print("EOV!"+cmd_ptr.toDebugString()+"!");
if (cmd_ptr == null) {
retcode = stmt.interp.unknown(objc, objv, file_name_obj, line_no);
} else {
if (cmd_ptr.command_type == stmt.interp.COMMAND_ENSEMBLE) {
var i = 1;
var ens = cmd_ptr.ensemble;
while (true) {
var found = false;
for (var z in ens) {
if (z == objv[i].getString()) {
found = true;
break;
}
}
if (found) {
if (ens[z].ensemble == null) {
cmd_ptr = ens[z];
break;
} else {
ens = ens[z].ensemble;
i++;
}
} else {
var str = "";
for (var k = 0; k <= i; k++) {
str += " "+objv[k];
}
stmt.interp.setResultString("no such command!"+str+"!");
return stmt.ERROR;
}
}
}
/* Call it -- Make sure result is an empty object. */
cmd_ptr.incrCmdRefCount();
stmt.interp.setEmptyResult();
if (cmd_ptr.is_proc) {
retcode = stmt.interp.command_obj_type.callProcedure(cmd_ptr, file_name_obj, line_no, objc, objv);
} else {
stmt.interp.cmd_priv_data = cmd_ptr.u.native_fcn.priv_data;
retcode = cmd_ptr.u.native_fcn.cmd_proc(stmt.interp, objv);
}
cmd_ptr.decrCmdRefCount();
}
/* Decr refcount of arguments and return the retcode */
for (i = 0; i < objc; i++) {
objv[i].decrRefCount("D_EVAL_STATEMENT_9");
}
return retcode;
},
/* ==================== evalObjVector ===================================== */
evalObjVector: function(objc, objv) {
var stmt = this;
return stmt._evalObjVector(objc, objv, stmt.interp.empty_obj, 1);
},
/* ==================== evalObjFromArray ===================================== */
evalObjFromArray: function(args) {
var stmt = this;
var my_str = "";
var my_ptr;
var sep = "";
var ret_code;
/* cannot use evalObjVector() as that makes problems with ensemble commands!! */
for (; i < args.length; i++) {
if (my_str.match(" ") != null) {
my_str += sep+"{"+args[i]+"}";
} else {
my_str += sep+args[i];
}
sep = " ";
}
my_ptr = stmt.interp.string_obj_type.newStringObj(my_str, -1, "EVAL_STATEMENT_8");
my_ptr.incrRefCount("I_EVAL_STATEMENT_9");
ret_code = stmt.evalObj(my_ptr);
my_ptr.decrRefCount("D_EVAL_STATEMENT_10");
return ret_code;
},
/* ==================== evalObjList ===================================== */
/* If list_ptr is a list, call evalObjVector() with the given source info.
* Otherwise eval with evalObj()
*/
evalObjList: function (list_ptr, file_name_obj, linenr) {
var stmt = this;
var retcode = stmt.OK;
stmt.interp.panic(!list_ptr.isListObj(), "evalObjList() called without list arg");
if (list_ptr.listValue.len()) {
list_ptr.incrRefCount("I_EVAL_STATEMENT_10");
retcode = stmt.evalObjVector(list_ptr.listValue.len(), list_ptr.listValue.elem(), file_name_obj, linenr);
list_ptr.decrRefCount("D_EVAL_STATEMENT_11");
}
return retcode;
},
/* ==================== commandMatchObj ===================================== */
/* Returns 1 if match, 0 if no match or -<error> on error (e.g. -stmt.ERROR, -stmt.BREAK)*/
commandMatchObj: function(command_obj, pattern_obj, string_obj, nocase) {
var stmt = this;
var parms = new Array();
var argc = 0;
var eq = new Array();
var rc;
parms[argc++] = command_obj;
if (nocase) {
parms[argc++] = stmt.interp.string_obj_type.newStringObj("-nocase", -1, "EVAL_STATEMENT_9");
}
parms[argc++] = pattern_obj;
parms[argc++] = string_obj;
rc = stmt.evalObjVector(argc, parms);
if (rc != stmt.OK || stmt.interp.int_obj_type.getLong(stmt.interp.getResult(), eq) != stmt.OK) {
eq[0] = -rc;
}
return eq[0];
},
/* ==================== addErrorToStack ===================================== */
addErrorToStack: function(retcode, file_name_obj, line) {
var stmt = this;
var rc = retcode;
if (rc == stmt.ERROR && !stmt.interp.error_flag) {
/* This is the first error, so save the file/line information and reset the stack */
stmt.interp.error_flag = 1;
file_name_obj.incrRefCount("I_EVAL_STATEMENT_11");
stmt.interp.error_file_name_obj.decrRefCount("D_EVAL_STATEMENT_12");
stmt.interp.error_file_name_obj = file_name_obj;
stmt.interp.error_line = line;
stmt.resetStackTrace();
/* Always add a level where the error first occurs */
stmt.interp.add_stack_trace++;
}
/* Now if this is an "interesting" level, add it to the stack trace */
if (rc == stmt.ERROR && stmt.interp.add_stack_trace > 0) {
/* Add the stack info for the current level */
stmt.appendStackTrace(file_name_obj.getString(stmt.interp.error_proc), file_name_obj, line);
/* Note: if we didn't have a filename for this level,
* don't clear the addStackTrace flag
* so we can pick it up at the next level
*/
if (file_name_obj.getStringLength()) {
stmt.interp.add_stack_trace = 0;
}
stmt.interp.error_proc.decrRefCount("D_EVAL_STATEMENT_13");
file_name_obj.interp.error_proc = stmt.interp.empty_obj;
stmt.interp.error_proc.incrRefCount("I_EVAL_STATEMENT_12");
} else {
if (rc == stmt.RETURN && stmt.interp.return_code == stmt.ERROR) {
/* Propagate the addStackTrace value through 'return -code error' */
} else {
stmt.interp.add_stack_trace = 0;
}
}
},
/* ==================== resetStackTrace ===================================== */
resetStackTrace: function() {
var stmt = this;
stmt.interp.stack_trace.decrRefCount("D_EVAL_STATEMENT_14");
stmt.interp.stack_trace = stmt.interp.list_obj_type.newListObj(null, 0);
stmt.interp.stack_trace.incrRefCount("I_EVAL_STATEMENT_13");
},
/* ==================== setStackTrace ===================================== */
setStackTrace: function(stack_trace_obj) {
var stmt = this;
var len;
/* Increment reference first in case these are the same object */
stack_trace_obj.incrRefCount("I_EVAL_STATEMENT_14");
stmt.interp.stack_trace.decrRefCount("D_EVAL_STATEMENT_15");
stmt.interp.stack_trace = stack_trace_obj;
stmt.interp_error_flag = 1;
/* This is a bit ugly.
* If the filename of the last entry of the stack trace is empty,
* the next stack level should be added.
*/
len = stmt.interp.stack_trace.getStringLength();
if (len >= 3) {
var filename_obj;
stmt.interp.list_obj_type.listIndex(stmt.interp.stack_trace, len - 2, filename_obj, stmt.FUNCTION_FLAGS_NONE);
len = filename_obj.getStringLength();
if (!filename_obj.getStringLength()) {
stmt.interp.add_stack_trace = 1;
}
}
},
/* ==================== appendStackTrace ===================================== */
/* Returns 1 if the stack trace information was used or 0 if not */
appendStackTrace: function(procname, file_name_obj, linenr) {
var stt = this;
if (procname == "unknown") {
procname = "";
}
if (!procname && !file_name_obj.getStringLength()) {
/* No useful info here */
return;
}
if (stmt.interp.stack_trace.isShared()) {
stmt.interp.stack_trace.decrRefCount("D_EVAL_STATEMENT_16");
stmt.interp.stack_trace = file_name_obj.duplicateObj(stmt.interp.stack_trace);
stmt.interp.stack_trace.incrRefCount("I_EVAL_STATEMENT_15");
}
/* If we have no procname but the previous element did, merge with that frame */
if (!procname && file_name_obj.getStringLength()) {
/* Just a filename. Check the previous entry */
var len = stmt.interp.list_obj_type.listLength(stmt.interp.stack_trace);
if (len >= 3) {
var obj_ptr;
if (stmt.interp.list_obj_type.listIndex(stmt.interp.stack_trace, len - 3, obj_ptr, stmt.FUNCTION_FLAGS_NONE) == stmt.OK && obj_ptr.getStringLength()) {
/* Yes, the previous level had procname */
if (stmt.interp.list_obj_type.listIndex(stmt.interp.stack_trace, len - 2, objPtr, stmt.FUNCTION_FLAGS_NONE) == stmt.OK && !obj_ptr.getStringLength()) {
/* But no filename, so merge the new info with that frame */
stmt.interp.list_obj_type.listSetIndex(stmt.interp.stack_trace, len - 2, file_name_obj, 0);
stmt.interp.list_obj_type.listSetIndex(stmt.interp.stack_trace, len - 1, stmt.interp.int_obj_type.newIntObj(linenr), 0);
return;
}
}
}
}
stmt.interp.list_obj_type.listAppendElement(stmt.interp.stack_trace, stmt.interp.string_obj_type.newStringObj(procname, -1, "EVAL_STATEMENT_10"));
stmt.interp.list_obj_type.listAppendElement(stmt.interp.stack_trace, file_name_obj);
stmt.interp.list_obj_type.listAppendElement(stmt.interp.stack_trace, stmt.interp.int_obj_type.newIntObj(linenr));
},
});
EvalStatement.prototype.constructor = EvalStatement;
R.EvalStatement = EvalStatement;
}, "0.0.1", {});