001: /*
002: * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.es.parser;
030:
031: import com.caucho.es.ESBase;
032: import com.caucho.es.ESBoolean;
033: import com.caucho.es.ESException;
034: import com.caucho.es.ESId;
035: import com.caucho.es.ESNumber;
036:
037: import java.io.IOException;
038:
039: /**
040: * Expr is an intermediate form representing an expression.
041: */
042: class Expr {
043: protected final static int TYPE_UNKNOWN = 0;
044: protected final static int TYPE_ES = TYPE_UNKNOWN + 1;
045: protected final static int TYPE_STRING = TYPE_ES + 1;
046: protected final static int TYPE_NUMBER = TYPE_STRING + 1;
047: protected final static int TYPE_LONG = TYPE_NUMBER;
048: protected final static int TYPE_INTEGER = TYPE_LONG + 1;
049: protected final static int TYPE_BOOLEAN = TYPE_INTEGER + 1;
050:
051: protected final static int TYPE_JAVA = TYPE_BOOLEAN + 1;
052: protected final static int TYPE_VOID = TYPE_JAVA + 1;
053:
054: protected ParseClass cl;
055: protected Block block;
056: protected Function function;
057: protected int type;
058: protected Class javaType;
059: protected boolean isTop;
060: protected boolean noValue;
061:
062: private String filename;
063: private int line;
064: protected int withDepth;
065:
066: Expr(Block block) {
067: this .block = block;
068: this .withDepth = block.getWithDepth();
069: this .function = block.function;
070: this .cl = function.cl;
071: this .filename = block.getFilename();
072: this .line = block.getLine();
073:
074: type = TYPE_UNKNOWN;
075: }
076:
077: String getFilename() {
078: return filename;
079: }
080:
081: int getLine() {
082: return line;
083: }
084:
085: void killValue() {
086: noValue = true;
087: }
088:
089: void setUsed() {
090: getType();
091: }
092:
093: void setTop() {
094: noValue = true;
095: isTop = true;
096: }
097:
098: /**
099: * Returns the javascript type of the expression.
100: */
101: int getType() {
102: return type;
103: }
104:
105: Expr getTypeExpr() {
106: return null;
107: }
108:
109: /**
110: * Returns the Java class representing this type.
111: */
112: Class getJavaClass() {
113: if (javaType != null)
114: return javaType;
115:
116: Expr type = getTypeExpr();
117:
118: if (!(type instanceof TypeExpr)) {
119: switch (getType()) {
120: case TYPE_STRING:
121: return String.class;
122:
123: case TYPE_INTEGER:
124: return int.class;
125:
126: case TYPE_NUMBER:
127: return double.class;
128:
129: case TYPE_BOOLEAN:
130: return boolean.class;
131:
132: default:
133: return ESBase.class;
134: }
135: }
136:
137: TypeExpr javaType = (TypeExpr) type;
138:
139: return javaType.getJavaClass();
140: }
141:
142: boolean isSimple() {
143: return false;
144: }
145:
146: /**
147: * True if the type of this expression is easily converted to a number.
148: */
149: boolean isNumeric() {
150: int type = getType();
151:
152: return type >= TYPE_NUMBER && type <= TYPE_BOOLEAN;
153: }
154:
155: boolean isNum() {
156: int type = getType();
157:
158: return type == TYPE_NUMBER || type == TYPE_INTEGER;
159: }
160:
161: /**
162: * This expression will be used in a boolean context.
163: */
164: Expr setBoolean() {
165: return new BooleanExpr(block, this );
166: }
167:
168: Expr next(String iter, Expr lhs) throws ESException {
169: return lhs
170: .assign(new SpecialExpr(block, SpecialExpr.NEXT, iter));
171: }
172:
173: /**
174: * Gets the field of the current expr
175: */
176: Expr fieldReference(Expr expr) {
177: return new FieldExpr(block, this , expr);
178: }
179:
180: /**
181: * Gets the field of the current expr
182: */
183: Expr fieldReference(ESId id) throws ESException {
184: return new FieldExpr(block, this , new LiteralExpr(block, id));
185: }
186:
187: /**
188: * A unary op
189: */
190: Expr unaryOp(int op) {
191: return new UnaryExpr(block, this , op);
192: }
193:
194: /**
195: * A unary op
196: */
197: Expr doVoid() {
198: return new UnaryExpr(block, this , 'v');
199: }
200:
201: /**
202: * The typeof operator
203: */
204: Expr typeof() {
205: return new UnaryExpr(block, this , 't');
206: }
207:
208: /**
209: * The delete operator
210: */
211: Expr delete() throws ESException {
212: return BinaryExpr.create(block, this , new LiteralExpr(block,
213: ESBoolean.TRUE), ',');
214: }
215:
216: /**
217: * The assignment operator
218: */
219: Expr assign(Expr value) throws ESException {
220: throw error("illegal left-hand-side of assignment");
221: }
222:
223: CallExpr startCall() throws ESException {
224: return new CallExpr(block, this , null, false);
225: }
226:
227: CallExpr startNew() throws ESException {
228: return new CallExpr(block, this , null, true);
229: }
230:
231: /**
232: * Handle autoincrement
233: */
234: Expr prefix(int op) throws ESException {
235: return unaryOp('+').binaryOp(op, op,
236: new LiteralExpr(block, ESNumber.create(1.0)));
237: }
238:
239: /**
240: * Handle autoincrement
241: */
242: Expr postfix(int op) {
243: return unaryOp('+');
244: }
245:
246: /**
247: * A binary op
248: */
249: Expr binaryOp(int lex, int op, Expr rexpr) throws ESException {
250: setUsed();
251: rexpr.setUsed();
252:
253: if (lex != '=') {
254: switch (op) {
255: case '<':
256: case '>':
257: case Lexer.LEQ:
258: case Lexer.GEQ:
259: case Lexer.EQ:
260: case Lexer.NEQ:
261: case Lexer.STRICT_EQ:
262: case Lexer.STRICT_NEQ:
263: return BooleanBinaryExpr.create(block, this , rexpr, op);
264:
265: case '+':
266: return PlusExpr.create(block, this , rexpr);
267:
268: default:
269: return BinaryExpr.create(block, this , rexpr, op);
270: }
271: } else if (op == '=')
272: return assign(rexpr);
273:
274: else
275: return assign(binaryOp(op, op, rexpr));
276: }
277:
278: Expr cast(Expr castType) throws ESException {
279: return CastExpr.create(block, this , (TypeExpr) castType);
280: }
281:
282: /**
283: * The conditional ? : operation
284: */
285: Expr conditional(Expr mexpr, Expr rexpr) {
286: return new ConditionalExpr(block, this , mexpr, rexpr);
287: }
288:
289: void printExpr() throws IOException {
290: print();
291: }
292:
293: void print() throws IOException {
294: if (ESBase.class.isAssignableFrom(getJavaClass())
295: || this instanceof LiteralExpr) {
296: printImpl();
297:
298: if (isTop)
299: cl.println(";");
300: return;
301: }
302:
303: switch (getType()) {
304: case TYPE_NUMBER:
305: if (!noValue)
306: cl.print("ESNumber.create(");
307: printNumImpl();
308: if (!noValue)
309: cl.print(")");
310: break;
311:
312: case TYPE_INTEGER:
313: if (!noValue)
314: cl.print("ESNumber.create(");
315: printInt32Impl();
316: if (!noValue)
317: cl.print(")");
318: break;
319:
320: case TYPE_BOOLEAN:
321: if (!noValue)
322: cl.print("(");
323: printBooleanImpl();
324: if (!noValue)
325: cl.print("?ESBoolean.TRUE:ESBoolean.FALSE)");
326: break;
327:
328: case TYPE_STRING:
329: if (ESBase.class.isAssignableFrom(getJavaClass()))
330: printImpl();
331: else {
332: if (!noValue)
333: cl.print("ESString.create(");
334: printStringImpl();
335: if (!noValue)
336: cl.print(")");
337: }
338: break;
339:
340: case TYPE_JAVA:
341: if (!noValue)
342: cl.print("_env.wrap(");
343: printJavaImpl();
344: if (!noValue)
345: cl.print(")");
346: break;
347:
348: case TYPE_VOID:
349: if (!noValue)
350: cl.print("_env.wrap(");
351: printJavaImpl();
352: if (!noValue)
353: cl.print(")");
354: break;
355:
356: default:
357: printImpl();
358: }
359:
360: if (isTop)
361: cl.println(";");
362: }
363:
364: void printBoolean() throws IOException {
365: switch (getType()) {
366: case TYPE_NUMBER:
367: cl.print("(");
368: printNumImpl();
369: cl.print("!=0.0)");
370: break;
371:
372: case TYPE_INTEGER:
373: cl.print("(");
374: printInt32Impl();
375: cl.print("!=0)");
376: break;
377:
378: case TYPE_BOOLEAN:
379: printBooleanImpl();
380: break;
381:
382: case TYPE_JAVA:
383: cl.print("(");
384: printJava();
385: cl.print("!=null)");
386: break;
387:
388: default:
389: print();
390: cl.print(".toBoolean()");
391: }
392:
393: if (isTop)
394: cl.println(";");
395: }
396:
397: void printInt32() throws IOException {
398: switch (getType()) {
399: case TYPE_INTEGER:
400: printInt32Impl();
401: break;
402:
403: case TYPE_NUMBER:
404: cl.print("((int)");
405: printNumImpl();
406: cl.print(")");
407: break;
408:
409: case TYPE_BOOLEAN:
410: cl.print("(");
411: printBooleanImpl();
412: cl.print("?1:0)");
413: break;
414:
415: default:
416: printImpl();
417: cl.print(".toInt32()");
418: }
419: }
420:
421: void printInt64() throws IOException {
422: printInt32();
423: }
424:
425: void printNum() throws IOException {
426: switch (getType()) {
427: case TYPE_NUMBER:
428: printNumImpl();
429: break;
430:
431: case TYPE_INTEGER:
432: cl.print("((double)");
433: printInt32Impl();
434: cl.print(")");
435: break;
436:
437: case TYPE_BOOLEAN:
438: cl.print("(");
439: printBooleanImpl();
440: cl.print("?1.0:0.0)");
441: break;
442:
443: default:
444: printImpl();
445: cl.print(".toNum()");
446: }
447: }
448:
449: /**
450: * Prints the expression as a java object.
451: */
452: void printJava() throws IOException {
453: switch (getType()) {
454: case TYPE_INTEGER:
455: printInt32Impl();
456: break;
457:
458: case TYPE_BOOLEAN:
459: printBooleanImpl();
460: break;
461:
462: case TYPE_STRING:
463: printStringImpl();
464: break;
465:
466: case TYPE_NUMBER:
467: printNumImpl();
468: break;
469:
470: case TYPE_JAVA:
471: printJavaImpl();
472: break;
473:
474: default:
475: print();
476: cl.print(".toJavaObject()");
477: break;
478: }
479: }
480:
481: /**
482: * Prints a string value
483: */
484: void printStr() throws IOException {
485: print();
486: cl.print(".toStr()");
487: }
488:
489: void printJavaString() throws IOException {
490: switch (getType()) {
491: case TYPE_STRING:
492: if (this instanceof LiteralExpr) {
493: printStringImpl();
494: } else {
495: cl.print("String.valueOf(");
496: printStringImpl();
497: cl.print(")");
498: }
499: break;
500:
501: case TYPE_JAVA:
502: if (getJavaClass().equals(String.class))
503: printJavaImpl();
504: else {
505: cl.print("String.valueOf(");
506: printJavaImpl();
507: cl.print(")");
508: }
509: break;
510:
511: // JavaScript's double printing differs from Java's, so
512: // we need to convert to the JavaScript object.
513: default:
514: print();
515: cl.print(".toStr().toString()");
516: break;
517: }
518: }
519:
520: void printJavaClass(Class type) throws IOException {
521: if (type.isArray()) {
522: printJavaClass(type.getComponentType());
523: cl.print("[]");
524: } else
525: cl.print(type.getName());
526: }
527:
528: /**
529: * Print where the result is a string.
530: */
531: void printString() throws IOException {
532: switch (getType()) {
533: case TYPE_INTEGER:
534: printInt32Impl();
535: break;
536:
537: case TYPE_BOOLEAN:
538: printBooleanImpl();
539: break;
540:
541: case TYPE_STRING:
542: printStringImpl();
543: break;
544:
545: case TYPE_JAVA:
546: printJavaImpl();
547: break;
548:
549: // JavaScript's double printing differs from Java's, so
550: // we need to convert to the JavaScript object.
551: case TYPE_NUMBER:
552: default:
553: print();
554: cl.print(".valueOf()");
555: break;
556: }
557: }
558:
559: void printImpl() throws IOException {
560: throw new RuntimeException("" + this );
561: }
562:
563: void printBooleanImpl() throws IOException {
564: throw new RuntimeException("" + this );
565: }
566:
567: void printNumImpl() throws IOException {
568: throw new RuntimeException("" + this );
569: }
570:
571: void printInt32Impl() throws IOException {
572: throw new RuntimeException("" + this );
573: }
574:
575: void printInt64Impl() throws IOException {
576: throw new RuntimeException("" + this );
577: }
578:
579: void printStringImpl() throws IOException {
580: throw new RuntimeException("no string impl for " + getClass());
581: }
582:
583: void printJavaImpl() throws IOException {
584: throw new RuntimeException("" + this );
585: }
586:
587: void printLiteral(ESBase literal) throws IOException {
588: cl.printLiteral(literal);
589: }
590:
591: void exprStatement(Function fun) throws ESException {
592: }
593:
594: private ESException error(String msg) {
595: return block.error(msg);
596: }
597: }
|