/* * Copyright 2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.runtime; import org.visage.runtime.sequence.Sequence; import org.visage.runtime.sequence.Sequences; // // CODING/NAMING RESTRICTIONS - In a perfect world, all Visage classes would inherit // from VisageBase. However, this is not the case. It's also possible to inherit // from pure java classes. To accommodate this requirement, VisageBase and VisageObject // are under some strict coding conventions. // // When an Visage class inherits from a java class, then all instance fields from // VisageBase are cloned into the Visage class, and accessor functions constructed for // them. Therefore; // // - All non-static fields defined in VisageBase should have a '$' in the name. // That '$' must not be the first character, to avoid conflict with user // vars. // - All non-static fields must have accessor methods defined in VisageBase. // The names of the accessors must be in the form 'get' + fieldName and // 'set' + fieldName. // - The accessor method declarations should be added to VisageObject, so that // java inheriting classes can define their own interface implementations. // // Ex. // // In VisageBase we define; // // MyClass myField$; // // public MyClass getmyField$() { // return myField$; // } // // public void setmyField$(final MyClass value) { // myField$ = value; // } // // In VisageObject we declare; // // public MyClass getmyField$(); // public void setmyField$(final MyClass value); // // When an Visage class inherits from a java class, all non-static methods are // cloned into the Visage class, with bodies that call the VisageBase static version of // method, inserting 'this' as the first argument. Therefore; // // - All functionality in VisageBase should be defined in static methods, // manipulating an VisageObject. The declaration of the method should have an // an VisageObject first argument. '$' naming conventions apply. // - A non-static method should be defined to relay 'this' and remaining // arguments thru to the static methods. // - The declaration of the non-static method should be added to VisageObject. // // Ex. // // In VisageBase we define; // // public int addIt$(int n) { // return addIt$(this, n); // } // // public static int addIt$(VisageObject obj, int n) { // return obj.count$() + n; // } // // In VisageObject we declare; // // public int addIt$(int n); // // /** * Base class for most Visage classes. The exception being classes that inherit from Java classes. * * @author Jim Laskey * @author Robert Field */ public class VisageBase implements VisageObject { public boolean initialized$internal$ = false; public boolean isInitialized$internal$() { return initialized$internal$; } public void setInitialized$internal$(boolean initialized) { this.initialized$internal$ = initialized; } // First class count. public int count$() { return 0; } public static int count$(VisageObject obj) { return 0; } private static final int VCNT$ = 0; public static int VCNT$() { return 0; } private static final int DCNT$ = 0; public static int DCNT$() { return 0; } private static final int FCNT$ = 0; public static int FCNT$() { return 0; } public int getFlags$(final int varNum) { return varChangeBits$(varNum, 0, 0); } public static int getFlags$(VisageObject obj, final int varNum) { return obj.varChangeBits$(varNum, 0, 0); } public void setFlags$(final int varNum, final int value) { varChangeBits$(varNum, VFLGS$ALL_FLAGS, value); } public static void setFlags$(VisageObject obj, final int varNum, final int value) { obj.varChangeBits$(varNum, VFLGS$ALL_FLAGS, value); } public boolean varTestBits$(final int varNum, final int maskBits, final int testBits) { return (varChangeBits$(varNum, 0, 0) & maskBits) == testBits; } public static boolean varTestBits$(VisageObject obj, final int varNum, final int maskBits, final int testBits) { return (obj.varChangeBits$(varNum, 0, 0) & maskBits) == testBits; } public int varChangeBits$(final int varNum, final int clearBits, final int setBits) { return 0; } public static int varChangeBits$(VisageObject obj, final int varNum, final int clearBits, final int setBits) { return 0; } public void restrictSet$(final int flags) { if ((flags & VFLGS$IS_READONLY) == VFLGS$IS_READONLY) { if ((flags & VFLGS$IS_BOUND) == VFLGS$IS_BOUND) { throw new AssignToBoundException("Cannot assign to bound variable"); } else { throw new AssignToDefException("Cannot assign to a variable defined with 'def'"); } } } public static void restrictSet$(VisageObject obj, final int flags) { if ((flags & VFLGS$IS_READONLY) == VFLGS$IS_READONLY) { if ((flags & VFLGS$IS_BOUND) == VFLGS$IS_BOUND) { throw new AssignToBoundException("Cannot assign to bound variable"); } else { throw new AssignToDefException("Cannot assign to a variable defined with 'def'"); } } } // dependents management public WeakBinderRef thisRef$internal$; public DepChain depChain$internal$; public WeakBinderRef getThisRef$internal$() { return thisRef$internal$; } public void setThisRef$internal$(WeakBinderRef bref) { thisRef$internal$ = bref; } public DepChain getDepChain$internal$() { return depChain$internal$; } public void setDepChain$internal$(DepChain depChain) { this.depChain$internal$ = depChain; } public void addDependent$(final int varNum, VisageObject dep, final int depNum) { addDependent$(this, varNum, dep, depNum); } public static void addDependent$(VisageObject obj, final int varNum, VisageObject dep, final int depNum) { assert varNum > -1 && varNum < obj.count$() : "invalid varNum: " + varNum; DependentsManager.addDependent(obj, varNum, dep, depNum); } public void removeDependent$(final int varNum, VisageObject dep) { removeDependent$(this, varNum, dep); } public static void removeDependent$(VisageObject obj, final int varNum, VisageObject dep) { assert varNum > -1 && varNum < obj.count$() : "invalid varNum: " + varNum; DependentsManager.removeDependent(obj, varNum, dep); } public void switchDependence$(VisageObject oldBindee, final int oldNum, VisageObject newBindee, final int newNum, final int depNum) { switchDependence$(this, oldBindee, oldNum, newBindee, newNum, depNum); } public static void switchDependence$(VisageObject obj, VisageObject oldBindee, final int oldNum, VisageObject newBindee, final int newNum, final int depNum) { if (oldBindee != newBindee) { DependentsManager.switchDependence(obj, oldBindee, oldNum, newBindee, newNum, depNum); } } public void notifyDependents$(final int varNum, final int phase) { notifyDependents$(this, varNum, phase); } public static void notifyDependents$(VisageObject obj, final int varNum, final int phase) { assert varNum > -1 && varNum < obj.count$() : "invalid varNum: " + varNum; DependentsManager.notifyDependents(obj, varNum, 0, Sequences.UNDEFINED_MARKER_INT, Sequences.UNDEFINED_MARKER_INT, phase); } public void notifyDependents$(int varNum, int startPos, int endPos, int newLength, int phase) { notifyDependents$(this, varNum, startPos, endPos, newLength, phase); } public static void notifyDependents$(VisageObject obj, final int varNum, int startPos, int endPos, int newLength, final int phase) { assert varNum > -1 && varNum < obj.count$() : "invalid varNum: " + varNum; DependentsManager.notifyDependents(obj, varNum, startPos, endPos, newLength, phase); } public boolean update$(VisageObject src, final int depNum, int startPos, int endPos, int newLength, final int phase) { return false; } public static boolean update$(VisageObject obj, VisageObject src, final int depNum, int startPos, int endPos, int newLength, final int phase) { return false; } public int getListenerCount$() { return DependentsManager.getListenerCount(this); } public static int getListenerCount$(VisageObject src) { return DependentsManager.getListenerCount(src); } public Object get$(int varNum) { throw new IllegalArgumentException("no such variable: " + varNum); } public static Object get$(VisageObject obj, int varNum) { throw new IllegalArgumentException("no such variable: " + varNum); } public void set$(int varNum, Object value) { throw new IllegalArgumentException("no such variable: " + varNum); } public static void set$(VisageObject obj, int varNum, Object value) { throw new IllegalArgumentException("no such variable: " + varNum); } public Class getType$(int varNum) { throw new IllegalArgumentException("no such variable: " + varNum); } public static Class getType$(VisageObject obj, int varNum) { throw new IllegalArgumentException("no such variable: " + varNum); } public void seq$(int varNum, Object value) { throw new IllegalArgumentException("no such variable: " + varNum); } public static void seq$(VisageObject obj, int varNum, Object value) { throw new IllegalArgumentException("no such variable: " + varNum); } public void invalidate$(int varNum, int startPos, int endPos, int newLength, int phase) { // VSGC-3964 - Var invalidate may be optimized away. } public static void invalidate$(VisageObject obj, int varNum, int startPos, int endPos, int newLength, int phase) { // VSGC-3964 - Var invalidate may be optimized away. } /** * Constructor called from Java or from object literal with no instance variable initializers */ public VisageBase() { this(false); initialize$(true); } /** * Constructor called for a (non-empty) Visage object literal. * @param dummy Marker only. Ignored. */ public VisageBase(boolean dummy) { // Make sure offsets are set. count$(); } public void initialize$(boolean applyDefaults) { initVars$(); if (applyDefaults) applyDefaults$(); complete$(); } public static void initialize$(VisageObject obj, boolean applyDefaults) { obj.initVars$(); if (applyDefaults) obj.applyDefaults$(); obj.complete$(); } public void complete$() { userInit$(); setInitialized$internal$(true); postInit$(); } public static void complete$(VisageObject obj) { obj.userInit$(); obj.setInitialized$internal$(true); obj.postInit$(); } public void initVars$() {} public static void initVars$(VisageObject obj) {} public void applyDefaults$(final int varNum) {} public static void applyDefaults$(VisageObject obj, final int varNum) {} public void applyDefaults$() { int cnt = count$(); for (int inx = 0; inx < cnt; inx += 1) { varChangeBits$(inx, 0, VFLGS$INIT$READY); applyDefaults$(inx); } } public static void applyDefaults$(VisageObject obj) { int cnt = obj.count$(); for (int inx = 0; inx < cnt; inx += 1) { obj.varChangeBits$(inx, 0, VFLGS$INIT$READY); obj.applyDefaults$(inx); } } public void userInit$() {} public static void userInit$(VisageObject obj) {} public void postInit$() {} public static void postInit$(VisageObject obj) {} // // makeInitMap$ constructs a field mapping table used in the switch portion // of a object literal initialization. Each entry in the table represents // a field in a class. The value in the slot is zero (no case) or the // switch case tag that has a value setting. // public static short [] makeInitMap$(int count, int... offsets) { final short [] map = new short[count]; for (int i = 0; i < offsets.length; i++) { map[offsets[i]] = (short)(i + 1); } return map; } public int size$(int varNum) { return ((Sequence<?>) get$(varNum)).size(); } public static int size$(VisageObject obj, int varNum) { return ((Sequence<?>) obj.get$(varNum)).size(); } public Object elem$(int varNum, int position) { return ((Sequence<?>) get$(varNum)).get(position); } public static Object elem$(VisageObject obj, int varNum, int position) { return ((Sequence<?>) obj.get$(varNum)).get(position); } public boolean getAsBoolean$(int varNum, int position) { return getAsBoolean$(this, varNum, position); } public static boolean getAsBoolean$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToBoolean(obj.elem$(varNum, position)) : false; } public char getAsChar$(int varNum, int position) { return getAsChar$(this, varNum, position); } public static char getAsChar$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToChar(obj.elem$(varNum, position)) : '\0'; } public byte getAsByte$(int varNum, int position) { return getAsByte$(this, varNum, position); } public static byte getAsByte$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToByte(obj.elem$(varNum, position)) : 0; } public short getAsShort$(int varNum, int position) { return getAsShort$(this, varNum, position); } public static short getAsShort$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToShort(obj.elem$(varNum, position)) : 0; } public int getAsInt$(int varNum, int position) { return getAsInt$(this, varNum, position); } public static int getAsInt$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToInt(obj.elem$(varNum, position)) : 0; } public long getAsLong$(int varNum, int position) { return getAsLong$(this, varNum, position); } public static long getAsLong$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToLong(obj.elem$(varNum, position)) : 0L; } public float getAsFloat$(int varNum, int position) { return getAsFloat$(this, varNum, position); } public static float getAsFloat$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToFloat(obj.elem$(varNum, position)) : 0f; } public double getAsDouble$(int varNum, int position) { return getAsDouble$(this, varNum, position); } public static double getAsDouble$(VisageObject obj, int varNum, int position) { return Sequences.withinBounds(obj, varNum, position) ? Util.objectToDouble(obj.elem$(varNum, position)) : 0.0; } public Object invoke$(int number, Object arg1, Object arg2, Object[] rargs) { throw new IllegalArgumentException("no such function: " + number); } public static Object invoke$(VisageObject obj, int number, Object arg1, Object arg2, Object[] rargs) { throw new IllegalArgumentException("no such function: " + number); } }