Package com.scriptographer.script.rhino

Source Code of com.scriptographer.script.rhino.RhinoEngine

/*
* Scriptographer
*
* This file is part of Scriptographer, a Scripting Plugin for Adobe Illustrator
* http://scriptographer.org/
*
* Copyright (c) 2002-2010, Juerg Lehni
* http://scratchdisk.com/
*
* All rights reserved. See LICENSE file for details.
*
* File created on Apr 10, 2007.
*/

package com.scriptographer.script.rhino;

import java.io.File;

import org.mozilla.javascript.Callable;
import org.mozilla.javascript.Context;
import org.mozilla.javascript.OperatorHandler;
import org.mozilla.javascript.ScriptRuntime;
import org.mozilla.javascript.Scriptable;
import org.mozilla.javascript.ScriptableObject;
import org.mozilla.javascript.Token;

import com.scratchdisk.script.Scope;
import com.scratchdisk.script.ScriptCanceledException;
import com.scratchdisk.script.rhino.RhinoScope;
import com.scriptographer.ScriptographerEngine;

/**
* @author lehni
*
*/
public class RhinoEngine extends com.scratchdisk.script.rhino.RhinoEngine implements OperatorHandler {

  public RhinoEngine() {
    super(new RhinoWrapFactory());
  }

  protected com.scratchdisk.script.rhino.TopLevel makeTopLevel(Context context) {
    return new TopLevel(context);
  }

  protected boolean hasFeature(Context cx, int feature, boolean defaultValue) {
    switch (feature) {
    case Context.FEATURE_DYNAMIC_SCOPE:
      return true;
    }
    return super.hasFeature(cx, feature, defaultValue);
  }

  protected void enter(Context context) {
    super.enter(context);
    // Use pure interpreter mode to allow for
    // observeInstructionCount(Context, int) to work
    context.setOptimizationLevel(-1);
    // Make Rhino runtime to call observeInstructionCount
    // each 20000 bytecode instructions
    context.setInstructionObserverThreshold(20000);
    context.setOperatorHandler(this);
  }

  protected void observeInstructionCount(Context cx, int instructionCount) {
    if (!ScriptographerEngine.updateProgress())
      throw new ScriptCanceledException();
  }

  public String[] getScriptPath(File file) {
    return ScriptographerEngine.getScriptPath(file, true);
  }

  public Object handleOperator(Context cx, Scriptable scope, int operator, Object lhs, Object rhs) {
    // There is a very simple convention for arithmetic operations on objects:
    // Just try to get the according functions on scriptable objects,
    // and perform the operation by executing these.
    // Fall back on the default ScriptRuntime.add for adding,
    // return null for everything else.

    // Wrap String as Scriptable for some of the operators, so we can access
    // its prototype easily too.
    // Note that only the operators that are natively defined for JS can
    // be overridden here!
    if (lhs instanceof String && (
        operator == Token.SUB ||
        operator == Token.MUL ||
        operator == Token.DIV))
      lhs = ScriptRuntime.toObject(cx, scope, lhs);
    // Now perform the magic
    if (lhs instanceof Scriptable) {
      String name = null;
      switch (operator) {
      case Token.ADD:
        name = "add";
        break;
      case Token.SUB:
        name = "subtract";
        break;
      case Token.MUL:
        name = "multiply";
        break;
      case Token.DIV:
        name = "divide";
        break;
      case Token.MOD:
        name = "modulo";
        break;
      case Token.EQ:
      case Token.NE:
        name = "equals";
        break;
      }
      if (name != null) {
        Scriptable scriptable = (Scriptable) lhs;
        Object obj = ScriptableObject.getProperty(scriptable, name);
        if (obj instanceof Callable) {
          Object result = ((Callable) obj).call(cx, scope, scriptable, new Object[] { rhs });
          if (operator == Token.EQ || operator == Token.NE) {
            boolean value = ScriptRuntime.toBoolean(result);
            if (operator == Token.NE)
              value = !value;
            return ScriptRuntime.wrapBoolean(value);
          } else {
            return result;
          }
        }
       }
    }
    return null;
  }

  public Object handleSignOperator(Context cx, Scriptable scope, int operator, Object rhs) {
    switch (operator) {
    case Token.NEG:
      // Wrap String as Scriptable, so we can access its prototype easily too.
      if (rhs instanceof String)
        rhs = ScriptRuntime.toObject(cx, scope, rhs);
      // Now perform the magic
      if (rhs instanceof Scriptable) {
        Scriptable scriptable = (Scriptable) rhs;
        Object obj = ScriptableObject.getProperty(scriptable, "negate");
        if (obj instanceof Callable)
          return ((Callable) obj).call(cx, scope, scriptable, new Object[] {});
      }
      break;
    case Token.POS:
      // Simple return the rhs, since the standard JS way would be to force conversion
      // to a number, which would give NaN for new Point(1, 2) * 1, since this is
      // converted top + new Point(1, 2) by the interpreter...
      return rhs;
    }
    return null;
  }

  public Scope createScope() {
    Scope scope = super.createScope();
    // Override global to point to the 'local' global scope ;)
    scope.put("global", ((RhinoScope) scope).getScope());
    return scope;
  }
}
TOP

Related Classes of com.scriptographer.script.rhino.RhinoEngine

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.