incubator-callback-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From purplecabb...@apache.org
Subject [51/52] [abbrv] [partial] re-org
Date Mon, 10 Sep 2012 23:57:45 GMT
http://git-wip-us.apache.org/repos/asf/incubator-cordova-windows/blob/03bf0cde/windows8/framework/Cordova-Metro/lib/Jscex/src/jscex-jit.js
----------------------------------------------------------------------
diff --git a/windows8/framework/Cordova-Metro/lib/Jscex/src/jscex-jit.js b/windows8/framework/Cordova-Metro/lib/Jscex/src/jscex-jit.js
new file mode 100644
index 0000000..43e09fd
--- /dev/null
+++ b/windows8/framework/Cordova-Metro/lib/Jscex/src/jscex-jit.js
@@ -0,0 +1,1692 @@
+(function () {
+    "use strict";
+    
+    var Jscex;
+    
+    var codeGenerator = (typeof eval("(function () {})") == "function") ?
+        function (code) { return code; } :
+        function (code) { return "false || " + code; };
+        
+    // support string type only.
+    var stringify = (typeof JSON !== "undefined" && JSON.stringify) ?
+        function (s) { return JSON.stringify(s); } :
+        (function () {
+            // Implementation comes from JSON2 (http://www.json.org/js.html)
+        
+            var escapable = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
+            
+            var meta = {    // table of character substitutions
+                '\b': '\\b',
+                '\t': '\\t',
+                '\n': '\\n',
+                '\f': '\\f',
+                '\r': '\\r',
+                '"' : '\\"',
+                '\\': '\\\\'
+            }
+            
+            return function (s) {
+                // If the string contains no control characters, no quote characters, and no
+                // backslash characters, then we can safely slap some quotes around it.
+                // Otherwise we must also replace the offending characters with safe escape
+                // sequences.
+
+                escapable.lastIndex = 0;
+                return escapable.test(s) ? '"' + s.replace(escapable, function (a) {
+                    var c = meta[a];
+                    return typeof c === 's' ? c :
+                        '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
+                }) + '"' : '"' + s + '"';
+            };
+        })();
+    
+    function sprintf(format) {
+        var args = arguments;
+        return format.toString().replace(new RegExp("{\\d+}", "g"), function (p) {
+            var n = parseInt(p.substring(1, p.length - 1), 10);
+            return args[n + 1];
+        });
+    }
+    
+    function trim(s) {
+        return s.replace(/ +/g, "");
+    }
+
+    function getPrecedence(ast) {
+        var type = ast[0];
+        switch (type) {
+            case "dot": // .
+            case "sub": // []
+            case "call": // ()
+                return 1;
+            case "unary-postfix": // ++ -- - ~ ! delete new typeof void
+            case "unary-prefix":
+                return 2;
+            case "var":
+            case "binary":
+                switch (ast[1]) {
+                    case "*":
+                    case "/":
+                    case "%":
+                        return 3;
+                    case "+":
+                    case "-":
+                        return 4;
+                    case "<<":
+                    case ">>":
+                    case ">>>":
+                        return 5;
+                    case "<":
+                    case "<=":
+                    case ">":
+                    case ">=":
+                    case "instanceof":
+                        return 6;
+                    case "==":
+                    case "!=":
+                    case "===":
+                    case "!==":
+                        return 7;
+                    case "&":
+                        return 8;
+                    case "^":
+                        return 9;
+                    case "|":
+                        return 10;
+                    case "&&":
+                        return 11;
+                    case "||":
+                        return 12;
+                }
+            case "conditional":
+                return 13;
+            case "assign":
+                return 14;
+            case "new":
+                return 15;
+            case "seq":
+            case "stat":
+            case "name":
+            case "object":
+            case "array":
+            case "num":
+            case "regexp":
+            case "string":
+            case "function":
+            case "defun":
+            case "for":
+            case "for-in":
+            case "block":
+            case "while":
+            case "do":
+            case "if":
+            case "break":
+            case "continue":
+            case "return":
+            case "throw":
+            case "try":
+            case "switch": 
+                return 0;
+            default:
+                return 100; // the lowest
+        }
+    }
+
+    var CodeWriter = function (indent) {
+        this._indent = indent || "    ";
+        this._indentLevel = 0;
+        
+        this.lines = [];
+    }
+    CodeWriter.prototype = {
+        write: function (str) {
+            if (str === undefined) return;
+            
+            if (this.lines.length == 0) {
+                this.lines.push("");
+            }
+
+            this.lines[this.lines.length - 1] += str;
+            return this;
+        },
+        
+        writeLine: function () {
+            this.write.apply(this, arguments);
+            this.lines.push("");
+            return this;
+        },
+        
+        writeIndents: function () {
+            var indents = new Array(this._indentLevel);
+            for (var i = 0; i < this._indentLevel; i++) {
+                indents[i] = this._indent;
+            }
+            
+            this.write(indents.join(""));
+            return this;
+        }, 
+        
+        addIndentLevel: function (diff) {
+            this._indentLevel += diff;
+            return this;
+        }
+    };
+    
+    var SeedProvider = function () {
+        this._seeds = {};
+    }
+    SeedProvider.prototype.next = function (key) {
+        var value = this._seeds[key];
+        if (value == undefined) {
+            this._seeds[key] = 0;
+            return 0;
+        } else {
+            this._seeds[key] = ++value;
+            return value;
+        }
+    }
+    
+    function isJscexPattern(ast) {
+        if (ast[0] != "call") return false;
+        
+        var evalName = ast[1];
+        if (evalName[0] != "name" || evalName[1] != "eval") return false;
+
+        var compileCall = ast[2][0];
+        if (!compileCall || compileCall[0] != "call") return false;
+
+        var compileMethod = compileCall[1];
+        if (!compileMethod || compileMethod[0] != "dot" || compileMethod[2] != "compile") return false;
+
+        var jscexName = compileMethod[1];
+        if (!jscexName || jscexName[0] != "name" || jscexName[1] != compile.rootName) return false;
+
+        var builder = compileCall[2][0];
+        if (!builder || builder[0] != "string") return false;
+
+        var func = compileCall[2][1];
+        if (!func || func[0] != "function") return false;
+
+        return true;
+    }
+    
+    function compileJscexPattern(ast, seedProvider, codeWriter, commentWriter) {
+
+        var builderName = ast[2][0][2][0][1];
+        var funcAst = ast[2][0][2][1];
+
+        var jscexTreeGenerator = new JscexTreeGenerator(builderName, seedProvider);
+        var jscexAst = jscexTreeGenerator.generate(funcAst);
+
+        commentWriter.write(builderName + " << ");
+        var codeGenerator = new CodeGenerator(builderName, seedProvider, codeWriter, commentWriter);
+        codeGenerator.generate(funcAst[2], jscexAst);
+    }
+        
+    var JscexTreeGenerator = function (builderName, seedProvider) {
+        this._binder = Jscex.binders[builderName];
+        this._seedProvider = seedProvider;
+    }
+    JscexTreeGenerator.prototype = {
+
+        generate: function (ast) {
+
+            var params = ast[2], statements = ast[3];
+
+            var rootAst = { type: "delay", stmts: [] };
+
+            this._visitStatements(statements, rootAst.stmts);
+
+            return rootAst;
+        },
+
+        _getBindInfo: function (stmt) {
+
+            var type = stmt[0];
+            if (type == "stat") {
+                var expr = stmt[1];
+                if (expr[0] == "call") {
+                    var callee = expr[1];
+                    if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
+                        return {
+                            expression: expr[2][0],
+                            argName: "",
+                            assignee: null
+                        };
+                    }
+                } else if (expr[0] == "assign") {
+                    var assignee = expr[2];
+                    expr = expr[3];
+                    if (expr[0] == "call") {
+                        var callee = expr[1];
+                        if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
+                            return {
+                                expression: expr[2][0],
+                                argName: "_result_$",
+                                assignee: assignee
+                            };
+                        }
+                    }
+                }
+            } else if (type == "var") {
+                var defs = stmt[1];
+                if (defs.length == 1) {
+                    var item = defs[0];
+                    var name = item[0];
+                    var expr = item[1];
+                    if (expr && expr[0] == "call") {
+                        var callee = expr[1];
+                        if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
+                            return {
+                                expression: expr[2][0],
+                                argName: name,
+                                assignee: null
+                            };                            
+                        }
+                    }
+                }
+            } else if (type == "return") {
+                var expr = stmt[1];
+                if (expr && expr[0] == "call") {
+                    var callee = expr[1];
+                    if (callee[0] == "name" && callee[1] == this._binder && expr[2].length == 1) {
+                        return {
+                            expression: expr[2][0],
+                            argName: "_result_$",
+                            assignee: "return"
+                        };
+                    }
+                }
+            }
+
+            return null;
+        },
+
+        _visitStatements: function (statements, stmts, index) {
+            if (arguments.length <= 2) index = 0;
+
+            if (index >= statements.length) {
+                stmts.push({ type: "normal" });
+                return this;
+            }
+
+            var currStmt = statements[index];
+            var bindInfo = this._getBindInfo(currStmt);
+
+            if (bindInfo) {
+                var bindStmt = { type: "bind", info: bindInfo };
+                stmts.push(bindStmt);
+
+                if (bindInfo.assignee != "return") {
+                    bindStmt.stmts = [];
+                    this._visitStatements(statements, bindStmt.stmts, index + 1);
+                }
+
+            } else {
+                var type = currStmt[0];
+                if (type == "return" || type == "break" || type == "continue" || type == "throw") {
+
+                    stmts.push({ type: type, stmt: currStmt });
+
+                } else if (type == "if" || type == "try" || type == "for" || type == "do"
+                           || type == "while" || type == "switch" || type == "for-in") {
+
+                    var newStmt = this._visit(currStmt);
+
+                    if (newStmt.type == "raw") {
+                        stmts.push(newStmt);
+                        this._visitStatements(statements, stmts, index + 1);
+                    } else {
+                        var isLast = (index == statements.length - 1);
+                        if (isLast) {
+                            stmts.push(newStmt);
+                        } else {
+
+                            var combineStmt = {
+                                type: "combine",
+                                first: { type: "delay", stmts: [newStmt] },
+                                second: { type: "delay", stmts: [] }
+                            };
+                            stmts.push(combineStmt);
+
+                            this._visitStatements(statements, combineStmt.second.stmts, index + 1);
+                        }
+                    }
+
+                } else {
+
+                    stmts.push({ type: "raw", stmt: currStmt });
+
+                    this._visitStatements(statements, stmts, index + 1);
+                }
+            }
+
+            return this;
+        },
+
+        _visit: function (ast) {
+
+            var type = ast[0];
+
+            function throwUnsupportedError() {
+                throw new Error('"' + type + '" is not currently supported.');
+            }
+
+            var visitor = this._visitors[type];
+
+            if (visitor) {
+                return visitor.call(this, ast);
+            } else {
+                throwUnsupportedError();
+            }
+        },
+
+        _visitBody: function (ast, stmts) {
+            if (ast[0] == "block") {
+                this._visitStatements(ast[1], stmts);
+            } else {
+                this._visitStatements([ast], stmts);
+            }
+        },
+
+        _noBinding: function (stmts) {
+            switch (stmts[stmts.length - 1].type) {
+                case "normal":
+                case "return":
+                case "break":
+                case "throw":
+                case "continue":
+                    return true;
+            }
+
+            return false;
+        },
+
+        _collectCaseStatements: function (cases, index) {
+            var res = [];
+
+            for (var i = index; i < cases.length; i++) {
+                var rawStmts = cases[i][1];
+                for (var j = 0; j < rawStmts.length; j++) {
+                    if (rawStmts[j][0] == "break") {
+                        return res
+                    }
+
+                    res.push(rawStmts[j]);
+                }
+            }
+
+            return res;
+        },
+
+        _visitors: {
+
+            "for": function (ast) {
+                var bodyStmts = [];
+                var body = ast[4];
+                this._visitBody(body, bodyStmts);
+
+                if (this._noBinding(bodyStmts)) {
+                    return { type: "raw", stmt: ast };
+                }
+                
+                var delayStmt = { type: "delay", stmts: [] };
+                
+                var setup = ast[1];
+                if (setup) {
+                    delayStmt.stmts.push({ type: "raw", stmt: setup });
+                }
+                
+                var forStmt = { type: "for", bodyStmt: { type: "delay", stmts: bodyStmts } };
+                delayStmt.stmts.push(forStmt);
+                
+                var condition = ast[2];
+                if (condition) {
+                    forStmt.condition = condition;
+                }
+                
+                var update = ast[3];
+                if (update) {
+                    forStmt.update = update;
+                }
+
+                return delayStmt;
+            },
+            
+            "for-in": function (ast) {
+
+                var body = ast[4];
+                
+                var bodyStmts = [];
+                this._visitBody(body, bodyStmts);
+
+                if (this._noBinding(bodyStmts)) {
+                    return { type: "raw", stmt: ast };
+                }
+                
+                var forInStmt = { type: "for-in", bodyStmts: bodyStmts, obj: ast[3] };
+            
+                var argName = ast[2][1]; // ast[2] == ["name", m]
+                if (ast[1][0] == "var") {
+                    forInStmt.argName = argName;
+                } else {
+                    var keyVar = "_forInKey_$" + this._seedProvider.next("forInKey");
+                    forInStmt.argName = keyVar;
+                    forInStmt.bodyStmts.unshift({
+                        type: "raw",
+                        stmt: Jscex.parse(argName + " = " + keyVar + ";")[1][0]
+                    });
+                }
+            
+                return forInStmt;
+            },
+        
+            "while": function (ast) {
+
+                var bodyStmts = [];
+                var body = ast[2];
+                this._visitBody(body, bodyStmts);
+
+                if (this._noBinding(bodyStmts)) {
+                    return { type: "raw", stmt: ast }
+                }
+
+                var loopStmt = { type: "while", bodyStmt: { type: "delay", stmts: bodyStmts } };
+
+                var condition = ast[1];
+                loopStmt.condition = condition;
+
+                return loopStmt;
+            },
+            
+            "do": function (ast) {
+
+                var bodyStmts = [];
+                var body = ast[2];
+                this._visitBody(body, bodyStmts);
+
+                if (this._noBinding(bodyStmts)) {
+                    return { type: "raw", stmt: ast };
+                }
+
+                var doStmt = {
+                    type: "do",
+                    bodyStmt: { type: "delay", stmts: bodyStmts },
+                    condition: ast[1]
+                };
+
+                return doStmt;
+            },
+
+            "switch": function (ast) {
+                var noBinding = true;
+
+                var switchStmt = { type: "switch", item: ast[1], caseStmts: [] };
+
+                var cases = ast[2];
+                for (var i = 0; i < cases.length; i++) {                    
+                    var caseStmt = { item: cases[i][0], stmts: [] };
+                    switchStmt.caseStmts.push(caseStmt);
+
+                    var statements = this._collectCaseStatements(cases, i);
+                    this._visitStatements(statements, caseStmt.stmts);
+                    noBinding = noBinding && this._noBinding(caseStmt.stmts);
+                }
+
+                if (noBinding) {
+                    return { type: "raw", stmt: ast };
+                } else {
+                    return switchStmt;
+                }
+            },
+
+            "if": function (ast) {
+
+                var noBinding = true;
+
+                var ifStmt = { type: "if", conditionStmts: [] };
+
+                var currAst = ast;
+                while (true) {
+                    var condition = currAst[1];
+                    var condStmt = { cond: condition, stmts: [] };
+                    ifStmt.conditionStmts.push(condStmt);
+
+                    var thenPart = currAst[2];
+                    this._visitBody(thenPart, condStmt.stmts);
+
+                    noBinding = noBinding && this._noBinding(condStmt.stmts);
+
+                    var elsePart = currAst[3];
+                    if (elsePart && elsePart[0] == "if") {
+                        currAst = elsePart;
+                    } else {
+                        break;
+                    }
+                }
+    
+                var elsePart = currAst[3];
+                if (elsePart) {
+                    ifStmt.elseStmts = [];
+
+                    this._visitBody(elsePart, ifStmt.elseStmts);
+                    
+                    noBinding = noBinding && this._noBinding(ifStmt.elseStmts);
+                }
+
+                if (noBinding) {
+                    return { type: "raw", stmt: ast };
+                } else {
+                    return ifStmt;
+                }
+            },
+
+            "try": function (ast, stmts) {
+
+                var bodyStmts = [];
+                var bodyStatements = ast[1];
+                this._visitStatements(bodyStatements, bodyStmts);
+
+                var noBinding = this._noBinding(bodyStmts)
+
+                var tryStmt = { type: "try", bodyStmt: { type: "delay", stmts: bodyStmts } };
+                
+                var catchClause = ast[2];
+                if (catchClause) {
+                    var exVar = catchClause[0];
+                    tryStmt.exVar = exVar;
+                    tryStmt.catchStmts = [];
+
+                    this._visitStatements(catchClause[1], tryStmt.catchStmts);
+
+                    noBinding = noBinding && this._noBinding(tryStmt.catchStmts);
+                }
+
+                var finallyStatements = ast[3];
+                if (finallyStatements) {
+                    tryStmt.finallyStmt = { type: "delay", stmts: [] };
+
+                    this._visitStatements(finallyStatements, tryStmt.finallyStmt.stmts);
+
+                    noBinding = noBinding && this._noBinding(tryStmt.finallyStmt.stmts);
+                }
+
+                if (noBinding) {
+                    return { type: "raw", stmt: ast };
+                } else {
+                    return tryStmt;
+                }
+            }
+        }
+    }
+    
+    var CodeGenerator = function (builderName, seedProvider, codeWriter, commentWriter) {
+        this._builderName = builderName;
+        this._binder = Jscex.binders[builderName];
+        this._seedProvider = seedProvider;
+        
+        this._codeWriter = codeWriter;
+        this._commentWriter = commentWriter;
+    }
+    CodeGenerator.prototype = {
+    
+        _code: function () {
+            this._codeWriter.write.apply(this._codeWriter, arguments);
+            return this;
+        },
+        
+        _codeLine: function () {
+            this._codeWriter.writeLine.apply(this._codeWriter, arguments);
+            return this;
+        },
+        
+        _codeIndents: function () {
+            this._codeWriter.writeIndents();
+            return this;
+        },
+        
+        _codeIndentLevel: function (diff) {
+            this._codeWriter.addIndentLevel(diff);
+            return this;
+        },
+        
+        _comment: function () {
+            this._commentWriter.write.apply(this._commentWriter, arguments);
+            return this;
+        },
+        
+        _commentLine: function () {
+            this._commentWriter.writeLine.apply(this._commentWriter, arguments);
+            return this;
+        },
+        
+        _commentIndents: function () {
+            this._commentWriter.writeIndents();
+            return this;
+        },
+        
+        _commentIndentLevel: function (diff) {
+            this._commentWriter.addIndentLevel(diff);
+            return this;
+        },
+        
+        _both: function () {
+            this._codeWriter.write.apply(this._codeWriter, arguments);
+            this._commentWriter.write.apply(this._commentWriter, arguments);
+
+            return this;
+        },
+        
+        _bothLine: function () {
+            this._codeWriter.writeLine.apply(this._codeWriter, arguments);
+            this._commentWriter.writeLine.apply(this._commentWriter, arguments);
+            
+            return this;
+        },
+        
+        _bothIndents: function () {
+            this._codeWriter.writeIndents();
+            this._commentWriter.writeIndents();
+            
+            return this;
+        },
+        
+        _bothIndentLevel: function (diff) {
+            this._codeWriter.addIndentLevel(diff);
+            this._commentWriter.addIndentLevel(diff);
+            
+            return this;
+        },
+        
+        _newLine: function () {
+            this._codeWriter.writeLine.apply(this._codeWriter, arguments);
+            this._commentWriter.writeLine(); // To Remove
+            return this;
+        },
+    
+        generate: function (params, jscexAst) {
+            this._normalMode = false;
+            this._builderVar = "_builder_$" + this._seedProvider.next("builderId");
+            
+            this._codeLine("(function (" + params.join(", ") + ") {")._commentLine("function (" + params.join(", ") + ") {");
+            this._bothIndentLevel(1);
+
+            this._codeIndents()._newLine("var " + this._builderVar + " = " + compile.rootName + ".builders[" + stringify(this._builderName) + "];");
+
+            this._codeIndents()._newLine("return " + this._builderVar + ".Start(this,");
+            this._codeIndentLevel(1);
+
+            this._pos = { };
+
+            this._bothIndents()._visitJscex(jscexAst)._newLine();
+            this._codeIndentLevel(-1);
+
+            this._codeIndents()._newLine(");");
+            this._bothIndentLevel(-1);
+
+            this._bothIndents()._code("})")._comment("}");
+        },
+
+        _visitJscex: function (ast) {
+            this._jscexVisitors[ast.type].call(this, ast);
+            return this;
+        },
+
+        _visitRaw: function (ast) {
+            var type = ast[0];
+
+            var visitor = this._rawVisitors[type];
+            if (visitor) {
+                visitor.call(this, ast);
+            } else {
+                throw new Error('"' + type + '" is not currently supported.');
+            }
+
+            return this;
+        },
+
+        _visitJscexStatements: function (statements) {
+            for (var i = 0; i < statements.length; i++) {
+                var stmt = statements[i];
+
+                if (stmt.type == "raw" || stmt.type == "if" || stmt.type == "switch") {
+                    this._bothIndents()._visitJscex(stmt)._newLine();
+                } else if (stmt.type == "delay") {
+                    this._visitJscexStatements(stmt.stmts);
+                } else {
+                    this._bothIndents()._code("return ")._visitJscex(stmt)._newLine(";");
+                }
+            }
+        },
+
+        _visitRawStatements: function (statements) {
+            for (var i = 0; i < statements.length; i++) {
+                var s = statements[i];
+
+                this._bothIndents()._visitRaw(s)._bothLine();
+
+                switch (s[0]) {
+                    case "break":
+                    case "return":
+                    case "continue":
+                    case "throw":
+                        return;
+                }
+            }
+        },
+
+        _visitRawBody: function (body) {
+            if (body[0] == "block") {
+                this._visitRaw(body);
+            } else {
+                this._bothLine();
+                this._bothIndentLevel(1);
+
+                this._bothIndents()._visitRaw(body);
+                this._bothIndentLevel(-1);
+            }
+
+            return this;
+        },
+
+        _visitRawFunction: function (ast) {
+            var funcName = ast[1] || "";
+            var args = ast[2];
+            var statements = ast[3];
+            
+            this._bothLine("function " + funcName + "(" + args.join(", ") + ") {")
+            this._bothIndentLevel(1);
+
+            var currInFunction = this._pos.inFunction;
+            this._pos.inFunction = true;
+
+            this._visitRawStatements(statements);
+            this._bothIndentLevel(-1);
+
+            this._pos.inFunction = currInFunction;
+
+            this._bothIndents()._both("}");
+        },
+        
+        _jscexVisitors: {
+            "delay": function (ast) {
+                if (ast.stmts.length == 1) {
+                    var subStmt = ast.stmts[0];
+                    switch (subStmt.type) {
+                        case "delay":
+                        case "combine":
+                        case "normal":
+                        case "break":
+                        case "continue":
+                        case "for":
+                        case "for-in":
+                        case "while":
+                        case "do":
+                        case "try":
+                            this._visitJscex(subStmt);
+                            return;
+                        case "return":
+                            if (!subStmt.stmt[1]) {
+                                this._visitJscex(subStmt);
+                                return;
+                            }
+                    }
+                }
+
+                this._newLine(this._builderVar + ".Delay(function () {");
+                this._codeIndentLevel(1);
+
+                this._visitJscexStatements(ast.stmts);
+                this._codeIndentLevel(-1);
+
+                this._codeIndents()._code("})");
+            },
+
+            "combine": function (ast) {
+                this._newLine(this._builderVar + ".Combine(");
+                this._codeIndentLevel(1);
+
+                this._bothIndents()._visitJscex(ast.first)._newLine(",");
+                this._bothIndents()._visitJscex(ast.second)._newLine();
+                this._codeIndentLevel(-1);
+
+                this._codeIndents()._code(")");
+            },
+            
+            "for": function (ast) {                
+                if (ast.condition) {
+                    this._codeLine(this._builderVar + ".For(function () {")
+                        ._commentLine("for (");
+                    this._codeIndentLevel(1);
+                    
+                    this._bothIndents()
+                        ._code("return ")
+                        ._comment("; ")
+                            ._visitRaw(ast.condition)
+                                ._newLine(";");
+                    this._codeIndentLevel(-1);
+                    
+                    this._bothIndents()._code("}, ");
+                } else {
+                    this._code(this._builderVar + ".For(null, ")
+                        ._comment("for (; ");
+                }
+                
+                if (ast.update) {
+                    this._newLine("function () {");
+                    this._codeIndentLevel(1);
+                    
+                    this._bothIndents()
+                        ._comment("; ")
+                            ._visitRaw(ast.update)
+                                ._codeLine(";")
+                                ._commentLine(") {");
+                    this._codeIndentLevel(-1);
+                    
+                    this._codeIndents()._newLine("},");
+                } else {
+                    this._codeLine("null,")._commentLine("; ) {");
+                }
+                this._bothIndentLevel(1);
+                
+                this._bothIndents()._visitJscex(ast.bodyStmt)._newLine();
+                this._bothIndentLevel(-1);
+                
+                this._bothIndents()._code(")")._comment("}");
+            },
+            
+            "for-in": function (ast) {
+                this._code(this._builderVar + ".ForIn(")
+                    ._comment("for (var " + ast.argName + " in ")
+                        ._visitRaw(ast.obj)
+                            ._codeLine(", function (" + ast.argName + ") {")
+                            ._commentLine(") {");
+                this._bothIndentLevel(1);
+                
+                this._visitJscexStatements(ast.bodyStmts);
+                this._bothIndentLevel(-1);
+                
+                this._bothIndents()._code("})")._comment("}");
+            },
+            
+            "while": function (ast) {
+                this._newLine(this._builderVar + ".While(function () {");
+                this._codeIndentLevel(1);
+                
+                this._bothIndents()
+                    ._code("return ")
+                    ._comment("while (")
+                        ._visitRaw(ast.condition)
+                            ._codeLine(";")
+                            ._commentLine(") {");
+                this._codeIndentLevel(-1);
+                
+                this._codeIndents()._newLine("},");
+                this._bothIndentLevel(1);
+                
+                this._bothIndents()._visitJscex(ast.bodyStmt)._newLine();
+                this._bothIndentLevel(-1);
+                
+                this._bothIndents()._code(")")._comment("}");
+            },
+            
+            "do": function (ast) {
+                this._codeLine(this._builderVar + ".Do(")._commentLine("do {");
+                this._bothIndentLevel(1);
+                
+                this._bothIndents()._visitJscex(ast.bodyStmt)._newLine(",");
+                this._commentIndentLevel(-1);
+                
+                this._codeIndents()._newLine("function () {");
+                this._codeIndentLevel(1);
+                
+                this._bothIndents()
+                    ._code("return ")
+                    ._comment("} while (")
+                        ._visitRaw(ast.condition)
+                            ._codeLine(";")
+                            ._commentLine(");");
+                this._codeIndentLevel(-1);
+                
+                this._codeIndents()._newLine("}");
+                this._codeIndentLevel(-1);
+                
+                this._codeIndents()._code(")");
+            },
+
+            "raw": function (ast) {
+                this._visitRaw(ast.stmt, true);
+            },
+
+            "bind": function (ast) {
+                var info = ast.info;
+                
+                var commentPrefix = "";
+                if (info.assignee == "return") {
+                    commentPrefix = "return ";
+                } else if (info.argName != "") {
+                    commentPrefix = "var " + info.argName + " = ";
+                }
+                
+                this._code(this._builderVar + ".Bind(")._comment(commentPrefix + this._binder + "(")._visitRaw(info.expression)._comment(");")._newLine(", function (" + info.argName + ") {");
+                this._codeIndentLevel(1);
+
+                if (info.assignee == "return") {
+                    this._codeIndents()
+                        ._newLine("return " + this._builderVar + ".Return(" + info.argName + ");");
+                } else {
+                    if (info.assignee) {
+                        this._bothIndents()
+                            ._visitRaw(info.assignee)._bothLine(" = " + info.argName + ";");
+                    }
+
+                    this._visitJscexStatements(ast.stmts);
+                }
+                this._codeIndentLevel(-1);
+
+                this._codeIndents()
+                    ._code("})");
+            },
+
+            "if": function (ast) {
+
+                for (var i = 0; i < ast.conditionStmts.length; i++) {
+                    var stmt = ast.conditionStmts[i];
+                    
+                    this._both("if (")._visitRaw(stmt.cond)._bothLine(") {");
+                    this._bothIndentLevel(1);
+
+                    this._visitJscexStatements(stmt.stmts);
+                    this._bothIndentLevel(-1);
+
+                    if (i < ast.conditionStmts.length - 1 || ast.elseStmts) {
+                        this._bothIndents()._both("} else ");
+                    } else {
+                        this._bothIndents()._code("} else ")._comment("}");
+                    }
+                }
+
+                if (ast.elseStmts) {
+                    this._bothLine("{");
+                    this._bothIndentLevel(1);
+                } else {
+                    this._newLine("{");
+                    this._codeIndentLevel(1);
+                }
+
+                if (ast.elseStmts) {
+                    this._visitJscexStatements(ast.elseStmts);
+                } else {
+                    this._codeIndents()
+                        ._newLine("return " + this._builderVar + ".Normal();");
+                }
+
+                if (ast.elseStmts) {
+                    this._bothIndentLevel(-1);
+                } else {
+                    this._codeIndentLevel(-1);
+                }
+
+                if (ast.elseStmts) {
+                    this._bothIndents()
+                        ._both("}");
+                } else {
+                    this._codeIndents()
+                        ._code("}");
+                }
+            },
+
+            "switch": function (ast) {
+                this._both("switch (")._visitRaw(ast.item)._bothLine(") {");
+                this._bothIndentLevel(1);
+
+                for (var i = 0; i < ast.caseStmts.length; i++) {
+                    var caseStmt = ast.caseStmts[i];
+                    
+                    if (caseStmt.item) {
+                        this._bothIndents()
+                            ._both("case ")._visitRaw(caseStmt.item)._bothLine(":");
+                    } else {
+                        this._bothIndents()._bothLine("default:");
+                    }
+                    this._bothIndentLevel(1);
+
+                    this._visitJscexStatements(caseStmt.stmts);                    
+                    this._bothIndentLevel(-1);
+                }
+
+                this._bothIndents()._code("}");
+            },
+
+            "try": function (ast) {
+                this._codeLine(this._builderVar + ".Try(")._commentLine("try {");
+                this._bothIndentLevel(1);
+
+                this._bothIndents()._visitJscex(ast.bodyStmt)._newLine(",");
+                this._commentIndentLevel(-1);
+                
+                if (ast.catchStmts) {
+                    this._bothIndents()
+                        ._codeLine("function (" + ast.exVar + ") {")
+                        ._commentLine("} catch (" + ast.exVar + ") {");
+                    this._bothIndentLevel(1);
+
+                    this._visitJscexStatements(ast.catchStmts);
+                    this._bothIndentLevel(-1);
+
+                    this._bothIndents()._codeLine("},");
+                    if (ast.finallyStmt) {
+                        this._commentLine("} finally {");
+                    } else {
+                        this._commentLine("}");
+                    }
+                } else {
+                    this._bothIndents()._codeLine("null,")._commentLine("} finally {");
+                }
+                
+                if (ast.finallyStmt) {
+                    this._commentIndentLevel(1);
+                    this._bothIndents()._visitJscex(ast.finallyStmt)._newLine();
+                    this._commentIndentLevel(-1);
+                } else {
+                    this._codeIndents()._newLine("null");
+                }
+                this._codeIndentLevel(-1);
+                
+                this._codeIndents()._code(")");
+                if (ast.finallyStmt) {
+                    this._commentIndents()._comment("}");
+                }
+            },
+
+            "normal": function (ast) {
+                this._code(this._builderVar + ".Normal()");
+            },
+
+            "throw": function (ast) {
+                this
+                    ._code(this._builderVar + ".Throw(")
+                    ._comment("throw ")
+                        ._visitRaw(ast.stmt[1])
+                            ._code(")")._comment(";");
+            },
+
+            "break": function (ast) {
+                this._code(this._builderVar + ".Break()")._comment("break;");
+            },
+
+            "continue": function (ast) {
+                this._code(this._builderVar + ".Continue()")._comment("continue;");
+            },
+
+            "return": function (ast) {
+                this._code(this._builderVar + ".Return(")._comment("return");
+                if (ast.stmt[1]) {
+                    this._comment(" ")._visitRaw(ast.stmt[1]);
+                }
+                
+                this._code(")")._comment(";");
+            }
+        },
+
+        _rawVisitors: {
+            "var": function (ast) {
+                this._both("var ");
+
+                var items = ast[1];
+                for (var i = 0; i < items.length; i++) {
+                    this._both(items[i][0]);
+                    if (items[i].length > 1) {
+                        this._both(" = ")._visitRaw(items[i][1]);
+                    }
+                    if (i < items.length - 1) this._both(", ");
+                }
+
+                this._both(";");
+            },
+
+            "seq": function (ast, noBracket) {
+                var left = ast[1];
+                var right = ast[2];
+                
+                if (!noBracket) this._both("(");
+                
+                this._visitRaw(left);
+                this._both(", ");
+                
+                if (right[0] == "seq") {
+                    arguments.callee.call(this, right, true);
+                } else {
+                    this._visitRaw(right);
+                }
+                
+                if (!noBracket) this._both(")");
+            },
+
+            "binary": function (ast) {
+                var op = ast[1], left = ast[2], right = ast[3];
+
+                if (getPrecedence(ast) < getPrecedence(left)) {
+                    this._both("(")._visitRaw(left)._both(") ");
+                } else {
+                    this._visitRaw(left)._both(" ");
+                }
+
+                this._both(op);
+
+                if (getPrecedence(ast) <= getPrecedence(right)) {
+                    this._both(" (")._visitRaw(right)._both(")");
+                } else {
+                    this._both(" ")._visitRaw(right);
+                }
+            },
+
+            "sub": function (ast) {
+                var prop = ast[1], index = ast[2];
+
+                if (getPrecedence(ast) < getPrecedence(prop)) {
+                    this._both("(")._visitRaw(prop)._both(")[")._visitRaw(index)._both("]");
+                } else {
+                    this._visitRaw(prop)._both("[")._visitRaw(index)._both("]");
+                }
+            },
+
+            "unary-postfix": function (ast) {
+                var op = ast[1];
+                var item = ast[2];
+                
+                if (getPrecedence(ast) <= getPrecedence(item)) {
+                    this._both("(")._visitRaw(item)._both(")");
+                } else {
+                    this._visitRaw(item);
+                }
+                
+                this._both(" " + op);
+            },
+
+            "unary-prefix": function (ast) {
+                var op = ast[1];
+                var item = ast[2];
+                
+                this._both(op + " ");
+                
+                if (getPrecedence(ast) < getPrecedence(item)) {
+                    this._both("(")._visitRaw(item)._both(")");
+                } else {
+                    this._visitRaw(item);
+                }
+            },
+
+            "assign": function (ast) {
+                var op = ast[1];
+                var name = ast[2];
+                var value = ast[3];
+                
+                if (name[0] == "assign") {
+                    this._both("(")._visitRaw(name)._both(")");
+                } else {
+                    this._visitRaw(name);
+                }
+                
+                if ((typeof op) == "string") {
+                    this._both(" " + op + "= ");
+                } else {
+                    this._both(" = ");
+                }
+                
+                this._visitRaw(value);
+            },
+
+            "stat": function (ast) {
+                this._visitRaw(ast[1])._both(";");
+            },
+
+            "dot": function (ast) {
+                var left = ast[1];
+                var right = ast[2];
+                
+                if (getPrecedence(ast) < getPrecedence(left)) {
+                    this._both("(")._visitRaw(left)._both(").")._both(right);
+                } else {
+                    this._visitRaw(left)._both(".")._both(right);
+                }
+            },
+
+            "new": function (ast) {
+                var ctor = ast[1];
+
+                this._both("new ")._visitRaw(ctor)._both("(");
+
+                var args = ast[2];
+                for (var i = 0, len = args.length; i < len; i++) {
+                    this._visitRaw(args[i]);
+                    if (i < len - 1) this._both(", ");
+                }
+
+                this._both(")");
+            },
+
+            "call": function (ast) {
+            
+                if (isJscexPattern(ast)) {
+                    compileJscexPattern(ast, this._seedProvider, this._codeWriter, this._commentWriter);
+                } else {
+                    var caller = ast[1];
+                
+                    var invalidBind = (caller[0] == "name") && (caller[1] == this._binder);
+                    // throw?
+
+                    if (getPrecedence(ast) < getPrecedence(caller)) {
+                        this._both("(")._visitRaw(caller)._both(")");
+                    } else {
+                        this._visitRaw(caller);
+                    }
+                    
+                    this._both("(");
+
+                    var args = ast[2];
+                    for (var i = 0; i < args.length; i++) {
+                        this._visitRaw(args[i]);
+                        if (i < args.length - 1) this._both(", ");
+                    }
+
+                    this._both(")");
+                }
+            },
+
+            "name": function (ast) {
+                this._both(ast[1]);
+            },
+
+            "object": function (ast) {
+                var items = ast[1];
+                if (items.length <= 0) {
+                    this._both("{ }");
+                } else {
+                    this._bothLine("{");
+                    this._bothIndentLevel(1);
+                    
+                    for (var i = 0; i < items.length; i++) {
+                        this._bothIndents()
+                            ._both(stringify(items[i][0]) + ": ")
+                            ._visitRaw(items[i][1]);
+                        
+                        if (i < items.length - 1) {
+                            this._bothLine(",");
+                        } else {
+                            this._bothLine("");
+                        }
+                    }
+                    
+                    this._bothIndentLevel(-1);
+                    this._bothIndents()._both("}");
+                }
+            },
+
+            "array": function (ast) {
+                this._both("[");
+
+                var items = ast[1];
+                for (var i = 0; i < items.length; i++) {
+                    this._visitRaw(items[i]);
+                    if (i < items.length - 1) this._both(", ");
+                }
+
+                this._both("]");
+            },
+
+            "num": function (ast) {
+                this._both(ast[1]);
+            },
+
+            "regexp": function (ast) {
+                this._both("/" + ast[1] + "/" + ast[2]);
+            },
+
+            "string": function (ast) {
+                this._both(stringify(ast[1]));
+            },
+
+            "function": function (ast) {
+                this._visitRawFunction(ast);
+            },
+
+            "defun": function (ast) {
+                this._visitRawFunction(ast);
+            },
+            
+            "for": function (ast) {
+                this._both("for (");
+
+                var setup = ast[1];
+                if (setup) {
+                    this._visitRaw(setup);
+                    if (setup[0] != "var") {
+                        this._both("; ");
+                    } else {
+                        this._both(" ");
+                    }
+                } else {
+                    this._both("; ");
+                }
+
+                var condition = ast[2];
+                if (condition) this._visitRaw(condition);
+                this._both("; ");
+
+                var update = ast[3];
+                if (update) this._visitRaw(update);
+                this._both(") ");
+
+                var currInLoop = this._pos.inLoop;
+                this._pos.inLoop = true;
+
+                var body = ast[4];
+                this._visitRawBody(body);
+
+                this._pos.inLoop = currInLoop;
+            },
+
+            "for-in": function (ast) {
+                this._both("for (");
+
+                var declare = ast[1];
+                if (declare[0] == "var") { // declare == ["var", [["m"]]]
+                    this._both("var " + declare[1][0][0]);
+                } else {
+                    this._visitRaw(declare);
+                }
+                
+                this._both(" in ")._visitRaw(ast[3])._both(") ");
+
+                var body = ast[4];
+                this._visitRawBody(body);
+            },
+
+            "block": function (ast) {
+                this._bothLine("{")
+                this._bothIndentLevel(1);
+
+                this._visitRawStatements(ast[1]);
+                this._bothIndentLevel(-1);
+
+                this._bothIndents()
+                    ._both("}");
+            },
+
+            "while": function (ast) {
+                var condition = ast[1];
+                var body = ast[2];
+
+                var currInLoop = this._pos.inLoop;
+                this._pos.inLoop = true;
+
+                this._both("while (")._visitRaw(condition)._both(") ")._visitRawBody(body);
+
+                this._pos.inLoop = currInLoop;
+            },
+
+            "do": function (ast) {
+                var condition = ast[1];
+                var body = ast[2];
+
+                var currInLoop = this._pos.inLoop;
+                this._pos.inLoop = true;
+
+                this._both("do ")._visitRawBody(body);
+
+                this._pos.inLoop = currInLoop;
+
+                if (body[0] == "block") {
+                    this._both(" ");
+                } else {
+                    this._bothLine()
+                        ._bothIndents();
+                }
+
+                this._both("while (")._visitRaw(condition)._both(");");
+            },
+
+            "if": function (ast) {
+                var condition = ast[1];
+                var thenPart = ast[2];
+
+                this._both("if (")._visitRaw(condition)._both(") ")._visitRawBody(thenPart);
+
+                var elsePart = ast[3];
+                if (elsePart) {
+                    if (thenPart[0] == "block") {
+                        this._both(" ");
+                    } else {
+                        this._bothLine("")
+                            ._bothIndents();
+                    }
+
+                    if (elsePart[0] == "if") {
+                        this._both("else ")._visitRaw(elsePart);
+                    } else {
+                        this._both("else ")._visitRawBody(elsePart);
+                    }
+                }
+            },
+
+            "break": function (ast) {
+                if (this._pos.inLoop || this._pos.inSwitch) {
+                    this._both("break;");
+                } else {
+                    this._code("return ")._visitJscex({ type: "break", stmt: ast })._code(";");
+                }
+            },
+
+            "continue": function (ast) {
+                if (this._pos.inLoop) {
+                    this._both("continue;");
+                } else {
+                    this._code("return ")._visitJscex({ type: "continue", stmt: ast })._code(";");
+                }
+            },
+
+            "return": function (ast) {
+                if (this._pos.inFunction) {
+                    this._both("return");
+                    var value = ast[1];
+                    if (value) this._both(" ")._visitRaw(value);
+                    this._both(";");
+                } else {
+                    this._code("return ")._visitJscex({ type: "return", stmt: ast })._code(";");
+                }
+            },
+
+            "throw": function (ast) {
+                var pos = this._pos;
+                if (pos.inTry || pos.inFunction) {
+                    this._both("throw ")._visitRaw(ast[1])._both(";");
+                } else {
+                    this._code("return ")._visitJscex({ type: "throw", stmt: ast })._code(";");
+                }
+            },
+
+            "conditional": function (ast) {
+                this._both("(")._visitRaw(ast[1])._both(") ? (")._visitRaw(ast[2])._both(") : (")._visitRaw(ast[3])._both(")");
+            },
+
+            "try": function (ast) {
+
+                this._bothLine("try {");
+                this._bothIndentLevel(1);
+
+                var currInTry = this._pos.inTry;
+                this._pos.inTry = true;
+
+                this._visitRawStatements(ast[1]);
+                this._bothIndentLevel(-1);
+
+                this._pos.inTry = currInTry;
+
+                var catchClause = ast[2];
+                var finallyStatements = ast[3];
+
+                if (catchClause) {
+                    this._bothIndents()
+                        ._bothLine("} catch (" + catchClause[0] + ") {")
+                    this._bothIndentLevel(1);
+
+                    this._visitRawStatements(catchClause[1]);
+                    this._bothIndentLevel(-1);
+                }
+
+                if (finallyStatements) {
+                    this._bothIndents()
+                        ._bothLine("} finally {");
+                    this._bothIndentLevel(1);
+
+                    this._visitRawStatements(finallyStatements);
+                    this._bothIndentLevel(-1);
+                }                
+
+                this._bothIndents()
+                    ._both("}");
+            },
+
+            "switch": function (ast) {
+                this._both("switch (")._visitRaw(ast[1])._bothLine(") {");
+                this._bothIndentLevel(1);
+
+                var currInSwitch = this._pos.inSwitch;
+                this._pos.inSwitch = true;
+
+                var cases = ast[2];
+                for (var i = 0; i < cases.length; i++) {
+                    var c = cases[i];
+                    this._bothIndents();
+
+                    if (c[0]) {
+                        this._both("case ")._visitRaw(c[0])._bothLine(":");
+                    } else {
+                        this._bothLine("default:");
+                    }
+                    this._bothIndentLevel(1);
+
+                    this._visitRawStatements(c[1]);
+                    this._bothIndentLevel(-1);
+                }
+                this._bothIndentLevel(-1);
+
+                this._pos.inSwitch = currInSwitch;
+
+                this._bothIndents()
+                    ._both("}");
+            }
+        }
+    };
+    
+    var merge = function (commentLines, codeLines) {
+        var length = commentLines.length;
+        
+        var maxShift = 0;
+        
+        for (var i = 0; i < length; i++) {
+            var matches = codeLines[i].match(" +");
+            var spaceLength = matches ? matches[0].length : 0;
+            
+            var shift = commentLines[i].length - spaceLength + 10;
+            if (shift > maxShift) {
+                maxShift = shift;
+            }
+        }
+        
+        var shiftBuffer = new Array(maxShift);
+        for (var i = 0; i < maxShift; i++) {
+            shiftBuffer[i] = " ";
+        }
+        
+        var shiftSpaces = shiftBuffer.join("");
+
+        var buffer = [];
+        for (var i = 0; i < length; i++) {
+            var comment = commentLines[i]; 
+            if (comment.replace(/ +/g, "").length > 0) {
+                comment = "/* " + comment + " */   ";
+            }
+            
+            var code = shiftSpaces + codeLines[i];
+            
+            buffer.push(comment);
+            buffer.push(code.substring(comment.length));
+            buffer.push("\n");
+        }
+        
+        return buffer.join("");
+    }
+    
+    var compile = function (builderName, func, separateCodeAndComment) {
+        var funcCode = func.toString();
+        var evalCode = "eval(" + compile.rootName + ".compile(" + stringify(builderName) + ", " + funcCode + "))"
+        var evalCodeAst = Jscex.parse(evalCode);
+
+        var codeWriter = new CodeWriter();
+        var commentWriter = new CodeWriter();
+        
+        // [ "toplevel", [ [ "stat", [ "call", ... ] ] ] ]
+        var evalAst = evalCodeAst[1][0][1];
+        compileJscexPattern(evalAst, new SeedProvider(), codeWriter, commentWriter);
+ 
+        if (separateCodeAndComment) {
+            return {
+                code: codeWriter.lines.join("\n"),
+                codeLines: codeWriter.lines,
+                comment: commentWriter.lines.join("\n"),
+                commentLines: commentWriter.lines
+            };
+        } else {
+            var newCode = merge(commentWriter.lines, codeWriter.lines);
+            Jscex.logger.debug("// Original: \r\n" + funcCode + "\r\n\r\n// Jscexified: \r\n" + newCode + "\r\n");
+            
+            return codeGenerator(newCode);
+        }
+    }
+
+    compile.rootName = "Jscex";
+
+    // CommonJS
+    var isCommonJS = !!(typeof require === "function" && typeof module !== "undefined" && module.exports);
+    // CommonJS AMD
+    var isAmd = !!(typeof require === "function" && typeof define === "function" && define.amd);
+
+    var defineModule = function () {
+        Jscex.define({
+            name: "jit",
+            version: "0.6.6",
+            exports: isCommonJS && module.exports,
+            require: isCommonJS && require,
+            autoloads: [ "parser" ],
+            dependencies: { parser: "~0.6.5" },
+            init: function () {
+                Jscex.compile = compile;
+            }
+        });
+    }
+
+    if (isCommonJS) {
+        try {
+            Jscex = require("./jscex");
+        } catch (ex) {
+            Jscex = require("jscex");
+        }
+        
+        defineModule();
+    } else if (isAmd) {
+        require(["jscex"], function (jscex) {
+            Jscex = jscex;
+            defineModule();
+        });
+    } else {
+        var Fn = Function, global = Fn('return this')();
+        if (!global.Jscex) {
+            throw new Error('Missing the root object, please load "jscex" component first.');
+        }
+        
+        Jscex = global.Jscex;
+        defineModule();
+    }
+})();


Mime
View raw message