/*====================================================
* 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', 'life', 'EvalStatement', true);
// kweight
var evalstmt = this;
evalstmt.interp = interp;
evalstmt.call_level = 0;
evalstmt.eval_level = 0;
evalstmt.expr_eval_level = 0;
evalstmt.level_infos = new Array();
evalstmt.enterstep_traces = new Array();
evalstmt.leavestep_traces = new Array();
evalstmt.inLoop = false;
evalstmt.level = 0;
evalstmt.callframes = new Array();
evalstmt.callframes.push(new R.Callframe(evalstmt.interp, evalstmt.CALL_TYPE_PROC));
evalstmt.curr_callframe = evalstmt.callframes[evalstmt.level];
evalstmt.curr_callframe.setNamespace(evalstmt.interp.root_namespace);
evalstmt.no_trace = false;
evalstmt.call_debug = 0;
evalstmt.eval_stmt_debug = 0;
evalstmt.eval_expr_debug = 0;
evalstmt.code = evalstmt.OK;
evalstmt.file_name = null;
evalstmt.in_quoted_string = false;
evalstmt.in_brace = false;
evalstmt.cmd_name = "";
evalstmt.last_token = 0;
R.Base.eval_statment_cnt++;
evalstmt.cnt = R.Base.eval_statement_cnt;
evalstmt.my_name = "RaplEvalStatement";
R.log('constructor end', '2.life', 'EvalStatement', true);
}
R.extend(EvalStatement, R.Token, {
/* ==================== isBracedParam ===================================== */
isBracedParam: function (val) {
return (val instanceof TclWord);
},
/* ==================== incrLevel ===================================== */
incrLevel: function(type) {
var class_object = this.getCallframeClassObject();
this.level++;
this.callframes.push(new TclCallframe(this.interp, type));
this.curr_callframe = this.callframes[this.level];
this.curr_callframe.setNamespace(this.interp.current_namespace);
this.curr_callframe.setClassObject(class_object);
return this.level;
},
/* ==================== decrLevel ===================================== */
decrLevel: function() {
this.callframes.pop();
this.level--;
if (this.level<0) {
throw "Exit application";
}
this.curr_callframe = this.callframes[this.level];
this.result = null;
},
/* ==================== setCallframeClassObject ===================================== */
setCallframeClassObject: function (class_object) {
this.curr_callframe.setClassObject(class_object);
},
/* ==================== getCallframeClassObject ===================================== */
getCallframeClassObject: function () {
return this.curr_callframe.getClassObject();
},
/* ==================== evalFileContents ================================ */
evalFileContents: function (file_name, code) {
this.interp.curr_file_name = file_name;
var stmts_obj;
if (typeof code == "string") {
stmts_obj = this.statement_parser.parse2Statements(file_name, 1, code);
return this.eval(stmts_obj);
} else {
throw "evalFileContents!"+file_name+"!"+typeof code+"! no type string of code";
}
},
/* ==================== eval ===================================== */
eval: function (code) {
try {
//print("EVAL1!"+(code instanceof Array)+"!"+(code instanceof TclStatement)+"!"+code+"!");
//print("EVAL1!"+code.hasStatementsValue()+"!");
//print("CODE!"+typeof code+"!");
if ((typeof code != "string") && code.hasStatementsValue()) {
//print(">>> eval TCL!"+code+"!");
var save_statments = this.curr_callframe.curr_statements;
var save_statment_idx = this.curr_callframe.curr_statement_idx;
this.curr_callframe.curr_statements = code;
this.curr_callframe.curr_statement_idx = 0;
result = this.evalTclStatements();
this.curr_callframe.curr_statements = save_statments;
this.curr_callframe.curr_statement_idx = save_statment_idx;
} else {
//print(">> eval2!"+code+"!"+(code instanceof TclObject)+"!"+typeof code+"!");
var stmts_obj = null;
if (typeof code == "string") {
stmts_obj = this.statement_parser.parse2Statements(this.interp.curr_file_name, this.interp.curr_line_no, code);
} else {
if (!(code instanceof TclObject)) {
throw "eval code is no string and no TclObject"
}
if (code.isNoExprOrStatement) {
stmts_obj = code.toStatements(this.interp.curr_file_name, this.interp.curr_line_no);
} else {
if (!code.hasStatementsValue()) {
throw "eval code is no string and has no StatementsValue"
} else {
stmts_obj = code.getStatementsValue();
}
}
}
//print("EVAL STMTS!"+stmts_obj+"!");
if (stmts_obj != null) {
var save_statments = this.curr_callframe.curr_statements;
var save_statment_idx = this.curr_callframe.curr_statement_idx;
this.curr_callframe.curr_statements = stmts_obj;
this.curr_callframe.curr_statement_idx = 0;
result = this.evalTclStatements();
this.curr_callframe.curr_statements = save_statments;
this.curr_callframe.curr_statement_idx = save_statment_idx;
}
}
//print("EV END!"+code.toString().substring(0,50)+"!"+result+"!");
return result;
} catch (e) {
if (this.code == Tcl.ERROR) {
// return this.interp.objectify(Tcl.GetErrorCode(this.interp));
}
for (var i = this.level-1; i >= 0; i--) {
//print("LEVEL_INFO!"+i+"!"+this.level_infos[i]+"!");
}
//print("CODE!"+code.toString()+"!");
var cmd = code.toString();
print("CCC!"+typeof cmd.substring+"!");
if (typeof cmd.substring != "undefined") {
cmd = cmd.substring(0,128);
}
print("CCC2!"+cmd+"!");
try {
if(!confirm(e+"/" + e.description + "\nwhile evaluating "+cmd+"...")) {
throw(e);
}
} catch(e2) {
print("CCCa!"+e2+"!");
}
print("CCC3!"+cmd+"!");
}
},
/* ==================== evalTclStatement ===================================== */
evalTclStatement: function(stmt) {
//print("evalTclStatement!"+stmt.toString().substring(0,40)+"!");
//print("DBG!"+stmt.toDebugString()+"!");
this.in_quoted_string = false;
var args = new Array();
var had_expand = false;
var had_no_word_sep = false;
var had_cmd = false;
//print("LL!"+typeof stmt+"!"+stmt+"!"+(stmt instanceof TclObject)+"!");
var statement_file_name = null;
var statement_line_no = -1;
var statement_last_line_no = -1;
this.cmd_name = "";
//print("STMT!"+(stmt instanceof TclStatement)+"!"+stmt.len);
//print("STMT!"+stmt.toDebugString()+"!");
var save_last_token = this.last_token;
this.last_token = Tcl.TOKEN_EOF;
for (var j = 0; j < stmt.len; j++) {
var word_obj = stmt.getWord(j);
var word = word_obj.getWordValue();
var token = word.getToken();
if (token == Tcl.TOKEN_QUOTED_STR) {
this.in_quoted_string = true;
}
try {
//print("ETS TOK!"+Tcl.getParserTokenString(token)+"!");
var val = word.getEvalValue();
//print("VAL!"+val+"!");
//print("evalTclSTMT!"+j+"!"+Tcl.getParserTokenString(token)+"!"+val.toString().substring(0,100)+"!");
var file_name = word.getFileName();
var last_line_no = word.getLastLineNo();
var line_no = word.getLineNo();
//print("WORD!"+j+"!"+file_name+"!"+last_line_no+"!"+line_no+"!"+word+"!");
if (j == 0) {
this.interp.curr_file_name = file_name;
this.interp.curr_line_no = line_no;
this.interp.last_line_no = last_line_no;
statement_file_name = file_name;
statement_line_no = line_no;
statement_last_line_no = last_line_no;
}
var val2 = null;
//print("ETS!"+j+"!"+stmt.len+"!"+Tcl.getParserTokenString(token)+"!"+word.toDebugString()+"!");
//print("EVTOK!"+Tcl.getParserTokenString(token)+"!");
var my_last_token = this.last_token;
switch(token) {
case Tcl.TOKEN_EXPR:
//print("evalTclSTMT Tcl.TOKEN_EXPR");
var result = this.evalExprTree(val);
break;
case Tcl.TOKEN_NO_WORD_SEP:
//print("evalTclSTMT Tcl.TOKEN_NO_WORD_SEP");
had_no_word_sep = true;
continue;
break;
case Tcl.TOKEN_CMD:
/* evaluation has already been done by getEvalValue !! */
var result = val;
//print(">>>CMD!"+val+"!");
args.push(this.interp.statement_parser.objectify(result));
break;
case Tcl.TOKEN_BRACE:
//print(">> TOKEN_BRACE!"+val+"!");
var word_parts = word.getWordParts();
var my_part = word_parts[0];
var sub_stmts = my_part.getStatements();
//print("BRACE!"+had_cmd+"!"+sub_stmts+"!"+(val instanceof TclObject)+"!"+my_part+"!"+word_parts.length+"!");
this.in_brace = true;
if (had_cmd) {
if (sub_stmts != null) {
args.push(new TclObject(this, sub_stmts, "STMTS"));
} else {
args.push(word_obj);
}
had_cmd = false;
}else {
//print("TB!"+typeof val+"!"+val+"!");
args.push(word_obj);
}
break;
case Tcl.TOKEN_STR_CMD:
had_cmd = true;
this.cmd_name = val;
//print(">>>STR_CMD!"+val+"!");
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_STR_PARAM:
//print(">>>STR_PARAM!"+val+"!");
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_EXPAND:
had_expand = true;
//print("Tcl.TOKEN_EXPAND:!"+val+"!"+(val instanceof Array)+"!"+val.length+"!");
for (var k = 0; k < val.length; k++) {
var val2 = val[k];
args.push(this.interp.statement_parser.objectify(val2));
}
break;
case Tcl.TOKEN_VAR:
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_VAR_ARRAY:
//print("TOKEN_VAR_ARRAY:!"+val+"!");
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_VAR_ARRAY_NAME:
//print("TOKEN_VAR_ARRAY_NAME:!"+val+"!");
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_ARRAY_NAME:
//print("TOKEN_ARRAY_NAME:!"+val+"!");
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_BRACED_VAR:
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_PAREN:
//print("STMT TOKEN_PAREN:!"+val+"!");
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_QUOTED_STR:
args.push(this.interp.statement_parser.objectify(val));
break;
case Tcl.TOKEN_WORD_SEP:
case Tcl.TOKEN_COMMENT:
case Tcl.TOKEN_EOL:
case Tcl.TOKEN_EOF:
//print("special token!"+Tcl.getParserTokenString(token)+"!");
/* these are only for reconstructing the source code again */
continue;
default:
throw "unexpected token in evalTclStatement!"+Tcl.getParserTokenString(token)+"!";
}
had_no_word_sep = false;
} catch(e) {
print("INNER ERROR");
throw "ERROR in INNER evalTclStatement:!"+e+"!"+word.toString()+"!";
}
this.last_token = token;
}
this.last_token = save_last_token;
if (this.eval_stmt_debug) {
print("+++ eval_stmt EOL call!"+args.toString().substring(0,100)+"!");
}
//print("STMT1!"+args.toString().substring(0,60)+"!");
if (args.length == 0) {
/* seems to be an emty statement like a comment or an empty line, so nothing to do */
this.code = Tcl.OK;
return interp.statement_parser.objectify("");
}
try {
//print("SETFL!"+statement_file_name+"!"+statement_last_line_no+"!"+statement_line_no+"!"+this.interp+"!"+this.interp.curr_file_name+"!");
this.interp.curr_file_name = statement_file_name;
this.interp.curr_line_no = statement_line_no;
this.interp.curr_statement = args;
//print("ARGS!"+args+"!");
result = this.call(args);
} catch(e) {
throw "ERROR in CALL evalTclStatements:!"+e+"!"+args+"!";
}
//print("evalTclStatement result!"+result.toString().substring(0,60)+"!"+stmt+"!");
return result;
},
/* ==================== evalTclStatements ===================================== */
evalTclStatements: function() {
try {
var result = "";
var statements_obj = this.curr_callframe.curr_statements;
var statements = statements_obj.getStatementsValue();
var i = this.curr_callframe.curr_statement_idx
for (; i < statements.length; i++) {
this.in_brace = false;
var stmt_obj = statements[i];
//print("EVTS!"+this.curr_callframe.curr_statement_idx+"!"+statements.length+"!");
//print("EVTS2!"+stmt_obj.getStatementValue().toDebugString()+"!");
//print("EVTS3!"+stmt_obj.getStatementValue().toString()+"!");
//print("EVTS4!"+stmt_obj.getStatementValue().toFullString()+"!");
this.curr_callframe.curr_statement_idx = i;
this.code = Tcl.OK;
result = this.evalTclStatement(stmt_obj.getStatementValue());
//print("EVTS5");
if (this.code != Tcl.OK) {
if (this.code == Tcl.RETURN) {
return result;
}
print(" had Tcl ERROR evalTclStatements call after evalTclStatement!"+this.code+"!"+result+"!");
result = this.interp.statement_parser.objectify(result);
return result;
}
}
} catch(e) {
throw "ERROR in OUTER evalTclStatements:!"+e+"!"+this.interp.current_statement+"!";
}
return result;
},
/* ==================== call ===================================== */
call: function(args) {
//print("CALL1");
//this.call_logs.push(args.toString());
if (this.call_debug) {
//print("IPCALL!"+args.toString()+"!");
}
//print("interp.call arg0!"+args[0]+"!length!"+args.length+"!arg1!"+args[1]+"!lv!"+this.level+"!call_lv!"+this.call_level+"!");
this.call_level++;
//print("CALL2a!"+args[0].toString()+"!");
if(_step && !confirm("this.call "+args)) {
throw "user abort";
}
//print("IPNS1!"+this.interp.current_namespace.full_name+"!");
var my_cmd = args[0].toString();
var func = this.interp.getCommand(my_cmd);
//print("CA!"+args[0]+"!"+func+"!");
if (this.call_debug) {
print("interp call func!"+func+"!type!"+func.type+"!name!"+func.name+"!NS!"+this.interp.command_namespace.name+"!");
}
//print("FUNC!"+(func instanceof Tcl.EnsembleCommand)+"!");
var pushed = 0;
if ((this.interp.current_namespace != this.interp.command_namespace) && (this.interp.command_namespace.name != "::")) {
this.interp.pushNamespace(this.interp.command_namespace.name, this.interp.command_namespace);
pushed = 1;
}
//print("IPNS!"+this.interp.current_namespace.full_name+"!");
var my_obj = new TclObject(this.interp, "", "TEXT");
var function_args = my_obj.getString(args);
if (!this.no_trace && (this.enterstep_traces.length > 0)) {
for (var i = 0; i < this.enterstep_traces.length; i++) {
var trace_obj = this.enterstep_traces[i];
var ops = trace_obj.getOps();
for (var j = 0; j < ops.length; j++) {
if (ops[j] == Tcl.TRACE_OP_ENTERSTEP) {
var code = trace_obj.getCommand()+" {"+function_args+"} enter";
try {
this.no_trace = true;
this.eval(code);
this.no_trace = false;
} catch(e) {
throw "error in executing enterstep trace: "+code+"!";
}
}
}
}
}
if (this.call_debug) {
print("CALL!"+args+"!");
}
var r = func.call(this.interp, args);
if (this.call_debug) {
print("CALL after!"+r+"!");
}
if (pushed) {
this.interp.popNamespace();
}
if (!this.no_trace && (this.leavestep_traces.length > 0)) {
for (var i = 0; i < this.leavestep_traces.length; i++) {
var trace_obj = this.leavestep_traces[i];
var ops = trace_obj.getOps();
for (var j = 0; j < ops.length; j++) {
if (ops[j] == Tcl.TRACE_OP_LEAVESTEP) {
var my_obj = new TclObject(this.interp, "", "TEXT");
var result = r;
if (result == null) {
result = "";
}
var code = trace_obj.getCommand()+" {"+function_args+"} "+this.code+" {"+result+"} leavestep";
try {
this.no_trace = true;
this.eval(code);
this.no_trace = false;
} catch(e) {
throw "error in executing leavestep trace: "+code+"!";
}
}
}
}
}
this.call_level--;
switch (this.code) {
case Tcl.OK:
case Tcl.ERROR:
case Tcl.RETURN:
return r;
case Tcl.BREAK:
if (!this.inLoop) {
throw "Invoked break outside of a loop";
}
break;
case Tcl.CONTINUE:
if (!this.inLoop) {
throw "Invoked continue outside of a loop";
}
break;
default:
throw "Unknown return code " + this.code;
}
return r;
},
/* ==================== evalExprSubTree ===================================== */
evalExprSubTree: function(node, parent, lv) {
//this.eval_expr_debug = 1;
if (this.eval_expr_debug) {
print("evalExprSubTree!"+lv+"!");
node.showTree(node, "");
}
var type_left = -1;
var type_right = -1;
var type_node = node.getNodeType();
var name_left = "";
var name_right = "";
var val_left = "{}";
var val_right = "{}";
var child_left = node.getChildLeft();
var child_right = node.getChildRight();
if ((child_left == null) && (child_right == null)) {
if (this.eval_expr_debug) {
print("evalExprSubTree bottom!N!"+node.name+"!"+lv+"!");
}
return this.interp.statement_parser.objectify(node.getNodeValue());
}
if (child_left != null) {
type_left = child_left.getNodeType();
name_left = child_left.name;
if (type_left >= Tcl.TOKEN_MINUS) {
left_val = this.statement_parser.tree2Expr(child_left, node, "", lv);
} else {
val_left = child_left.getNodeValue();
}
}
if (child_right != null) {
type_right = child_right.getNodeType();
name_right = child_right.name;
if (type_right >= Tcl.TOKEN_MINUS) {
val_right = this.statement_parser.tree2Expr(child_right, node, "", lv);
} else {
val_right = child_right.getNodeValue();
}
}
if (this.eval_expr_debug) {
print("evalExprSubTree!N!"+node.name+"!L!"+name_left+"!T!"+type_left+"!V!"+val_left+"!R!"+name_right+"!T!"+type_right+"!V!"+val_right+"!"+lv+"!");
}
lv++;
var val;
if ((type_left < Tcl.TOKEN_PAREN) && (type_right < Tcl.TOKEN_PAREN) && (type_node != Tcl.TOKEN_NOT)) {
left_val = child_left.getNodeValue();
right_val = child_right.getNodeValue();
var code = node.name+" "+left_val+" "+right_val;
if (Tcl.isStringOperatorType(node.getNodeType())) {
code = node.name+" {"+left_val+"} {"+right_val+"}";
}
//print("ESU!"+code+"!");
val = this.eval(code);
lv--;
return this.interp.statement_parser.objectify(val);
}
var left_val;
var right_val;
if ((child_left == null) && (child_right == null)) {
lv--;
return this.interp.statement_parser.objectify(node.getNodeValue());
}
if ((type_left == Tcl.TOKEN_STR) || (type_left == Tcl.TOKEN_VAR)) {
left_val = child_left.getNodeValue();
} else {
if (type_left == Tcl.TOKEN_PAREN) {
left_val = this.statement_parser.tree2Expr(child_left.getChildLeft(), node, "", lv);
} else {
left_val = this.statement_parser.tree2Expr(child_left, node, "", lv);
}
}
if (node.getNodeType() == Tcl.TOKEN_NOT) {
if (left_val == 0) {
val = this.interp.statement_parser.objectify("1");
} else {
val = this.interp.statement_parser.objectify("0");
}
if (this.eval_expr_debug) {
print("RET NOT!"+val+"!"+node.name+"!"+left_val+"!");
}
return val;
lv--;
}
if (child_right == null) {
lv--;
return this.interp.statement_parser.objectify(left_val);
}
if (type_right == Tcl.TOKEN_STR) {
right_val = child_right.getNodeValue();
} else {
if (type_right == Tcl.TOKEN_PAREN) {
right_val = this.statement_parser.tree2Expr(child_right.getChildLeft(), node, "", lv);
} else {
right_val = this.statement_parser.tree2Expr(child_right, node, "", lv);
}
}
var code = node.name+" "+left_val+" "+right_val;
if (Tcl.isStringOperatorType(node.getNodeType())) {
code = node.name+" {"+left_val+"} {"+right_val+"}";
}
val = this.eval(code);
if (this.eval_expr_debug) {
print("RET!"+val+"!"+node.name);
}
lv--;
return this.interp.statement_parser.objectify(val);
},
/* ==================== evalExprTree ===================================== */
evalExprTree: function(word) {
var node = word.getValue();
//print("evalExprTree!"+typeof node+"!");
//node.showTree(node, "");
var result = this.evalExprSubTree(node, null, 0);
result = this.interp.statement_parser.objectify(result);
//print("evalExprTree!"+result+"!");
return result;
},
});
EvalStatement.prototype.constructor = EvalStatement;
R.EvalStatement = EvalStatement;
}, "0.0.1", {});