KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > es > parser > Function


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

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 JavaDoc;
36 import java.util.ArrayList JavaDoc;
37 import java.util.HashMap JavaDoc;
38 import java.util.Iterator JavaDoc;
39
40 /**
41  * Function is an intermediate form representing an expression.
42  */

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 JavaDoc formals;
54   Expr returnType;
55   
56   ArrayList JavaDoc variables = new ArrayList JavaDoc();
57
58   // child closures
59
ArrayList JavaDoc functions;
60   private IntMap funMap;
61   
62
63   boolean isClass;
64   ESId classProto; // null for non-classes
65
Function constructor;
66
67   String JavaDoc 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 JavaDoc data = new ArrayList JavaDoc();
78   private HashMap JavaDoc vars = new HashMap JavaDoc();
79   CharBuffer tail;
80   private int iterCount;
81   private int tempCount;
82   private int stmtCount;
83   private int stmtTop;
84   private HashMap JavaDoc usedVars;
85   private boolean isGlobal;
86   // True if an arguments variable needs to be created. eval, closures,
87
// the arguments variable and "with" will set this.
88
private boolean needsArguments;
89   private boolean needsStatementResults;
90   // True if any variable can be used even if not explicitly referenced
91
// e.g. if the "arguments" variable is used.
92
private boolean useAllVariables;
93   // True if the function contains an eval
94
private boolean isEval;
95   // True if the function contains a switch
96
private boolean hasSwitch;
97
98   Function(ParseClass cl, Function parent,
99            String JavaDoc 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 JavaDoc 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   /**
202    * Force all unassigned variables to become object vars.
203    */

204   void setVars()
205   {
206     Iterator JavaDoc 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 JavaDoc();
282         fun.usedVars.put(name, name);
283       }
284     }
285   }
286
287   /**
288    * Returns true if the variable is declared.
289    */

290   boolean hasVar(ESId name)
291   {
292     return vars.get(name) != null;
293   }
294   
295   /**
296    * Returns a new variable.
297    */

298   IdExpr newVar(Block block, ESId name)
299   {
300     return newVar(block, name, null);
301   }
302   
303   /**
304    * Returns a new variable.
305    */

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   /**
332    * Add a variable to the function. If the function is the global
333    * function, add it to the class.
334    */

335   void addVariable(Block block, ESId id, Expr type)
336   {
337     if (variables == null)
338       variables = new ArrayList JavaDoc();
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       // Only add global variables if they're declared, not if defined
349
// by use.
350
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 JavaDoc 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 JavaDoc();
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 JavaDoc();
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 JavaDoc value)
467   {
468     if (tail == null)
469       tail = CharBuffer.allocate();
470     tail.append(String.valueOf(value));
471   }
472
473   void println(String JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc 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 JavaDoc chunk = data.remove(data.size() - 1);
549       data.add(top, chunk);
550     }
551   }
552
553   void writeCode(ParseClass cl) throws IOException JavaDoc
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     // Eval just uses the calling scope
594
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     // do closures
615
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 JavaDoc 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         //cl.setLine(expr.getFilename(), expr.getLine());
672
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 JavaDoc
685   {
686     formal:
687     for (int i = 0; formals != null && i < formals.size(); i++) {
688       Variable formal = (Variable) formals.get(i);
689       
690       // Functions have priority
691
if (funMap != null && funMap.get(formal.getId()) >= 0)
692         continue formal;
693
694       // Duplicate formals use the last one
695
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   /**
712    * Initializes the local variables for a function.
713    */

714   void printLocalVariables()
715     throws IOException JavaDoc
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         // already initialized
727
}
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