com.github.anba.test262.environment.RhinoEnv.java Source code

Java tutorial

Introduction

Here is the source code for com.github.anba.test262.environment.RhinoEnv.java

Source

/**
 * Copyright (c) 2011-2012 Andr Bargull
 * Alle Rechte vorbehalten / All Rights Reserved.  Use is subject to license terms.
 *
 * <https://github.com/anba/test262-junit>
 */
package com.github.anba.test262.environment;

import static com.github.anba.test262.util.Functional.of;
import static com.github.anba.test262.util.Reflection.__new__;
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import java.util.regex.Pattern;

import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
import org.mozilla.javascript.CompilerEnvirons;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.EcmaError;
import org.mozilla.javascript.Evaluator;
import org.mozilla.javascript.EvaluatorException;
import org.mozilla.javascript.IRFactory;
import org.mozilla.javascript.JavaScriptException;
import org.mozilla.javascript.Parser;
import org.mozilla.javascript.RhinoException;
import org.mozilla.javascript.Script;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.ast.AstRoot;
import org.mozilla.javascript.ast.ScriptNode;

import com.github.anba.test262.util.CollectingErrorReporter;
import com.github.anba.test262.util.EcmaErrorMatcher;
import com.github.anba.test262.util.Functional.Tuple2;

/**
 * 
 * @author Andr Bargull
 * 
 */
abstract class RhinoEnv<GLOBAL extends Scriptable & GlobalObject> implements Environment<GLOBAL> {
    private Context context() {
        return Context.getCurrentContext();
    }

    private final CompilerEnvirons compilerEnv;
    {
        compilerEnv = new CompilerEnvirons();
        compilerEnv.initFromContext(context());
        // compilerEnv.setIdeMode(true);
        // compilerEnv.setRecordingComments(true);
        // compilerEnv.setRecoverFromErrors(true);
    }

    @Override
    public abstract GLOBAL global();

    protected abstract String getEvaluator();

    protected abstract String getCharsetName();

    @Override
    public Class<?>[] exceptions() {
        return new Class[] { EcmaError.class, EvaluatorException.class, JavaScriptException.class };
    }

    @Override
    public EcmaErrorMatcher<RhinoException> matcher(String errorType) {
        return new EcmaErrorMatcher<RhinoException>() {
            @Override
            public boolean matches(RhinoException error, String errorType) {
                // errorType is now a regular expression
                Pattern p = Pattern.compile(errorType, Pattern.CASE_INSENSITIVE);
                String name;
                if (error instanceof EcmaError) {
                    name = ((EcmaError) error).getName();
                } else if (error instanceof JavaScriptException) {
                    Object value = ((JavaScriptException) error).getValue();
                    if (value != null && value.getClass().getName().equals("org.mozilla.javascript.NativeError")) {
                        Object message = ((ScriptableObject) value).get("message");
                        name = ScriptRuntime.toString(message);
                    } else {
                        name = error.details();
                    }
                } else if (error instanceof EvaluatorException) {
                    name = "SyntaxError";
                } else {
                    name = "";
                }

                return p.matcher(name).find();
                // return errorType.equals(name);
            }

            @Override
            public Class<? extends RhinoException> exception() {
                return RhinoException.class;
            }
        };
    }

    /**
     * Parses, compiles and executes the javascript file
     */
    @Override
    public void eval(String sourceName, InputStream source) throws IOException {
        Reader reader = newReader(source, getCharsetName());
        Tuple2<AstRoot, List<EvaluatorException>> parsed = parse(sourceName, reader);
        if (!parsed._2().isEmpty()) {
            throw parsed._2().get(0);
        }
        execute(parsed._1());
    }

    /**
     * Parses the test file with the current settings
     */
    protected final Tuple2<AstRoot, List<EvaluatorException>> parse(String sourceName, Reader source)
            throws IOException {
        CollectingErrorReporter errorCollector = new CollectingErrorReporter();
        Parser p = new Parser(compilerEnv, errorCollector);
        AstRoot ast = p.parse(source, sourceName, 1);
        return of(ast, errorCollector.getErrors());
    }

    /**
     * Executes the parsed AST with the current settings
     */
    protected final Object execute(AstRoot ast) {
        Script script = compile(ast);
        return script.exec(context(), global());
    }

    /**
     * Compiles {@code ast} with the current settings and returns the created
     * {@link Script}
     */
    protected final Script compile(AstRoot ast) {
        IRFactory irf = new IRFactory(compilerEnv);
        ScriptNode tree = irf.transformTree(ast);
        Evaluator compiler = __new__(getEvaluator());
        Object bytecode = compiler.compile(compilerEnv, tree, tree.getEncodedSource(), false);
        Script script = compiler.createScriptObject(bytecode, null);
        return script;
    }

    /**
     * Returns a new {@link Reader} for the {@code stream} parameter
     */
    private static Reader newReader(InputStream stream, String defaultCharset) throws IOException {
        BOMInputStream bomstream = new BOMInputStream(stream, ByteOrderMark.UTF_8, ByteOrderMark.UTF_16LE,
                ByteOrderMark.UTF_16BE);
        String charset = defaultIfNull(bomstream.getBOMCharsetName(), defaultCharset);
        return new InputStreamReader(bomstream, charset);
    }
}