1 28 29 package com.caucho.es; 30 31 34 public class ESClosure extends ESObject { 35 static ESString LENGTH = ESId.intern("length"); 36 static ESString CALLEE = ESId.intern("callee"); 37 static ESString ARGUMENTS = ESId.intern("arguments"); 38 static ESString OBJECT = ESId.intern("Object"); 39 static ESString PROTOTYPE = ESId.intern("prototype"); 40 static ESString CONSTRUCTOR = ESId.intern("constructor"); 41 42 public ESString name; 43 private ESCallable esClass; 44 public int n; 45 46 ESId []formals; 47 int nFormals; 48 49 ESBase proto; 50 51 ESGlobal global; 52 int stackRequired; int scopeRequired; ESBase []scope; 55 int scopeLength; 56 57 boolean hasFields; 58 59 public ESClosure(ESString name, ESCallable esClass, ESObject proto, 60 int n, ESId []formals, ESObject global) 61 { 62 this.className = "Function"; 63 this.prototype = Global.getGlobalProto().funProto; 64 this.name = name; 65 this.esClass = esClass; 66 this.proto = proto; 67 this.n = n; 68 this.formals = formals; 69 this.nFormals = formals.length; 70 71 if (global instanceof ESGlobal) 72 this.global = (ESGlobal) global; 73 74 if (global != null) { 75 this.scopeLength = 1; 76 this.scope = new ESBase[1]; 77 this.scope[0] = global; 78 } 79 } 80 81 protected ESClosure(ESBase []scope, int scopeLength) 82 { 83 super("Function", null); 84 85 hasFields = true; 86 this.scope = scope; 87 this.scopeLength = scopeLength; 88 } 89 92 protected ESClosure() {} 93 94 public void closure(Call env) 95 { 96 if (scope == null) { 97 scope = new ESBase[16]; 98 } 99 100 for (; scopeLength < env.scopeLength; scopeLength++) 101 scope[scopeLength] = env.scope[scopeLength]; 102 103 if (scopeLength == 0) 104 scope[scopeLength++] = env.global; 105 106 global = (ESGlobal) scope[0]; 107 } 108 109 112 void setScope(ESBase []scope, int scopeLength) 113 { 114 this.scope = scope; 115 this.scopeLength = scopeLength; 116 } 117 118 public ESBase hasProperty(ESString id) 119 throws Throwable 120 { 121 if (id.equals(PROTOTYPE)) { 122 if (proto == null) { 123 ESObject obj = Global.getGlobalProto().createObject(); 124 proto = obj; 125 obj.put(CONSTRUCTOR, this, DONT_ENUM); 126 } 127 128 return proto; 129 } else if (id.equals(LENGTH)) { 130 return ESNumber.create(nFormals); 131 } else if (hasFields) { 132 return super.hasProperty(id); 133 } else if (prototype != null) 134 return prototype.hasProperty(id); 135 else 136 return ESBase.esEmpty; 137 } 138 139 public ESBase getProperty(ESString id) 140 throws Throwable 141 { 142 if (id.equals(PROTOTYPE)) { 143 if (proto == null) { 144 ESObject obj = Global.getGlobalProto().createObject(); 145 proto = obj; 146 obj.put(CONSTRUCTOR, this, DONT_ENUM); 147 } 148 149 return proto; 150 } else if (id.equals(LENGTH)) { 151 return ESNumber.create(nFormals); 152 } else if (hasFields) { 153 return super.getProperty(id); 154 } else 155 return prototype.getProperty(id); 156 } 157 158 public boolean canPut(ESString id) 159 { 160 if (id.equals(PROTOTYPE)) { 161 return true; 162 } else if (id.equals(LENGTH)) { 163 return false; 164 } else if (hasFields) { 165 return super.canPut(id); 166 } else { 167 return true; 168 } 169 } 170 171 public void setProperty(ESString id, ESBase value) 172 throws Throwable 173 { 174 if (id.equals(PROTOTYPE)) { 175 proto = value; 176 } else if (id.equals(LENGTH)) { 177 } else if (hasFields) { 178 super.setProperty(id, value); 179 } else { 180 init(className, prototype); 181 hasFields = true; 182 super.setProperty(id, value); 183 } 184 } 185 186 public void put(ESString id, ESBase value, int flags) 187 { 188 if (id.equals(PROTOTYPE)) { 189 proto = value; 190 } else if (id.equals(LENGTH)) { 191 } else if (hasFields) { 192 super.put(id, value, flags); 193 } else { 194 init(className, prototype); 195 hasFields = true; 196 super.put(id, value, flags); 197 } 198 } 199 200 public ESBase delete(ESString id) 201 throws Throwable 202 { 203 if (id.equals(PROTOTYPE)) { 204 proto = ESBase.esEmpty; 205 return ESBoolean.TRUE; 206 } else if (id.equals(LENGTH)) { 207 return ESBoolean.FALSE; 208 } else if (hasFields) { 209 return super.delete(id); 210 } else 211 return ESBoolean.TRUE; 212 } 213 214 public ESString toStr() 215 { 216 return ESString.create(decompile()); 217 } 218 219 String decompile() 220 { 221 StringBuffer sbuf = new StringBuffer (); 222 223 sbuf.append("function "); 224 if (name != null && ! name.toString().startsWith("$lambda")) 225 sbuf.append(name); 226 sbuf.append("("); 227 for (int i = 0; formals != null && i < nFormals; i++) { 228 if (i != 0) 229 sbuf.append(", "); 230 sbuf.append(formals[i]); 231 } 232 233 sbuf.append(") "); 234 235 sbuf.append("{ "); 236 sbuf.append("[compiled code]"); 237 sbuf.append(" }"); 238 239 return sbuf.toString(); 240 } 241 242 protected ESBase dispatch() throws ESException 243 { 244 throw new ESException("dispatch not specialized"); 245 } 246 247 public ESBase call(Call call, int length) throws Throwable 248 { 249 if (global != null) 250 call.global = global; 251 252 if (esClass != null) 253 return esClass.call(n, call, length); 254 else 255 return ESBase.esUndefined; 256 } 257 258 public ESBase construct(Call eval, int length) throws Throwable 259 { 260 Global resin = Global.getGlobalProto(); 261 ESObject obj = Global.getGlobalProto().createObject(); 262 ESBase proto = this.proto; 263 264 if (! (proto instanceof ESObject)) 265 proto = resin.object.getProperty(PROTOTYPE); 266 267 if (proto instanceof ESObject) 268 obj.prototype = proto; 269 270 eval.setThis(obj); 271 272 ESBase value = call(eval, length); 273 274 return value instanceof ESObject ? (ESObject) value : obj; 275 } 276 277 public ESBase typeof() throws ESException 278 { 279 return ESString.create("function"); 280 } 281 282 protected void copy(Object newObj) 283 { 284 ESClosure closure = (ESClosure) newObj; 285 286 super.copy(newObj); 287 288 closure.name = name; 289 closure.esClass = esClass; 290 closure.n = n; 291 closure.formals = formals; 292 closure.nFormals = nFormals; 293 294 closure.stackRequired = stackRequired; 295 closure.scopeRequired = scopeRequired; 296 closure.scopeLength = scopeLength; 297 closure.scope = new ESBase[scopeLength]; 298 closure.hasFields = hasFields; 299 300 for (int i = 0; i < scopeLength; i++) { 301 if (scope[i] != null) { 302 closure.scope[i] = (ESBase) scope[i]; 303 } 304 } 305 306 closure.proto = proto; } 308 309 public ESObject dup() { return new ESClosure(); } 310 311 ESObject resinCopy() 312 { 313 ESObject obj = dup(); 314 315 copy(obj); 316 317 return obj; 318 } 319 320 ESObject getClassPrototype() 321 throws Throwable 322 { 323 ESBase proto = hasProperty(PROTOTYPE); 324 325 return (ESObject) proto; 326 } 327 328 void setClassPrototype(ESObject proto) 329 throws ESException 330 { 331 this.proto = proto; 332 proto.put(CONSTRUCTOR, this, DONT_ENUM); 333 } 334 } 335 | Popular Tags |