/*=======================================================
* Interp.java
*
* "A Tcl like language implementation in Java named APWTCL
* ((Java) Arnulf's Preferred Web Tcl)"
*
* APWTCL Interp class
*
* Released under same BSD license as Tcl.
* (Tcl BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
*
* Copyright 2012 Arnulf P. Wiedemann
*
*/
package org.apwtcl.lang;
//#if memdebug
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import org.apwtcl.lang.objtype.ArrayObjType;
import org.apwtcl.lang.objtype.CommandObjType;
import org.apwtcl.lang.objtype.DictObjType;
import org.apwtcl.lang.objtype.DoubleObjType;
import org.apwtcl.lang.objtype.ExprObjType;
import org.apwtcl.lang.objtype.IndexObjType;
import org.apwtcl.lang.objtype.IntObjType;
import org.apwtcl.lang.objtype.ItclObjType;
import org.apwtcl.lang.objtype.ListObjType;
import org.apwtcl.lang.objtype.NamespaceObjType;
import org.apwtcl.lang.objtype.ParamObjType;
import org.apwtcl.lang.objtype.ReturnCodeObjType;
import org.apwtcl.lang.objtype.ScriptLineObjType;
import org.apwtcl.lang.objtype.ScriptObjType;
import org.apwtcl.lang.objtype.SourceObjType;
import org.apwtcl.lang.objtype.StringObjType;
import org.apwtcl.lang.objtype.VariableObjType;
public class Interp extends Token implements Debug {
//#if memdebug
/* keep track on how many ApwtclObjs have been created */
static long interp_count = 0;
/* actually keep track via weak references of all allocated ApwtclObjs */
//#endif
private long id;
public ArrayObjType array_obj_type;
public CommandObjType command_obj_type;
public DictObjType dict_obj_type;
public DoubleObjType double_obj_type;
public ExprObjType expr_obj_type;
public IndexObjType index_obj_type;
public IntObjType int_obj_type;
public ItclObjType itcl_obj_type;
public ListObjType list_obj_type;
public NamespaceObjType namespace_obj_type;
public ParamObjType param_obj_type;
public ReturnCodeObjType return_code_obj_type;
public ScriptLineObjType script_line_obj_type;
public ScriptObjType script_obj_type;
public SourceObjType source_obj_type;
public StringObjType string_obj_type;
public VariableObjType variable_obj_type;
public ApwtclObj default_obj;
public ApwtclObj empty_string_obj;
public CallFrame frame_ptr;
public CallFrame var_frame_ptr;
public CallFrame top_frame_ptr;
public EvalStatement eval_statement;
public Namespace global_ns_ptr;
public Namespace current_namespace;
public String current_namespace_name;
public Resolve command_resolver;
public Resolve variable_resolver;
public ApwtclObj true_obj;
public ApwtclObj false_obj;
public ApwtclObj result;
public HashMap<String, ItclClass> classes;
public boolean error_flag;
public ArrayList<ApwtclObj> cmd_priv_data;
public ApwtclObj error_file_name_obj;
public int return_code;
public int error_line;
public int add_stack_trace;
public ApwtclObj error_proc;
public ApwtclObj stack_trace;
public Method call_procedure;
public int proc_epoch;
public int flags;
public String curr_file_name;
public int curr_line_no;
public ApwtclObj rewrite_name_obj;
public int rewrite_name_count;
public int local;
public ApwtclObj full_class_name;
public int class_type;
public ApwtclObj local_procs;
public int max_nesting_depth;
public int return_level;
public int last_line_no;
public int uplevel_dist;
public ArrayList<Namespace> namespaces;
public HashMap<Interp, ArrayList<InterpAlias>> aliases;
public HashMap<String, ItclObject> class_objects;
public int unknown_called;
public ApwtclObj unknown;
public Resolve lookup_resolve_var;
public ApwtclObj error_code;
public Expr eval_expression;
public ItclClass curr_class_info;
public LoadedClassInfo loaded_class_info;
public TclTest tcl_tests;
public ApwtclObj win;
public ApwtclObj xhdr_object;
public String start_dir;
public String current_dir;
public ApwtclObj current_script_obj;
/* ==================== Interp ================================== */
public Interp() {
++interp_count;
id = interp_count;
/* initialise the ObjType Objects */
array_obj_type = new ArrayObjType(this);
dict_obj_type = new DictObjType(this);
expr_obj_type = new ExprObjType(this);
double_obj_type = new DoubleObjType(this);
index_obj_type = new IndexObjType(this);
int_obj_type = new IntObjType(this);
itcl_obj_type = new ItclObjType(this);
list_obj_type = new ListObjType(this);
namespace_obj_type = new NamespaceObjType(this);
param_obj_type = new ParamObjType(this);
return_code_obj_type = new ReturnCodeObjType(this);
script_line_obj_type = new ScriptLineObjType(this);
script_obj_type = new ScriptObjType(this);
source_obj_type = new SourceObjType(this);
string_obj_type = new StringObjType(this);
variable_obj_type = new VariableObjType(this);
/* next line must be at end it needs other *ObjType objects !! */
command_obj_type = new CommandObjType(this);
default_obj = new ApwtclObj(this);
empty_string_obj = string_obj_type.newEmptyStringObj("INTERP_1");
true_obj = int_obj_type.newIntObj(1);
true_obj.incrRefCount("I_INTERP_3");
false_obj = int_obj_type.newIntObj(0);
false_obj.incrRefCount("I_INTERP_4");
eval_statement = new EvalStatement(this);
myInit();
command_resolver = null;
variable_resolver = null;
result = empty_string_obj;
result.incrRefCount("I_INTERP_5");
classes = new HashMap<String, ItclClass>();
error_flag = false;
cmd_priv_data = null;
error_file_name_obj = empty_string_obj;
error_file_name_obj.incrRefCount("INTERP_6");
error_line = 0;
add_stack_trace = 0;
error_proc = empty_string_obj;
error_proc.incrRefCount("INTERP_7");
return_code = 0;
proc_epoch = 0;
flags = 0;
stack_trace = empty_string_obj;
stack_trace.incrRefCount("INTERP_8");
curr_file_name = "";
curr_line_no = 0;
rewrite_name_obj = empty_string_obj;
rewrite_name_obj.incrRefCount("INTERP_9");
rewrite_name_count = 0;
local = 0;
full_class_name = null;
class_type = -1;
local_procs = null;
max_nesting_depth = 20;
return_level = 0;
last_line_no = 0;
uplevel_dist = 0;
namespaces = new ArrayList<Namespace>();
aliases = new HashMap<Interp, ArrayList<InterpAlias>>();
class_objects = new HashMap<String, ItclObject>();
unknown_called = 0;
unknown = string_obj_type.newStringObj("unknown", -1, "INTERP_7");
lookup_resolve_var = null;
error_code = null;
eval_expression = new Expr(this);
curr_class_info = null;
loaded_class_info = new LoadedClassInfo(this);
tcl_tests = null;
win = null;
xhdr_object = null;
start_dir = "/home/arnulf/workspace/apwtcl/src/org/apwtcl/lang";
current_dir = ".";
current_script_obj = null;
}
/* ==================== mySelf ================================== */
public String mySelf() {
String str = "Interp!"+id+"!";
return str;
}
/* ==================== toString ================================== */
public String toString() {
String str = mySelf();
return str;
}
/* ==================== toDebugString ================================== */
public String toDebugString() {
StringBuffer str = new StringBuffer();
str.append(mySelf()+"\n");
if (frame_ptr == null) {
str.append(" frame_ptr: <null>\n");
} else {
str.append(" frame_ptr: "+frame_ptr.toDebugString()+"\n");
}
return str.toString();
}
/* ==================== myInit ===================================== */
public void myInit (/* Window win */) {
/*
if (win.DOMParser) {
// this.dom_parser=new DOMParser();
// xmlDoc=this.dom_parser.parseFromString(text,"text/xml");
} else {
// Internet Explorer
// xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
// xmlDoc.async="false";
// xmlDoc.loadXML(text);
}
*/
// this.win = win;
global_ns_ptr = namespace_obj_type.createNamespace("");
if (global_ns_ptr == null) {
panic(true, "createInterp: can't create global namespace");
}
current_namespace = global_ns_ptr;
this.frame_ptr = new CallFrame(this, CALL_TYPE_NAMESPACE);
this.frame_ptr.ns_ptr = global_ns_ptr;
CallFrame frame_ptr = this.frame_ptr.newCallFrame(/* call_type */ CALL_TYPE_NAMESPACE, this.frame_ptr);
int result = namespace_obj_type.pushCallFrame(frame_ptr, global_ns_ptr, /*isProcCallFrame*/ CALL_TYPE_NAMESPACE);
if (result != OK) {
panic(true, "createInterp: failed to push the root stack frame");
}
this.frame_ptr.argc = 0;
this.frame_ptr.level = 0;
this.frame_ptr = frame_ptr;
this.var_frame_ptr = frame_ptr;
this.top_frame_ptr = frame_ptr;
current_namespace_name = global_ns_ptr.name;
current_namespace = global_ns_ptr;
}
/* ==================== getCurrentNamespace ===================================== */
public Namespace getCurrentNamespace() {
if (uplevel_dist == 0) {
return current_namespace;
}
return namespaces.get(frame_ptr.level - uplevel_dist);
}
/* ==================== getCommand ===================================== */
public Command getCommand(ApwtclObj obj_ptr, int flags, ArrayList<ArrayList<ApwtclObj>> extra_args_ptr) {
String cmd_name = obj_ptr.getString();
ApwtclObj my_obj_ptr;
//print("cmd_name!"+cmd_name+"!"+((cmd_name.charAt(0) == ':' ) && (cmd_name.charAt(1) == ':')));
if (!((cmd_name.charAt(0) == ':' ) && (cmd_name.charAt(1) == ':'))) {
String ns_name = frame_ptr.ns_ptr.full_name;
if (!ns_name.equals("::")) {
ns_name = ns_name+"::";
}
my_obj_ptr = string_obj_type.newStringObj(ns_name+cmd_name, -1, "INTERP_11");
} else {
my_obj_ptr = obj_ptr;
}
ArrayList<InterpAlias> my_aliases = aliases.get(this);
Command cmd_obj = null;
boolean had_extra_args = false;
//print("aliases!"+aliases+"!"+my_obj_ptr+"!");
for (int i = 0; i < aliases.size(); i++) {
InterpAlias my_alias = my_aliases.get(i);
//print("alias!"+i+"!"+my_alias+"!");
InterpAlias have_alias = my_alias.getAlias(empty_string_obj, my_obj_ptr);
//print("have_alias!"+have_alias+"!"+my_obj_ptr+"!");
if (have_alias != null) {
if (have_alias.params.size() != 0) {
/* have arguments !!! */
//print("TARG!"+have_alias.target_cmd.getString()+"!"+have_alias.params+"!");
extra_args_ptr.add(have_alias.params);
had_extra_args = true;
}
obj_ptr = have_alias.target_cmd;
break;
}
}
if (!had_extra_args) {
extra_args_ptr.add(null);
}
cmd_name = obj_ptr.getString();
//print("new cmd_name!"+cmd_name+"!");
/* optimization: we check, if the command is in the command_cache and if the command epoch
* R.Base.command_oid <= call frame.command_oid and if yes, we can use the cached command
*/
/*
if ((frame_ptr.top_command_oid == R.Base.command_oid) &&
(frame_ptr.top_itcl_command_oid == R.Base.itcl_command_oid) &&
(frame_ptr.top_class_function_oid == R.Base.class_function_oid)) {
var my_command_cache = frame_ptr.command_cache;
if (typeof my_command_cache[cmd_name] != "undefined") {
print("found cmd!"+cmd_name+"!"+frame_ptr.top_command_oid+"!"+R.Base.command_oid+"!");
cmd_obj = my_command_cache[cmd_name];
}
} else {
var my_command_cache = frame_ptr.command_cache;
my_command_cache = new Object();
frame_ptr.top_command_oid = R.Base.command_oid;
frame_ptr.top_itcl_command_oid = R.Base.itcl_command_oid;
frame_ptr.top_class_function_oid = R.Base.class_function_oid;
}
*/
/* FIXME !! need to not use cache for these otherwise problems
* have to figure out why
*/
if ((cmd_name == "constructor") || (cmd_name == "destructor") || (cmd_name == "join") || (cmd_name == "function")) {
cmd_obj = null;
}
if (cmd_obj == null) {
cmd_obj = command_obj_type.getCommandFromObj(obj_ptr);
//print("getCFO!"+cmd_obj+"!");
if (cmd_obj == null) {
/* check if we have to load one of the tcl_pkg_*cmd packages to resolve the command */
// cmd_obj = intp.checkStubsCommand(cmd_name);
}
if (cmd_obj != null) {
// var my_command_cache = intp.frame_ptr.command_cache;
// my_command_cache[cmd_name] = cmd_obj;
}
}
if (cmd_obj == null) {
// throw "No such command '"+cmd_name+"'";
//print("cmd_obj null!");
} else {
//print("cmd_obj!"+cmd_obj.toDebugString()+"!");
}
return cmd_obj;
}
/* ==================== getNamespace ===================================== */
public Namespace getNamespace() {
int level = eval_statement.level - uplevel_dist;
//print("getNamespace!"+level+"!"+eval_statement.level+"!"+uplevel_dist+"!"+"!");
//print("getNamespace a!"+level+"!"+"!");
return eval_statement.call_frames.get(level).ns_ptr;
}
/* ==================== getNamespaceName ===================================== */
public String getNamespaceName() {
return current_namespace_name;
}
/* ==================== getGlobalNamespace ===================================== */
public Namespace getGlobalNamespace() {
return global_ns_ptr;
}
/* ==================== setLookupResolveVar ===================================== */
public void setLookupResolveVar(Resolve val) {
lookup_resolve_var = val;
}
/* ==================== getLookupResolveVar ===================================== */
public Resolve getLookupResolveVar() {
return lookup_resolve_var;
}
/* ==================== setClassObject ===================================== */
public ItclClass setClassObject(String name, ItclClass val) {
return classes.put(name, val);
}
/* ==================== getClassObject ===================================== */
public int getClassObject(String name, ArrayList<ItclClass> result_ptr) {
// FIXME need better handling of uplevel namespace for ::itcl::type here !!!
name = escapeKey(name);
if (classes.get(name) == null) {
if (classes.get("::"+name) == null) {
result_ptr.add(null);
return ERROR;
} else {
result_ptr.add(classes.get("::"+name));
}
} else {
result_ptr.add(classes.get(name));
}
return OK;
}
/* ==================== getItclObject ===================================== */
public int getItclObject(String name, ArrayList<ItclObject>result_ptr) {
// FIXME need better handling of uplevel namespace for ::itcl::type here !!!
name = escapeKey(name);
//print("getItclObject!"+name+"!"+intp.frame_ptr.toDebugString()+"!");
if (class_objects.get(name) == null) {
if (class_objects.get("::"+name) == null) {
if (class_objects.get(frame_ptr.ns_ptr.full_name+"::"+name) == null) {
if (class_objects.get(frame_ptr.ns_ptr.parent_namespace.full_name+"::"+name) == null) {
result_ptr.add(null);
} else {
result_ptr.add(class_objects.get(frame_ptr.ns_ptr.parent_namespace.full_name+"::"+name));
}
} else {
result_ptr.add(class_objects.get(frame_ptr.ns_ptr.full_name+"::"+name));
}
} else {
result_ptr.add(class_objects.get("::"+name));
}
} else {
result_ptr.add(class_objects.get(name));
}
return OK;
}
/* ==================== validName ===================================== */
public int validName(String type, ApwtclObj name_obj_ptr) {
if (name_obj_ptr.obj_type != OBJ_TYPE_VARIABLE) {
String str = name_obj_ptr.getString();
int len = string_obj_type.getStringLength(name_obj_ptr);
for (int i = 0; i < len; i++) {
// if (str.charAt(i) == '\0') {
// setResultFormatted(type+" name contains embedded null");
// return ERROR;
// }
}
}
return OK;
}
/* ==================== incrProcEpoch ===================================== */
public void incrProcEpoch() {
proc_epoch++;
}
/* ==================== wrongNumArgs ===================================== */
public void wrongNumArgs(int offset, ArrayList<ApwtclObj> argv, String msg) {
ApwtclObj obj_ptr;
ApwtclObj list_obj_ptr;
int argv_idx = 0;
ArrayList<ApwtclObj> result = new ArrayList<ApwtclObj>();
print("wrongNumArgs! "+offset+"!"+argv+"!"+msg+"!");
if (false) {
if (rewrite_name_obj != null) {
offset -= rewrite_name_count;
argv_idx += rewrite_name_count;
list_obj_ptr = list_obj_type.newListObj(result, 1);
rewrite_name_obj = result.get(0);
// list_obj_type.insertElements(list_obj_ptr, -1, argv.size(), argv_idx, argv);
} else {
list_obj_ptr = list_obj_type.newListObj(result, 1);
}
if (msg != null) {
list_obj_type.listAppendElement(list_obj_ptr, string_obj_type.newStringObj(msg, -1, "INTERP_10"));
}
list_obj_ptr.incrRefCount("I_INTERP_10");
// obj_ptr = list_obj_type.ListJoin(list_obj_ptr, " ", 1);
list_obj_ptr.decrRefCount("D_INTERP_1");
obj_ptr.incrRefCount("I_INTERP_11");
setResultFormatted("wrong # args: should be \"%#s\"", obj_ptr);
obj_ptr.decrRefCount("D_INTERP_2");
}
return;
}
/* ==================== setEmptyResult ================================== */
public void setEmptyResult() {
setResult(empty_string_obj);
}
/* ==================== setResult ================================== */
public void setResult(ApwtclObj obj_ptr) {
obj_ptr.incrRefCount("I_INTERP_12");
result.decrRefCount("D_INTERP_3");
result = obj_ptr;
}
/* ==================== setResultString ================================== */
public void setResultString(String str) {
result.decrRefCount("D_INTERP_4");
result = string_obj_type.newStringObj(str, -1, "INTERP11");
result.incrRefCount("I_INTERP_13");
}
/* ==================== setResultBool ================================== */
public void setResultBool(boolean val) {
int my_val = 0;
if (val == true) {
my_val = 1;
}
if (val == false) {
my_val = 0;
}
setResult(int_obj_type.newIntObj(my_val));
}
/* ==================== setResultInt ================================== */
public void setResultInt(int val) {
setResult(int_obj_type.newIntObj(val));
}
/* ==================== setResultFormatted ===================================== */
/**
* Very simple printf-like formatting, designed for error messages.
*
* The format may contain up to 5 '%s' or '%#s', corresponding to variable arguments.
* The resulting string is created and set as the result.
*
* Each '%s' should correspond to a regular string parameter.
* Each '%#s' should correspond to a (ApwtclObj *) parameter.
* Any other printf specifier is not allowed (but %% is allowed for the % character).
*
* e.g. setResultFormatted("Bad option \"%#s\" in proc \"%#s\"", optionObjPtr, procNamePtr);
*
* Note: We take advantage of the fact that printf has the same behaviour for
* both %s and %#s
*/
public void setResultFormatted(String format, ArrayList<Object> arguments) {
/* Initial space needed */
int n = 1;
StringBuffer buf = new StringBuffer("");
int i;
int start_idx = 0;
int len = format.length();
String str;
for (i = 0; i < len; i++) {
if (format.charAt(i) == '%') {
switch (format.charAt(i + 1)) {
case 's':
buf.append(format.substring(start_idx, i));
str = (String)arguments.get(n);
buf.append(str);
n++;
i += 1;
start_idx = i + 1;
break;
case '#':
if (format.charAt(i + 2) == 's') {
ApwtclObj obj_ptr;
buf.append(format.substring(start_idx, i));
obj_ptr = (ApwtclObj)arguments.get(n);
buf.append(obj_ptr.getString());
n++;
i += 2;
start_idx = i + 1;
break;
} else {
i++;
}
default:
i++;
}
}
}
buf.append(format.substring(start_idx, i));
len = buf.length();
setResult(string_obj_type.newStringObjNoAlloc(buf.toString(), len, "INTERP_12"));
}
/* ==================== getResult ===================================== */
public ApwtclObj getResult() {
return result;
}
/* ==================== deleteLocalProcs ================================== */
public void deleteLocalProcs() {
print("ERROR deleteLocalProcs not yet implemented");
}
/* ==================== setObjErrorCode ===================================== */
/*
*----------------------------------------------------------------------
*
* setObjErrorCode --
*
* This function is called to record machine-readable information about
* an error that is about to be returned. The caller should build a list
* object up and pass it to this routine.
*
* Results:
* None.
*
* Side effects:
* The error_code field of the interp is set to the new value.
*
*----------------------------------------------------------------------
*/
public void setObjErrorCode(ApwtclObj error_obj_ptr) {
if (error_code != null) {
error_code.decrRefCount("D_INTERP_5");
}
error_code = error_obj_ptr;
error_code.incrRefCount("I_INTERP_14");
}
/* ==================== setErrorCode ===================================== */
/*
*----------------------------------------------------------------------
*
* setErrorCode --
*
* This function is called to record machine-readable information about
* an error that is about to be returned.
*
* Results:
* None.
*
* Side effects:
* The error_code field of the interp is modified to hold all of the
* arguments to this function, in a list form with each argument becoming
* one element of the list.
*
*----------------------------------------------------------------------
*/
public void setErrorCode(ArrayList<String> args) {
ApwtclObj error_obj = string_obj_type.newStringObj("", -1, "INTERP_13");
int i;
/*
* Scan through the arguments one at a time, appending them to the
* error_code field as list elements.
*/
for (i = 0; i < args.size(); i++) {
list_obj_type.listAppendElement(error_obj, string_obj_type.newStringObj(args.get(i), -1, "INNTERP_14"));
}
setObjErrorCode(error_obj);
}
/* ==================== getCallFrameByInteger ===================================== */
/* Similar to getCallFrameByLevel() but the level is specified
* as a relative integer like in the [info level ?level?] command.
*/
public CallFrame getCallFrameByInteger(ApwtclObj level_obj_ptr) {
ArrayList<Long> level_ptr = new ArrayList<Long>();
CallFrame my_frame_ptr;
int level;
if (int_obj_type.getLong(level_obj_ptr, level_ptr) == OK) {
level = (int)(level_ptr.get(0) & 0xffffffff);
if (level <= 0) {
/* Convert from a relative to an absolute level */
level = frame_ptr.level + level;
}
if (level == 0) {
return top_frame_ptr;
}
/* Lookup */
for (my_frame_ptr = frame_ptr; my_frame_ptr != null; my_frame_ptr = frame_ptr.parent_call_frame) {
if (my_frame_ptr.level == level) {
return my_frame_ptr;
}
}
}
setResultFormatted("bad level \"%#s\"", level_obj_ptr);
return null;
}
/* ==================== getCallFrameByLevel ===================================== */
/* Returns the call frame relative to the level represented by
* level_obj_ptr. If level_obj_ptr == null, the * level is assumed to be '1'.
*
* This function accepts the 'level' argument in the form
* of the commands [uplevel] and [upvar].
*
* For a function accepting a relative integer as level suitable
* for implementation of [info level ?level?] check the
* getCallFrameByInteger() function.
*
* Returns null on error.
*/
public CallFrame getCallFrameByLevel(ApwtclObj level_obj_ptr) {
int level;
String str;
CallFrame my_frame_ptr;
//print("getFrameByLevel!"+level_obj_ptr.toDebugString()+"!"+intp.frame_ptr.toDebugString()+"!");
if (level_obj_ptr != null) {
str = level_obj_ptr.getString();
if (str.charAt(0) == '#') {
level = Integer.parseInt(str.substring(1));
if (str.length() == 0) {
level = -1;
}
} else {
ArrayList<Long> level_ptr = new ArrayList<Long>();
if (int_obj_type.getLong(level_obj_ptr, level_ptr) != OK || level_ptr.get(0) < 0) {
level = -1;
} else {
level = (int)(level_ptr.get(0) & 0xffffffff);
/* Convert from a relative to an absolute level */
level = frame_ptr.level - level;
}
}
} else {
str = "1"; /* Needed to format the error message. */
level = frame_ptr.level - 1;
}
if (level == 0) {
return top_frame_ptr;
}
if (level > 0) {
/* Lookup */
for (my_frame_ptr = frame_ptr; my_frame_ptr != null; my_frame_ptr = frame_ptr.parent_call_frame) {
if (my_frame_ptr.level == level) {
return my_frame_ptr;
}
}
}
setResultString("bad level \""+str+"\"");
return null;
}
/* ==================== infoLevel ===================================== */
public int infoLevel(ApwtclObj level_obj_ptr, ArrayList<ApwtclObj> obj_ptr_ptr, boolean is_info_level_cmd) {
CallFrame target_call_frame;
target_call_frame = getCallFrameByInteger(level_obj_ptr);
if (target_call_frame == null) {
return ERROR;
}
/* No proc call at toplevel call frame */
if (target_call_frame == top_frame_ptr) {
setResultFormatted("bad level \"%#s\"", level_obj_ptr);
return ERROR;
}
if (is_info_level_cmd) {
obj_ptr_ptr.add(list_obj_type.newListObj(target_call_frame.argv, target_call_frame.argc));
} else {
ApwtclObj list_obj = list_obj_type.newListObj(null, 0);
list_obj_type.listAppendElement(list_obj, target_call_frame.argv.get(0));
list_obj_type.listAppendElement(list_obj, target_call_frame.file_name_obj);
list_obj_type.listAppendElement(list_obj, int_obj_type.newIntObj(target_call_frame.line));
obj_ptr_ptr.add(list_obj);
}
return OK;
}
/* ==================== unknownFcn ===================================== */
public int unknownFcn(int argc, ArrayList<ApwtclObj> argv, ApwtclObj file_name_obj, int line_no) {
print("UNKNOWN!"+argc+"!"+argv+"!"+file_name_obj+"!"+line_no+"!");
ArrayList<ApwtclObj> v = new ArrayList<ApwtclObj>();
int ret_code;
/* If unknown() is recursively called too many times...
* done here
*/
if (unknown_called > 50) {
return ERROR;
}
/* If the [unknown] command does not exists returns
* just now
*/
ArrayList<ArrayList<ApwtclObj>> extra_args_ptr = new ArrayList<ArrayList<ApwtclObj>>();
if (getCommand(unknown, FUNCTION_FLAGS_NONE, extra_args_ptr) == null) {
return ERROR;
}
/* The object interp.unknown just contains
* the "unknown" string, it is used in order to
* avoid to lookup the unknown command every time
* but instead to cache the result.
*/
/* Make a copy of the arguments vector, but shifted on
* the right of one position. The command name of the
* command will be instead the first argument of the
* [unknown] call.
*/
v.add(unknown);
for (int i = 0; i < argc; i++) {
v.add(argv.get(i));
}
/* Call it */
unknown_called++;
ret_code = eval_statement._evalObjVector(argc + 1, v, file_name_obj, line_no);
unknown_called--;
/* Clean up */
return ret_code;
}
/* ==================== getTclTests ===================================== */
public TclTest getTclTests() {
if (tcl_tests == null) {
tcl_tests = new TclTest(this);
}
return tcl_tests;
}
/* ==================== setResultFormatted ================================== */
public int setResultFormatted(String str, ApwtclObj obj_ptr) {
return OK;
}
/* ==================== resetResult ================================== */
public void resetResult() {
}
/* ==================== incrCoreCommand ================================== */
public int incrCoreCommand() {
return OK;
}
/* ==================== unknown ===================================== */
public int unknown(int argc, ArrayList<ApwtclObj> argv) {
return -1;
}
}