001: /*
002: * @(#)StackFrameInspector.java 1.3 05/04/22
003: *
004: * Copyright (c) 2003 Sun Microsystems, Inc. All Rights Reserved.
005: *
006: * See the file "LICENSE.txt" for information on usage and redistribution
007: * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
008: */
009: package pnuts.tools;
010:
011: import java.lang.reflect.Field;
012: import java.lang.reflect.InvocationTargetException;
013: import java.lang.reflect.Method;
014: import java.util.Enumeration;
015: import java.util.HashMap;
016: import java.util.Map;
017:
018: import pnuts.lang.Context;
019: import pnuts.lang.Function;
020:
021: /**
022: * This class allows to enumerate local variables in pure interpreter mode.
023: *
024: * <pre>
025: *
026: * function foo(a){
027: * println(StackFrameInspector::localSymbols(getContext()))
028: * }
029: * foo(100)
030: * => {a=100}
031: *
032: * </pre>
033: */
034: public class StackFrameInspector {
035:
036: static Field stackFrameField; // Context.stackFrame
037: static Field symbolTableField; // StackFrame.symbolTable
038: static Field parentField; // SymbolTable.parent
039: static Field nameField; // Binding.name
040: static Field valueField; // Binding.value
041: static Field parentFrame; // StackFrame.parent
042: static Method bindingsMethod; // SymbolTable.bindings()
043: static Field frameField; // Context.frame
044: static Field lexicalScopeField; // Function.lexicalScope
045: static {
046: try {
047: Class StackFrameClass = Class
048: .forName("pnuts.lang.StackFrame");
049: Class SymbolTableClass = Class
050: .forName("pnuts.lang.SymbolTable");
051: Class BindingClass = Class.forName("pnuts.lang.Binding");
052: stackFrameField = Context.class
053: .getDeclaredField("stackFrame");
054: stackFrameField.setAccessible(true);
055: frameField = Context.class.getDeclaredField("frame");
056: frameField.setAccessible(true);
057: lexicalScopeField = Function.class
058: .getDeclaredField("lexicalScope");
059: lexicalScopeField.setAccessible(true);
060: symbolTableField = StackFrameClass
061: .getDeclaredField("symbolTable");
062: symbolTableField.setAccessible(true);
063: parentField = SymbolTableClass.getDeclaredField("parent");
064: parentField.setAccessible(true);
065: nameField = BindingClass.getDeclaredField("name");
066: nameField.setAccessible(true);
067: valueField = BindingClass.getDeclaredField("value");
068: valueField.setAccessible(true);
069: bindingsMethod = SymbolTableClass.getMethod("bindings",
070: new Class[] {});
071: bindingsMethod.setAccessible(true);
072: parentFrame = StackFrameClass.getDeclaredField("parent");
073: parentFrame.setAccessible(true);
074: } catch (Exception e) {
075: e.printStackTrace();
076: }
077: }
078:
079: public static Map localSymbols(Context context) {
080: try {
081: HashMap map = new HashMap();
082: localSymbols(context, map);
083: return map;
084: } catch (Exception e) {
085: e.printStackTrace();
086: return null;
087: }
088: }
089:
090: public static void localSymbols(Context context, Map map)
091: throws IllegalAccessException, InvocationTargetException {
092: Object stackFrame = stackFrameField.get(context);
093: if (stackFrame != null) {
094: scanSymbolTable(symbolTableField.get(stackFrame), map,
095: false);
096: }
097: Object frame = frameField.get(context);
098: if (frame != null) {
099: Object lexicalScope = lexicalScopeField.get(frame);
100: if (lexicalScope != null) {
101: scanSymbolTable(lexicalScope, map, true);
102: }
103: }
104: }
105:
106: static void scanSymbolTable(Object st, Map map, boolean lexicalScope)
107: throws IllegalAccessException, InvocationTargetException {
108: while (st != null) {
109: Enumeration bindings = (Enumeration) bindingsMethod.invoke(
110: st, new Object[] {});
111: while (bindings.hasMoreElements()) {
112: Object b = bindings.nextElement();
113: String name = (String) nameField.get(b);
114: int idx = name.indexOf('!');
115: if (idx > 0) {
116: name = name.substring(0, idx);
117: } else if (idx == 0) {
118: continue;
119: }
120: Object value = valueField.get(b);
121: if (lexicalScope) {
122: value = valueField.get(value);
123: }
124: if (!map.keySet().contains(name)) {
125: map.put(name, value);
126: }
127: }
128: st = parentField.get(st);
129: }
130: }
131: }
|