Files
sdk/compiler/java/com/google/dart/runner/RhinoLauncher.java
T
2011-10-07 19:28:26 +00:00

219 lines
5.9 KiB
Java

// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
package com.google.dart.runner;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.Function;
import org.mozilla.javascript.FunctionObject;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.Undefined;
import java.io.PrintStream;
import java.lang.reflect.Member;
/**
* Runs a given JS script.
*/
public class RhinoLauncher implements JavaScriptLauncher {
/**
* Rhino-callable assert() method.
*
* TODO(acleung): Deprecate it to just follow DartVM's test cases.
*/
private static class AssertFunction extends SimpleFunction {
@Override
public Object call(Context ctx, Scriptable scope, Scriptable thisObj, Object[] args) {
// Validate arguments (god, I hate this dynamic stuff).
if ((args.length < 1) || (args.length > 2)) {
Context.reportError("Invalid call to assertThat(" + args + ")");
}
if (!(args[0] instanceof Boolean)) {
Context.reportError("Argument 0 must be of type boolean");
}
if (args.length == 2 && !(args[1] instanceof String)) {
Context.reportError("Argument 1 must be of type String");
}
if (!(Boolean) args[0]) {
Context.reportError("assert() failed" + ((args.length == 2) ? ": " + args[1] : ""));
}
return null;
}
}
/**
* Emulates the Expect_throwException() function.
*/
public static class ThrowException extends FunctionObject {
public ThrowException(String name, Member methodOrConstructor, Scriptable scope) {
super(name, methodOrConstructor, scope);
}
@Override
public Object call(Context ctx, Scriptable scope, Scriptable thisObj, Object[] args) {
if (args.length != 1) {
Context.reportError("Invalid call to Expect_throwException(e)");
}
throwException(args[0]);
return Undefined.instance;
}
public void throwException(Object arg0) {
Context.reportError(arg0.toString());
}
}
/**
* Emulates the V8 'write' function.
*/
public static class Write extends FunctionObject {
private PrintStream out;
public Write(String name, Member methodOrConstructor, Scriptable scope, PrintStream out) {
super(name, methodOrConstructor, scope);
this.out = out;
}
@Override
public Object call(Context ctx, Scriptable scope, Scriptable thisObj, Object[] args) {
write(args[0]);
return Undefined.instance;
}
public void write(Object arg0) {
out.print(arg0);
}
}
/**
* Simple Rhino-callable function object.
*/
private static abstract class SimpleFunction implements Function {
@Override
public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
return null;
}
@Override
public void delete(int index) {
}
@Override
public void delete(String name) {
}
@Override
public Object get(int index, Scriptable start) {
return null;
}
@Override
public Object get(String name, Scriptable start) {
return null;
}
@Override
public String getClassName() {
return "Function";
}
@Override
public Object getDefaultValue(Class<?> hint) {
return null;
}
@Override
public Object[] getIds() {
return null;
}
@Override
public Scriptable getParentScope() {
return null;
}
@Override
public Scriptable getPrototype() {
return null;
}
@Override
public boolean has(int index, Scriptable start) {
return false;
}
@Override
public boolean has(String name, Scriptable start) {
return false;
}
@Override
public boolean hasInstance(Scriptable instance) {
return false;
}
@Override
public void put(int index, Scriptable start, Object value) {
}
@Override
public void put(String name, Scriptable start, Object value) {
}
@Override
public void setParentScope(Scriptable parent) {
}
@Override
public void setPrototype(Scriptable prototype) {
}
}
@Override
public void execute(String jsScript, String sourceName, String[] args, RunnerOptions options,
PrintStream stdout, PrintStream stderr)
throws RunnerError {
try {
Context ctx = Context.enter();
Scriptable scope = ctx.initStandardObjects();
scope.put("assert", scope, new AssertFunction());
scope.put("native_Expect__throwException", scope, new ThrowException("Expect__throwException",
ThrowException.class.getMethod("throwException", Object.class), scope));
scope.put("write", scope, new Write("write",
Write.class.getMethod("write", Object.class), scope, stderr));
// The variable 'arguments' is also used in d8.
// Rhino differentiates between Java Strings and JS Strings. If the args-array is not
// converted the JS execution will work, but Rhino will complain.
scope.put("arguments", scope, Context.javaToJS(args, scope));
// Evaluate the application.
ctx.evaluateString(scope, jsScript, sourceName, 1, null);
} catch (NoSuchMethodException e) {
throw new RunnerError(e);
} catch (RhinoException e) {
// TODO(jgw): This is a hack to dump the translated source when something goes wrong. It can
// be removed as soon as we have a source map we can use to provide source-level errors.
if (options.verbose()) {
stdout.println(jsScript);
stdout.flush();
}
StringBuffer msg = new StringBuffer();
msg.append(e.sourceName());
msg.append(" (" + e.lineNumber() + ":" + e.columnNumber() + ")");
msg.append(" : " + e.details());
stderr.println(msg.toString());
throw e;
} finally {
Context.exit();
}
}
}