Source Code Cross Referenced for CodeGenerator.java in  » Ajax » Laszlo-4.0.10 » org » openlaszlo » sc » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Ajax » Laszlo 4.0.10 » org.openlaszlo.sc 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        /* -*- mode: Java; c-basic-offset: 2; -*- */
0002:
0003:        /***
0004:         * CodeGenerator.java
0005:         * Author: Oliver Steele, P T Withington
0006:         * Description: JavaScript -> SWF bytecode compiler
0007:         */package org.openlaszlo.sc;
0008:
0009:        import java.io.*;
0010:        import java.util.*;
0011:        import java.nio.ByteBuffer;
0012:
0013:        import org.openlaszlo.sc.parser.*;
0014:        import org.openlaszlo.sc.Instructions;
0015:        import org.openlaszlo.sc.Instructions.Instruction;
0016:
0017:        import org.openlaszlo.cache.PersistentMap;
0018:
0019:        // The code generator dispatches a node whose class is named ASTName to
0020:        // a method visitName, passing the node, a context, and the node's
0021:        // children as arguments.  The context for a statement visitor is a
0022:        // TranslationContext, defined above.  The context for an expression
0023:        // visitor is a boolean value, that is true iff the value of the
0024:        // expression is used.  The return value of a statement visitor is
0025:        // ignored.  The return value of an expression visitor is true iff it
0026:        // generated code that did NOT leave a value on the stack.  (This is so
0027:        // that an expression visitor that ignores its context need do nothing
0028:        // special to indicate that it ignored it: the default return value of
0029:        // null signals this.)
0030:        //
0031:        // Methods of the form visitName are AST node visitors, and follow the
0032:        // protocol described above.  Methods of the form translateName are
0033:        // helper functions for the visitors, and have arbitrary parameter
0034:        // lists and return values.
0035:
0036:        // TODO: [2006-01-17 ptw] Remove some day
0037:        // Replace instruction subsequences by a BLOB instruction that
0038:        // represents the same bytes.  By default, the BLOB instructions are
0039:        // separated by PUSH's (which depend on the constant pool), and
0040:        // branches and targets (since they can't be resolved until the size of
0041:        // the PUSH instructions is known).  When noConstantPool=true, PUSH's
0042:        // are compiled against a null constant pool, and branches and targets
0043:        // are compiled, so the instructions combine to a single BLOB.
0044:        // public void combineInstructions(instrsIn, noConstantPool=false) {
0045:        //     instrsOut = [];
0046:        //     buffer = ByteBuffer.allocate(64000);
0047:        //     public void flush(instrsOut=instrsOut,buffer=buffer) {
0048:        //         if (buffer.position()) {
0049:        //             import jarray;
0050:        //             bytes = jarray.zeros(buffer.position(), "b");
0051:        //             buffer.flip();
0052:        //             buffer.get(bytes);
0053:        //             buffer.clear();
0054:        //             instrsOut.append(BLOB("bytes", bytes));
0055:        //     for (instr in instrsIn) {
0056:        //         if (noConstantPool || instr.isPush || instr.isLabel || instr.hasTarget) {
0057:        //             flush();
0058:        //             instrsOut.append(instr);
0059:        //         } else {
0060:        //             instr.writeBytes(buffer, null);
0061:        //     flush();
0062:        //     return instrsOut;
0063:        // }
0064:
0065:        public class CodeGenerator extends CommonGenerator implements 
0066:                Translator {
0067:
0068:            protected void setRuntime(String runtime) {
0069:                assert org.openlaszlo.compiler.Compiler.SWF_RUNTIMES
0070:                        .contains(runtime) : "unknown runtime " + runtime;
0071:                Instructions.setRuntime(runtime);
0072:            }
0073:
0074:            public SimpleNode translate(SimpleNode program) {
0075:                // Make a new collector each time, since the old one may be
0076:                // referenced by the instruction cache
0077:                this .collector = new InstructionCollector(this .options
0078:                        .getBoolean(Compiler.DISABLE_CONSTANT_POOL), true);
0079:                translateInternal(program, "b", true);
0080:                return program;
0081:            }
0082:
0083:            public String newLabel(SimpleNode node) {
0084:                return newLabel(node, null);
0085:            }
0086:
0087:            public String newLabel(SimpleNode node, String name) {
0088:                return collector.newLabel((name != null ? name + ":" : "")
0089:                        + node.filename + ":" + node.beginLine);
0090:            }
0091:
0092:            static LessHalfAssedHashMap XfixInstrs = new LessHalfAssedHashMap();
0093:            static {
0094:                XfixInstrs.put(ParserConstants.INCR, Instructions.Increment);
0095:                XfixInstrs.put(ParserConstants.DECR, Instructions.Decrement);
0096:            };
0097:
0098:            static LessHalfAssedHashMap UnopInstrs = new LessHalfAssedHashMap();
0099:            static {
0100:                UnopInstrs.put(ParserConstants.PLUS, new Instruction[] {});
0101:                UnopInstrs.put(ParserConstants.MINUS, new Instruction[] {
0102:                        Instructions.PUSH.make(-1), Instructions.MULTIPLY });
0103:                UnopInstrs.put(ParserConstants.BANG,
0104:                        new Instruction[] { Instructions.NOT });
0105:                UnopInstrs.put(ParserConstants.TILDE, new Instruction[] {
0106:                        Instructions.PUSH.make(-1), Instructions.BitwiseXor });
0107:                UnopInstrs.put(ParserConstants.TYPEOF,
0108:                        new Instruction[] { Instructions.TypeOf });
0109:                UnopInstrs.put(ParserConstants.VOID, new Instruction[] {
0110:                        Instructions.POP,
0111:                        Instructions.PUSH.make(Values.Undefined) });
0112:            };
0113:
0114:            // Binop translation for swf6.  visitBinaryExpression handles swf5
0115:            // exceptions.
0116:            // TODO: [2006-06-17 ptw] Remove swf6 kludges now that we only
0117:            // support swf7 and above
0118:            static LessHalfAssedHashMap BinopInstrs = new LessHalfAssedHashMap();
0119:            static {
0120:                BinopInstrs.put(ParserConstants.PLUS,
0121:                        new Instruction[] { Instructions.ADD });
0122:                BinopInstrs.put(ParserConstants.MINUS,
0123:                        new Instruction[] { Instructions.SUBTRACT });
0124:                BinopInstrs.put(ParserConstants.STAR,
0125:                        new Instruction[] { Instructions.MULTIPLY });
0126:                BinopInstrs.put(ParserConstants.SLASH,
0127:                        new Instruction[] { Instructions.DIVIDE });
0128:                BinopInstrs.put(ParserConstants.REM,
0129:                        new Instruction[] { Instructions.MODULO });
0130:                BinopInstrs.put(ParserConstants.BIT_AND,
0131:                        new Instruction[] { Instructions.BitwiseAnd });
0132:                BinopInstrs.put(ParserConstants.BIT_OR,
0133:                        new Instruction[] { Instructions.BitwiseOr });
0134:                BinopInstrs.put(ParserConstants.XOR,
0135:                        new Instruction[] { Instructions.BitwiseXor });
0136:                BinopInstrs.put(ParserConstants.LSHIFT,
0137:                        new Instruction[] { Instructions.ShiftLeft });
0138:                BinopInstrs.put(ParserConstants.RSIGNEDSHIFT,
0139:                        new Instruction[] { Instructions.ShiftRight });
0140:                BinopInstrs.put(ParserConstants.RUNSIGNEDSHIFT,
0141:                        new Instruction[] { Instructions.UShiftRight });
0142:                // swf6 returns undefined for comparisons with NaN, it
0143:                // is supposed to return false (note that you cannot
0144:                // eliminate one NOT by inverting the sense of the
0145:                // comparison
0146:                BinopInstrs.put(ParserConstants.LT, new Instruction[] {
0147:                        Instructions.LessThan, Instructions.NOT,
0148:                        Instructions.NOT });
0149:                BinopInstrs.put(ParserConstants.GT, new Instruction[] {
0150:                        Instructions.GreaterThan, Instructions.NOT,
0151:                        Instructions.NOT });
0152:                // swf6 does not have GE or LE, but inverting the
0153:                // complement operator does not work for NaN ordering
0154:                // Luckily, LogicalOr coerces undefined to false, so we
0155:                // don't have to play the NOT NOT trick above
0156:                BinopInstrs.put(ParserConstants.LE, new Instruction[] {
0157:                        Instructions.SetRegister.make(0), // a b
0158:                        Instructions.POP, // a
0159:                        Instructions.DUP, // a a
0160:                        Instructions.PUSH.make(Values.Register(0)), // a a b
0161:                        Instructions.EQUALS, // a a==b
0162:                        Instructions.SWAP, // a==b a
0163:                        Instructions.PUSH.make(Values.Register(0)), // a==b a b
0164:                        Instructions.LessThan, // a==b a<b
0165:                        Instructions.LogicalOr // a==b||a<b
0166:                        });
0167:                BinopInstrs.put(ParserConstants.GE, new Instruction[] {
0168:                        Instructions.SetRegister.make(0), // a b
0169:                        Instructions.POP, // a
0170:                        Instructions.DUP, // a a
0171:                        Instructions.PUSH.make(Values.Register(0)), // a a b
0172:                        Instructions.EQUALS, // a a==b
0173:                        Instructions.SWAP, // a==b a
0174:                        Instructions.PUSH.make(Values.Register(0)), // a==b a b
0175:                        Instructions.GreaterThan, // a==b a>b
0176:                        Instructions.LogicalOr // a==b||a>b
0177:                        });
0178:                BinopInstrs.put(ParserConstants.EQ,
0179:                        new Instruction[] { Instructions.EQUALS });
0180:                BinopInstrs.put(ParserConstants.SEQ,
0181:                        new Instruction[] { Instructions.StrictEquals });
0182:                // swf6 does not have NE or SNE either, but inverting
0183:                // the complement is correct for NaN
0184:                BinopInstrs.put(ParserConstants.NE, new Instruction[] {
0185:                        Instructions.EQUALS, Instructions.NOT });
0186:                BinopInstrs.put(ParserConstants.SNE, new Instruction[] {
0187:                        Instructions.StrictEquals, Instructions.NOT });
0188:                BinopInstrs.put(ParserConstants.INSTANCEOF,
0189:                        new Instruction[] { Instructions.InstanceOf });
0190:                // Approximate a in b as b.a =! void 0
0191:                BinopInstrs.put(ParserConstants.IN, new Instruction[] {
0192:                        Instructions.SWAP, Instructions.GetMember,
0193:                        Instructions.PUSH.make(Values.Undefined),
0194:                        Instructions.StrictEquals, Instructions.NOT });
0195:            };
0196:
0197:            static LessHalfAssedHashMap AssignOpTable = new LessHalfAssedHashMap();
0198:            static {
0199:                AssignOpTable.put(ParserConstants.PLUSASSIGN,
0200:                        ParserConstants.PLUS);
0201:                AssignOpTable.put(ParserConstants.MINUSASSIGN,
0202:                        ParserConstants.MINUS);
0203:                AssignOpTable.put(ParserConstants.STARASSIGN,
0204:                        ParserConstants.STAR);
0205:                AssignOpTable.put(ParserConstants.SLASHASSIGN,
0206:                        ParserConstants.SLASH);
0207:                AssignOpTable.put(ParserConstants.ANDASSIGN,
0208:                        ParserConstants.BIT_AND);
0209:                AssignOpTable.put(ParserConstants.ORASSIGN,
0210:                        ParserConstants.BIT_OR);
0211:                AssignOpTable.put(ParserConstants.XORASSIGN,
0212:                        ParserConstants.XOR);
0213:                AssignOpTable.put(ParserConstants.REMASSIGN,
0214:                        ParserConstants.REM);
0215:                AssignOpTable.put(ParserConstants.LSHIFTASSIGN,
0216:                        ParserConstants.LSHIFT);
0217:                AssignOpTable.put(ParserConstants.RSIGNEDSHIFTASSIGN,
0218:                        ParserConstants.RSIGNEDSHIFT);
0219:                AssignOpTable.put(ParserConstants.RUNSIGNEDSHIFTASSIGN,
0220:                        ParserConstants.RUNSIGNEDSHIFT);
0221:            };
0222:
0223:            // Code to meter a function call.  If name is set, uses that,
0224:            // otherwise uses arguments.callee.name.  This code must be appended
0225:            // to the function prefix or suffix, as appropriate
0226:            SimpleNode[] meterFunctionEvent(SimpleNode node, String event,
0227:                    String name) {
0228:                String getname;
0229:                if (name != null) {
0230:                    getname = "'" + name + "'";
0231:                } else {
0232:                    getname = "arguments.callee.name";
0233:                }
0234:
0235:                // Note _root.$lzprofiler can be undedefined to disable profiling
0236:                // at run time.
0237:
0238:                // N.B., According to the Javascript spec, getTime() returns
0239:                // the time in milliseconds, but we have observed that the
0240:                // Flash player on some platforms tries to be accurate to
0241:                // microseconds (by including fractional milliseconds).  On
0242:                // other platforms, the time is not even accurate to
0243:                // milliseconds, hence the kludge to manually increment the
0244:                // clock to create a monotonic ordering.
0245:
0246:                // The choice of 0.01 to increment by is based on the
0247:                // observation that when floats are used as member names in an
0248:                // object they are coerced to strings with only 15 significant
0249:                // digits.  This should suffice for the next (10^13)-1
0250:                // microseconds (about 300 years).
0251:
0252:                // TODO [2005-05016 ptw] (LPP-350) $flasm can clobber registers, so
0253:                // we have to refresh then for each event
0254:                String code = "" + "{"
0255:                        + "\n#pragma 'warnUndefinedReferences=false'\n"
0256:                        + "var $lzsc$lzp = _root['$lzprofiler'];"
0257:                        + "if ($lzsc$lzp) {"
0258:                        + "var $lzsc$tick = $lzsc$lzp.tick;"
0259:                        + "var $lzsc$now = (new Date).getTime();"
0260:                        + "if ($lzsc$tick >= $lzsc$now) {"
0261:                        + "$lzsc$now = $lzsc$tick + 0.0078125;" + "}"
0262:                        + "$lzsc$lzp.tick = $lzsc$now;" + "$lzsc$lzp." + event
0263:                        + "[$lzsc$now] = " + getname + ";" + "}" + "}" + "";
0264:                return (new Compiler.Parser()).parse(code).getChildren();
0265:            }
0266:
0267:            // Only used by warning generator, hence not metered.
0268:            // FIXME: [2006-01-17 ptw] Regression compatibility Object -> String
0269:            void report(String reportMethod, SimpleNode node, Object message) {
0270:                collector.push(message);
0271:                collector.push(node.beginLine);
0272:                collector.push(node.filename);
0273:                collector.push(3);
0274:                collector.push(reportMethod);
0275:                collector.emit(Instructions.CallFunction);
0276:            }
0277:
0278:            // Only used by warning generator, hence not metered.
0279:            // FIXME: [2006-01-17 ptw] Regression compatibility Object -> String
0280:            void report(String reportMethod, SimpleNode node, Object message,
0281:                    Instruction inst) {
0282:                // the dup is already emitted, this is a kludge
0283:                assert Instructions.DUP.equals(inst);
0284:                collector.push(message);
0285:                collector.push(node.beginLine);
0286:                collector.push(node.filename);
0287:                collector.push(4);
0288:                collector.push(reportMethod);
0289:                collector.emit(Instructions.CallFunction);
0290:            }
0291:
0292:            // Emits code to check that a function is defined.  If reference is
0293:            // set, expects the function reference to be at the top of the stack
0294:            // when called, otherwise expects the function object.
0295:            // TODO: [2006-01-04 ptw] Rewrite as a source transform
0296:            void checkUndefinedFunction(SimpleNode node, String reference) {
0297:                if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)
0298:                        && node.filename != null) {
0299:                    String label = newLabel(node);
0300:                    collector.emit(Instructions.DUP); // ref ref
0301:                    // Get the value of a function reference
0302:                    if (reference != null) {
0303:                        collector.emit(Instructions.GetVariable); // ref val
0304:                    }
0305:                    collector.emit(Instructions.DUP); // ref val val
0306:                    collector.emit(Instructions.TypeOf); // ref val type
0307:                    collector.push("function"); // ref val type "function"
0308:                    collector.emit(Instructions.StringEqual); // ref val type=="function"
0309:                    collector.emit(Instructions.BranchIfTrue.make(label));
0310:                    // FIXME: [2006-01-17 ptw] Regression compatibility: 0 -> ""
0311:                    report("$reportNotFunction", node,
0312:                            reference != null ? (Object) reference
0313:                                    : (Object) (new Integer(0)),
0314:                            Instructions.DUP);
0315:                    collector.emit(Instructions.LABEL.make(label));
0316:                    collector.emit(Instructions.POP); // pop error return
0317:                }
0318:            }
0319:
0320:            // Emits code to check that an object method is defined.  Expects the
0321:            // object to be at the top of stack when called and does a trial
0322:            // GetMember on methodName to verify that it is a function.  Object is
0323:            // left on the stack.
0324:            // TODO: [2006-01-04 ptw] Rewrite as a source transform
0325:            void checkUndefinedMethod(SimpleNode node, String methodName) {
0326:                if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)
0327:                        && node.filename != null) {
0328:                    // Check that object is not undefined
0329:                    String isUndefined = newLabel(node); // stack: object
0330:                    collector.emit(Instructions.DUP); // stack: object, object
0331:                    collector.emit(Instructions.TypeOf); // stack: object, TypeOf(object)
0332:                    collector.push("undefined"); // stack object, TypeOf(object), "undefined"
0333:                    collector.emit(Instructions.EQUALS); //  stack: object, TypeOf(object) == "undefined"
0334:                    collector.emit(Instructions.BranchIfTrue.make(isUndefined)); // stack: object
0335:                    // Check that property is a function (i.e., it is a method)
0336:                    String isMethod = newLabel(node);
0337:                    collector.emit(Instructions.DUP); // stack: object, object
0338:                    collector.push(methodName); // stack: object, object, method
0339:                    collector.emit(Instructions.GetMember); // stack: object, object.method
0340:                    collector.emit(Instructions.DUP); // stack object, object.method, object.method
0341:                    collector.emit(Instructions.TypeOf); // stack object, object.method, TypeOf(object.method)
0342:                    collector.push("function"); // stack object, object.method, TypeOf(object.method), "function"
0343:                    collector.emit(Instructions.EQUALS); // stack object, object.method, TypeOf(object.method) == "function"
0344:                    collector.emit(Instructions.BranchIfTrue.make(isMethod)); // stack object, object.method
0345:                    report("$reportUndefinedMethod", node, methodName,
0346:                            Instructions.DUP); // stack: object, null
0347:                    collector.emit(Instructions.BRANCH.make(isMethod));
0348:                    collector.emit(Instructions.LABEL.make(isUndefined)); // stack: object
0349:                    report("$reportUndefinedObjectProperty", node, methodName); // stack: object, null
0350:                    collector.emit(Instructions.LABEL.make(isMethod));
0351:                    collector.emit(Instructions.POP); // stack: object
0352:                }
0353:            }
0354:
0355:            void translateInternal(SimpleNode program, String cpass, boolean top) {
0356:                assert program instanceof  ASTProgram;
0357:                this .context = new TranslationContext(ASTProgram.class, null);
0358:                visitProgram(program, program.getChildren(), cpass, top);
0359:            }
0360:
0361:            String prevStatFile = null;
0362:            int prevStatLine = -1;
0363:
0364:            void showStats(SimpleNode node) {
0365:                if (!options.getBoolean(Compiler.INSTR_STATS)) {
0366:                    return;
0367:                }
0368:                String statFile;
0369:                int statLine;
0370:                if (node != null) {
0371:                    statFile = node.filename;
0372:                    statLine = node.beginLine;
0373:                } else if (prevStatFile != null) {
0374:                    statFile = prevStatFile;
0375:                    statLine = prevStatLine + 1;
0376:                } else {
0377:                    return;
0378:                }
0379:                if (prevStatFile.equals(statFile) && prevStatLine == statLine) {
0380:                    return;
0381:                }
0382:                collector.emit(Instructions.CHECKPOINT.make(statFile + ":"
0383:                        + statLine));
0384:                prevStatFile = statFile;
0385:                prevStatLine = statLine;
0386:            }
0387:
0388:            public SimpleNode visitProgram(SimpleNode node,
0389:                    SimpleNode[] directives, String cpass) {
0390:                return visitProgram(node, directives, cpass, false);
0391:            }
0392:
0393:            public SimpleNode visitProgram(SimpleNode node,
0394:                    SimpleNode[] directives, String cpass, boolean top) {
0395:                // cpass is "b"oth, 1, or 2
0396:                assert "b".equals(cpass) || "1".equals(cpass)
0397:                        || "2".equals(cpass) : "bad pass: " + cpass;
0398:                if ("b".equals(cpass)) {
0399:                    visitProgram(node, directives, "1", top);
0400:                    // Everything is done in one pass for now.
0401:                    //       visitProgram(node, directives, "2", top);
0402:                    return node;
0403:                }
0404:                if ("1".equals(cpass) && top &&
0405:                // Here this means 'compiling the LFC' we only want to emit
0406:                        // the constants into the LFC
0407:                        // FIXME: There needs to be a way that the object writer
0408:                        // ensures that the constants the LZX is compiled with are the
0409:                        // same ones as are set in the LFC it is linked to
0410:                        options
0411:                                .getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY)) {
0412:                    // emit compile-time contants to runtime
0413:                    Map constants = (Map) options
0414:                            .get(Compiler.COMPILE_TIME_CONSTANTS);
0415:                    if (constants != null) {
0416:                        for (Iterator i = constants.entrySet().iterator(); i
0417:                                .hasNext();) {
0418:                            Map.Entry entry = (Map.Entry) i.next();
0419:                            collector.push(entry.getKey());
0420:                            collector.push(entry.getValue());
0421:                            collector.emit(Instructions.VarEquals);
0422:                        }
0423:                    }
0424:                }
0425:                int index = 0;
0426:                int len = directives.length;
0427:                while (index < len) {
0428:                    SimpleNode directive = directives[index];
0429:                    index += 1;
0430:                    SimpleNode[] children = directive.getChildren();
0431:                    if (directive instanceof  ASTDirectiveBlock) {
0432:                        Compiler.OptionMap savedOptions = options;
0433:                        try {
0434:                            options = options.copy();
0435:                            visitProgram(directive, children, cpass);
0436:                        } finally {
0437:                            options = savedOptions;
0438:                        }
0439:                        continue;
0440:                    } else if (directive instanceof  ASTIfDirective) {
0441:                        if (!options
0442:                                .getBoolean(Compiler.CONDITIONAL_COMPILATION)) {
0443:                            // TBD: different type; change to CONDITIONALS
0444:                            throw new CompilerError("`if` at top level");
0445:                        }
0446:                        Boolean value = evaluateCompileTimeConditional(directive
0447:                                .get(0));
0448:                        if (value == null) {
0449:                            throw new CompilerError(
0450:                                    "undefined compile-time conditional "
0451:                                            + Compiler.nodeString(directive
0452:                                                    .get(0)));
0453:                        }
0454:                        if (value.booleanValue()) {
0455:                            visitProgram(directive, directive.get(1)
0456:                                    .getChildren(), cpass);
0457:                        } else if (directive.size() > 2) {
0458:                            visitProgram(directive, directive.get(2)
0459:                                    .getChildren(), cpass);
0460:                        }
0461:                        continue;
0462:                    } else if (directive instanceof  ASTIncludeDirective) {
0463:                        // Disabled by default, since it isn't supported in the
0464:                        // product.  (It doesn't go through the compilation
0465:                        // manager for dependency tracking.)
0466:                        if (!options.getBoolean(Compiler.INCLUDES)) {
0467:                            throw new UnimplementedError(
0468:                                    "unimplemented: #include", directive);
0469:                        }
0470:                        String userfname = (String) ((ASTLiteral) directive
0471:                                .get(0)).getValue();
0472:                        translateInclude(userfname, cpass);
0473:                        continue;
0474:                    } else if (directive instanceof  ASTPragmaDirective) {
0475:                        visitPragmaDirective(directive, directive.getChildren());
0476:                        continue;
0477:                    }
0478:                    if ("1".equals(cpass)) {
0479:                        // Function, class, and top-level expressions are processed in pass 1
0480:                        if (directive instanceof  ASTFunctionDeclaration) {
0481:                            visitStatement(directive);
0482:                        } else if (directive instanceof  ASTClassDefinition) {
0483:                            visitClassDefinition(directive, directive
0484:                                    .getChildren());
0485:                        } else if (directive instanceof  ASTModifiedDefinition) {
0486:                            visitModifiedDefinition(directive, directive
0487:                                    .getChildren());
0488:                        } else if (directive instanceof  ASTStatement) {
0489:                            // Statements are processed in pass 1 for now
0490:                            visitStatement(directive);
0491:                        } else {
0492:                            visitExpression(directive, false);
0493:                        }
0494:                    }
0495:                    if ("2".equals(cpass)) {
0496:                        // There is no pass 2 any more
0497:                        assert false : "bad pass " + cpass;
0498:                    }
0499:                }
0500:                showStats(node);
0501:                return node;
0502:            }
0503:
0504:            public SimpleNode visitTryStatement(SimpleNode node,
0505:                    SimpleNode[] children) {
0506:                SimpleNode block = children[0];
0507:                int len = children.length;
0508:                assert len == 2 || len == 3;
0509:                SimpleNode catchNode = null;
0510:                SimpleNode finallyNode = null;
0511:                int flags = 0;
0512:
0513:                if (len == 2) {
0514:                    // Could be catch or finally clause
0515:                    if (children[1] instanceof  ASTCatchClause) {
0516:                        catchNode = children[1];
0517:                    } else {
0518:                        finallyNode = children[1];
0519:                    }
0520:                } else {
0521:                    catchNode = children[1];
0522:                    finallyNode = children[2];
0523:                }
0524:
0525:                String catchVarName = "";
0526:
0527:                // For catch and finally, reach down to get
0528:                // the target node to visit.
0529:                //
0530:                if (catchNode != null) {
0531:                    SimpleNode[] catchchildren = catchNode.getChildren();
0532:                    SimpleNode id = catchchildren[0];
0533:                    assert id instanceof  ASTIdentifier;
0534:                    catchVarName = ((ASTIdentifier) id).getName();
0535:                    catchNode = catchchildren[1];
0536:                    flags |= Instructions.TryInstruction.FLAGS_HAS_CATCH;
0537:                }
0538:                if (finallyNode != null) {
0539:                    finallyNode = finallyNode.getChildren()[0];
0540:                    flags |= Instructions.TryInstruction.FLAGS_HAS_FINALLY;
0541:                }
0542:
0543:                // Try statement code looks like this in the general case:
0544:                //
0545:                //       try size0, size1, size2, 'varname'
0546:                //     label0:
0547:                //       ...try-block...
0548:                //       branch label2:
0549:                //     label1:
0550:                //       ...catch-block...
0551:                //     label2:
0552:                //       ...finally-block...
0553:                //     label3:
0554:                //
0555:                // where sizeN is the size of the code block between labelN and labelN+1.
0556:                // either catch or finally blocks may be missing.  Whether or not
0557:                // they are missing, we push out all the labels, it just makes it
0558:                // easier to calculate the block sizes.
0559:
0560:                ArrayList code = new ArrayList();
0561:
0562:                // The first six args are 3 pairs of labels to represent the size of
0563:                // each code block, e.g. label1 - label0 => size0
0564:                Object[] tryargs = { new Integer(1), new Integer(0), // label1 - label0
0565:                        new Integer(2), new Integer(1), // label2 - label1
0566:                        new Integer(3), new Integer(2), // label3 - label2
0567:                        catchVarName, new Integer(flags) };
0568:                code.add(Instructions.TRY.make(tryargs));
0569:                code.add(new Integer(0));
0570:                code.add(block);
0571:                if (catchNode != null) // if catch is missing, no need for branch.
0572:                    code.add(Instructions.BRANCH.make(2));
0573:                code.add(new Integer(1));
0574:                if (catchNode != null)
0575:                    code.add(catchNode);
0576:                code.add(new Integer(2));
0577:                if (finallyNode != null)
0578:                    code.add(finallyNode);
0579:                code.add(new Integer(3));
0580:
0581:                translateControlStructure(node, code.toArray());
0582:
0583:                return node;
0584:            }
0585:
0586:            public SimpleNode visitThrowStatement(SimpleNode node,
0587:                    SimpleNode[] children) {
0588:                assert children.length == 1 : "throw statement missing expression";
0589:                SimpleNode expr = children[0];
0590:
0591:                visitExpression(expr);
0592:                collector.emit(Instructions.THROW);
0593:                return node;
0594:            }
0595:
0596:            SimpleNode translateInclude(String userfname, String cpass) {
0597:
0598:                if (Compiler.CachedInstructions == null) {
0599:                    Compiler.CachedInstructions = new ScriptCompilerCache();
0600:                }
0601:
0602:                File file = includeNameToFile(userfname);
0603:                String source = includeFileToSourceString(file, userfname);
0604:
0605:                try {
0606:                    String optionsKey = getCodeGenerationOptionsKey(Collections
0607:                            .singletonList(
0608:                            // The constant pool isn't cached, so it doesn't affect code
0609:                            // generation so far as the cache is concerned.
0610:                            Compiler.DISABLE_CONSTANT_POOL));
0611:                    // If these could be omitted from the key for files that didn't
0612:                    // reference them, then the cache could be shared between krank
0613:                    // and krank debug.  (The other builds differ either on OBFUSCATE,
0614:                    // RUNTIME, NAMEFUNCTIONS, or PROFILE, so there isn't any other
0615:                    // possible sharing.)
0616:                    String instrsKey = file.getAbsolutePath() + cpass;
0617:                    // Only cache on file and pass, to keep cache size resonable,
0618:                    // but check against optionsKey
0619:                    String instrsChecksum = "" + file.lastModified()
0620:                            + optionsKey; // source;
0621:                    List instrs = null;
0622:                    if (options.getBoolean(Compiler.CACHE_COMPILES)) {
0623:                        instrs = (List) Compiler.CachedInstructions.get(
0624:                                instrsKey, instrsChecksum);
0625:                    }
0626:                    if ((instrs != null)
0627:                            && (!options.getBoolean(Compiler.VALIDATE_CACHES))) {
0628:                        collector.appendInstructions(instrs);
0629:                    } else {
0630:                        ParseResult result = parseFile(file, userfname, source);
0631:                        int startpos = collector.size();
0632:                        if (false && options.getBoolean(Compiler.PROGRESS)) {
0633:                            System.err.println("Translating " + userfname
0634:                                    + " (pass " + cpass + ")...");
0635:                        }
0636:                        translateInternal(result.parse, cpass, false);
0637:                        if ((!result.hasIncludes)) { // && collector.size() != startpos
0638:                            assert (!collector.constantsGenerated);
0639:                            // Copy for cache
0640:                            List realinstrs = new ArrayList(collector.subList(
0641:                                    startpos, collector.size()));
0642:                            if ((instrs != null)
0643:                                    && options
0644:                                            .getBoolean(Compiler.VALIDATE_CACHES)) {
0645:                                if ((!realinstrs.equals(instrs))) {
0646:                                    System.err.println("Bad instr cache for "
0647:                                            + instrsKey + ": " + instrs
0648:                                            + " != " + realinstrs);
0649:                                }
0650:                            }
0651:                            // The following line only speeds up buildlfc when
0652:                            // noConstantPool=true, which produces vastly
0653:                            // larger binaries.
0654:                            //instrs = combineInstructions(instrs, true)
0655:                            if (options.getBoolean(Compiler.CACHE_COMPILES)) {
0656:                                Compiler.CachedInstructions.put(instrsKey,
0657:                                        instrsChecksum, realinstrs);
0658:                            }
0659:                        }
0660:                    }
0661:                } catch (ParseException e) {
0662:                    System.err.println("while compiling "
0663:                            + file.getAbsolutePath());
0664:                    throw e;
0665:                }
0666:                return null; // dummy return is ultimately ignored
0667:            }
0668:
0669:            public SimpleNode visitFunctionDeclaration(SimpleNode node,
0670:                    SimpleNode[] ast) {
0671:                // Inner functions are handled by translateFunction
0672:                if (ASTProgram.class.equals(context.type)) {
0673:                    assert (!options.getBoolean(Compiler.CONSTRAINT_FUNCTION));
0674:                    // Make sure all our top-level functions have root context
0675:                    String block;
0676:                    if (true) {
0677:                        block = newLabel(node);
0678:                        collector.push("_root");
0679:                        collector.emit(Instructions.GetVariable);
0680:                        collector.emit(Instructions.WITH.make(block));
0681:                    }
0682:                    translateFunction(node, true, ast);
0683:                    if (true) {
0684:                        collector.emit(Instructions.LABEL.make(block));
0685:                    }
0686:                }
0687:                return node;
0688:            }
0689:
0690:            //
0691:            // Statements
0692:            //
0693:
0694:            public SimpleNode visitVariableDeclaration(SimpleNode node,
0695:                    SimpleNode[] children) {
0696:                ASTIdentifier id = (ASTIdentifier) children[0];
0697:                if (children.length > 1) {
0698:                    SimpleNode initValue = children[1];
0699:                    Reference ref = translateReference(id).preset();
0700:                    visitExpression(initValue);
0701:                    ref.init();
0702:                } else if (ASTProgram.class.equals(context.type)) {
0703:                    // In a function, variable declarations will already be done
0704:                    Reference ref = translateReference(id).preset();
0705:                    ref.declare();
0706:                }
0707:                return node;
0708:            }
0709:
0710:            public SimpleNode visitIfStatement(SimpleNode node,
0711:                    SimpleNode[] children) {
0712:                SimpleNode test = children[0];
0713:                SimpleNode a = children[1];
0714:                SimpleNode b = (children.length > 2) ? children[2] : null;
0715:                // Compile-time conditional evaluations
0716:                Boolean value = evaluateCompileTimeConditional(test);
0717:                if (value != null) {
0718:                    if (value.booleanValue()) {
0719:                        visitStatement(a);
0720:                    } else if (b != null) {
0721:                        visitStatement(b);
0722:                    }
0723:                } else if (b != null) {
0724:                    Object[] code = { new ForValue(test),
0725:                            Instructions.BranchIfFalse.make(0), a,
0726:                            Instructions.BRANCH.make(1), new Integer(0), b,
0727:                            new Integer(1) };
0728:                    translateControlStructure(node, code);
0729:                } else {
0730:                    Object[] code = { new ForValue(test),
0731:                            Instructions.BranchIfFalse.make(0), a,
0732:                            new Integer(0) };
0733:                    translateControlStructure(node, code);
0734:                }
0735:                return node;
0736:            }
0737:
0738:            // for function prefix/suffix parsing
0739:            public SimpleNode visitWhileStatement(SimpleNode node,
0740:                    SimpleNode[] children) {
0741:                SimpleNode test = children[0];
0742:                SimpleNode body = children[1];
0743:                // TODO: [2003-04-15 ptw] bind context slot macro
0744:                try {
0745:                    context = new TranslationContext(ASTWhileStatement.class,
0746:                            context);
0747:                    String continueLabel = newLabel(node);
0748:                    String breakLabel = newLabel(node);
0749:                    context.setTarget("break", breakLabel);
0750:                    context.setTarget("continue", continueLabel);
0751:                    Object[] code = { Instructions.LABEL.make(continueLabel),
0752:                            new ForValue(test),
0753:                            Instructions.BranchIfFalse.make(breakLabel), body,
0754:                            Instructions.BRANCH.make(continueLabel),
0755:                            Instructions.LABEL.make(breakLabel) };
0756:                    translateControlStructure(node, code);
0757:                    return node;
0758:                } finally {
0759:                    context = context.parent;
0760:                }
0761:            }
0762:
0763:            public SimpleNode visitDoWhileStatement(SimpleNode node,
0764:                    SimpleNode[] children) {
0765:                SimpleNode body = children[0];
0766:                SimpleNode test = children[1];
0767:                // TODO: [2003-04-15 ptw] bind context slot macro
0768:                try {
0769:                    context = new TranslationContext(ASTDoWhileStatement.class,
0770:                            context);
0771:                    String continueLabel = newLabel(node);
0772:                    String breakLabel = newLabel(node);
0773:                    context.setTarget("break", breakLabel);
0774:                    context.setTarget("continue", continueLabel);
0775:                    Object[] code = { Instructions.LABEL.make(continueLabel),
0776:                            body, new ForValue(test),
0777:                            Instructions.BranchIfTrue.make(continueLabel),
0778:                            Instructions.LABEL.make(breakLabel) };
0779:                    translateControlStructure(node, code);
0780:                    return node;
0781:                } finally {
0782:                    context = context.parent;
0783:                }
0784:            }
0785:
0786:            public SimpleNode visitForStatement(SimpleNode node,
0787:                    SimpleNode[] children) {
0788:                return translateForStatement(node, children);
0789:            }
0790:
0791:            public SimpleNode visitForVarStatement(SimpleNode node,
0792:                    SimpleNode[] children) {
0793:                return translateForStatement(node, children);
0794:            }
0795:
0796:            SimpleNode translateForStatement(SimpleNode node,
0797:                    SimpleNode[] children) {
0798:                SimpleNode init = children[0];
0799:                SimpleNode test = children[1];
0800:                SimpleNode step = children[2];
0801:                SimpleNode body = children[3];
0802:                // TODO: [2003-04-15 ptw] bind context slot macro
0803:                Compiler.OptionMap savedOptions = options;
0804:                try {
0805:                    options = options.copy();
0806:                    context = new TranslationContext(ASTForStatement.class,
0807:                            context);
0808:                    String continueLabel = newLabel(node);
0809:                    String breakLabel = newLabel(node);
0810:                    context.setTarget("break", breakLabel);
0811:                    context.setTarget("continue", continueLabel);
0812:                    options.putBoolean(Compiler.WARN_GLOBAL_ASSIGNMENTS, true);
0813:                    visitStatement(init);
0814:                    options.putBoolean(Compiler.WARN_GLOBAL_ASSIGNMENTS, false);
0815:                    Object[] code = { new Integer(0), new ForValue(test),
0816:                            Instructions.BranchIfFalse.make(breakLabel), body,
0817:                            Instructions.LABEL.make(continueLabel), step,
0818:                            Instructions.BRANCH.make(0),
0819:                            Instructions.LABEL.make(breakLabel) };
0820:                    translateControlStructure(node, code);
0821:                    return node;
0822:                } finally {
0823:                    context = context.parent;
0824:                    options = savedOptions;
0825:                }
0826:            }
0827:
0828:            public SimpleNode visitForInStatement(SimpleNode node,
0829:                    SimpleNode[] children) {
0830:                SimpleNode var = children[0];
0831:                SimpleNode obj = children[1];
0832:                SimpleNode body = children[2];
0833:                translateForInStatement(node, var, Instructions.SetVariable,
0834:                        obj, body);
0835:                return node;
0836:            }
0837:
0838:            // This works because keys are always strings, and enumerate pushes
0839:            // a null before all the keys
0840:            public void unwindEnumeration(SimpleNode node) {
0841:                String label = newLabel(node);
0842:                collector.emit(Instructions.LABEL.make(label));
0843:                collector.push(Values.Null);
0844:                collector.emit(Instructions.EQUALS);
0845:                collector.emit(Instructions.NOT);
0846:                collector.emit(Instructions.BranchIfTrue.make(label));
0847:            }
0848:
0849:            SimpleNode translateForInStatement(SimpleNode node, SimpleNode var,
0850:                    Instruction varset, SimpleNode obj, SimpleNode body) {
0851:                // TODO: [2003-04-15 ptw] bind context slot macro
0852:                try {
0853:                    String continueLabel = newLabel(node);
0854:                    String breakLabel = newLabel(node);
0855:                    context = new TranslationContext(ASTForInStatement.class,
0856:                            context);
0857:                    context.setTarget("break", breakLabel);
0858:                    context.setTarget("continue", continueLabel);
0859:                    context.isEnumeration = true;
0860:                    Integer r0 = new Integer(0);
0861:                    visitExpression(obj);
0862:                    Object[] code = { Instructions.EnumerateValue,
0863:                            Instructions.LABEL.make(continueLabel),
0864:                            Instructions.SetRegister.make(r0),
0865:                            Instructions.PUSH.make(Values.Null),
0866:                            Instructions.EQUALS,
0867:                            Instructions.BranchIfTrue.make(breakLabel) };
0868:                    translateControlStructure(node, code);
0869:                    Reference ref = translateReference(var).preset();
0870:                    collector.emit(Instructions.PUSH.make(Values.Register(0)));
0871:                    if (varset == Instructions.VarEquals) {
0872:                        ref.init();
0873:                    } else {
0874:                        ref.set(true);
0875:                    }
0876:                    Object[] moreCode = { body,
0877:                            Instructions.BRANCH.make(continueLabel),
0878:                            Instructions.LABEL.make(breakLabel) };
0879:                    translateControlStructure(node, moreCode);
0880:                    return node;
0881:                } finally {
0882:                    context = context.parent;
0883:                }
0884:            }
0885:
0886:            SimpleNode translateAbruptCompletion(SimpleNode node, String type,
0887:                    ASTIdentifier label) {
0888:                TranslationContext targetContext = context
0889:                        .findLabeledContext(label != null ? label.getName()
0890:                                : null);
0891:                if (targetContext == null) {
0892:                    if (label != null) {
0893:                        throw new SemanticError("unknown " + type + " target: "
0894:                                + label.getName(), node);
0895:                    } else {
0896:                        throw new SemanticError("can't " + type
0897:                                + " from current statement", node);
0898:                    }
0899:                }
0900:                String targetLabel = (String) targetContext.getTarget(type);
0901:                if (targetLabel == null) {
0902:                    throw new SemanticError("can't " + type
0903:                            + " from current statement", node);
0904:                }
0905:                // For each intervening enumeration, pop the stack
0906:                TranslationContext c = context;
0907:                while (!targetContext.equals(c)) {
0908:                    c.emitBreakPreamble(node, this );
0909:                    c = c.getParentStatement();
0910:                }
0911:                if ("break".equals(type)) {
0912:                    targetContext.emitBreakPreamble(node, this );
0913:                }
0914:                collector.emit(Instructions.BRANCH.make(targetLabel));
0915:                return node;
0916:            }
0917:
0918:            public SimpleNode visitReturnStatement(SimpleNode node,
0919:                    SimpleNode[] children) {
0920:                SimpleNode value = children[0];
0921:                TranslationContext c = context;
0922:                while ((!c.isFunctionBoundary())) {
0923:                    c.emitBreakPreamble(node, this );
0924:                    c = c.getParentStatement();
0925:                    if (c == null) {
0926:                        throw new SemanticError(
0927:                                "return not within a function body");
0928:                    }
0929:                }
0930:                visitExpression(value);
0931:                if (options.getBoolean(Compiler.PROFILE)
0932:                        || options.getBoolean(Compiler.DEBUG_BACKTRACE)) {
0933:                    collector.emit(Instructions.BRANCH.make(c.label));
0934:                } else {
0935:                    collector.emit(Instructions.RETURN);
0936:                }
0937:                return node;
0938:            }
0939:
0940:            public SimpleNode visitWithStatement(SimpleNode node,
0941:                    SimpleNode[] children) {
0942:                SimpleNode expr = children[0];
0943:                SimpleNode stmt = children[1];
0944:                Object[] code = { new ForValue(expr),
0945:                        Instructions.WITH.make(new Integer(0)), stmt,
0946:                        new Integer(0) };
0947:                return translateControlStructure(node, code);
0948:            }
0949:
0950:            public SimpleNode visitSwitchStatement(SimpleNode node,
0951:                    SimpleNode[] children) {
0952:                SimpleNode expr = children[0];
0953:                LinkedHashMap tests = new LinkedHashMap();
0954:                LinkedHashMap targets = new LinkedHashMap();
0955:                String defaultLabel = null;
0956:                String label = newLabel(node, "label" + 0);
0957:                for (int i = 1, len = children.length; i < len; i++) {
0958:                    SimpleNode clause = children[i];
0959:                    if (clause instanceof  ASTDefaultClause) {
0960:                        if (defaultLabel != null) {
0961:                            throw new SemanticError("duplicate default clause");
0962:                        }
0963:                        defaultLabel = label;
0964:                        // Empty cases share label with subsequent
0965:                        if (clause.size() > 0) {
0966:                            targets.put(label, clause.get(0));
0967:                            label = newLabel(node, "label" + i);
0968:                        }
0969:                    } else {
0970:                        assert clause instanceof  ASTCaseClause : "case clause expected";
0971:                        tests.put(clause.get(0), label);
0972:                        // Empty cases share label with subsequent
0973:                        if (clause.size() > 1) {
0974:                            targets.put(label, clause.get(1));
0975:                            label = newLabel(node, "label" + i);
0976:                        }
0977:                    }
0978:                }
0979:                String finalLabel = newLabel(node, "finalLabel");
0980:                // TODO: [2003-04-15 ptw] bind context slot macro
0981:                try {
0982:                    context = new TranslationContext(ASTSwitchStatement.class,
0983:                            context);
0984:                    context.setTarget("break", finalLabel);
0985:                    visitExpression(expr);
0986:                    // TODO: [2002 ows] warn on duplicate tests
0987:                    for (Iterator i = tests.keySet().iterator(); i.hasNext();) {
0988:                        SimpleNode value = (SimpleNode) i.next();
0989:                        String l = (String) tests.get(value);
0990:                        collector.emit(Instructions.DUP);
0991:                        visitExpression(value);
0992:                        collector.emit(Instructions.EQUALS);
0993:                        collector.emit(Instructions.BranchIfTrue.make(l));
0994:                    }
0995:                    if (defaultLabel != null) {
0996:                        collector.emit(Instructions.BRANCH.make(defaultLabel));
0997:                    } else {
0998:                        collector.emit(Instructions.POP);
0999:                        collector.emit(Instructions.BRANCH.make(finalLabel));
1000:                    }
1001:                    String nextLabel = null;
1002:                    for (Iterator i = targets.keySet().iterator(); i.hasNext();) {
1003:                        String l = (String) i.next();
1004:                        SimpleNode stmt = (SimpleNode) targets.get(l);
1005:                        collector.emit(Instructions.LABEL.make(l));
1006:                        collector.emit(Instructions.POP);
1007:                        if (l.equals(defaultLabel)) {
1008:                            defaultLabel = null;
1009:                        }
1010:                        if (nextLabel != null) {
1011:                            collector.emit(Instructions.LABEL.make(nextLabel));
1012:                            nextLabel = null;
1013:                        }
1014:                        visitStatement(stmt);
1015:                        Instruction previous = (Instruction) collector
1016:                                .get(collector.size() - 1);
1017:                        if (!previous.isUnconditionalRedirect()) {
1018:                            nextLabel = newLabel(node, "nextLabel");
1019:                            collector.emit(Instructions.BRANCH.make(nextLabel));
1020:                        }
1021:                    }
1022:                    // Handle empty default as last clause
1023:                    if (defaultLabel != null) {
1024:                        collector.emit(Instructions.LABEL.make(defaultLabel));
1025:                        collector.emit(Instructions.POP);
1026:                    }
1027:                    // Handle fall-though in last clause
1028:                    if (nextLabel != null) {
1029:                        collector.emit(Instructions.LABEL.make(nextLabel));
1030:                    }
1031:                    collector.emit(Instructions.LABEL.make(finalLabel));
1032:                } finally {
1033:                    context = context.parent;
1034:                }
1035:                return node;
1036:            }
1037:
1038:            static class LabelMap {
1039:                Map labels = new HashMap();
1040:                SimpleNode node;
1041:                Translator translator;
1042:
1043:                LabelMap(SimpleNode node, Translator translator) {
1044:                    this .node = node;
1045:                    this .translator = translator;
1046:                }
1047:
1048:                String lookupLabel(Object n) { // integer -> label
1049:                    if (labels.containsKey(n)) {
1050:                        return (String) labels.get(n);
1051:                    }
1052:                    String label = translator.newLabel(node);
1053:                    labels.put(n, label);
1054:                    return label;
1055:                }
1056:
1057:                String[] lookupLabels(Object[] vals) {
1058:                    String[] rets = new String[vals.length];
1059:                    for (int i = 0; i < vals.length; i++) {
1060:                        rets[i] = lookupLabel(vals[i]);
1061:                    }
1062:                    return rets;
1063:                }
1064:
1065:                Instruction resolveLocalLabel(Object instr) {
1066:                    if (instr instanceof  Integer) {
1067:                        return Instructions.LABEL.make(lookupLabel(instr));
1068:                    }
1069:                    if (instr instanceof  Instructions.TargetInstruction) {
1070:                        Instructions.TargetInstruction target = (Instructions.TargetInstruction) instr;
1071:                        Object targetval = target.getTarget();
1072:                        if (targetval instanceof  Object[]) {
1073:                            return target
1074:                                    .replaceTarget(lookupLabels((Object[]) targetval));
1075:                        }
1076:                        if (targetval instanceof  Integer) {
1077:                            return target.replaceTarget(lookupLabel(targetval));
1078:                        }
1079:                    }
1080:                    return (Instruction) instr;
1081:                }
1082:            }
1083:
1084:            // Used to mark items in the sequence to be evaluated for a value
1085:            static class ForValue {
1086:                SimpleNode node;
1087:
1088:                ForValue(SimpleNode node) {
1089:                    this .node = node;
1090:                }
1091:            }
1092:
1093:            // seq is a list whose items are interpreted thus:
1094:            // - numbers are turned into labels
1095:            // - target instructions have their targets, which are numbers,
1096:            //   resolved to labels
1097:            // - ForValue's are evaluated as expressions (for value)
1098:            // - Other nodes are compiled as statements
1099:            // - all other instructions are emitted as is
1100:            // Ensure context targets are not ambiguous
1101:            SimpleNode translateControlStructure(SimpleNode node, Object[] seq) {
1102:                for (Iterator i = context.targets.values().iterator(); i
1103:                        .hasNext();) {
1104:                    Object v = i.next();
1105:                    assert (!(v instanceof  Integer)) : "Ambiguous context target "
1106:                            + v;
1107:                }
1108:                LabelMap lm = new LabelMap(node, this );
1109:                for (int i = 0, len = seq.length; i < len; i++) {
1110:                    Object item = seq[i];
1111:                    if (item instanceof  Integer || item instanceof  Instruction) {
1112:                        // TODO [2004-03-04 ptw] Handle this in the assembler
1113:                        if (item instanceof  Instructions.BranchIfFalseInstruction) {
1114:                            collector.emit(Instructions.NOT);
1115:                            item = Instructions.BranchIfTrue
1116:                                    .make(((Instructions.BranchIfFalseInstruction) item)
1117:                                            .getTarget());
1118:                        }
1119:                        collector.emit(lm.resolveLocalLabel(item));
1120:                    } else if (item instanceof  ForValue) {
1121:                        visitExpression(((ForValue) item).node);
1122:                    } else {
1123:                        SimpleNode n = (SimpleNode) item;
1124:                        visitStatement(n, n.getChildren());
1125:                    }
1126:                }
1127:                return node;
1128:            }
1129:
1130:            //
1131:            // Expressions
1132:            //
1133:
1134:            public SimpleNode visitExpression(SimpleNode node) {
1135:                return visitExpression(node, true);
1136:            }
1137:
1138:            /* This function, unlike the other expression visitors, can be
1139:               applied to any expression node, so it dispatches based on the
1140:               node's class. */
1141:            public SimpleNode visitExpression(SimpleNode node,
1142:                    boolean isReferenced) {
1143:                assert isExpressionType(node) : "" + node + ": "
1144:                        + (new ParseTreePrinter()).visit(node)
1145:                        + " is not an expression";
1146:
1147:                if (this .debugVisit) {
1148:                    System.err.println("visitExpression: " + node.getClass());
1149:                }
1150:
1151:                SimpleNode newNode = dispatchExpression(node, isReferenced);
1152:
1153:                if ((!isReferenced) && (newNode != null)) {
1154:                    collector.emit(Instructions.POP);
1155:                    newNode = null;
1156:                }
1157:                if (this .debugVisit) {
1158:                    if (!newNode.equals(node)) {
1159:                        System.err.println("expression: " + node + " -> "
1160:                                + newNode);
1161:                    }
1162:                }
1163:                return newNode;
1164:            }
1165:
1166:            public SimpleNode visitIdentifier(SimpleNode node,
1167:                    boolean isReferenced, SimpleNode[] children) {
1168:                // Side-effect free expressions can be suppressed if not referenced
1169:                // Following is disabled by default for regression testing.
1170:                // TODO: [2003-02-17 ows] enable this
1171:                if ((!isReferenced)
1172:                        && options
1173:                                .getBoolean(Compiler.ELIMINATE_DEAD_EXPRESSIONS)) {
1174:                    return null;
1175:                }
1176:                if ("_root".equals(((ASTIdentifier) node).getName())
1177:                        && (!options.getBoolean(Compiler.ALLOW_ROOT))) {
1178:                    throw new SemanticError("Illegal variable name: " + node,
1179:                            node);
1180:                }
1181:                return translateReference(node).get().node;
1182:            }
1183:
1184:            public SimpleNode visitLiteral(SimpleNode node,
1185:                    boolean isReferenced, SimpleNode[] children) {
1186:                // Side-effect free expressions can be suppressed if not referenced
1187:                // Following is disabled by default for regression testing.
1188:                // TODO: [2003-02-17 ows] enable this
1189:                if ((!isReferenced)
1190:                        && options
1191:                                .getBoolean(Compiler.ELIMINATE_DEAD_EXPRESSIONS)) {
1192:                    return null;
1193:                }
1194:                Object value = translateLiteralNode(node);
1195:                if (value instanceof  String) {
1196:                    String str = (String) value;
1197:                    // Can't push a constant that will cause the instruction to have
1198:                    // a byte length > 2^16-1.  String constant needs a type byte
1199:                    // and a (byte) 0 terminator, plus a 2-byte length field.
1200:                    // Strings are UTF-8, so may be more than one byte per
1201:                    // character.
1202:                    int maxBytes = (1 << 16) - 1 - 1 - 1 - 2;
1203:                    int byteLen = 0;
1204:                    // Assume worst case (that every character will take 4 bytes
1205:                    // when UTF-8 encoded), since the only way to be more exact is to
1206:                    // loop over the string trying different splits and measuring
1207:                    // the length of the encoded bytes.
1208:                    byteLen = str.length() * 4;
1209:                    if (byteLen > maxBytes) {
1210:                        // Find a split that makes it fit
1211:                        // wtf doesn't Java have ceil, etc. methods on frickin' ints?
1212:                        int nChunks = (byteLen + (maxBytes - 1)) / maxBytes; // (int)Math.ceil((double)l/(double)maxBytes);
1213:                        int strLen = str.length();
1214:                        int chunkLen = (strLen + (nChunks - 1)) / nChunks; // (int)Math.ceil((double)l/(double)nChunks);
1215:                        int start = 0, end = chunkLen, next;
1216:                        while (start < strLen) {
1217:                            collector.push(str.substring(start, end));
1218:                            start = end;
1219:                            next = end + chunkLen;
1220:                            end = (next > strLen) ? strLen : next;
1221:                        }
1222:                        while (--nChunks > 0) {
1223:                            collector.emit(Instructions.ADD);
1224:                        }
1225:                        return node;
1226:                    }
1227:                }
1228:                collector.push(value);
1229:                return node;
1230:            }
1231:
1232:            public SimpleNode visitExpressionList(SimpleNode node,
1233:                    boolean isReferenced, SimpleNode[] children) {
1234:                // all but last expression will not be referenced, so
1235:                // visitExpression will pop it.  If the list is not referenced,
1236:                // then the last will be popped too
1237:                int i = 0, len = children.length - 1;
1238:                for (; i < len; i++) {
1239:                    visitExpression(children[i], false);
1240:                }
1241:                return visitExpression(children[len], isReferenced);
1242:            }
1243:
1244:            public SimpleNode visitEmptyExpression(SimpleNode node,
1245:                    boolean isReferenced, SimpleNode[] children) {
1246:                // Side-effect free expressions can be suppressed if not referenced
1247:                if ((!isReferenced)) {
1248:                    return null;
1249:                }
1250:                collector.push(Values.Undefined);
1251:                return node;
1252:            }
1253:
1254:            public SimpleNode visitThisReference(SimpleNode node,
1255:                    boolean isReferenced, SimpleNode[] children) {
1256:                // Side-effect free expressions can be suppressed if not referenced
1257:                if ((!isReferenced)) {
1258:                    return null;
1259:                }
1260:                return translateReference(node).get().node;
1261:            }
1262:
1263:            public SimpleNode visitArrayLiteral(SimpleNode node,
1264:                    boolean isReferenced, SimpleNode[] children) {
1265:                boolean suppressed = (!isReferenced);
1266:                // Wrong evaluation order
1267:                int len = 0;
1268:                for (int i = children.length - 1; i >= 0; i--) {
1269:                    if (visitExpression(children[i], isReferenced) != null) {
1270:                        len++;
1271:                        suppressed = false;
1272:                    }
1273:                }
1274:                if (!suppressed) {
1275:                    collector.push(len);
1276:                    collector.emit(Instructions.InitArray);
1277:                    return node;
1278:                } else
1279:                    return null;
1280:            }
1281:
1282:            public SimpleNode visitObjectLiteral(SimpleNode node,
1283:                    boolean isReferenced, SimpleNode[] children) {
1284:                boolean isKey = true;
1285:                for (int i = 0, len = children.length; i < len; i++) {
1286:                    SimpleNode item = children[i];
1287:                    if (isKey && item instanceof  ASTIdentifier) {
1288:                        collector.push(((ASTIdentifier) item).getName());
1289:                    } else {
1290:                        visitExpression(item);
1291:                    }
1292:                    isKey = (!isKey);
1293:                }
1294:                collector.push(children.length / 2);
1295:                collector.emit(Instructions.InitObject);
1296:                return node;
1297:            }
1298:
1299:            public SimpleNode visitFunctionExpression(SimpleNode node,
1300:                    boolean isReferenced, SimpleNode[] children) {
1301:                Compiler.OptionMap savedOptions = options;
1302:                try {
1303:                    options = options.copy();
1304:                    options.putBoolean(Compiler.CONSTRAINT_FUNCTION, false);
1305:                    // Make sure all our top-level functions have root context
1306:                    String block = null;
1307:                    if (ASTProgram.class.equals(context.type)) {
1308:                        block = newLabel(node);
1309:                        collector.push("_root");
1310:                        collector.emit(Instructions.GetVariable);
1311:                        collector.emit(Instructions.WITH.make(block));
1312:                    }
1313:                    translateFunction(node, false, children);
1314:                    if (block != null) {
1315:                        collector.emit(Instructions.LABEL.make(block));
1316:                    }
1317:                } finally {
1318:                    options = savedOptions;
1319:                }
1320:                return node;
1321:            }
1322:
1323:            public SimpleNode visitFunctionCallParameters(SimpleNode node,
1324:                    boolean isReferenced, SimpleNode[] children) {
1325:                // FIXME: [2002-01-07 ows] This evaluates function call
1326:                // parameters in the wrong order.
1327:                for (int i = children.length - 1; i >= 0; i--) {
1328:                    visitExpression(children[i]);
1329:                }
1330:                collector.push(children.length);
1331:                return node;
1332:            }
1333:
1334:            public SimpleNode visitPropertyIdentifierReference(SimpleNode node,
1335:                    boolean isReferenced, SimpleNode[] children) {
1336:                // TODO: [2002-12-12 ows] consolidate with the code in for..in
1337:                // TODO: [2002-12-12 ows] find out how this generalizes to a.b.c
1338:                // TODO: [2002-12-18 ows] enabling this saves 2K of the LFC, but
1339:                // doesn't seem to improve speed, and changes the background color
1340:                // of the menu items in contacts to white (don't know why).
1341:                if (false && children[0] instanceof  ASTIdentifier
1342:                        && children[1] instanceof  ASTIdentifier) {
1343:                    collector.push(((ASTIdentifier) children[0]).getName()
1344:                            + ":" + ((ASTIdentifier) children[1]).getName());
1345:                    collector.emit(Instructions.GetVariable);
1346:                    return node;
1347:                }
1348:                return translateReference(node).get().node;
1349:            }
1350:
1351:            public SimpleNode visitPropertyValueReference(SimpleNode node,
1352:                    boolean isReferenced, SimpleNode[] children) {
1353:                return translateReference(node).get().node;
1354:            }
1355:
1356:            void noteCallSite(SimpleNode node) {
1357:                // Note current call-site in a function context and backtracing
1358:                if ((options.getBoolean(Compiler.DEBUG_BACKTRACE) && (node.beginLine != 0))
1359:                        && (context.findFunctionContext() != null)) {
1360:                    Map registers = (Map) context
1361:                            .get(TranslationContext.REGISTERS);
1362:                    // We know arguments register will exist if we are doing
1363:                    // bactraces because it will be referenced in the function
1364:                    // prefix.
1365:                    if (registers != null && registers.containsKey("arguments")) {
1366:                        collector.push(Values
1367:                                .Register(((Instructions.Register) registers
1368:                                        .get("arguments")).regno));
1369:                        collector.push("lineno");
1370:                        collector.push(node.beginLine);
1371:                        collector.emit(Instructions.SetMember);
1372:                    }
1373:                }
1374:            }
1375:
1376:            public SimpleNode visitCallExpression(SimpleNode node,
1377:                    boolean isReferenced, SimpleNode[] children) {
1378:                SimpleNode fnexpr = children[0];
1379:                SimpleNode[] args = children[1].getChildren();
1380:                int arglen = args.length;
1381:                if (fnexpr instanceof  ASTIdentifier) {
1382:                    ASTIdentifier fn = (ASTIdentifier) fnexpr;
1383:                    String name = fn.getName();
1384:                    // Expose getTimer at our API
1385:                    //
1386:                    // FIXME: [2002-12-23 ows] This substitution is not correct
1387:                    // because it assumes that the value for "getTimer" that"s
1388:                    // in scope is the global variable.
1389:                    if ("getTimer".equals(name) && arglen == 0) {
1390:                        collector.emit(Instructions.GetTimer);
1391:                        return node;
1392:                    }
1393:                    if (options
1394:                            .getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY)) {
1395:                        if ("trace".equals(name)) {
1396:                            if (options.get(Compiler.COMPILE_TRACE) == "flash") {
1397:                                // FIXME: [2003-01-08 ows] Nicer warning for trace()
1398:                                // FIXME: [2003-01-08 ows] Warn, at least, when
1399:                                // there's more than one arg.
1400:                                visitExpression(args[0]);
1401:                                // FIXME: [2003-03-13 ptw] Why doesn't the trace instruction work?
1402:                                collector.push(1);
1403:                                collector.push("trace");
1404:                                collector.emit(Instructions.CallFunction);
1405:                                return node; // was true for trace instruction?
1406:                            } else if (options.get(Compiler.COMPILE_TRACE) == "debug") {
1407:                                visitExpression(args[0]);
1408:                                collector.push("_root");
1409:                                collector.emit(Instructions.GetVariable);
1410:                                collector.push("Debug");
1411:                                collector.emit(Instructions.GetMember);
1412:                                collector.push("write");
1413:                                collector.emit(Instructions.CallMethod);
1414:                                return node;
1415:                            }
1416:                            // else fall through
1417:                            return null;
1418:                        }
1419:                        if ("fscommand".equals(name) && arglen == 2) {
1420:                            assert args[0] instanceof  ASTLiteral;
1421:                            Object v = translateLiteralNode(args[0]);
1422:                            assert v instanceof  String;
1423:                            collector.push("FSCommand:" + v);
1424:                            visitExpression(args[1]);
1425:                            collector.emit(Instructions.GetURL2.make(0));
1426:                            return null;
1427:                        }
1428:                        if ("FSCommand2".equals(name)) {
1429:                            visitFunctionCallParameters(node, isReferenced,
1430:                                    args);
1431:                            collector.emit(Instructions.FSCommand2);
1432:                            return null;
1433:                        }
1434:                        if ("removeMovieClip".equals(name) && arglen == 1) {
1435:                            visitExpression(args[0]);
1436:                            collector.emit(Instructions.RemoveClip);
1437:                            return null; // no return value
1438:                        }
1439:                        if ("ord".equals(name) && arglen == 1) {
1440:                            visitExpression(args[0]);
1441:                            collector.emit(Instructions.ORD);
1442:                            return node;
1443:                        }
1444:                        if ("targetPath".equals(name) && arglen == 1) {
1445:                            visitExpression(args[0]);
1446:                            collector.emit(Instructions.TargetPath);
1447:                            return node;
1448:                        }
1449:                        // TODO: [2002-11-30 ows] The following clause needs to
1450:                        // swap the arguments.  To preserve evaluation order,
1451:                        // it could visit them in reverse order if they don't
1452:                        // have side effects, otherwise emit SWAP.
1453:                        //- if "getURL".equals(name) && arglen == 2:
1454:                        //-    collector.emit(Instructions.GetURL2.make(0)); return
1455:                        if ("getVersion".equals(name) && arglen == 0) {
1456:                            collector.push("/:$version");
1457:                            collector.emit(Instructions.GetVariable);
1458:                            return node;
1459:                        }
1460:                        if ("eval".equals(name) && arglen == 1) {
1461:                            visitExpression(args[0]);
1462:                            collector.emit(Instructions.GetVariable);
1463:                            return node;
1464:                        }
1465:                    }
1466:                }
1467:                // TODO: [2002-12-03 ptw] There should be a more general
1468:                // mechanism for matching patterns against AST's and replacing
1469:                // them.
1470:                // FIXME: [2002-12-03 ptw] This substitution is not correct
1471:                // because it does not verify that the method being inlined is
1472:                // actually LzNode.setAttribute.
1473:                if (
1474:                // Here this means 'compiling the lfc'
1475:                options.getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY)
1476:                        && (!options.getBoolean("passThrough"))
1477:                        && (fnexpr instanceof  ASTPropertyIdentifierReference)) {
1478:                    SimpleNode[] fnchildren = fnexpr.getChildren();
1479:                    String name = ((ASTIdentifier) fnchildren[1]).getName();
1480:                    // We can't expand this if an expression value is expected,
1481:                    // since we don't have 'let'
1482:                    if (name.equals("setAttribute") && (!isReferenced)) {
1483:                        SimpleNode scope = fnchildren[0];
1484:                        SimpleNode property = args[0];
1485:                        SimpleNode value = args[1];
1486:                        List newBody = new ArrayList();
1487:                        String this var = "$lzsc$" + UUID().toString();
1488:                        String propvar = "$lzsc$" + UUID().toString();
1489:                        String valvar = "$lzsc$" + UUID().toString();
1490:                        String changedvar = "$lzsc$" + UUID().toString();
1491:                        String svar = "$lzsc$" + UUID().toString();
1492:                        String evtvar = "$lzsc$" + UUID().toString();
1493:                        String decls = "";
1494:                        ParseTreePrinter ptp = new ParseTreePrinter();
1495:                        if (scope instanceof  ASTIdentifier
1496:                                || scope instanceof  ASTThisReference) {
1497:                            this var = ptp.visit(scope);
1498:                        } else {
1499:                            decls += "var " + this var + " = "
1500:                                    + ptp.visit(scope) + ";";
1501:                        }
1502:                        if (property instanceof  ASTLiteral
1503:                                || property instanceof  ASTIdentifier) {
1504:                            propvar = ptp.visit(property);
1505:                            if (property instanceof  ASTLiteral) {
1506:                                assert propvar.startsWith("\"")
1507:                                        || propvar.startsWith("'");
1508:                                evtvar = propvar.substring(0, 1) + "on"
1509:                                        + propvar.substring(1);
1510:                            }
1511:                        } else {
1512:                            decls += "var " + propvar + " = "
1513:                                    + ptp.visit(property) + ";";
1514:                        }
1515:                        if (value instanceof  ASTLiteral
1516:                                || value instanceof  ASTIdentifier) {
1517:                            valvar = ptp.visit(value);
1518:                        } else {
1519:                            decls += "var " + valvar + " = " + ptp.visit(value)
1520:                                    + ";";
1521:                        }
1522:                        if (arglen > 2) {
1523:                            SimpleNode ifchanged = args[2];
1524:                            if (ifchanged instanceof  ASTLiteral
1525:                                    || ifchanged instanceof  ASTIdentifier) {
1526:                                changedvar = ptp.visit(ifchanged);
1527:                            } else {
1528:                                decls += "var " + changedvar + " = "
1529:                                        + ptp.visit(ifchanged) + ";";
1530:                            }
1531:                        }
1532:                        newBody.add(parseFragment(decls));
1533:                        String fragment = "if (! ("
1534:                                + this var
1535:                                + ".__LZdeleted "
1536:                                + ((arglen > 2) ? ("|| (" + changedvar
1537:                                        + " && (" + this var + "[" + propvar
1538:                                        + "] == " + valvar + "))") : "")
1539:                                + ")) {"
1540:                                + "var "
1541:                                + svar
1542:                                + " = "
1543:                                + this var
1544:                                + ".setters;"
1545:                                + "if ("
1546:                                + svar
1547:                                + " && ("
1548:                                + propvar
1549:                                + " in "
1550:                                + svar
1551:                                + ")) {"
1552:                                + "    "
1553:                                + this var
1554:                                + "["
1555:                                + svar
1556:                                + "["
1557:                                + propvar
1558:                                + "]]("
1559:                                + valvar
1560:                                + ");"
1561:                                + "} else {"
1562:                                + "    if ($debug) {"
1563:                                + "        if ("
1564:                                + svar
1565:                                + " == null) {"
1566:                                + "            Debug.warn('null setters on', "
1567:                                + this var
1568:                                + ", "
1569:                                + propvar
1570:                                + ", "
1571:                                + valvar
1572:                                + ");"
1573:                                + "        }"
1574:                                + "    }"
1575:                                + "    "
1576:                                + this var
1577:                                + "[ "
1578:                                + propvar
1579:                                + " ] = "
1580:                                + valvar
1581:                                + ";"
1582:                                + ((property instanceof  ASTLiteral) ? ""
1583:                                        : ("    var " + evtvar
1584:                                                + " = (\"on\" + " + propvar + ");"))
1585:                                + "    if (" + evtvar + " in " + this var
1586:                                + ") {" + "        if (" + this var + "["
1587:                                + evtvar + "].ready) {" + this var + "[ "
1588:                                + evtvar + " ].sendEvent( " + valvar + " ); }"
1589:                                + "    }" + "}}";
1590:                        newBody.add(parseFragment(fragment));
1591:                        SimpleNode newStmts = new ASTStatementList(0);
1592:                        newStmts.setChildren((SimpleNode[]) newBody
1593:                                .toArray(new SimpleNode[0]));
1594:                        visitStatement(newStmts);
1595:                        return null;
1596:                    }
1597:                }
1598:
1599:                noteCallSite(node);
1600:                // Okay, it is not going to be transformed.  Just do it!
1601:                visitFunctionCallParameters(node, isReferenced, args);
1602:                boolean isref = translateReferenceForCall(fnexpr, true, node);
1603:                if (isref) {
1604:                    if (fnexpr instanceof  ASTPropertyIdentifierReference
1605:                            || fnexpr instanceof  ASTPropertyValueReference) {
1606:                        collector.emit(Instructions.CallMethod);
1607:                    } else {
1608:                        collector.emit(Instructions.CallFunction);
1609:                    }
1610:                } else {
1611:                    // This is how you invoke a function value
1612:                    collector.push(Values.Undefined);
1613:                    collector.emit(Instructions.CallMethod);
1614:                }
1615:                return node;
1616:            }
1617:
1618:            public SimpleNode visitSuperCallExpression(SimpleNode node,
1619:                    boolean isReferenced, SimpleNode[] children) {
1620:                SimpleNode n = translateSuperCallExpression(node, isReferenced,
1621:                        children);
1622:                visitCallExpression(n, isReferenced, n.getChildren());
1623:                return n;
1624:            }
1625:
1626:            public SimpleNode visitNewExpression(SimpleNode node,
1627:                    boolean isReferenced, SimpleNode[] children) {
1628:                SimpleNode ref = children[0];
1629:                SimpleNode[] args = children[1].getChildren();
1630:                noteCallSite(node);
1631:                visitFunctionCallParameters(node, isReferenced, args);
1632:                boolean isref = translateReferenceForCall(ref, true, node);
1633:                if (isref) {
1634:                    if (ref instanceof  ASTPropertyIdentifierReference
1635:                            || ref instanceof  ASTPropertyValueReference) {
1636:                        collector.emit(Instructions.NewMethod);
1637:                    } else {
1638:                        collector.emit(Instructions.NEW);
1639:                    }
1640:                } else {
1641:                    // This is how you invoke a function value
1642:                    collector.push(Values.Undefined);
1643:                    collector.emit(Instructions.NewMethod);
1644:                }
1645:                return node;
1646:            }
1647:
1648:            public SimpleNode visitPrefixExpression(SimpleNode node,
1649:                    boolean isReferenced, SimpleNode[] children) {
1650:                SimpleNode op = children[0];
1651:                SimpleNode ref = children[1];
1652:                return translateXfixExpression(ref, op, true, isReferenced);
1653:            }
1654:
1655:            public SimpleNode visitPostfixExpression(SimpleNode node,
1656:                    boolean isReferenced, SimpleNode[] children) {
1657:                SimpleNode ref = children[0];
1658:                SimpleNode op = children[1];
1659:                return translateXfixExpression(ref, op, false, isReferenced);
1660:            }
1661:
1662:            SimpleNode translateXfixExpression(SimpleNode refnode,
1663:                    SimpleNode opnode, boolean isPrefix, boolean isReferenced) {
1664:                Instruction op = (Instruction) XfixInstrs
1665:                        .get(((ASTOperator) opnode).getOperator());
1666:                if (isReferenced) {
1667:                    if (!isPrefix) {
1668:                        // Old value is left on stack
1669:                        Reference ref = translateReference(refnode, 3).get()
1670:                                .preset().get();
1671:                        collector.emit(op);
1672:                        ref.set();
1673:                    } else {
1674:                        // New value is left on stack
1675:                        Reference ref = translateReference(refnode, 2).preset()
1676:                                .get();
1677:                        collector.emit(op);
1678:                        collector.emit(Instructions.SetRegister.make(0));
1679:                        ref.set();
1680:                        collector.push(Values.Register(0));
1681:                    }
1682:                    return refnode;
1683:                } else {
1684:                    // Not referenced, no value left on stack
1685:                    Reference ref = translateReference(refnode, 2).preset()
1686:                            .get();
1687:                    collector.emit(op);
1688:                    ref.set();
1689:                    return null;
1690:                }
1691:            }
1692:
1693:            public SimpleNode visitUnaryExpression(SimpleNode node,
1694:                    boolean isReferenced, SimpleNode[] children) {
1695:                int op = ((ASTOperator) children[0]).getOperator();
1696:                // I guess the parser doesn't know the difference
1697:                if (ParserConstants.INCR == (op)
1698:                        || ParserConstants.DECR == (op)) {
1699:                    return visitPrefixExpression(node, isReferenced, children);
1700:                }
1701:                SimpleNode arg = children[1];
1702:                // a little bit of constant-folding, so that "-1" looks like a constant
1703:                if (ParserConstants.MINUS == (op) && arg instanceof  ASTLiteral) {
1704:                    Object v = translateLiteralNode(arg);
1705:                    if (v instanceof  Number) {
1706:                        // This works because swf represents all numbers as doubles
1707:                        collector
1708:                                .push(new Double((-((Number) v).doubleValue())));
1709:                        return node;
1710:                    }
1711:                }
1712:                // special-cased, since this operates on a ref rather than a value
1713:                if (ParserConstants.DELETE == (op)) {
1714:                    boolean isref = translateReferenceForCall(arg);
1715:                    if (isref) {
1716:                        collector.emit(Instructions.DELETE);
1717:                    } else {
1718:                        collector.emit(Instructions.DELETE2);
1719:                    }
1720:                    return node;
1721:                }
1722:                if (options.getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY)
1723:                        && ParserConstants.MINUS == (op)) {
1724:                    collector.push(0);
1725:                    visitExpression(arg);
1726:                    collector.emit(Instructions.SUBTRACT);
1727:                    return node;
1728:                }
1729:                // special-case typeof(variable) to not emit undefined-variable
1730:                // checks so there is a warning-free way to check for undefined
1731:                if (ParserConstants.TYPEOF == (op)
1732:                        && (arg instanceof  ASTIdentifier
1733:                                || arg instanceof  ASTPropertyValueReference || arg instanceof  ASTPropertyIdentifierReference)) {
1734:                    translateReference(arg).get(false);
1735:                } else {
1736:                    visitExpression(arg);
1737:                }
1738:                Instruction[] instrs = (Instruction[]) UnopInstrs.get(op);
1739:                assert instrs != null : "No instrr for op " + op;
1740:                if (options.getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY)
1741:                        && ParserConstants.TILDE == (op)) {
1742:                    instrs = new Instruction[] {
1743:                            Instructions.PUSH.make(new Long(0xffffffffL)),
1744:                            Instructions.BitwiseXor };
1745:                }
1746:                for (int i = 0, len = instrs.length; i < len; i++) {
1747:                    collector.emit(instrs[i]);
1748:                }
1749:                return node;
1750:            }
1751:
1752:            public SimpleNode visitBinaryExpressionSequence(SimpleNode node,
1753:                    boolean isReferenced, SimpleNode[] children) {
1754:                SimpleNode a = children[0];
1755:                SimpleNode op = children[1];
1756:                SimpleNode b = children[2];
1757:                return translateBinaryExpression(node, isReferenced,
1758:                        (ASTOperator) op, a, b);
1759:            }
1760:
1761:            SimpleNode translateBinaryExpression(SimpleNode node,
1762:                    boolean isReferenced, ASTOperator op, SimpleNode a,
1763:                    SimpleNode b) {
1764:                if (ParserConstants.CAST == ((ASTOperator) op).getOperator()) {
1765:                    // Approximate a cast b as a
1766:                    // TODO: [2008-01-08 ptw] We could typecheck and throw an error
1767:                    // in debug mode
1768:                    visitExpression(a);
1769:                    return node;
1770:                }
1771:                visitExpression(a);
1772:                visitExpression(b);
1773:                if (ParserConstants.IS == ((ASTOperator) op).getOperator()) {
1774:                    // Approximate a is b as b['$lzsc$isa'] ? b.$lzsc$isa(a) : (a
1775:                    // instanceof b)
1776:                    ArrayList code = new ArrayList();
1777:                    code.add(Instructions.DUP); // a b b
1778:                    code.add(Instructions.PUSH.make("$lzsc$isa"));
1779:                    code.add(Instructions.GetMember); // a b b.$lzsc$isa
1780:                    code.add(Instructions.BranchIfTrue.make(1)); // a b
1781:                    code.add(Instructions.InstanceOf); // (a instanceof b)
1782:                    code.add(Instructions.BRANCH.make(2));
1783:                    code.add(new Integer(1)); // a b
1784:                    code.add(Instructions.PUSH.make(1)); // a b 1
1785:                    code.add(Instructions.SWAP); // a 1 b
1786:                    code.add(Instructions.PUSH.make("$lzsc$isa")); // a 1 b '$lzsc$isa'
1787:                    code.add(Instructions.CallMethod); // b.$lzsc$isa(a)
1788:                    code.add(new Integer(2));
1789:                    translateControlStructure(node, code.toArray());
1790:                } else {
1791:                    Instruction[] instrs = (Instruction[]) BinopInstrs.get(op
1792:                            .getOperator());
1793:                    for (int i = 0, len = instrs.length; i < len; i++) {
1794:                        collector.emit(instrs[i]);
1795:                    }
1796:                }
1797:                return node;
1798:            }
1799:
1800:            SimpleNode translateAndOrExpression(SimpleNode node, boolean isand,
1801:                    SimpleNode a, SimpleNode b) {
1802:                visitExpression(a);
1803:                collector.emit(Instructions.DUP);
1804:                if (isand) {
1805:                    collector.emit(Instructions.NOT);
1806:                }
1807:                String label = newLabel(node);
1808:                collector.emit(Instructions.BranchIfTrue.make(label));
1809:                collector.emit(Instructions.POP);
1810:                visitExpression(b);
1811:                collector.emit(Instructions.LABEL.make(label));
1812:                return node;
1813:            }
1814:
1815:            public SimpleNode visitConditionalExpression(SimpleNode node,
1816:                    boolean isReferenced, SimpleNode[] children) {
1817:                SimpleNode test = children[0];
1818:                SimpleNode a = children[1];
1819:                SimpleNode b = children[2];
1820:                String l1 = newLabel(node);
1821:                String l2 = newLabel(node);
1822:                visitExpression(test);
1823:                collector.emit(Instructions.BranchIfTrue.make(l1));
1824:                visitExpression(b);
1825:                collector.emit(Instructions.BRANCH.make(l2));
1826:                collector.emit(Instructions.LABEL.make(l1));
1827:                visitExpression(a);
1828:                collector.emit(Instructions.LABEL.make(l2));
1829:                return node;
1830:            }
1831:
1832:            public SimpleNode visitAssignmentExpression(SimpleNode node,
1833:                    boolean isReferenced, SimpleNode[] children) {
1834:                SimpleNode lhs = children[0];
1835:                ASTOperator opnode = (ASTOperator) children[1];
1836:                SimpleNode rhs = children[2];
1837:                int op = opnode.getOperator();
1838:                Reference ref = null;
1839:                if (ParserConstants.ASSIGN == (op)) {
1840:                    ref = translateReference(lhs).preset();
1841:                    visitExpression(rhs);
1842:                } else {
1843:                    ref = translateReference(lhs, 2).preset();
1844:                    ref.get();
1845:                    visitExpression(rhs);
1846:                    Instruction[] instrs = (Instruction[]) BinopInstrs
1847:                            .get(AssignOpTable.get(op));
1848:                    for (int i = 0, len = instrs.length; i < len; i++) {
1849:                        collector.emit(instrs[i]);
1850:                    }
1851:                }
1852:                if (isReferenced) {
1853:                    collector.emit(Instructions.SetRegister.make(0));
1854:                }
1855:                ref.set();
1856:                if (isReferenced) {
1857:                    collector.push(Values.Register(0));
1858:                    // Python version always returned true, but that is clearly wrong
1859:                    return node;
1860:                }
1861:                return null;
1862:            }
1863:
1864:            // useName => declaration not expression
1865:            void translateFunction(SimpleNode node, boolean useName,
1866:                    SimpleNode[] children) {
1867:                // label for profiling return
1868:                String label = newLabel(node);
1869:                // TODO: [2003-04-15 ptw] bind context slot macro
1870:                SimpleNode dependencies = null;
1871:                // methodName and scriptElement
1872:                Compiler.OptionMap savedOptions = options;
1873:                try {
1874:                    options = options.copy();
1875:                    context = new TranslationContext(
1876:                            ASTFunctionExpression.class, context, label);
1877:                    dependencies = translateFunctionInternal(node, useName,
1878:                            children);
1879:                } finally {
1880:                    options = savedOptions;
1881:                    context = context.parent;
1882:                }
1883:                // Dependency function is not compiled in the function context
1884:                if (dependencies != null) {
1885:                    collector.emit(Instructions.DUP);
1886:                    collector.push("dependencies");
1887:                    visitExpression(dependencies);
1888:                    collector.emit(Instructions.SetMember);
1889:                }
1890:            }
1891:
1892:            // Internal helper function for above
1893:            // useName => declaration not expression
1894:            SimpleNode translateFunctionInternal(SimpleNode node,
1895:                    boolean useName, SimpleNode[] children) {
1896:                // ast can be any of:
1897:                //   FunctionDefinition(name, args, body)
1898:                //   FunctionDeclaration(name, args, body)
1899:                //   FunctionDeclaration(args, body)
1900:                // Handle the two arities:
1901:                String functionName = null;
1902:                SimpleNode params;
1903:                SimpleNode stmts;
1904:                SimpleNode depExpr = null;
1905:                if (children.length == 3) {
1906:                    ASTIdentifier functionNameIdentifier = (ASTIdentifier) children[0];
1907:                    params = children[1];
1908:                    stmts = children[2];
1909:                    functionName = functionNameIdentifier.getName();
1910:                } else {
1911:                    params = children[0];
1912:                    stmts = children[1];
1913:                }
1914:
1915:                // function block
1916:                String block = newLabel(node);
1917:                String userFunctionName = null;
1918:                String filename = node.filename != null ? node.filename
1919:                        : "unknown file";
1920:                String lineno = "" + node.beginLine;
1921:                if (functionName != null) {
1922:                    userFunctionName = functionName;
1923:                } else {
1924:                    // TODO: [2003-06-19 ptw] (krank) Sanitization of names to
1925:                    // identifiers moved to krank user, remove #- when it works
1926:                    //- from string import translate, maketrans
1927:                    //- trans = maketrans(" /.", "___")
1928:                    //- filename = translateInternal(node.filename or "unknown file", trans, """);
1929:                    // Why do .as filenames have quotes around the string?
1930:                    //- userFunctionName = "%s$%d_%d" % (filename, node.lineNumber, node.columnNumber)
1931:                    // FIXME: [2006-01-17 ptw] Regression compatibility \" ->
1932:                    userFunctionName = "" + filename + "#" + lineno + "/"
1933:                            + node.beginColumn;
1934:                }
1935:                if ((!useName)) {
1936:                    functionName = null;
1937:                }
1938:                // Tell metering to look up the name at runtime if it is not a
1939:                // global name (this allows us to name closures more
1940:                // mnemonically at runtime
1941:                String meterFunctionName = functionName;
1942:                Set pnames = new LinkedHashSet();
1943:                SimpleNode[] paramIds = params.getChildren();
1944:                for (int i = 0, len = paramIds.length; i < len; i++) {
1945:                    pnames.add(((ASTIdentifier) paramIds[i]).getName());
1946:                }
1947:                // Pull all the pragmas from the beginning of the
1948:                // statement list: process them, and remove them
1949:                assert stmts instanceof  ASTStatementList;
1950:                List stmtList = new ArrayList(Arrays
1951:                        .asList(stmts.getChildren()));
1952:                while (stmtList.size() > 0) {
1953:                    SimpleNode stmt = (SimpleNode) stmtList.get(0);
1954:                    if (stmt instanceof  ASTPragmaDirective) {
1955:                        visitStatement(stmt);
1956:                        stmtList.remove(0);
1957:                    } else {
1958:                        break;
1959:                    }
1960:                }
1961:                if (options.getBoolean(Compiler.CONSTRAINT_FUNCTION)) {
1962:                    //       assert (functionName != null);
1963:                    if (ReferenceCollector.DebugConstraints) {
1964:                        System.err.println("stmts: " + stmts);
1965:                    }
1966:                    // Find dependencies.
1967:                    //
1968:                    // Compute this before any transformations on the function body.
1969:                    //
1970:                    // The job of a constraint function is to compute a value.
1971:                    // The current implementation inlines the call to set the
1972:                    // attribute that the constraint is attached to, within the
1973:                    // constraint function it  Walking the statements of
1974:                    // the function will process the expression that computes
1975:                    // the value; it will also process the call to
1976:                    // setAttribute, but ReferenceCollector knows to ignore
1977:                    //
1978:                    ReferenceCollector dependencies = new ReferenceCollector(
1979:                            options.getBoolean(Compiler.COMPUTE_METAREFERENCES));
1980:                    // Only visit original body
1981:                    for (Iterator i = stmtList.iterator(); i.hasNext();) {
1982:                        SimpleNode stmt = (SimpleNode) i.next();
1983:                        dependencies.visit(stmt);
1984:                    }
1985:                    depExpr = dependencies.computeReferences(userFunctionName);
1986:                    if (options.getBoolean(Compiler.PRINT_CONSTRAINTS)) {
1987:                        (new ParseTreePrinter()).print(depExpr);
1988:                    }
1989:                }
1990:                List prefix = new ArrayList();
1991:                List postfix = new ArrayList();
1992:                if (options.getBoolean(Compiler.DEBUG_BACKTRACE)) {
1993:                    prefix
1994:                            .addAll(Arrays
1995:                                    .asList((new Compiler.Parser())
1996:                                            .parse(
1997:                                                    ""
1998:                                                            + "{"
1999:                                                            + "\n#pragma 'warnUndefinedReferences=false'\n"
2000:                                                            + "var $lzsc$s = Debug['backtraceStack'];"
2001:                                                            + "if ($lzsc$s) {"
2002:                                                            + "var $lzsc$l = $lzsc$s.length;"
2003:                                                            + "$lzsc$s.length = $lzsc$l + 1;"
2004:                                                            + "arguments['this'] = this;"
2005:                                                            + "$lzsc$s[$lzsc$l] = arguments;"
2006:                                                            + "if ($lzsc$l > $lzsc$s.maxDepth) {Debug.stackOverflow()};"
2007:                                                            + "}" + "}" + "")
2008:                                            .getChildren()));
2009:                    postfix
2010:                            .addAll(Arrays
2011:                                    .asList((new Compiler.Parser())
2012:                                            .parse(
2013:                                                    ""
2014:                                                            + "{"
2015:                                                            + "\n#pragma 'warnUndefinedReferences=false'\n"
2016:                                                            + "if ($lzsc$s) {"
2017:                                                            + "$lzsc$s.length--;"
2018:                                                            + "}" + "}" + "")
2019:                                            .getChildren()));
2020:                }
2021:                if (options.getBoolean(Compiler.PROFILE)) {
2022:                    prefix.addAll(Arrays.asList(meterFunctionEvent(node,
2023:                            "calls", meterFunctionName)));
2024:                    postfix.addAll(Arrays.asList(meterFunctionEvent(node,
2025:                            "returns", meterFunctionName)));
2026:                }
2027:
2028:                // Analyze local variables (and functions)
2029:                VariableAnalyzer analyzer = new VariableAnalyzer(
2030:                        params,
2031:                        options
2032:                                .getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY));
2033:                for (Iterator i = prefix.iterator(); i.hasNext();) {
2034:                    analyzer.visit((SimpleNode) i.next());
2035:                }
2036:                for (Iterator i = stmtList.iterator(); i.hasNext();) {
2037:                    analyzer.visit((SimpleNode) i.next());
2038:                }
2039:                for (Iterator i = postfix.iterator(); i.hasNext();) {
2040:                    analyzer.visit((SimpleNode) i.next());
2041:                }
2042:                analyzer.computeReferences();
2043:                // Parameter _must_ be in order
2044:                LinkedHashSet parameters = analyzer.parameters;
2045:                // Linked for determinism for regression testing
2046:                Set variables = analyzer.variables;
2047:                LinkedHashMap fundefs = analyzer.fundefs;
2048:                Set closed = analyzer.closed;
2049:                Set free = analyzer.free;
2050:                // Note usage due to activation object and withThis
2051:                if (!free.isEmpty()) {
2052:                    // TODO: [2005-06-29 ptw] with (_root) should not be
2053:                    // necessary for the activation object case now that it is
2054:                    // done at top level to get [[scope]] right.
2055:                    if (options.getBoolean(Compiler.ACTIVATION_OBJECT)) {
2056:                        analyzer.incrementUsed("_root");
2057:                    }
2058:                    if (options.getBoolean(Compiler.WITH_THIS)) {
2059:                        analyzer.incrementUsed("this");
2060:                    }
2061:                }
2062:                Map used = analyzer.used;
2063:                // If this is a closure, annotate the Username for metering
2064:                if ((!closed.isEmpty()) && (functionName != null)
2065:                        && options.getBoolean(Compiler.PROFILE)) {
2066:                    // Is there any other way to construct a closure in js
2067:                    // other than a function returning a function?
2068:                    if (context.findFunctionContext().parent
2069:                            .findFunctionContext() != null) {
2070:                        userFunctionName = "" + closed + "." + userFunctionName;
2071:                    }
2072:                }
2073:                if (false) {
2074:                    System.err.println(userFunctionName + ":: parameters: "
2075:                            + parameters + ", variables: " + variables
2076:                            + ", fundefs: " + fundefs + ", used: " + used
2077:                            + ", closed: " + closed + ", free: " + free);
2078:                }
2079:                // Deal with warnings
2080:                if (options.getBoolean(Compiler.WARN_UNUSED_PARAMETERS)) {
2081:                    Set unusedParams = new LinkedHashSet(parameters);
2082:                    unusedParams.removeAll(used.keySet());
2083:                    for (Iterator i = unusedParams.iterator(); i.hasNext();) {
2084:                        System.err.println("Warning: parameter " + i.next()
2085:                                + " of " + userFunctionName + " unused in "
2086:                                + filename + "(" + lineno + ")");
2087:                    }
2088:                }
2089:                if (options.getBoolean(Compiler.WARN_UNUSED_LOCALS)) {
2090:                    Set unusedVariables = new LinkedHashSet(variables);
2091:                    unusedVariables.removeAll(used.keySet());
2092:                    for (Iterator i = unusedVariables.iterator(); i.hasNext();) {
2093:                        System.err.println("Warning: variable " + i.next()
2094:                                + " of " + userFunctionName + " unused in "
2095:                                + filename + "(" + lineno + ")");
2096:                    }
2097:                }
2098:                // auto-declared locals
2099:                Set auto = new LinkedHashSet(Instructions.Register.AUTO_REG);
2100:                auto.retainAll(used.keySet());
2101:                // parameters, locals, and auto-registers
2102:                Set known = new LinkedHashSet(parameters);
2103:                known.addAll(variables);
2104:                known.addAll(auto);
2105:                // for now, ensure that super has a value
2106:                known.remove("super");
2107:                Set knownSet = new LinkedHashSet(known);
2108:                Set lowerKnownSet = new LinkedHashSet();
2109:                for (Iterator i = knownSet.iterator(); i.hasNext();) {
2110:                    lowerKnownSet.add(((String) i.next()).toLowerCase());
2111:                }
2112:                context.setProperty(TranslationContext.VARIABLES, knownSet);
2113:                context.setProperty(TranslationContext.LOWERVARIABLES,
2114:                        lowerKnownSet);
2115:
2116:                boolean scriptElement = options
2117:                        .getBoolean(Compiler.SCRIPT_ELEMENT);
2118:                Map registerMap = new HashMap();
2119:                Map lowerRegisterMap = new HashMap();
2120:                // Always set register map.  Inner functions should not see
2121:                // parent registers (which they would if the setting of the
2122:                // registermap were conditional on function vs. function2)
2123:                context.setProperty(TranslationContext.REGISTERS, registerMap);
2124:                context.setProperty(TranslationContext.LOWERREGISTERS,
2125:                        lowerRegisterMap);
2126:                // TODO: [2004-03-24] Analyze register usage in $flasm and
2127:                // account for it (or rename $flasm regs?)
2128:                // NB: Only Flash Player 6r65 or better understands function2
2129:                if (options.getBoolean(Compiler.GENERATE_FUNCTION_2)
2130:                        && (options
2131:                                .getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY) || options
2132:                                .getBoolean(Compiler.GENERATE_FUNCTION_2_FOR_LZX))
2133:                        && (!scriptElement) && (!used.containsKey("eval"))
2134:                        && (!used.containsKey("$flasm"))) {
2135:                    Set autoRegisters = new LinkedHashSet();
2136:                    for (Iterator i = auto.iterator(); i.hasNext();) {
2137:                        autoRegisters.add(Instructions.Register
2138:                                .make(((String) i.next())));
2139:                    }
2140:                    // fnArgs _must_ be in order
2141:                    Set fnArgs = new LinkedHashSet(autoRegisters);
2142:                    SortedMap paramRegisters = new TreeMap();
2143:                    SortedMap varRegisters = new TreeMap(new DoubleCollator());
2144:                    // TODO: [2004-03-27 ptw] Should use threshold for
2145:                    // parameters be 0 or 1?  Presumably there is a getVariable
2146:                    // cost to loading the register.
2147:                    int j = parameters.size();
2148:                    for (Iterator i = parameters.iterator(); i.hasNext(); j--) {
2149:                        String v = (String) i.next();
2150:                        if (used.containsKey(v) && (!closed.contains(v))) {
2151:                            Instructions.Register reg = Instructions.Register
2152:                                    .make(v);
2153:                            fnArgs.add(reg);
2154:                            paramRegisters.put("" + j, reg);
2155:                        } else {
2156:                            // Always accept the arg, even if not used, since they are positional
2157:                            fnArgs.add(v);
2158:                        }
2159:                    }
2160:                    j = 0;
2161:                    // FIXME: [2006-01-17 ptw] TreeSet is for Regression compatibility
2162:                    variables = new TreeSet(variables);
2163:                    for (Iterator i = variables.iterator(); i.hasNext(); j++) {
2164:                        String v = (String) i.next();
2165:                        if (used.containsKey(v) && (!closed.contains(v))) {
2166:                            Instructions.Register reg = Instructions.Register
2167:                                    .make(v);
2168:                            // Most used first, original order disambiguates
2169:                            varRegisters
2170:                                    .put(
2171:                                            new Double(
2172:                                                    -(((Integer) used.get(v))
2173:                                                            .doubleValue() + (double) j / 1000)),
2174:                                            reg);
2175:                        } else {
2176:                            ;
2177:                        }
2178:                    }
2179:                    if ((!autoRegisters.isEmpty())
2180:                            || (!paramRegisters.isEmpty())
2181:                            || (!varRegisters.isEmpty())) {
2182:                        // Don't know how Flash assigns registers (one would
2183:                        // have thought the parameters should be in stack order
2184:                        // and others by frequency of use), but we do know the
2185:                        // auto registers always come first in order and r:0 is
2186:                        // never assigned.  It appears the parameters are
2187:                        // assigned last.
2188:                        // TODO: [2004-03-29 ptw] Measure the cost of loading a
2189:                        // parameter register so we know whether to weight them
2190:                        // the same as var registers when there aren't enough
2191:                        // registers
2192:                        List registers = new ArrayList(autoRegisters);
2193:                        for (Iterator i = varRegisters.values().iterator(); i
2194:                                .hasNext();) {
2195:                            registers.add(i.next());
2196:                        }
2197:                        for (Iterator i = paramRegisters.values().iterator(); i
2198:                                .hasNext();) {
2199:                            registers.add(i.next());
2200:                        }
2201:                        // Assign register numbers [1, 255]
2202:                        if (registers.size() > 254) {
2203:                            registers = registers.subList(0, 254);
2204:                        }
2205:                        byte regno = 1;
2206:                        for (Iterator i = registers.iterator(); i.hasNext(); regno++) {
2207:                            Instructions.Register r = (Instructions.Register) i
2208:                                    .next();
2209:                            r.regno = regno;
2210:                            registerMap.put(r.name, r);
2211:                            lowerRegisterMap.put(r.name.toLowerCase(), r);
2212:                        }
2213:                        // It appears you have to always allocate r:0, hence
2214:                        // regno, not len(registers)
2215:                        List args = new ArrayList();
2216:                        args.add(block);
2217:                        args.add(functionName);
2218:                        args.add(new Integer(regno));
2219:                        args.addAll(fnArgs);
2220:                        collector.emit(Instructions.DefineFunction2.make(args
2221:                                .toArray()));
2222:                    } else {
2223:                        List args = new ArrayList();
2224:                        args.add(block);
2225:                        args.add(functionName);
2226:                        args.addAll(parameters);
2227:                        collector.emit(Instructions.DefineFunction.make(args
2228:                                .toArray()));
2229:                    }
2230:                } else {
2231:                    List args = new ArrayList();
2232:                    args.add(block);
2233:                    args.add(functionName);
2234:                    args.addAll(parameters);
2235:                    collector.emit(Instructions.DefineFunction.make(args
2236:                            .toArray()));
2237:                }
2238:
2239:                int activationObjectSize = 0;
2240:                if (scriptElement) {
2241:                    // Create all variables (including inner functions) in global scope
2242:                    if (!variables.isEmpty()) {
2243:                        if (registerMap.containsKey("_root")) {
2244:                            collector
2245:                                    .push(Values
2246:                                            .Register(((Instructions.Register) registerMap
2247:                                                    .get("_root")).regno));
2248:                        } else {
2249:                            collector.push("_root");
2250:                            collector.emit(Instructions.GetVariable);
2251:                        }
2252:                        // Optimization dups fetch of root for all but last which consumes it
2253:                        int j = 0, len = variables.size() - 1;
2254:                        for (Iterator i = variables.iterator(); i.hasNext(); j++) {
2255:                            if (j < len) {
2256:                                collector.emit(Instructions.DUP);
2257:                            }
2258:                            collector.push((String) i.next());
2259:                            collector.push(Values.Undefined);
2260:                            collector.emit(Instructions.SetMember);
2261:                        }
2262:                    }
2263:                } else {
2264:                    // create unregistered, used variables in activation context
2265:                    LinkedHashSet toCreate = new LinkedHashSet(variables);
2266:                    toCreate.retainAll(used.keySet());
2267:                    toCreate.removeAll(registerMap.keySet());
2268:                    if (options.getBoolean(Compiler.ACTIVATION_OBJECT)) {
2269:                        for (Iterator i = toCreate.iterator(); i.hasNext();) {
2270:                            Object var = i.next();
2271:                            collector.push(var);
2272:                            collector.push(Values.Undefined);
2273:                            activationObjectSize += 1;
2274:                        }
2275:                    } else {
2276:                        for (Iterator i = toCreate.iterator(); i.hasNext();) {
2277:                            Object var = i.next();
2278:                            collector.push(var);
2279:                            collector.emit(Instructions.VAR);
2280:                        }
2281:                    }
2282:                }
2283:                // create unregistered, used parameters in activation context
2284:                // (only needed for activation object, they are already in context)
2285:                if (options.getBoolean(Compiler.ACTIVATION_OBJECT)) {
2286:                    LinkedHashSet toCreate = new LinkedHashSet(parameters);
2287:                    toCreate.retainAll(used.keySet());
2288:                    toCreate.removeAll(registerMap.keySet());
2289:                    for (Iterator i = toCreate.iterator(); i.hasNext();) {
2290:                        Object param = i.next();
2291:                        collector.push(param);
2292:                        collector.push(param);
2293:                        collector.emit(Instructions.GetVariable);
2294:                        activationObjectSize += 1;
2295:                    }
2296:                }
2297:                if (activationObjectSize > 0) {
2298:                    collector.push(activationObjectSize);
2299:                    collector.emit(Instructions.InitObject);
2300:                }
2301:                // scriptElements must be compiled inside with(_root) -- that
2302:                // is their required environment because all their local
2303:                // bindings are transformed to _root bindings (and will not be
2304:                // if they are loaded as snippets)
2305:                // TODO: [2005-06-29 ptw] with (_root) should not be necessary
2306:                // for the activation object case now that it is done at top
2307:                // level to get [[scope]] right.
2308:                if (((!free.isEmpty()) && activationObjectSize > 0)
2309:                        || scriptElement) {
2310:                    if (registerMap.containsKey("_root")) {
2311:                        collector.push(Values
2312:                                .Register(((Instructions.Register) registerMap
2313:                                        .get("_root")).regno));
2314:                    } else {
2315:                        collector.push("_root");
2316:                        collector.emit(Instructions.GetVariable);
2317:                    }
2318:                    collector.emit(Instructions.WITH.make(block));
2319:                }
2320:                if ((!free.isEmpty()) && options.getBoolean(Compiler.WITH_THIS)) {
2321:                    if (registerMap.containsKey("this")) {
2322:                        collector.push(Values
2323:                                .Register(((Instructions.Register) registerMap
2324:                                        .get("this")).regno));
2325:                    } else {
2326:                        collector.push("this");
2327:                        collector.emit(Instructions.GetVariable);
2328:                    }
2329:                    collector.emit(Instructions.WITH.make(block));
2330:                }
2331:                if (activationObjectSize > 0) {
2332:                    collector.emit(Instructions.WITH.make(block));
2333:                }
2334:                // inner functions do not get scriptElement treatment
2335:                options.putBoolean(Compiler.SCRIPT_ELEMENT, false);
2336:                // or the magic with(this) treatment
2337:                options.putBoolean(Compiler.WITH_THIS, false);
2338:                // Now emit functions in the activation context
2339:                if (scriptElement) {
2340:                    // create functions in global scope
2341:                    // Note: variable has already been declared so SetVariable
2342:                    // does the right thing
2343:                    for (Iterator i = fundefs.keySet().iterator(); i.hasNext();) {
2344:                        String name = (String) i.next();
2345:                        SimpleNode fun = (SimpleNode) fundefs.get(name);
2346:                        // Make sure all our top-level functions have root context
2347:                        String withBlock = newLabel(node);
2348:                        collector.push("_root");
2349:                        collector.emit(Instructions.GetVariable);
2350:                        collector.emit(Instructions.WITH.make(withBlock));
2351:                        collector.push(name);
2352:                        translateFunction(fun, false, fun.getChildren());
2353:                        collector.emit(Instructions.SetVariable);
2354:                        collector.emit(Instructions.LABEL.make(withBlock));
2355:                    }
2356:                } else {
2357:                    for (Iterator i = fundefs.keySet().iterator(); i.hasNext();) {
2358:                        String name = (String) i.next();
2359:                        SimpleNode fun = (SimpleNode) fundefs.get(name);
2360:                        if (used.containsKey(name)) {
2361:                            if ((!registerMap.containsKey(name))) {
2362:                                collector.push(name);
2363:                            }
2364:                            translateFunction(fun, false, fun.getChildren());
2365:                            if (registerMap.containsKey(name)) {
2366:                                collector
2367:                                        .emit(Instructions.SetRegister
2368:                                                .make(((Instructions.Register) registerMap
2369:                                                        .get(name)).regno));
2370:                                collector.emit(Instructions.POP);
2371:                            } else {
2372:                                collector.emit(Instructions.SetVariable);
2373:                            }
2374:                        }
2375:                    }
2376:                } // end of else scriptElement
2377:                if (!prefix.isEmpty()) {
2378:                    visitStatementList(node, (SimpleNode[]) prefix
2379:                            .toArray(new SimpleNode[0]));
2380:                    // label flushes optimizer
2381:                    collector.emit(Instructions.LABEL.make(newLabel(node)));
2382:                }
2383:                visitStatementList(node, (SimpleNode[]) stmtList
2384:                        .toArray(new SimpleNode[0]));
2385:                // runtime handles implicit return except if postfix
2386:                if (!postfix.isEmpty()) {
2387:                    collector.push(Values.Undefined);
2388:                    collector.emit(Instructions.LABEL.make(context
2389:                            .findFunctionContext().label));
2390:                    visitStatementList(node, (SimpleNode[]) postfix
2391:                            .toArray(new SimpleNode[0]));
2392:                    collector.emit(Instructions.RETURN);
2393:                }
2394:                // close function
2395:                collector.emit(Instructions.LABEL.make(block));
2396:                if (options.getBoolean(Compiler.NAME_FUNCTIONS)) {
2397:                    if (functionName != null) {
2398:                        // Named functions do not leave a value on the stack
2399:                        collector.push(functionName);
2400:                        collector.emit(Instructions.GetVariable);
2401:                    } else {
2402:                        // Function expression leaves function on stack
2403:                        collector.emit(Instructions.DUP);
2404:                    }
2405:                    collector.push("name");
2406:                    collector.push(userFunctionName);
2407:                    collector.emit(Instructions.SetMember);
2408:                    if (options.getBoolean(Compiler.DEBUG_BACKTRACE)) {
2409:                        // TODO: [2007-09-04 ptw] Come up with a better way to
2410:                        // distinguish LFC from user stack frames.  See
2411:                        // lfc/debugger/LzBactrace
2412:                        String fn = (options
2413:                                .getBoolean(Compiler.FLASH_COMPILER_COMPATABILITY) ? "lfc/"
2414:                                : "")
2415:                                + filename;
2416:                        if (functionName != null) {
2417:                            collector.push(functionName);
2418:                            collector.emit(Instructions.GetVariable);
2419:                        } else {
2420:                            collector.emit(Instructions.DUP);
2421:                        }
2422:                        collector.push("_dbg_filename");
2423:                        collector.push(fn);
2424:                        collector.emit(Instructions.SetMember);
2425:                        if (functionName != null) {
2426:                            collector.push(functionName);
2427:                            collector.emit(Instructions.GetVariable);
2428:                        } else {
2429:                            collector.emit(Instructions.DUP);
2430:                        }
2431:                        collector.push("_dbg_lineno");
2432:                        collector.push(lineno);
2433:                        collector.emit(Instructions.SetMember);
2434:                    }
2435:                }
2436:                if (options.getBoolean(Compiler.CONSTRAINT_FUNCTION)) {
2437:                    return depExpr;
2438:                }
2439:                return null;
2440:            }
2441:
2442:            Object translateLiteralNode(SimpleNode node) {
2443:                Object value = ((ASTLiteral) node).getValue();
2444:                if (value == null) {
2445:                    return Values.Null;
2446:                } else if (value instanceof  Boolean) {
2447:                    return (((Boolean) value).booleanValue()) ? Values.True
2448:                            : Values.False;
2449:                }
2450:                return value;
2451:            }
2452:
2453:            boolean translateReferenceForCall(SimpleNode ast) {
2454:                return translateReferenceForCall(ast, false, null);
2455:            }
2456:
2457:            /* Contract is to leave a reference on the stack that will be
2458:               dereferenced by CallFunction, etc.  Returns true if it
2459:               succeeds.  Returns false if the ast is such that only the
2460:               value of the reference can be pushed.  In this case, the
2461:               callee, must use "CallMethod UNDEF" to call the value
2462:               instead */
2463:            boolean translateReferenceForCall(SimpleNode ast,
2464:                    boolean checkDefined, SimpleNode node) {
2465:                if (checkDefined) {
2466:                    assert node != null : "Must supply node for checkDefined";
2467:                }
2468:                if (ast instanceof  ASTPropertyIdentifierReference) {
2469:                    translateReference(ast.get(0)).get();
2470:                    String name = ((ASTIdentifier) ast.get(1)).getName();
2471:                    if (checkDefined) {
2472:                        checkUndefinedMethod(node, name);
2473:                    }
2474:                    collector.push(name);
2475:                    return true;
2476:                }
2477:                if (ast instanceof  ASTPropertyValueReference) {
2478:                    // TODO: [2002-10-26 ptw] (undefined reference coverage) Check
2479:                    translateReference(ast.get(0)).get();
2480:                    visitExpression(ast.get(1));
2481:                    return true;
2482:                }
2483:                // The only other reason you visit a reference is to make a funcall
2484:                boolean isref = true;
2485:                if (ast instanceof  ASTIdentifier) {
2486:                    Reference ref = translateReference(ast);
2487:                    if (ref instanceof  VariableReference
2488:                            && ((VariableReference) ref).register != null) {
2489:                        ref.get();
2490:                        isref = false;
2491:                    } else {
2492:                        ref.preset();
2493:                    }
2494:                } else {
2495:                    visitExpression(ast);
2496:                    isref = false;
2497:                }
2498:                if (checkDefined) {
2499:                    checkUndefinedFunction(
2500:                            node,
2501:                            isref && ast instanceof  ASTIdentifier ? ((ASTIdentifier) ast)
2502:                                    .getName()
2503:                                    : null);
2504:                }
2505:                return isref;
2506:            }
2507:
2508:            /***
2509:             * A Reference represents a variable, property, or array reference ---
2510:             * a LeftHandSide in the grammar.  References can be retrieved or
2511:             * assigned.
2512:             */
2513:            static public abstract class Reference {
2514:                public CodeGenerator translator;
2515:                public SimpleNode node;
2516:                public int referenceCount;
2517:                protected Compiler.OptionMap options;
2518:                protected InstructionCollector collector;
2519:
2520:                public Reference(CodeGenerator translator, SimpleNode node,
2521:                        int referenceCount) {
2522:                    this .translator = translator;
2523:                    this .options = translator.getOptions();
2524:                    this .collector = translator.getCollector();
2525:                    this .node = node;
2526:                    this .referenceCount = referenceCount;
2527:                }
2528:
2529:                protected void report(String reportMethod, String message) {
2530:                    // TODO: [2005-12-21 ptw]
2531:                    //       collector.emitCall(reportMethod,
2532:                    //                          fname, lineno, propertyName);
2533:                    collector.push(message);
2534:                    collector.push(node.beginLine);
2535:                    collector.push(node.filename);
2536:                    collector.push(3);
2537:                    collector.push(reportMethod);
2538:                    collector.emit(Instructions.CallFunction);
2539:                    //
2540:                    collector.emit(Instructions.POP); // pop error return
2541:                }
2542:
2543:                // Check that the reference count supplied at initialization
2544:                // time was large enough.
2545:                protected void _pop() {
2546:                    assert referenceCount > 0;
2547:                    referenceCount -= 1;
2548:                }
2549:
2550:                // Emit instructions that push this reference's value onto the
2551:                // stack.
2552:                public abstract Reference get(boolean checkUndefined);
2553:
2554:                public Reference get() {
2555:                    return get(true);
2556:                }
2557:
2558:                // Emit instructions that set the stack up to set this
2559:                // reference's value.  Example use:
2560:                //           reference.preset()
2561:                //           generator.push(1)
2562:                //           reference.set().
2563:                public abstract Reference preset();
2564:
2565:                // Emit instructions that set the value of this object.  See
2566:                // preset() for an example.
2567:                public abstract Reference set(Boolean warnGlobal);
2568:
2569:                public Reference set() {
2570:                    return set(null);
2571:                }
2572:
2573:                public Reference set(boolean warnGlobal) {
2574:                    return set(Boolean.valueOf(warnGlobal));
2575:                }
2576:
2577:                public Reference declare() {
2578:                    throw new CompilerError(
2579:                            "unsupported reference operation: declare");
2580:                }
2581:
2582:                public Reference init() {
2583:                    throw new CompilerError(
2584:                            "unsupported reference operation: init");
2585:                }
2586:            }
2587:
2588:            static public abstract class MemberReference extends Reference {
2589:                protected SimpleNode object;
2590:
2591:                public MemberReference(CodeGenerator translator,
2592:                        SimpleNode node, int referenceCount, SimpleNode object) {
2593:                    super (translator, node, referenceCount);
2594:                    this .object = object;
2595:                }
2596:
2597:                // Emits code to check that the object exists before making a
2598:                // property reference.  Expects the object to be at the top of stack
2599:                // when called.
2600:                protected void checkUndefinedObjectProperty(String propertyName) {
2601:                    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)
2602:                            && node.filename != null) {
2603:                        String label = translator.newLabel(node);
2604:                        collector.emit(Instructions.DUP);
2605:                        collector.emit(Instructions.TypeOf);
2606:                        collector.push("undefined");
2607:                        collector.emit(Instructions.EQUALS);
2608:                        collector.emit(Instructions.NOT);
2609:                        collector.emit(Instructions.BranchIfTrue.make(label));
2610:                        report("$reportUndefinedObjectProperty", propertyName);
2611:                        collector.emit(Instructions.LABEL.make(label));
2612:                    }
2613:                }
2614:
2615:                // Emits code to check that an object property selector is
2616:                // defined.  Note this test is a little looser than other undefined
2617:                // tests -- we want to warn if someone is using null as a selector
2618:                // too, hence the '==undefined' test.  Expects the object member to
2619:                // be at the top of stack when called.
2620:                protected void checkUndefinedPropertySelector(
2621:                        String propertyName) {
2622:                    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)
2623:                            && node.filename != null) {
2624:                        String label = translator.newLabel(node);
2625:                        collector.emit(Instructions.DUP); // s s
2626:                        collector.push(Values.Undefined); // s s UNDEF
2627:                        collector.emit(Instructions.EQUALS); // s s==UNDEF
2628:                        collector.emit(Instructions.NOT); // s s!=UNDEF
2629:                        collector.emit(Instructions.BranchIfTrue.make(label));
2630:                        report("$reportUndefinedProperty", propertyName);
2631:                        collector.emit(Instructions.LABEL.make(label));
2632:                    }
2633:                }
2634:
2635:                // Emits code to check that an object property is defined.
2636:                // Expects the object member to be at the top of stack when
2637:                // called.
2638:                protected void checkUndefinedProperty(String propertyName) {
2639:                    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)
2640:                            && node.filename != null) {
2641:                        String label = translator.newLabel(node);
2642:                        collector.emit(Instructions.DUP);
2643:                        collector.emit(Instructions.TypeOf);
2644:                        collector.push("undefined");
2645:                        collector.emit(Instructions.EQUALS);
2646:                        collector.emit(Instructions.NOT);
2647:                        collector.emit(Instructions.BranchIfTrue.make(label));
2648:                        report("$reportUndefinedProperty", propertyName);
2649:                        collector.emit(Instructions.LABEL.make(label));
2650:                    }
2651:                }
2652:
2653:                protected abstract void pushObject(boolean checkUndefined);
2654:
2655:                public Reference preset() {
2656:                    _pop();
2657:                    pushObject(true);
2658:                    return this ;
2659:                }
2660:
2661:                public Reference set(Boolean warnGlobal) {
2662:                    collector.emit(Instructions.SetMember);
2663:                    return this ;
2664:                }
2665:            }
2666:
2667:            static public class VariableReference extends Reference {
2668:                TranslationContext context;
2669:                public final String name;
2670:                public final Instructions.Register register;
2671:                boolean known;
2672:
2673:                public VariableReference(CodeGenerator translator,
2674:                        SimpleNode node, int referenceCount, String name) {
2675:                    super (translator, node, referenceCount);
2676:                    this .name = name;
2677:                    this .context = (TranslationContext) translator.getContext();
2678:                    Map registers = (Map) context
2679:                            .get(TranslationContext.REGISTERS);
2680:                    if (registers != null) {
2681:                        this .register = (Instructions.Register) registers
2682:                                .get(name);
2683:                        if ("swf6".equals(Instructions.getRuntime())) {
2684:                            Map lowerRegisters = (Map) context
2685:                                    .get(TranslationContext.LOWERREGISTERS);
2686:                            if (register != null
2687:                                    && (!lowerRegisters.containsKey(name
2688:                                            .toLowerCase()))) {
2689:                                System.err
2690:                                        .println("Warning: Different case used for "
2691:                                                + name
2692:                                                + " in "
2693:                                                + node.filename
2694:                                                + " (" + node.beginLine + ")");
2695:                            }
2696:                        }
2697:                    } else {
2698:                        this .register = null;
2699:                    }
2700:                    Set variables = (Set) context
2701:                            .get(TranslationContext.VARIABLES);
2702:                    if (variables != null) {
2703:                        this .known = variables.contains(name);
2704:                        if ("swf6".equals(Instructions.getRuntime())) {
2705:                            Set lowerVariables = (Set) context
2706:                                    .get(TranslationContext.LOWERVARIABLES);
2707:                            if (known
2708:                                    && (!lowerVariables.contains(name
2709:                                            .toLowerCase()))) {
2710:                                System.err
2711:                                        .println("Warning: Different case used for "
2712:                                                + name
2713:                                                + " in "
2714:                                                + node.filename
2715:                                                + " (" + node.beginLine + ")");
2716:                            }
2717:                        }
2718:                        // TODO: [2005-12-22 ptw] Not true ECMAscript
2719:                        // Ensure undefined is "defined"
2720:                        known |= "undefined".equals(name);
2721:                    }
2722:                }
2723:
2724:                // Emits code to check that an object variable is defined.
2725:                // Expects the value of the variable to be at the top of stack when
2726:                // called.
2727:                private void checkUndefinedVariable(SimpleNode node,
2728:                        String variableName) {
2729:                    if (options.getBoolean(Compiler.WARN_UNDEFINED_REFERENCES)
2730:                            && node.filename != null) {
2731:                        String label = translator.newLabel(node);
2732:                        collector.emit(Instructions.DUP);
2733:                        collector.emit(Instructions.TypeOf);
2734:                        collector.push("undefined");
2735:                        collector.emit(Instructions.EQUALS);
2736:                        collector.emit(Instructions.NOT);
2737:
2738:                        collector.emit(Instructions.BranchIfTrue.make(label));
2739:                        report("$reportUndefinedVariable", variableName);
2740:                        collector.emit(Instructions.LABEL.make(label));
2741:                    }
2742:                }
2743:
2744:                public Reference get(boolean checkUndefined) {
2745:                    _pop();
2746:                    if (register != null) {
2747:                        collector.emit(Instructions.PUSH.make(Values
2748:                                .Register(register.regno)));
2749:                    } else {
2750:                        collector.push(name);
2751:                        collector.emit(Instructions.GetVariable);
2752:                    }
2753:                    if (checkUndefined && (!known)) {
2754:                        checkUndefinedVariable(node, name);
2755:                    }
2756:                    return this ;
2757:                }
2758:
2759:                public Reference preset() {
2760:                    _pop();
2761:                    if (register == null) {
2762:                        if ("undefined".equals(name)) {
2763:                            throw new SemanticError("Invalid l-value", node);
2764:                        }
2765:                        collector.push(name);
2766:                    }
2767:                    return this ;
2768:                }
2769:
2770:                public Reference set(Boolean warnGlobal) {
2771:                    if (warnGlobal == null) {
2772:                        if (context.type instanceof  ASTProgram) {
2773:                            warnGlobal = Boolean.FALSE;
2774:                        } else {
2775:                            warnGlobal = Boolean
2776:                                    .valueOf(options
2777:                                            .getBoolean(Compiler.WARN_GLOBAL_ASSIGNMENTS));
2778:                        }
2779:                    }
2780:                    if ((!known) && warnGlobal.booleanValue()) {
2781:                        System.err
2782:                                .println("Warning: Assignment to free variable "
2783:                                        + name
2784:                                        + " in "
2785:                                        + node.filename
2786:                                        + " ("
2787:                                        + node.beginLine + ")");
2788:                    }
2789:                    if (register != null) {
2790:                        collector.emit(Instructions.SetRegister
2791:                                .make(new Integer(register.regno)));
2792:                        // TODO: [2004-03-24 ptw] Optimize this away if the value is used
2793:                        collector.emit(Instructions.POP);
2794:                    } else {
2795:                        collector.emit(Instructions.SetVariable);
2796:                    }
2797:                    return this ;
2798:                }
2799:
2800:                public Reference declare() {
2801:                    // If in a function, already declared
2802:                    if (!known) {
2803:                        collector.emit(Instructions.VAR);
2804:                    }
2805:                    return this ;
2806:                }
2807:
2808:                public Reference init() {
2809:                    // If in a function, already declared
2810:                    if (known) {
2811:                        set();
2812:                    } else {
2813:                        collector.emit(Instructions.VarEquals);
2814:                    }
2815:                    return this ;
2816:                }
2817:            }
2818:
2819:            static public class PropertyReference extends MemberReference {
2820:                String propertyName;
2821:
2822:                public PropertyReference(CodeGenerator translator,
2823:                        SimpleNode node, int referenceCount, SimpleNode object,
2824:                        ASTIdentifier propertyName) {
2825:                    super (translator, node, referenceCount, object);
2826:                    this .propertyName = (String) propertyName.getName();
2827:                }
2828:
2829:                protected void pushObject(boolean checkUndefined) {
2830:                    translator.visitExpression(object);
2831:                    if (checkUndefined) {
2832:                        checkUndefinedObjectProperty(propertyName);
2833:                        if (propertyName == "undefined") {
2834:                            throw new SemanticError("Invalid l-value", node);
2835:                        }
2836:                    }
2837:                    collector.push(propertyName);
2838:                }
2839:
2840:                public Reference get(boolean checkUndefined) {
2841:                    _pop();
2842:                    pushObject(checkUndefined);
2843:                    collector.emit(Instructions.GetMember);
2844:                    if (checkUndefined) {
2845:                        checkUndefinedProperty(propertyName);
2846:                    }
2847:                    return this ;
2848:                }
2849:
2850:            }
2851:
2852:            static public class IndexReference extends MemberReference {
2853:                SimpleNode indexExpr;
2854:
2855:                public IndexReference(CodeGenerator translator,
2856:                        SimpleNode node, int referenceCount, SimpleNode object,
2857:                        SimpleNode indexExpr) {
2858:                    super (translator, node, referenceCount, object);
2859:                    this .indexExpr = indexExpr;
2860:                }
2861:
2862:                protected void pushObject(boolean checkUndefined) {
2863:                    // incorrect semantics, but compatible with Flash
2864:                    translator.visitExpression(object);
2865:                    if (checkUndefined) {
2866:                        checkUndefinedObjectProperty("[]");
2867:                    }
2868:                    translator.visitExpression(indexExpr);
2869:                    if (checkUndefined) {
2870:                        // TODO: [2005-04-17 ptw] Perhaps use Compiler.nodeString(node)
2871:                        // instead of "[]"?
2872:                        checkUndefinedPropertySelector("[]");
2873:                    }
2874:                }
2875:
2876:                public Reference get(boolean checkUndefined) {
2877:                    _pop();
2878:                    pushObject(checkUndefined);
2879:                    collector.emit(Instructions.GetMember);
2880:                    // TODO: [2003-05-14 ptw] checkUndefined
2881:                    if (false) { // (checkUndefined) {
2882:                        checkUndefinedProperty("[]");
2883:                    }
2884:                    return this ;
2885:                }
2886:
2887:            }
2888:
2889:            // NOTE: [2002-10-24 ptw] Not completely right, this handles the case
2890:            // where a literal is the target of a method operation.  It is like a
2891:            // reference but it is not an lvalue.
2892:            static public class LiteralReference extends Reference {
2893:
2894:                public LiteralReference(CodeGenerator translator,
2895:                        SimpleNode node, int referenceCount) {
2896:                    super (translator, node, referenceCount);
2897:                }
2898:
2899:                public Reference get(boolean checkUndefined) {
2900:                    _pop();
2901:                    translator.visitExpression(node);
2902:                    return this ;
2903:                }
2904:
2905:                public Reference preset() {
2906:                    throw new SemanticError("Invalid literal operation", node);
2907:                }
2908:
2909:                public Reference set(Boolean warnGlobal) {
2910:                    throw new SemanticError("Invalid literal operation", node);
2911:                }
2912:            }
2913:
2914:            Reference translateReference(SimpleNode node) {
2915:                return translateReference(node, 1);
2916:            }
2917:
2918:            Reference translateReference(SimpleNode node, int referenceCount) {
2919:                if (node instanceof  ASTIdentifier) {
2920:                    return new VariableReference(this , node, referenceCount,
2921:                            ((ASTIdentifier) node).getName());
2922:                }
2923:                if (node instanceof  ASTThisReference) {
2924:                    return new VariableReference(this , node, referenceCount,
2925:                            "this");
2926:                }
2927:                SimpleNode[] args = node.getChildren();
2928:                if (node instanceof  ASTPropertyIdentifierReference) {
2929:                    return new PropertyReference(this , node, referenceCount,
2930:                            args[0], (ASTIdentifier) args[1]);
2931:                } else if (node instanceof  ASTPropertyValueReference) {
2932:                    return new IndexReference(this , node, referenceCount,
2933:                            args[0], args[1]);
2934:                }
2935:
2936:                return new LiteralReference(this , node, referenceCount);
2937:            }
2938:        }
2939:
2940:        /* J_LZ_COPYRIGHT_BEGIN *******************************************************
2941:         * Copyright 2001-2008 Laszlo Systems, Inc.  All Rights Reserved.              *
2942:         * Use is subject to license terms.                                            *
2943:         * J_LZ_COPYRIGHT_END *********************************************************/
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.