JavaScript: Remove obsolete Rhino interface classes.

This commit is contained in:
Max Schaefer
2018-11-09 09:03:19 +00:00
parent 2cd5702aa6
commit 585347fb5d
2 changed files with 0 additions and 348 deletions

View File

@@ -1,196 +0,0 @@
package com.semmle.js.parser;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.UniqueTag;
import com.semmle.js.ast.Position;
import com.semmle.js.ast.SourceElement;
import com.semmle.js.ast.SourceLocation;
import com.semmle.util.exception.CatastrophicError;
/**
* Decode SpiderMonkey AST objects into their Java equivalents.
*
* We assume that every AST node has a <code>type</code> property uniquely identifying its
* type, which is also the name of the corresponding Java class.
*
* For each Java class, a list of properties to read from the SpiderMonkey AST object has to be provided.
* It is assumed that the Java class has a single constructor which takes exactly those
* properties as arguments.
*/
public class JSObjectDecoder<T extends SourceElement> {
private final ScriptLoader loader;
private final String source;
private final String pkg;
private final Map<Class<? extends T>, List<String>> spec;
/**
* Construct a new object decoder.
*
* @param source the source code from which the AST was parsed
* @param loader the Rhino instance to use
* @param pkg the package in which to look for Java classes
* @param spec a mapping from Java classes to properties
*/
public JSObjectDecoder(String source, ScriptLoader loader, String pkg, Map<Class<? extends T>, List<String>> spec) {
this.source = source;
this.loader = loader;
this.pkg = pkg;
this.spec = spec;
}
/**
* Decode a given SpiderMonkey AST object.
*
* Any exceptions that occur during conversion are caught and re-thrown as {@link CatastrophicError},
* except for {@link ClassNotFoundException}s resulting from unsupported AST node types, which are
* re-thrown as {@link ParseError}s.
*/
@SuppressWarnings("unchecked")
public T decodeObject(NativeObject object) throws ParseError {
String type = (String) loader.readProperty(object, "type");
try {
Class<? extends T> clazz = (Class<? extends T>)Class.forName(pkg + "." + type);
return decodeObject(object, clazz);
} catch (ClassNotFoundException e) {
throw new ParseError("Unexpected node type " + e, decodeLocation(object).getStart());
}
}
/**
* Decode a given SpiderMonkey AST object as an instance of a given class.
*
* Any exceptions that occur during conversion are caught and re-thrown as {@link CatastrophicError},
* except for {@link ClassNotFoundException}s resulting from unsupported AST node types, which are
* re-thrown as {@link ParseError}s.
*/
@SuppressWarnings("unchecked")
public <V> V decodeObject(NativeObject object, Class<V> clazz) throws ParseError {
SourceLocation loc = decodeLocation(object);
Object[] ctorArgs = null;
try {
List<String> props = spec.get(clazz);
if (props == null)
throw new CatastrophicError("Unsupported node type " + clazz.getName());
ctorArgs = new Object[props.size()+1];
ctorArgs[0] = loc;
for (int i=1; i<ctorArgs.length; ++i) {
String argName = props.get(i-1);
Object arg = loader.readProperty(object, argName);
if (arg instanceof NativeObject) {
ctorArgs[i] = decodeObject((NativeObject)arg);
} else if (arg instanceof NativeArray) {
ctorArgs[i] = decodeObjects((NativeArray)arg);
} else if (arg == UniqueTag.NOT_FOUND) {
ctorArgs[i] = null;
} else if (arg instanceof CharSequence) {
// Rhino has its own funny string types; normalise
ctorArgs[i] = arg.toString();
} else {
ctorArgs[i] = arg;
}
}
return (V)clazz.getConstructors()[0].newInstance(ctorArgs);
} catch (InstantiationException e) {
throw new CatastrophicError(e);
} catch (IllegalAccessException e) {
throw new CatastrophicError(e);
} catch (IllegalArgumentException e) {
throw new CatastrophicError(e);
} catch (InvocationTargetException e) {
throw new CatastrophicError(e);
} catch (SecurityException e) {
throw new CatastrophicError(e);
}
}
/**
* Decode an array of SpiderMonkey AST objects.
*/
public List<T> decodeObjects(NativeArray objects) throws ParseError {
List<T> result = new ArrayList<T>(objects.size());
for (Object object : objects) {
if (object == null)
result.add(null);
else
result.add(decodeObject((NativeObject)object));
}
return result;
}
/**
* Decode an array of SpiderMonkey AST objects as instances of a given class.
*/
public <V> List<V> decodeObjects(Class<V> clazz, NativeArray objects) throws ParseError {
List<V> result = new ArrayList<V>(objects.size());
for (Object object : objects) {
if (object == null)
result.add(null);
else
result.add(decodeObject((NativeObject)object, clazz));
}
return result;
}
/**
* Bound <code>x</code> between <code>lo</code> and <code>hi</code>, inclusive.
*/
private int bound(int x, int lo, int hi) {
if (x < lo)
return lo;
if (x > hi)
return hi;
return x;
}
/**
* Decode a SpiderMonkey location object into a {@link SourceLocation}.
*/
public SourceLocation decodeLocation(NativeObject object) {
Integer startOffset, endOffset;
Position start, end;
Object loc = loader.readProperty(object, "loc");
if (loc == null) {
// no 'loc' property; check whether we have 'range'
Object range = loader.readProperty(object, "range");
if (range instanceof NativeArray) {
// good; make up a source location on line 0
startOffset = loader.readIntProperty(range, 0);
endOffset = loader.readIntProperty(range, 1);
start = new Position(1, startOffset, startOffset);
end = new Position(1, endOffset, endOffset);
return new SourceLocation(getSource(startOffset, endOffset), start, end);
}
return null;
}
startOffset = loader.readIntProperty(object, "start");
endOffset = loader.readIntProperty(object, "end");
start = decodePosition((NativeObject)loader.readProperty(loc, "start"), startOffset);
end = decodePosition((NativeObject)loader.readProperty(loc, "end"), endOffset);
return new SourceLocation(getSource(startOffset, endOffset), start, end);
}
/**
* Extract the source code between a given start and end offset.
*/
public String getSource(Integer startOffset, Integer endOffset) {
if (startOffset == null || endOffset == null || startOffset > endOffset)
return "";
return source.substring(bound(startOffset, 0, source.length()), bound(endOffset, 0, source.length()));
}
/**
* Decode a SpiderMonkey position object into a {@link SourceLocation}.
*/
private Position decodePosition(NativeObject object, int offset) {
return new Position(loader.readIntProperty(object, "line"), loader.readIntProperty(object, "column"), offset);
}
}

