1 29 30 package com.caucho.quercus.env; 31 32 import com.caucho.quercus.QuercusRuntimeException; 33 import com.caucho.quercus.expr.*; 34 import com.caucho.quercus.program.AbstractFunction; 35 import com.caucho.quercus.program.ClassDef; 36 import com.caucho.quercus.program.Function; 37 import com.caucho.quercus.program.InstanceInitializer; 38 import com.caucho.util.IdentityIntMap; 39 import com.caucho.util.L10N; 40 41 import java.util.ArrayList ; 42 import java.util.HashMap ; 43 import java.util.IdentityHashMap ; 44 import java.util.LinkedHashMap ; 45 import java.util.Map ; 46 import java.util.Set ; 47 import java.util.logging.Logger ; 48 49 52 public class QuercusClass { 53 private final L10N L = new L10N(QuercusClass.class); 54 private final Logger log = Logger.getLogger(QuercusClass.class.getName()); 55 56 private final ClassDef _classDef; 57 58 private ClassDef []_classDefList; 59 60 private QuercusClass _parent; 61 62 private AbstractFunction _constructor; 63 64 private AbstractFunction _get; 65 private AbstractFunction _set; 66 private AbstractFunction _call; 67 68 private final ArrayList <InstanceInitializer> _initializers 69 = new ArrayList <InstanceInitializer>(); 70 71 private final ArrayList <String > _fieldNames 72 = new ArrayList <String >(); 73 74 private final IdentityIntMap _fieldMap 75 = new IdentityIntMap(); 76 77 private final HashMap <StringValue,Expr> _fieldInitMap 78 = new HashMap <StringValue,Expr>(); 79 80 private final IdentityHashMap <String ,AbstractFunction> _methodMap 81 = new IdentityHashMap <String ,AbstractFunction>(); 82 83 private final HashMap <String ,AbstractFunction> _lowerMethodMap 84 = new HashMap <String ,AbstractFunction>(); 85 86 private final IdentityHashMap <String ,Expr> _constMap 87 = new IdentityHashMap <String ,Expr>(); 88 89 private final HashMap <String ,Expr> _staticFieldMap 90 = new LinkedHashMap <String ,Expr>(); 91 92 public QuercusClass(ClassDef classDef, QuercusClass parent) 93 { 94 _classDef = classDef; 95 _parent = parent; 96 97 ClassDef []classDefList; 98 99 if (_parent != null) { 100 classDefList = new ClassDef[parent._classDefList.length + 1]; 101 102 System.arraycopy(parent._classDefList, 0, classDefList, 1, 103 parent._classDefList.length); 104 105 classDefList[0] = classDef; 106 } 107 else { 108 classDefList = new ClassDef[] { classDef }; 109 } 110 111 _classDefList = classDefList; 112 113 for (int i = classDefList.length - 1; i >= 0; i--) { 114 classDefList[i].initClass(this); 115 } 116 } 117 118 121 public String getName() 122 { 123 return _classDef.getName(); 124 } 125 126 129 public QuercusClass getParent() 130 { 131 return _parent; 132 } 133 134 137 public void setConstructor(AbstractFunction fun) 138 { 139 _constructor = fun; 140 } 141 142 145 public void setGet(AbstractFunction fun) 146 { 147 _get = fun; 148 } 149 150 153 public void setSet(AbstractFunction fun) 154 { 155 _set = fun; 156 } 157 158 161 public AbstractFunction getSetField() 162 { 163 return _set; 164 } 165 166 169 public void setCall(AbstractFunction fun) 170 { 171 _call = fun; 172 } 173 174 177 public AbstractFunction getCall() 178 { 179 return _call; 180 } 181 182 185 public void addInitializer(InstanceInitializer init) 186 { 187 _initializers.add(init); 188 } 189 190 193 public void addField(String name, int index, Expr initExpr) 194 { 195 _fieldNames.add(name); 196 _fieldMap.put(name, index); 197 _fieldInitMap.put(new StringValueImpl(name), initExpr); 198 } 199 200 203 public int addFieldIndex(String name) 204 { 205 int index = _fieldMap.get(name); 206 207 if (index >= 0) 208 return index; 209 else { 210 index = _fieldNames.size(); 211 212 _fieldMap.put(name, index); 213 _fieldNames.add(name); 214 215 return index; 216 } 217 } 218 219 222 public HashMap <StringValue,Expr> getClassVars() 223 { 224 return _fieldInitMap; 225 } 226 227 231 public Set <Map.Entry<String , AbstractFunction>> getClassMethods() 232 { 233 return _classDef.functionSet(); 234 } 235 236 239 public void addMethod(String name, AbstractFunction fun) 240 { 241 _methodMap.put(name.intern(), fun); 242 _lowerMethodMap.put(name.toLowerCase(), fun); 243 } 244 245 248 public void addStaticField(String name, Expr expr) 249 { 250 _staticFieldMap.put(name, expr); 251 } 252 253 256 public void addConstant(String name, Expr expr) 257 { 258 _constMap.put(name, expr); 259 } 260 261 264 public int getFieldSize() 265 { 266 return _fieldNames.size(); 267 } 268 269 272 public int findFieldIndex(String name) 273 { 274 return _fieldMap.get(name); 275 } 276 277 280 public ArrayList <String > getFieldNames() 281 { 282 return _fieldNames; 283 } 284 285 public void validate(Env env) 286 { 287 if (! _classDef.isAbstract() && ! _classDef.isInterface()) { 288 for (AbstractFunction absFun : _methodMap.values()) { 289 if (! (absFun instanceof Function)) 290 continue; 291 292 Function fun = (Function) absFun; 293 294 if (fun.isAbstract()) 295 throw env.errorException(L.l("Abstract function '{0}' must be implemented in concrete class {1}.", 296 fun.getName(), getName())); 297 } 298 } 299 } 300 301 public void init(Env env) 302 { 303 for (Map.Entry<String ,Expr> entry : _staticFieldMap.entrySet()) { 304 Value val; 305 Expr expr = entry.getValue(); 306 307 if (expr instanceof ClassConstExpr) 309 val = ((ClassConstExpr)expr).eval(env, this); 310 else 311 val = expr.eval(env); 312 313 env.setGlobalValue(entry.getKey(), val); 314 } 315 } 316 317 321 324 public Value callNew(Env env, Expr []args) 325 { 326 Value object = _classDef.callNew(env, args); 327 328 if (object != null) 329 return object; 330 331 object = newInstance(env); 332 333 AbstractFunction fun = findConstructor(); 334 335 if (fun != null) { 336 fun.callMethod(env, object, args); 337 } 338 339 return object; 340 } 341 342 345 public Value callNew(Env env, Value []args) 346 { 347 Value object = _classDef.callNew(env, args); 348 349 if (object != null) 350 return object; 351 352 object = newInstance(env); 353 354 AbstractFunction fun = findConstructor(); 355 356 if (fun != null) 357 fun.callMethod(env, object, args); 358 else { 359 } 361 362 return object; 363 } 364 365 368 public String getParentName() 369 { 370 return _classDefList[0].getParentName(); 371 } 372 373 376 public boolean isA(String name) 377 { 378 for (int i = _classDefList.length - 1; i >= 0; i--) { 379 if (_classDefList[i].isA(name)) 380 return true; 381 } 382 383 return false; 384 } 385 386 389 public Value newInstance(Env env) 390 { 391 Value obj = _classDef.newInstance(env, this); 392 393 for (int i = 0; i < _initializers.size(); i++) { 394 _initializers.get(i).initInstance(env, obj); 395 } 396 397 return obj; 398 } 399 400 403 public AbstractFunction findConstructor() 404 { 405 return _constructor; 406 } 407 408 412 415 public Value getField(Env env, Value qThis, String field) 416 { 417 if (_get != null) 418 return _get.callMethod(env, qThis, new StringValueImpl(field)); 419 else 420 return UnsetValue.UNSET; 421 } 422 423 426 public void setField(Env env, Value qThis, String field, Value value) 427 { 428 if (_set != null) 429 _set.callMethod(env, qThis, new StringValueImpl(field), value); 430 } 431 432 435 public AbstractFunction findFunction(String name) 436 { 437 AbstractFunction fun = _methodMap.get(name); 438 439 if (fun == null) 440 fun = _lowerMethodMap.get(name.toLowerCase()); 441 442 return fun; 443 } 444 445 448 public AbstractFunction findFunctionExact(String name) 449 { 450 return _methodMap.get(name); 451 } 452 453 456 public AbstractFunction findFunctionLowerCase(String name) 457 { 458 return _lowerMethodMap.get(name.toLowerCase()); 459 } 460 461 464 public AbstractFunction findStaticFunction(String name) 465 { 466 return findFunction(name); 467 } 468 469 472 public final AbstractFunction getFunction(String name) 473 { 474 AbstractFunction fun = findFunction(name); 475 476 if (fun != null) 477 return fun; 478 479 fun = findFunctionLowerCase(name.toLowerCase()); 480 481 if (fun != null) 482 return fun; 483 else { 484 throw new QuercusRuntimeException(L.l("{0}::{1} is an unknown method", 485 getName(), name)); 486 } 487 } 488 489 492 public Value callMethod(Env env, 493 Value thisValue, 494 String methodName, 495 Expr []args) 496 { 497 AbstractFunction fun = findFunction(methodName); 498 499 if (fun != null) 500 return fun.callMethod(env, thisValue, args); 501 else if (getCall() != null) { 502 Expr []newArgs = new Expr[args.length + 1]; 503 newArgs[0] = new StringLiteralExpr(methodName); 504 System.arraycopy(args, 0, newArgs, 1, args.length); 505 506 return getCall().callMethod(env, thisValue, newArgs); 507 } 508 else 509 return env.error(L.l("Call to undefined method {0}::{1}", 510 getName(), methodName)); 511 } 512 513 516 public Value callMethod(Env env, Value thisValue, String name, Value []args) 517 { 518 return getFunction(name).callMethod(env, thisValue, args); 519 } 520 521 524 public Value callMethod(Env env, Value thisValue, String name) 525 { 526 return getFunction(name).callMethod(env, thisValue); 527 } 528 529 532 public Value callMethod(Env env, 533 Value thisValue, 534 String methodName, 535 Value a1) 536 { 537 AbstractFunction fun = findFunction(methodName); 538 539 if (fun != null) 540 return fun.callMethod(env, thisValue, a1); 541 else if (getCall() != null) { 542 return getCall().callMethod(env, 543 thisValue, 544 new StringValueImpl(methodName), 545 new ArrayValueImpl() 546 .append(a1)); 547 } 548 else 549 return env.error(L.l("Call to undefined method {0}::{1}()", 550 getName(), methodName)); 551 } 552 553 556 public Value callMethod(Env env, Value thisValue, String name, 557 Value a1, Value a2) 558 { 559 return getFunction(name).callMethod(env, thisValue, a1, a2); 560 } 561 562 565 public Value callMethod(Env env, Value thisValue, String name, 566 Value a1, Value a2, Value a3) 567 { 568 return getFunction(name).callMethod(env, thisValue, a1, a2, a3); 569 } 570 571 574 public Value callMethod(Env env, Value thisValue, String name, 575 Value a1, Value a2, Value a3, Value a4) 576 { 577 return getFunction(name).callMethod(env, thisValue, a1, a2, a3, a4); 578 } 579 580 583 public Value callMethod(Env env, Value thisValue, String name, 584 Value a1, Value a2, Value a3, Value a4, Value a5) 585 { 586 return getFunction(name).callMethod(env, thisValue, a1, a2, a3, a4, a5); 587 } 588 589 592 public Value callMethodRef(Env env, Value thisValue, String name, Expr []args) 593 { 594 return getFunction(name).callMethodRef(env, thisValue, args); 595 } 596 597 600 public Value callMethodRef(Env env, Value thisValue, String name, Value []args) 601 { 602 return getFunction(name).callMethodRef(env, thisValue, args); 603 } 604 605 608 public Value callMethodRef(Env env, Value thisValue, String name) 609 { 610 return getFunction(name).callMethodRef(env, thisValue); 611 } 612 613 616 public Value callMethodRef(Env env, Value thisValue, String name, 617 Value a1) 618 { 619 return getFunction(name).callMethodRef(env, thisValue, a1); 620 } 621 622 625 public Value callMethodRef(Env env, Value thisValue, String name, 626 Value a1, Value a2) 627 { 628 return getFunction(name).callMethodRef(env, thisValue, a1, a2); 629 } 630 631 634 public Value callMethodRef(Env env, Value thisValue, String name, 635 Value a1, Value a2, Value a3) 636 { 637 return getFunction(name).callMethodRef(env, thisValue, a1, a2, a3); 638 } 639 640 643 public Value callMethodRef(Env env, Value thisValue, String name, 644 Value a1, Value a2, Value a3, Value a4) 645 { 646 return getFunction(name).callMethodRef(env, thisValue, a1, a2, a3, a4); 647 } 648 649 652 public Value callMethodRef(Env env, Value thisValue, String name, 653 Value a1, Value a2, Value a3, Value a4, Value a5) 654 { 655 return getFunction(name).callMethodRef(env, thisValue, a1, a2, a3, a4, a5); 656 } 657 658 661 public AbstractFunction findStaticFunctionLowerCase(String name) 662 { 663 return null; 664 } 665 666 669 public final AbstractFunction getStaticFunction(String name) 670 { 671 AbstractFunction fun = findStaticFunction(name); 672 673 if (fun != null) 674 return fun; 675 676 fun = findStaticFunctionLowerCase(name.toLowerCase()); 677 678 if (fun != null) 679 return fun; 680 else { 681 throw new QuercusRuntimeException(L.l("{0}::{1} is an unknown method", 682 getName(), name)); 683 } 684 } 685 686 689 public final Value getConstant(Env env, String name) 690 { 691 Expr expr = _constMap.get(name); 692 693 if (expr != null) 694 return expr.eval(env); 695 696 throw new QuercusRuntimeException(L.l("{0}::{1} is an unknown constant", 697 getName(), name)); 698 } 699 700 public String toString() 701 { 702 return "QuercusClass[" + getName() + "]"; 703 } 704 } 705 706 | Popular Tags |