1 28 29 package com.caucho.es.parser; 30 31 import com.caucho.es.ESId; 32 import com.caucho.util.CharBuffer; 33 import com.caucho.util.IntMap; 34 35 import java.io.IOException ; 36 import java.util.ArrayList ; 37 import java.util.HashMap ; 38 import java.util.Iterator ; 39 40 43 class Function { 44 static ESId PROTOTYPE = ESId.intern("prototype"); 45 46 Parser parser; 47 ParseClass cl; 48 private Function parent; 49 50 int funDepth; 51 private int lambdaCount = 0; 52 53 ArrayList formals; 54 Expr returnType; 55 56 ArrayList variables = new ArrayList (); 57 58 ArrayList functions; 60 private IntMap funMap; 61 62 63 boolean isClass; 64 ESId classProto; Function constructor; 66 67 String name; 68 ESId id; 69 int num; 70 boolean isSilent; 71 boolean hasCall; 72 boolean hasThis; 73 boolean allowLocals; 74 boolean allowJavaLocals; 75 boolean needsScope; 76 77 ArrayList data = new ArrayList (); 78 private HashMap vars = new HashMap (); 79 CharBuffer tail; 80 private int iterCount; 81 private int tempCount; 82 private int stmtCount; 83 private int stmtTop; 84 private HashMap usedVars; 85 private boolean isGlobal; 86 private boolean needsArguments; 89 private boolean needsStatementResults; 90 private boolean useAllVariables; 93 private boolean isEval; 95 private boolean hasSwitch; 97 98 Function(ParseClass cl, Function parent, 99 String name, ESId id, boolean isClass) 100 { 101 this.id = id; 102 this.name = name; 103 this.parent = parent; 104 this.cl = cl; 105 106 if (parent == null || isClass) 107 funDepth = 0; 108 else 109 funDepth = parent.funDepth + 1; 110 111 num = -1; 112 113 isGlobal = parent == null; 114 allowLocals = funDepth >= 1 || isClass; 115 allowJavaLocals = allowLocals; 116 needsStatementResults = parent == null; 117 } 118 119 void setFast(boolean isFast) 120 { 121 if (isFast) { 122 allowLocals = true; 123 allowJavaLocals = true; 124 } 125 } 126 127 Function getParent() 128 { 129 return parent; 130 } 131 132 boolean isGlobalScope() 133 { 134 return ! needsScope && (getFunctionDepth() == 0 || 135 getFunctionDepth() == 1 && ! needsArguments()); 136 } 137 138 boolean needsStatementResults() 139 { 140 return needsStatementResults; 141 } 142 143 void setNeedsResults() 144 { 145 needsStatementResults = true; 146 } 147 148 void setEval() 149 { 150 setArguments(); 151 needsStatementResults = true; 152 isEval = true; 153 } 154 155 boolean useAllVariables() 156 { 157 return isEval || useAllVariables; 158 } 159 160 void setUseAllVariables() 161 { 162 useAllVariables = true; 163 } 164 165 String getStatementVar() 166 { 167 if (! needsStatementResults()) 168 return null; 169 else 170 return "_val" + stmtCount; 171 } 172 173 void pushStatementLoop() 174 { 175 if (! needsStatementResults()) 176 return; 177 178 stmtCount++; 179 if (stmtCount > stmtTop) 180 stmtTop = stmtCount; 181 } 182 183 void popStatementLoop() 184 { 185 if (! needsStatementResults()) 186 return; 187 188 stmtCount--; 189 } 190 191 void setCall() 192 { 193 this.hasCall = true; 194 } 195 196 void setThis() 197 { 198 this.hasThis = true; 199 } 200 201 204 void setVars() 205 { 206 Iterator iter = vars.values().iterator(); 207 while (iter.hasNext()) { 208 Variable var = (Variable) iter.next(); 209 var.getType(); 210 } 211 } 212 213 boolean isGlobal() 214 { 215 return isGlobal; 216 } 217 218 int getFunctionDepth() 219 { 220 return funDepth; 221 } 222 223 void disableGlobal() 224 { 225 isGlobal = false; 226 } 227 228 void disallowLocal() 229 { 230 if (parent != null) { 231 allowJavaLocals = false; 232 allowLocals = false; 233 needsScope = true; 234 } 235 } 236 237 void disallowJavaLocal() 238 { 239 allowJavaLocals = false; 240 } 241 242 void setNeedsScope() 243 { 244 if (parent != null) 245 needsScope = true; 246 } 247 248 void setArguments() 249 { 250 needsArguments = true; 251 setNeedsScope(); 252 disallowLocal(); 253 } 254 255 boolean needsArguments() 256 { 257 return needsArguments; 258 } 259 260 boolean allowLocals() 261 { 262 return allowLocals; 263 } 264 265 boolean allowJavaLocals() 266 { 267 return allowLocals && allowJavaLocals; 268 } 269 270 void useClosureVar(ESId name) 271 { 272 for (Function fun = parent; fun != null; fun = fun.parent) { 273 Variable var = (Variable) fun.vars.get(name); 274 275 fun.needsArguments = true; 276 277 if (var != null) 278 var.setUsedByClosure(); 279 else { 280 if (fun.usedVars == null) 281 fun.usedVars = new HashMap (); 282 fun.usedVars.put(name, name); 283 } 284 } 285 } 286 287 290 boolean hasVar(ESId name) 291 { 292 return vars.get(name) != null; 293 } 294 295 298 IdExpr newVar(Block block, ESId name) 299 { 300 return newVar(block, name, null); 301 } 302 303 306 IdExpr newVar(Block block, ESId name, Expr type) 307 { 308 Variable var = (Variable) vars.get(name); 309 310 if (var == null && type == null) { 311 var = cl.getVariable(name); 312 if (var != null) { 313 return new IdExpr(block, var); 314 } 315 } 316 317 if (var == null) { 318 319 var = new Variable(block, name, type, false); 320 vars.put(name, var); 321 322 if (usedVars != null && usedVars.get(name) != null) 323 var.setUsedByClosure(); 324 } 325 326 useClosureVar(name); 327 328 return new IdExpr(block, var); 329 } 330 331 335 void addVariable(Block block, ESId id, Expr type) 336 { 337 if (variables == null) 338 variables = new ArrayList (); 339 340 Variable var = (Variable) vars.get(id); 341 if (var == null) { 342 var = new Variable(block, id, type, allowLocals); 343 vars.put(id, var); 344 345 if (usedVars != null && usedVars.get(id) != null) 346 var.setUsedByClosure(); 347 348 if (parent == null && type != null) 351 cl.addVariable(id, var); 352 } 353 else if (parent != null) 354 var.setLocal(); 355 356 if (! variables.contains(var) && 357 (formals == null || ! formals.contains(var))) 358 variables.add(var); 359 360 useClosureVar(id); 361 } 362 363 int getIter() 364 { 365 return iterCount++; 366 } 367 368 String getTemp() 369 { 370 return "temp" + tempCount++; 371 } 372 373 void setConstructor(Function constructor) 374 { 375 isClass = true; 376 this.constructor = constructor; 377 } 378 379 void setClassProto(ESId classProto) 380 { 381 isClass = true; 382 this.classProto = classProto; 383 } 384 385 void setCodeNumber(int num) 386 { 387 this.num = num; 388 } 389 390 void addFormal(Block block, ESId id, Expr type) 391 { 392 if (formals == null) 393 formals = new ArrayList (); 394 395 Variable var = new Variable(block, id, type, true); 396 var.setUsed(); 397 formals.add(var); 398 vars.put(id, var); 399 } 400 401 int getFormalSize() 402 { 403 return formals == null ? 0 : formals.size(); 404 } 405 406 Variable getFormal(int j) 407 { 408 return (Variable) formals.get(j); 409 } 410 411 Expr getReturnType() 412 { 413 return returnType; 414 } 415 416 void setReturnType(Expr type) 417 { 418 returnType = type; 419 } 420 421 int getVariableSize() 422 { 423 return variables == null ? 0 : variables.size(); 424 } 425 426 void addFunction(Function function) 427 { 428 if (functions == null) { 429 functions = new ArrayList (); 430 funMap = new IntMap(); 431 } 432 int pos = funMap.get(function.id); 433 434 if (pos < 0) { 435 funMap.put(function.id, functions.size()); 436 functions.add(function); 437 } 438 else 439 functions.set(pos, function); 440 } 441 442 int getFunctionSize() 443 { 444 return functions == null ? 0 : functions.size(); 445 } 446 447 Function getFunction(int i) 448 { 449 return (Function) functions.get(i); 450 } 451 452 Function getFunction(ESId id) 453 { 454 if (funMap == null) 455 return null; 456 457 int index = funMap.get(id); 458 459 if (index >= 0) { 460 return (Function) functions.get(index); 461 } 462 else 463 return null; 464 } 465 466 void print(Object value) 467 { 468 if (tail == null) 469 tail = CharBuffer.allocate(); 470 tail.append(String.valueOf(value)); 471 } 472 473 void println(String value) 474 { 475 if (tail == null) 476 tail = CharBuffer.allocate(); 477 tail.append(String.valueOf(value)); 478 tail.append('\n'); 479 } 480 481 void addExpr(Expr expr) 482 { 483 if (tail != null) 484 data.add(tail); 485 tail = null; 486 data.add(expr); 487 expr.setUsed(); 488 } 489 490 void addBoolean(Expr expr) 491 { 492 if (tail != null) 493 data.add(tail); 494 tail = null; 495 496 data.add(expr.setBoolean()); 497 expr.setUsed(); 498 } 499 500 Object getTop() 501 { 502 if (tail != null) 503 return tail; 504 else if (data.size() > 0) 505 return data.get(data.size() - 1); 506 else { 507 tail = new CharBuffer(); 508 return tail; 509 } 510 } 511 512 Object getSwitch() 513 { 514 if (tail != null) 515 data.add(tail); 516 tail = null; 517 518 hasSwitch = true; 519 520 return data.get(data.size() - 1); 521 } 522 523 int mark() 524 { 525 if (tail != null) 526 data.add(tail); 527 tail = null; 528 529 return data.size(); 530 } 531 532 void moveChunk(Object topObject, int mark) 533 { 534 if (tail != null) 535 data.add(tail); 536 tail = null; 537 538 int top; 539 for (top = 0; top < mark; top++) { 540 if (data.get(top) == topObject) 541 break; 542 } 543 top++; 544 545 int here = data.size(); 546 547 for (int i = 0; i < here - mark; i++) { 548 Object chunk = data.remove(data.size() - 1); 549 data.add(top, chunk); 550 } 551 } 552 553 void writeCode(ParseClass cl) throws IOException 554 { 555 cl.print("public "); 556 557 if (returnType == null) 558 cl.print("ESBase "); 559 else if (returnType.getType() == Expr.TYPE_INTEGER) 560 cl.print("int "); 561 else 562 cl.print("ESBase "); 563 564 cl.print(name + "(Call _env, int _length"); 565 566 for (int i = 0; i < getFormalSize(); i++) { 567 Variable formal = (Variable) formals.get(i); 568 569 if (formal.getTypeExpr() instanceof TypeExpr) { 570 TypeExpr type = (TypeExpr) formal.getTypeExpr(); 571 572 if (type.getTypeName() != null) 573 cl.print(", " + type.getTypeName() + " " + formal.getId()); 574 } 575 } 576 cl.println(")"); 577 578 cl.println("throws Throwable"); 579 cl.println("{"); 580 cl.pushDepth(); 581 582 if (hasCall) 583 cl.println("Call _call = _env.getCall();"); 584 585 if (hasThis) 586 cl.println("ESObject _this = _env.getThis();"); 587 588 if (parent != null && functions != null && functions.size() > 0) { 589 needsArguments = true; 590 setNeedsScope(); 591 } 592 593 if (isEval) { 595 cl.println("ESObject _arg = _env.getEval();"); 596 } 597 else { 598 if (needsScope && parent != null) 599 cl.println("_env.fillScope();"); 600 601 if (needsArguments && parent != null) { 602 cl.print("ESObject _arg = _env.createArg("); 603 if (getFormalSize() > 0) 604 cl.print("_js._a_" + num); 605 else 606 cl.print("_js._a_null"); 607 cl.println(", _length);"); 608 } 609 } 610 611 printFormals(); 612 printLocalVariables(); 613 614 for (int i = 0; 616 needsArguments && functions != null && i < functions.size(); 617 i++) { 618 if (i == 0) 619 cl.println("ESClosure _closure;"); 620 621 Function fun = (Function) functions.get(i); 622 Variable var = (Variable) vars.get(fun.id); 623 624 if (! isGlobal && ! isEval && 625 var != null && ! var.isUsed() && ! useAllVariables) { 626 continue; 627 } 628 629 cl.print("_closure = new ESClosure("); 630 cl.printLiteral(fun.id); 631 cl.println(", _js, null, " + fun.num + ", _js._a_null, null);"); 632 cl.println("_closure.closure(_env);"); 633 634 if (! isEval && allowLocals && 635 var != null && var.isUsed() && var.isJavaLocal()) { 636 cl.println("ESBase " + fun.id + " = _closure;"); 637 continue; 638 } 639 else if (! isEval && parent != null) 640 cl.print("_arg.put("); 641 else 642 cl.print("_env.global.put("); 643 cl.printLiteral(fun.id); 644 cl.print(", _closure, "); 645 if (! isEval) 646 cl.print("ESBase.DONT_ENUM|ESBase.DONT_DELETE"); 647 else 648 cl.print("0"); 649 cl.println(");"); 650 } 651 652 for (int i = 0; i < iterCount; i++) 653 cl.println("java.util.Iterator iter" + i + ";"); 654 for (int i = 0; i < tempCount; i++) 655 cl.println("ESBase temp" + i + ";"); 656 if (needsStatementResults()) 657 cl.println("ESBase _val0 = ESBase.esUndefined;"); 658 for (int i = 1; i <= stmtTop; i++) 659 cl.println("ESBase _val" + i + " = ESBase.esUndefined;"); 660 if (hasSwitch) { 661 cl.println("int _switchcode;"); 662 cl.println("ESBase _switchtemp;"); 663 } 664 665 for (int i = 0; i < data.size(); i++) { 666 Object d = data.get(i); 667 if (d instanceof CharBuffer) 668 cl.print((CharBuffer) d); 669 else if (d instanceof Expr) { 670 Expr expr = (Expr) d; 671 expr.printExpr(); 673 } 674 } 675 676 if (tail != null) 677 cl.print(tail); 678 679 cl.popDepth(); 680 cl.println("}"); 681 } 682 683 void printFormals() 684 throws IOException 685 { 686 formal: 687 for (int i = 0; formals != null && i < formals.size(); i++) { 688 Variable formal = (Variable) formals.get(i); 689 690 if (funMap != null && funMap.get(formal.getId()) >= 0) 692 continue formal; 693 694 for (int j = i + 1; j < formals.size(); j++) { 696 if (formal.getId() == ((Variable) formals.get(j)).getId()) 697 continue formal; 698 } 699 700 if (! allowLocals) { 701 } 702 else if (formal.getTypeExpr() instanceof JavaTypeExpr) { 703 } 704 else if (formal.getType() != Expr.TYPE_INTEGER) { 705 cl.print("ESBase " + formal.getId()); 706 cl.println(" = _env.getArg(" + i + ", _length);"); 707 } 708 } 709 } 710 711 714 void printLocalVariables() 715 throws IOException 716 { 717 for (int i = 0; i < variables.size(); i++) { 718 Variable var = (Variable) variables.get(i); 719 720 if (funMap != null && funMap.get(var.getId()) >= 0) { 721 var.killLocal(); 722 continue; 723 } 724 725 if (var.isJavaGlobal()) { 726 } 728 else if ((! allowLocals || ! var.isJavaLocal()) && isGlobal()) { 729 cl.print("_env.global.setProperty("); 730 cl.printLiteral(var.getId()); 731 cl.println(", ESBase.esUndefined);"); 732 } 733 else if (! var.isUsed() && ! useAllVariables()) { 734 } 735 else if (! allowLocals || ! var.isJavaLocal()) { 736 if (isEval) { 737 cl.print("if (_arg.getProperty("); 738 cl.printLiteral(var.getId()); 739 cl.println(") == ESBase.esEmpty)"); 740 cl.print(" "); 741 } 742 if (! var.hasInit()) { 743 cl.print("_arg.put("); 744 cl.printLiteral(var.getId()); 745 cl.print(", ESBase.esUndefined, "); 746 if (! isEval) 747 cl.print("ESBase.DONT_ENUM|ESBase.DONT_DELETE"); 748 else 749 cl.print("0"); 750 cl.println(");"); 751 } 752 } 753 else if (var.getType() == Expr.TYPE_BOOLEAN) { 754 cl.println("boolean " + var.getId() + ";"); 755 if (! var.hasInit()) 756 cl.println(var.getId() + " = false;"); 757 } 758 else if (var.getType() == Expr.TYPE_INTEGER) { 759 cl.println("int " + var.getId() + ";"); 760 if (! var.hasInit()) 761 cl.println(var.getId() + " = 0;"); 762 } 763 else if (var.getType() == Expr.TYPE_NUMBER) { 764 cl.println("double " + var.getId() + ";"); 765 if (! var.hasInit()) 766 cl.println(var.getId() + " = Double.NaN;"); 767 } 768 else if (var.getType() == Expr.TYPE_STRING) { 769 cl.println("ESString " + var.getId() + ";"); 770 if (! var.hasInit()) 771 cl.println(var.getId() + " = null;"); 772 } 773 else if (var.getType() == Expr.TYPE_JAVA && 774 var.getTypeExpr() != null) { 775 TypeExpr type = (TypeExpr) var.getTypeExpr(); 776 777 cl.println(type.getTypeName() + " " + var.getId() + " = null;"); 778 } 779 else if (var.isLocal()) { 780 if (! var.hasInit()) 781 cl.println("ESBase " + var.getId() + " = ESBase.esUndefined;"); 782 else 783 cl.println("ESBase " + var.getId() + ";"); 784 } 785 else { 786 cl.print(" _env.global.setProperty("); 787 cl.printLiteral(var.getId()); 788 cl.println(", ESBase.esUndefined);"); 789 } 790 } 791 } 792 } 793 | Popular Tags |