View File

@@ -1,152 +0,0 @@
package com.semmle.js.parser;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.NativeArray;
import org.mozilla.javascript.NativeJSON;
import org.mozilla.javascript.NativeObject;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Undefined;
import org.mozilla.javascript.UniqueTag;
import com.semmle.util.exception.CatastrophicError;
import com.semmle.util.files.FileUtil;
/**
* Helper class for executing JavaScript programs through Rhino and reading out values from the
* resulting environment.
*/
public class ScriptLoader {
private final Context cx;
private final ScriptableObject scope;
public ScriptLoader(String scriptPath) {
InputStreamReader inputStreamReader = null;
this.cx = Context.enter();
this.scope = cx.initStandardObjects();
try {
URL script = ScriptLoader.class.getResource(scriptPath);
if (script == null)
throw new IOException();
InputStream scriptStream = script.openStream();
inputStreamReader = new InputStreamReader(scriptStream, FileUtil.UTF8);
cx.evaluateReader(scope, inputStreamReader, scriptPath, 1, null);
} catch (IOException e) {
throw new CatastrophicError("Could not load script " + scriptPath + ".", e);
} finally {
if (inputStreamReader != null)
FileUtil.close(inputStreamReader);
}
}
/**
* Read a global variable.
*/
public Object readGlobal(String name) {
return scope.get(name, scope);
}
/**
* Read an object property; the property name may be a path of several individual
* names separated by dots.
*
* @return The value of the property, or {@literal null} if it could not be found.
*/
public Object readProperty(Object obj, String prop) {
Object res = obj;
for (String p : prop.split("\\."))
res = ScriptableObject.getProperty((ScriptableObject)res, p);
if (res == UniqueTag.NOT_FOUND)
return null;
return res;
}
/**
* Read an array element.
*
* @return The value of the element, or {@literal null} if it could not be found.
*/
public Object readProperty(Object obj, int idx) {
Object res = ((ScriptableObject)obj).get(idx, scope);
if (res == UniqueTag.NOT_FOUND)
return null;
return res;
}
/**
* Read an object property and return its value cast to an integer.
*/
public Integer readIntProperty(Object obj, String prop) {
Object res = readProperty(obj, prop);
if (res == null || res == Undefined.instance)
return null;
return ((Number)res).intValue();
}
/**
* Read an array element and return its value cast to an integer.
*/
public Integer readIntProperty(Object obj, int idx) {
Object res = readProperty(obj, idx);
if (res == null || res == Undefined.instance)
return null;
return ((Number)res).intValue();
}
/**
* Read an object property and return its value cast to a string.
*/
public String readStringProperty(Object obj, String prop) {
Object val = readProperty(obj, prop);
if (val == null || val == Undefined.instance)
return null;
return String.valueOf(val);
}
/**
* Create an empty JavaScript array.
*/
public NativeArray mkArray() {
return (NativeArray)cx.newArray(scope, 0);
}
/**
* Create a JavaScript object.
*
* @param properties a list of alternating keys and values to populate the object with
*/
public NativeObject mkObject(Object... properties) {
NativeObject obj = new NativeObject();
for (int i=0; i+1<properties.length; i += 2)
obj.defineProperty((String)properties[i], properties[i+1], 0);
return obj;
}
/**
* Call a method on an object.
*/
public Object callMethod(ScriptableObject obj, String method, Object... args) {
Function f = (Function)readProperty(obj, method);
return f.call(cx, scope, obj, args);
}
/**
* Construct an instance of a JavaScript constructor function.
*/
public ScriptableObject construct(Function ctor, Object... args) {
return (ScriptableObject)ctor.construct(cx, scope, args);
}
/**
* Pretty-print an object as JSON.
*/
public String stringify(Object obj) {
return (String) NativeJSON.stringify(cx, scope, obj, null, 2);
}
}