| /* --COPYRIGHT--,EPL |
| * Copyright (c) 2008 Texas Instruments and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * Texas Instruments - initial implementation |
| * |
| * --/COPYRIGHT--*/ |
| package xdc.services.intern.xsr; |
| |
| import java.util.Vector; |
| import java.util.LinkedHashMap; |
| import java.util.Iterator; |
| import java.util.HashMap; |
| import java.util.Collection; |
| |
| import org.mozilla.javascript.Context; |
| import org.mozilla.javascript.Function; |
| import org.mozilla.javascript.NativeJavaObject; |
| import org.mozilla.javascript.Scriptable; |
| import org.mozilla.javascript.Undefined; |
| |
| /* |
| * ======== Proto ======== |
| */ |
| public abstract class Proto extends XScriptO |
| implements Function |
| { |
| interface ObjRef {}; |
| public interface Pred{}; |
| interface Sealable {}; |
| |
| interface Aggregate { |
| Object create(Value prnt, String name, boolean ronly, Object initval, |
| boolean check); |
| } |
| |
| interface Embedded extends Aggregate {} |
| |
| public interface Typedef { |
| Proto getBase(); |
| Function getEncFxn(); |
| void init( String name, Object base, Object encFxn ); |
| } |
| |
| abstract Object assign( Object oldval, Object newval ); |
| abstract boolean assignable( Proto proto ); |
| |
| String toText( Object val ) |
| { |
| if (val == null) { |
| return "null"; |
| } |
| else if (val instanceof Undefined) { |
| return "undefined"; |
| } |
| else { |
| return val.toString(); |
| } |
| } |
| |
| static Object unwrap( Object o ) |
| { |
| return (o instanceof NativeJavaObject ? ((NativeJavaObject)o).unwrap() : o); |
| } |
| |
| int depth() { return 0; } |
| |
| // interface Function |
| |
| public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] args ) |
| { |
| Err.exit("unsupported operation"); |
| return Context.getUndefinedValue(); |
| } |
| |
| public Scriptable construct( Context cx, Scriptable scope, Object[] args ) |
| { |
| Err.exit("unsupported operation"); |
| return null; |
| } |
| |
| // Proto.Adr |
| /* This type represents configuration parameters of pointer types */ |
| static public class Adr extends Proto |
| implements ObjRef, Pred |
| { |
| String sig; |
| boolean anyT; |
| boolean fxnT; |
| |
| public Adr( String sig, String code ) |
| { |
| this.sig = sig; |
| this.anyT = code.equals("Pv"); |
| this.fxnT = code.startsWith("PF"); |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| if (newval == null || newval instanceof Undefined |
| || newval == Value.DEFAULT || newval == Value.NOGEN) { |
| return newval; |
| } |
| |
| // System.out.println("Proto.Adr.assign: (" + this.sig + ")" |
| // + this |
| // + " = (" + newval.getClass().getName() + ")" |
| // + newval); |
| if (this.anyT) { |
| |
| if (newval instanceof AnyType) { |
| return newval; |
| } |
| if (newval instanceof CharSequence || newval instanceof Number |
| || newval instanceof Boolean ) { |
| return newval; |
| } |
| } |
| |
| if (newval instanceof Value.Obj && this.sig.equals( |
| ((Value.Obj) newval).proto.name.replace('.', '_') + "*")) { |
| return newval; |
| } |
| |
| if (newval instanceof Extern) { |
| /* An Extern of the correct type can be assigned to a pointer |
| * config parameter. |
| */ |
| Extern ext = (Extern)newval; |
| if (ext.sig == null) { |
| /* This Extern is created by calling the operator $externPtr |
| * and the signature was set to 'null'. Now we know the |
| * signature of the pointer we are assigning too, so we |
| * should adjust the type. We use the pointer's type when |
| * 'newval' is a string starting with '&'. |
| */ |
| Extern typed = new Extern(ext.getName(), this.sig, |
| ext.isFxnT(), ext.isRaw()); |
| return ext.isFxnT() == this.isFxnT() ? typed : Value.ERROR; |
| } |
| else { |
| return this.sig.equals(ext.sig) ? newval : Value.ERROR; |
| } |
| } |
| |
| if (newval instanceof Ptr) { |
| return newval; |
| } |
| |
| /* This is the case where the assigned value is a string with the |
| * name of a global variable preceeded by '&'. That syntax works |
| * only for types that do not accept values of multiple types |
| * (this.anyT flags such types). If a config parameter of type Ptr |
| * is assigned "&label", it cannot mean a symbol 'label', because |
| * then we wouldn't be able to assign the string "&label" to that |
| * parameter, which is a valid value for Ptr. We have to use |
| * $externPtr when we mean "the symbol 'label'". Therefore, the |
| * IF statement that checks if anyT is true comes first, and it |
| * will catch any string, and treat it as a string. If anyT is |
| * false, the IF block below will convert a string that starts |
| * with '&' to an Extern. |
| * The type Fxn cannot accept strings, and anyT is always false |
| * for that type, so both syntaxes above can only mean "the symbol |
| * 'label'", and we accept them both in the following IF block. |
| * |
| * The implementation of the logic described here is based on the |
| * type we return from this function. In case of Ptr, we return a |
| * string and for Fxn, we return an Extern instance. Then, in |
| * gen/Config.java, in ptrToStr(), an Extern is always treated as |
| * a symbol, while a string is just copied and quoted. |
| */ |
| if (newval instanceof CharSequence) { |
| String s = newval.toString(); |
| if (s.startsWith("&") && s.length() > 1) { |
| if (s.matches(".*\\s.*")) { |
| return (Value.ERROR); |
| } |
| return new Extern(s.substring(1), this.sig, this.fxnT, |
| true); |
| } |
| } |
| |
| if (newval instanceof Addr) { |
| return ((Addr)newval).val == 0 ? null : newval; |
| } |
| /* |
| if (!this.anyT) { |
| return Value.ERROR; |
| } |
| |
| if (newval instanceof String || newval instanceof Number || newval instanceof Boolean ) { |
| return newval; |
| } |
| |
| if (newval instanceof Value || newval instanceof Enum || newval instanceof Extern) { |
| return newval; |
| } |
| */ |
| /* allow "config Bits8 *FOO = 0x32;" */ |
| if (newval instanceof Number) { |
| return newval; |
| } |
| |
| return Value.ERROR; |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| // TODO: fix this |
| return true; |
| } |
| |
| public final String getSig() { return this.sig; } |
| |
| public final boolean isAnyT() { return this.anyT; } |
| public final boolean isFxnT() { return this.fxnT; } |
| |
| String toText( Object val ) |
| { |
| if (val instanceof Value.Obj) { |
| return (String) ((Value.Obj) val).getDefaultValue(null); |
| } |
| else if (val instanceof Extern) { |
| Extern e = (Extern) val; |
| return e.name.startsWith("0x") ? e.name : "&" + e.name; |
| } |
| else if (val instanceof Number) { |
| return Proto.Elm.numval((Number) val); |
| } |
| else { |
| return super.toText(val); |
| } |
| } |
| } |
| |
| // Proto.Arr |
| |
| static public class Arr extends Proto |
| implements Aggregate, Embedded, Pred, Sealable |
| { |
| Proto base; |
| boolean lflag; |
| int dim; |
| int curid = 0; |
| |
| public Arr( Object base ) |
| { |
| this(base, true, -1); |
| } |
| |
| public Arr( Object base, boolean lflag ) |
| { |
| this(base, lflag, -1); |
| } |
| |
| public Arr( Object base, boolean lflag, Number dim ) |
| { |
| this(base, lflag, dim.intValue()); |
| } |
| |
| public Arr( Object base, boolean lflag, long dim ) |
| { |
| this(base, lflag, (int)dim); |
| } |
| |
| public Arr( Object base, boolean lflag, int dim ) |
| { |
| this.base = (Proto)base; |
| this.lflag = lflag; |
| this.dim = dim; |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| |
| if (newval instanceof Undefined) { |
| newval = Value.DEFAULT; |
| } |
| |
| Value.Arr varr = (Value.Arr)oldval; |
| Object res; |
| |
| if (varr != null && varr.sealed(null)) { |
| varr.error("sealed array"); |
| } |
| |
| if (newval instanceof Value.Arr) { |
| if (!(this.assignable(((Value.Arr)newval).proto))) { |
| res = Value.ERROR; |
| } |
| else if (varr != null) { |
| varr.assignV(newval); |
| res = varr; |
| } |
| else { |
| res = newval; |
| } |
| } |
| |
| else if (newval instanceof Addr) { |
| varr.bind("$addr", new Long(((Addr)newval).val)); |
| res = varr; |
| } |
| |
| else if (newval instanceof Scriptable) { |
| if (varr == null) { |
| res = this.create(null, null, false, newval, true); |
| } |
| else { |
| varr.assignS((Scriptable)newval); |
| res = varr; |
| } |
| } |
| |
| else { |
| res = Value.ERROR; |
| } |
| |
| return res; |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| if (!(proto instanceof Proto.Arr)) { |
| return false; |
| } |
| |
| Proto.Arr parr = (Proto.Arr)proto; |
| return (this.base.assignable(parr.base)); |
| } |
| |
| public int depth() { return this.base.depth() + 1; } |
| |
| public final Proto getBase() { return this.base; } |
| public final int getDim() { return this.dim; } |
| public final boolean getLflag() { return this.lflag; } |
| |
| // interface Aggregate |
| |
| public Object create( Value prnt, String name, boolean ronly, Object initval, boolean check ) |
| { |
| Value.Arr varr = new Value.Arr(); |
| varr.init(this, prnt, name == null ? "[]#" + curid++ : name, ronly, initval, check); |
| return varr; |
| } |
| |
| // OVERRIDE Function |
| |
| public Scriptable construct( Context cx, Scriptable scope, Object[] args ) |
| { |
| return (Scriptable)this.create(null, null, false, args.length == 1 ? args[0] : Value.DEFAULT, true); |
| } |
| } |
| |
| // Proto.Elm |
| |
| static public class Elm extends Proto |
| { |
| Class cls; |
| String cast = null; |
| |
| static public Elm newBool() |
| { |
| Elm e = new Elm(); |
| e.cls = Boolean.class; |
| return e; |
| } |
| |
| static public Elm newCNum( String cast ) |
| { |
| Elm e = new Elm(); |
| e.cls = Number.class; |
| e.cast = cast; |
| return e; |
| } |
| |
| static public Elm newNum() |
| { |
| Elm e = new Elm(); |
| e.cls = Number.class; |
| return e; |
| } |
| |
| static public Elm newObj() |
| { |
| Elm e = new Elm(); |
| e.cls = Object.class; |
| return e; |
| } |
| |
| static public Elm newStr() |
| { |
| Elm e = new Elm(); |
| e.cls = String.class; |
| return e; |
| } |
| |
| static public String numval( Number num ) |
| { |
| long lg = num.longValue(); |
| double d = num.doubleValue(); |
| if (d != lg) { |
| return num.toString(); |
| } |
| else if (lg < 0) { |
| return "(-0x" + Long.toHexString(-(lg+1)) + " - 1)"; |
| } |
| else { |
| return "0x" + Long.toHexString(lg); |
| } |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| |
| if (newval instanceof Enum) { |
| newval = ((Enum)newval).ival; |
| } |
| |
| if (this.cls.isInstance(newval) || newval instanceof Undefined) { |
| // fall through |
| } |
| else if (newval == null || newval == Value.DEFAULT) { |
| newval = |
| (cls == Number.class) ? (Object)(new Integer(0)) : |
| (cls == Boolean.class) ? (Object)(Boolean.FALSE) : |
| null; |
| } |
| else if (cls == Number.class && newval instanceof Boolean) { |
| boolean b = ((Boolean)newval).booleanValue(); |
| newval = b ? new Integer(1) : new Integer(0); |
| } |
| else if (cls == Boolean.class && newval instanceof Number) { |
| int i = ((Number)newval).intValue(); |
| newval = i != 0 ? Boolean.TRUE : Boolean.FALSE; |
| } |
| else if (cls == String.class && newval instanceof CharSequence) { |
| newval = newval.toString(); |
| } |
| else if (cls == String.class && newval instanceof Addr) { |
| newval = ((Addr)newval).val == 0 ? null : newval; |
| } |
| else { |
| return Value.ERROR; |
| } |
| |
| return newval; |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| return (proto instanceof Proto.Elm |
| && ((Proto.Elm)proto).cls == this.cls); |
| } |
| |
| public final String getCast() { return this.cast; } |
| |
| String toText( Object val ) |
| { |
| if (val instanceof Number) { |
| return Proto.Elm.numval((Number) val); |
| } |
| else { |
| return super.toText(val); |
| } |
| } |
| } |
| |
| // Proto.Enm |
| |
| static public class Enm extends Proto |
| { |
| String name; |
| HashMap valmap = new HashMap(); |
| |
| public Enm( String name ) |
| { |
| this.name = name; |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| |
| if (newval instanceof Undefined) { |
| return newval; |
| } |
| else if (newval instanceof Enum && ((Enum)newval).proto == this) { |
| return newval; |
| } |
| else { |
| return Value.ERROR; |
| } |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| return this == proto; |
| } |
| } |
| |
| /** |
| * This is a prototype object for JavaScript functions. |
| */ |
| // Proto.Fxn |
| static public class Fxn extends Proto |
| { |
| Proto.Obj owner; |
| Proto ret; |
| int minargc; |
| boolean vflag; |
| Member[] args; |
| |
| static OpTab optab = new OpTab(Proto.Fxn.class, new String[] { |
| "addArg:$$arg" |
| }); |
| |
| public Fxn(Object owner, Object ret, int argc, int minargc, |
| boolean vflag) |
| { |
| this.owner = (Proto.Obj)owner; |
| this.ret = (Proto)ret; |
| this.minargc = minargc; |
| this.vflag = vflag; |
| this.args = new Member[argc]; |
| this.bindtab.putAll(Proto.Fxn.optab); |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| return Value.ERROR; |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| return false; |
| } |
| |
| public void addArg( int idx, String name, Proto proto, Object defval ) |
| { |
| Member mbr = this.args[idx] = new Member(); |
| |
| mbr.name = name; |
| mbr.proto = proto; |
| mbr.defval = defval; |
| } |
| } |
| |
| // Proto.Map |
| |
| static public class Map extends Proto |
| implements Aggregate, Embedded, Sealable |
| { |
| Proto base; |
| int curid = 0; |
| |
| public Map( Object base ) |
| { |
| this.base = (Proto)base; |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| |
| if (newval instanceof Undefined) { |
| newval = Value.DEFAULT; |
| } |
| |
| Value.Map vmap = (Value.Map)oldval; |
| Object res; |
| |
| if (vmap != null && vmap.sealed(null)) { |
| vmap.error("sealed map"); |
| } |
| |
| if (newval instanceof Value.Map) { |
| if (!(this.assignable(((Value.Map)newval).proto))) { |
| res = Value.ERROR; |
| } |
| else if (vmap != null) { |
| vmap.assignV(newval); |
| res = vmap; |
| } |
| else { |
| res = newval; |
| } |
| } |
| |
| else if (newval instanceof Scriptable) { |
| if (vmap == null) { |
| res = this.create(null, null, false, newval, true); |
| } |
| else { |
| vmap.assignS((Scriptable)newval); |
| res = vmap; |
| } |
| } |
| |
| else { |
| res = Value.ERROR; |
| } |
| |
| return res; |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| if (!(proto instanceof Proto.Map)) { |
| return false; |
| } |
| |
| Proto.Map pmap = (Proto.Map)proto; |
| return (this.base.assignable(pmap.base)); |
| } |
| |
| // interface Aggregate |
| |
| // interface Aggregate |
| |
| public Object create( Value prnt, String name, boolean ronly, Object initval, boolean check ) |
| { |
| Value.Map map = new Value.Map(); |
| map.init(this, prnt, name == null ? "{}#" + curid++ : name, ronly, initval, check); |
| return map; |
| } |
| |
| // OVERRIDE Function |
| |
| public Scriptable construct( Context cx, Scriptable scope, Object[] args ) |
| { |
| return (Scriptable)this.create(null, null, false, args.length == 1 ? args[0] : Value.DEFAULT, true); |
| } |
| } |
| |
| // Proto.Obj |
| |
| static public class Obj extends Proto |
| implements Aggregate, Function, ObjRef |
| { |
| static OpTab optab = new OpTab(Proto.Obj.class, new String[] { |
| "addFld:$$fld", |
| "addFldV:$$fldv", |
| "addFxn:$$fxn", |
| "init:$$init", |
| "make:$$make", |
| "patchFxn:$patch" |
| }); |
| |
| static int curkey = 0; |
| |
| String name; |
| Proto.Obj sup; |
| int key; |
| int curid = 0; |
| int fldcnt = 0; |
| |
| /* mbrlist holds a list of all properties, while fldlist does |
| * not contain functions |
| */ |
| LinkedHashMap<String,Member> mbrlist = new LinkedHashMap(); |
| LinkedHashMap<String,Member> fldlist = new LinkedHashMap(); |
| |
| public Obj() |
| { |
| this.bindtab.putAll(Proto.Obj.optab); |
| } |
| |
| public void addFld( String name, Proto proto, Object defval, String flags ) |
| { |
| addFldV(name, proto, defval, flags, null, null); |
| } |
| |
| public void addFldV( String name, Proto proto, Object defval, String flags, Object getter, Object setter ) |
| { |
| Member mbr = (Member)this.mbrlist.get(name); |
| |
| if (mbr == null) { |
| mbr = new Member(); |
| mbr.name = name; |
| mbr.idx = this.fldcnt++; |
| mbr.owner = this; |
| } |
| else { |
| try { |
| mbr = (Member)mbr.clone(); |
| } |
| catch (Exception e) { Err.exit(e); } |
| } |
| |
| mbr.proto = proto; |
| mbr.defval = defval; |
| mbr.getter = (Function)getter; |
| mbr.setter = (Function)setter; |
| mbr.hflag = flags.indexOf('h') != -1; |
| mbr.rflag = flags.indexOf('r') != -1; |
| |
| this.mbrlist.put(name, mbr); |
| this.fldlist.put(name, mbr); |
| } |
| |
| public void addFxn( String name, Proto.Fxn proto, Object ofxn ) |
| { |
| if (!(ofxn instanceof Function)) { |
| return; |
| } |
| |
| Member mbr = new Member(); |
| |
| mbr.name = name; |
| mbr.proto = proto; |
| mbr.owner = proto.owner == null ? this : proto.owner; |
| mbr.defval = new Invoke(name, (Function)ofxn, this, proto); |
| |
| this.mbrlist.put(name, mbr); |
| } |
| |
| public Collection<Member> allFlds() |
| { |
| return this.fldlist.values(); |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| |
| if (newval == null || newval instanceof Undefined) { |
| return newval; |
| } |
| else if (newval instanceof Value.Obj) { |
| return this.cast((Value.Obj)newval); |
| } |
| else if (newval == Value.DEFAULT) { /// necessary??? |
| return Context.getUndefinedValue(); |
| } |
| else if (newval instanceof Addr) { |
| return ((Addr)newval).val == 0 ? null : newval; |
| } |
| else if (newval instanceof XScriptO || !(newval instanceof Scriptable)) { |
| return Value.ERROR; |
| } |
| else { |
| return this.create(null, null, false, (Scriptable)newval, true); |
| } |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| if (!(proto instanceof Proto.Obj)) { |
| return false; |
| } |
| |
| for (Proto.Obj pobj = (Proto.Obj)proto; pobj != null; pobj = pobj.sup) { |
| if (pobj == this) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| Object cast( Value.Obj vobj ) |
| { |
| for (Proto.Obj pobj = (Proto.Obj)vobj.orig.proto; pobj != null; pobj = pobj.sup) { |
| if (pobj == this) { |
| return vobj.castTo(pobj); |
| } |
| } |
| |
| return Value.ERROR; |
| } |
| |
| String compat( Scriptable sobj ) /// FIX: pre-filter for arrays, etc. |
| { |
| Object[] ids = sobj.getIds(); |
| for (int i = 0; i < ids.length; i++) { |
| if (!this.fldlist.containsKey(ids[i])) { |
| return ids[i].toString(); |
| } |
| } |
| return null; |
| } |
| |
| Object[] getMbrIds( String pre ) |
| { |
| Vector idvec = new Vector(); |
| |
| for (Iterator it = this.fldlist.keySet().iterator(); it.hasNext(); ) { |
| String key = (String)it.next(); |
| if (pre == null || !key.startsWith(pre)) { |
| idvec.add(key); |
| } |
| } |
| |
| return idvec.toArray(); |
| } |
| |
| public final String getName() { return this.name; } |
| public final Proto.Obj getSuper() { return this.sup; } |
| |
| public Proto.Obj init( String name, Object sup ) { return this.init(name, sup, false); } |
| public Proto.Obj init( String name, Object sup, boolean newflg ) |
| { |
| this.name = name; |
| this.sup = (Proto.Obj)sup; |
| this.key = Proto.Obj.curkey++; |
| |
| this.setName(name); |
| |
| if (sup != null) { |
| this.mbrlist.putAll(this.sup.mbrlist); |
| this.fldlist.putAll(this.sup.fldlist); |
| this.fldcnt = this.sup.fldcnt; |
| } |
| |
| return this; |
| } |
| |
| Object lookupBind( String name ) |
| { |
| this.errflg = false; |
| |
| Object res = this.get(name, this); |
| if (res == NOT_FOUND && this.sup != null) { |
| res = this.sup.lookupBind(name); |
| } |
| |
| this.errflg = true; |
| return res; |
| } |
| |
| public Member lookupFld( String name ) |
| { |
| return (Member)this.fldlist.get(name); |
| } |
| |
| public Member lookupMbr( String name, Proto.Obj proto ) |
| { |
| Member mbr = (Member)this.mbrlist.get(name); |
| return (mbr != null && mbr.owner.key <= proto.key) ? mbr : null; |
| } |
| |
| public Object make() |
| { |
| return this.create(null, null, false, Value.DEFAULT, false); |
| } |
| |
| public void patchFxn( String name, Function newFxn ) |
| { |
| Member mbr = (Member)this.mbrlist.get(name); |
| if (mbr == null || !(mbr.defval instanceof Invoke)) { |
| return; |
| } |
| |
| Invoke inv = (Invoke)mbr.defval; |
| this.addFxn(name, (Proto.Fxn)mbr.proto, new Patch(inv.fxn, newFxn)); |
| } |
| |
| public String tname() |
| { |
| return this.name; |
| } |
| |
| // OVERRIDE Scriptable |
| |
| /* |
| * ======== Proto.Obj.get ======== |
| */ |
| public Object get( String name, Scriptable start ) |
| { |
| Member mbr = (Member)this.mbrlist.get(name); |
| return (mbr != null) ? mbr.defval : super.get(name, start); |
| } |
| |
| public Object getDefaultValue( java.lang.Class hint ) |
| { |
| return this.name; |
| } |
| |
| /* |
| * ======== Proto.Obj.has ======== |
| */ |
| public boolean has( String name, Scriptable start ) |
| { |
| Member mbr = (Member)this.mbrlist.get(name); |
| if (mbr != null) { |
| return (true); |
| } |
| else { |
| return (super.has(name, start)); |
| } |
| } |
| |
| public boolean hasInstance( Scriptable value ) |
| { |
| return value instanceof Value.Obj ? this.assignable(((Value.Obj)value).orig.proto) : false; |
| } |
| |
| // OVERRIDE Function |
| |
| public Object call( Context cx, Scriptable scope, Scriptable thisObj, Object[] args ) |
| { |
| if (args.length == 0) { |
| Err.exit("an object argument is required"); |
| return Context.getUndefinedValue(); |
| } |
| |
| Value.Obj vobj; |
| |
| if (args[0] instanceof Value.Obj) { |
| vobj = (Value.Obj)args[0]; |
| } |
| else { |
| Err.exit("an object argument is required"); |
| return Context.getUndefinedValue(); |
| } |
| |
| if (vobj == null) { |
| return null; |
| } |
| for (Proto.Obj pobj = (Proto.Obj)vobj.orig.proto; pobj != null; pobj = pobj.sup) { |
| if (pobj == this) { |
| return vobj.castTo(pobj); |
| } |
| } |
| |
| return Context.getUndefinedValue(); |
| } |
| |
| // interface Aggregate |
| |
| public Object create( Value prnt, String name, boolean ronly, |
| Object initval, boolean check ) |
| { |
| if (initval == null || initval instanceof Undefined) { |
| return initval; |
| } |
| else { |
| String ns = (name == null) ? (this.name + '#' + this.curid++) |
| : name; |
| Value.Obj vobj = new Value.Obj(ns, this); |
| vobj.init(this, prnt, ns, ronly, initval, check); |
| return vobj; |
| } |
| } |
| } |
| |
| // Proto.Str |
| |
| static public class Str extends Proto |
| implements Aggregate, Embedded, ObjRef, Pred, Sealable |
| { |
| static OpTab optab = new OpTab(Proto.Str.class, new String[] { |
| "make:$$make", |
| }); |
| |
| Proto.Obj base; |
| boolean metaonly; |
| |
| public Str( Proto.Obj base ) |
| { |
| this(base, true); |
| this.setName(base.name); |
| } |
| |
| public Str( Proto.Obj base, boolean metaonly ) |
| { |
| this.base = base; |
| this.metaonly = metaonly; |
| this.bindtab.putAll(Proto.Str.optab); |
| } |
| |
| public final Proto getBase() { |
| return this.base; |
| } |
| |
| /* This function is invoked when a function is called and one of the |
| * function's typed parameters is a structure type, or in case of a |
| * typed assignment to a variable of a structure type. |
| * In the first case, oldval is 'null'. |
| */ |
| Object assign( Object oldval, Object newval ) |
| { |
| newval = Proto.unwrap(newval); |
| |
| if (newval instanceof Undefined) { |
| newval = Value.DEFAULT; |
| } |
| |
| if (oldval == null) { |
| /* primitive types are not allowed */ |
| if (!(newval instanceof Scriptable)) { |
| return (Value.ERROR); |
| } |
| return this.create(null, null, false, newval, true); |
| } |
| |
| Value.Obj vobj = (Value.Obj)oldval; |
| Object res = vobj; |
| |
| if (vobj.sealed(null)) { |
| vobj.error("sealed object"); |
| } |
| |
| if (newval == null) { |
| vobj.error("illegal assignment of 'null'"); |
| res = Value.ERROR; |
| } |
| else if (newval instanceof Value.Obj) { |
| Object oval = this.base.cast((Value.Obj)newval); |
| if (oval == Value.ERROR) { |
| vobj.error("incompatible assignment"); |
| res = Value.ERROR; |
| } |
| else { |
| vobj.assignV((Value.Obj)oval); |
| } |
| } |
| else if (newval instanceof XScriptO && newval != Value.DEFAULT || !(newval instanceof Scriptable)) { |
| vobj.error("incompatible assignment: " + newval); |
| res = Value.ERROR; |
| } |
| else { |
| vobj.assignS((Scriptable)newval); |
| } |
| |
| return res; |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| return proto instanceof Proto.Str ? this.base.assignable(((Proto.Str)proto).base) : false; |
| } |
| |
| public Object make( Object prnt, String name ) |
| { |
| return this.create((Value)prnt, name, false, Value.DEFAULT, false); |
| } |
| |
| public Object newInstance() |
| { |
| Value.Obj vobj = (Value.Obj)this.create(null, null, false, Value.DEFAULT, true); |
| vobj.bind("$category", "Struct"); |
| |
| return vobj; |
| } |
| |
| // OVERRIDE scriptable |
| |
| public boolean hasInstance( Scriptable value ) |
| { |
| return this.base.hasInstance(value); |
| } |
| |
| // OVERRIDE function |
| |
| public Scriptable construct( Context cx, Scriptable scope, Object[] args ) |
| { |
| Value.Obj vobj = (Value.Obj)this.create(null, null, false, args.length == 1 ? args[0] : Value.DEFAULT, true); |
| vobj.bind("$category", "Struct"); |
| |
| return vobj; |
| } |
| |
| // interface Aggregate |
| |
| public Object create( Value prnt, String name, boolean ronly, Object initval, boolean check ) |
| { |
| if (initval == null) { |
| Err.exit("illegal assignment of 'null'"); |
| return Value.ERROR; |
| } |
| |
| if (initval instanceof Undefined) { |
| initval = Value.DEFAULT; |
| } |
| |
| Value.Obj vobj = (Value.Obj)this.base.create(prnt, name, ronly, initval, check); |
| |
| return vobj; |
| } |
| } |
| |
| // Proto.Tag |
| |
| static public class Tag extends Proto |
| implements Aggregate, Embedded, Pred, Sealable, Typedef |
| { |
| static OpTab optab = new OpTab(Proto.Tag.class, new String[] { |
| "init:$$init", |
| }); |
| |
| String name; |
| Proto base; |
| Function encFxn; |
| |
| public Tag() |
| { |
| this.bindtab.putAll(Proto.Tag.optab); |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| return this.base.assign(oldval, newval); |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| return this.base.assignable(proto); |
| } |
| |
| public Object create( Value prnt, String name, boolean ronly, Object initval, boolean check ) |
| { |
| return ((Aggregate)this.base).create(prnt, name, ronly, initval, check); |
| } |
| |
| int depth() { return this.base.depth(); } |
| |
| public Proto getBase() { return this.base; } |
| public Function getEncFxn() { return this.encFxn; } |
| |
| public void init( String name, Object base, Object encFxn ) |
| { |
| this.name = name; |
| this.base = (Proto)base; |
| this.encFxn = encFxn == null || encFxn instanceof Undefined ? null : (Function)encFxn; |
| } |
| } |
| |
| // Proto.Tel |
| |
| static public class Tel extends Proto |
| implements Pred, Typedef |
| { |
| static OpTab optab = new OpTab(Proto.Tel.class, new String[] { |
| "init:$$init", |
| }); |
| |
| String name; |
| Proto base; |
| Function encFxn; |
| |
| public Tel() |
| { |
| this.bindtab.putAll(Proto.Tel.optab); |
| } |
| |
| Object assign( Object oldval, Object newval ) |
| { |
| return this.base.assign(oldval, newval); |
| } |
| |
| boolean assignable( Proto proto ) |
| { |
| return this.base.assignable(proto); |
| } |
| |
| public Proto getBase() { return this.base; } |
| public Function getEncFxn() { return this.encFxn; } |
| |
| public void init( String name, Object base, Object encFxn ) |
| { |
| this.name = name; |
| this.base = (Proto)base; |
| this.encFxn = encFxn == null || encFxn instanceof Undefined ? null : (Function)encFxn; |
| } |
| |
| // OVERRIDE scriptable |
| |
| public boolean hasInstance( Scriptable value ) |
| { |
| return this.base.hasInstance(value); |
| } |
| } |
| } |