mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 04:57:03 +00:00
Added new faster compiler based on acorn parser
This commit is contained in:
@@ -804,7 +804,8 @@ BundleTask.prototype.defineStaticTask = function()
|
||||
BundleTask.prototype.defineSourceTasks = function()
|
||||
{
|
||||
// Use new compiler
|
||||
require("objective-j").ObjJCompiler.setCurrentUsedVersion("objj_compiler2");
|
||||
//require("objective-j").ObjJCompiler.setCurrentUsedVersion("acorn");
|
||||
//require("objective-j").ObjJCompiler.setCurrentUsedVersion("objj_compiler2");
|
||||
var sources = this.sources();
|
||||
|
||||
if (!sources)
|
||||
|
||||
@@ -497,7 +497,7 @@ Executable.fileExecutableSearcherForURL = function(/*CFURL*/ referenceURL)
|
||||
{
|
||||
if (!aStaticResource)
|
||||
{
|
||||
var compilingFileUrl = ObjJCompiler && ObjJCompiler.currentCompileFile ? ObjJCompiler.currentCompileFile : null;
|
||||
var compilingFileUrl = ObjJCompiler && ObjJCompiler.currentCompileFile ? ObjJCompiler.currentCompileFile : ObjJAcornCompiler ? ObjJAcornCompiler.currentCompileFile : null;
|
||||
throw new Error("Could not load file at " + aURL + (compilingFileUrl ? " when compiling " + compilingFileUrl : ""));
|
||||
}
|
||||
|
||||
|
||||
@@ -43,12 +43,18 @@ function FileExecutable(/*CFURL|String*/ aURL, /*Dictionary*/ aFilenameTranslate
|
||||
|
||||
else if ((extension === "j" || !extension) && !fileContents.match(/^{/))
|
||||
{
|
||||
if (!exports.ObjJCompiler.usedVersion || exports.ObjJCompiler.usedVersion === "preprocessor")
|
||||
executable = exports.preprocess(fileContents, aURL, Preprocessor.Flags.IncludeDebugSymbols);
|
||||
var start = new Date().getTime();
|
||||
if (!exports.ObjJCompiler.usedVersion || exports.ObjJCompiler.usedVersion === "acorn")
|
||||
executable = exports.ObjJAcornCompiler.compileFileDependencies(fileContents, aURL, ObjJCompiler.Flags.IncludeDebugSymbols);
|
||||
else if (exports.ObjJCompiler.usedVersion === "objj_compiler2")
|
||||
executable = exports.compileFileDependencies(fileContents, aURL, ObjJCompiler.Flags.IncludeDebugSymbols);
|
||||
executable = exports.ObjJCompiler.compileFileDependencies(fileContents, aURL, ObjJCompiler.Flags.IncludeDebugSymbols);
|
||||
else if (exports.ObjJCompiler.usedVersion === "preprocessor")
|
||||
executable = exports.preprocess(fileContents, aURL, Preprocessor.Flags.IncludeDebugSymbols);
|
||||
else
|
||||
throw new Error("Compiler to use is set to " + exports.ObjJCompiler.usedVersion + " but we only support 'preprocessor' (old compiler) and 'objj_compiler2' (new compiler)");
|
||||
throw new Error("Compiler to use is set to " + exports.ObjJCompiler.usedVersion + " but we only support 'preprocessor' (old compiler), 'objj_compiler2' and 'acorn'");
|
||||
|
||||
var time = (new Date().getTime() - start) / 1000;
|
||||
//print("Compile '" + (exports.ObjJCompiler.usedVersion || "preprocessor") + "' " + aURL + " in " + time + " seconds");
|
||||
}
|
||||
else
|
||||
executable = new Executable(fileContents, [], aURL);
|
||||
|
||||
@@ -45,6 +45,9 @@
|
||||
#include "Preprocessor.js"
|
||||
#include "Parser.js"
|
||||
#include "ObjJCompiler.js"
|
||||
#include "acorn.js"
|
||||
#include "acornwalk.js"
|
||||
#include "ObjJAcornCompiler.js"
|
||||
#include "FileDependency.js"
|
||||
#include "Executable.js"
|
||||
#include "FileExecutable.js"
|
||||
|
||||
@@ -0,0 +1,732 @@
|
||||
/*
|
||||
* ObjJAcornCompiler.js
|
||||
* Objective-J
|
||||
*
|
||||
* Created by Martin Carlberg.
|
||||
* Copyright 2013, Martin Carlberg.
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var Scope = function(prev, base)
|
||||
{
|
||||
this.vars = Object.create(null);
|
||||
if (base) for (var key in base) this[key] = base[key];
|
||||
this.prev = prev;
|
||||
if (prev) this.compiler = prev.compiler;
|
||||
}
|
||||
|
||||
Scope.prototype.compiler = function()
|
||||
{
|
||||
return this.compiler;
|
||||
}
|
||||
|
||||
Scope.prototype.currentClassName = function()
|
||||
{
|
||||
return this.classDef ? this.classDef.className : this.prev ? this.prev.currentClassName() : null;
|
||||
}
|
||||
|
||||
Scope.prototype.getIvarForCurrentClass = function(/* String */ ivarName)
|
||||
{
|
||||
if (this.ivars)
|
||||
{
|
||||
var ivar = this.ivars[ivarName];
|
||||
if (ivar)
|
||||
return ivar;
|
||||
}
|
||||
|
||||
var prev = this.prev;
|
||||
|
||||
// Stop at the class declaration
|
||||
if (prev && !this.classDef)
|
||||
return prev.getIvarForCurrentClass(ivarName);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Scope.prototype.getLvarForCurrentMethod = function(/* String */ lvarName)
|
||||
{
|
||||
if (this.vars)
|
||||
{
|
||||
var lvar = this.vars[lvarName];
|
||||
if (lvar)
|
||||
return lvar;
|
||||
}
|
||||
|
||||
var prev = this.prev;
|
||||
|
||||
// Stop at the method declaration
|
||||
if (prev && !this.methodtype)
|
||||
return prev.getLvarForCurrentMethod(lvarName);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Scope.prototype.currentMethodType = function()
|
||||
{
|
||||
return this.methodType ? this.methodType : this.prev ? this.prev.currentMethodType() : null;
|
||||
}
|
||||
|
||||
var currentCompilerFlags = "";
|
||||
|
||||
var ObjJAcornCompiler = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags, /*unsigned*/ pass)
|
||||
{
|
||||
this.source = aString;
|
||||
this.URL = new CFURL(aURL);
|
||||
this.pass = pass;
|
||||
this.jsBuffer = new StringBuffer();
|
||||
this.imBuffer = null;
|
||||
this.cmBuffer = null;
|
||||
this.warnings = [];
|
||||
|
||||
var start = new Date().getTime();
|
||||
#ifdef BROWSER
|
||||
console.time("Parse with Acorn - " + aURL);
|
||||
#endif
|
||||
try {
|
||||
this.tokens = exports.acorn.parse(aString);
|
||||
}
|
||||
catch (e) {
|
||||
if (e.lineStart)
|
||||
{
|
||||
var message = this.prettifyMessage(e, "ERROR");
|
||||
#ifdef BROWSER
|
||||
console.log(message);
|
||||
#else
|
||||
print(message);
|
||||
#endif
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
var end = new Date().getTime();
|
||||
var time = (end - start) / 1000;
|
||||
//print("Parse with Acorn: " + aURL + " in " + time + " seconds");
|
||||
#ifdef BROWSER
|
||||
console.timeEnd("Parse with Acorn - " + aURL);
|
||||
#endif
|
||||
this.dependencies = [];
|
||||
this.flags = flags | ObjJAcornCompiler.Flags.IncludeDebugSymbols;
|
||||
this.classDefs = Object.create(null);
|
||||
this.lastPos = 0;
|
||||
//var start = new Date().getTime();
|
||||
#ifdef BROWSER
|
||||
console.time("Compile pass " + pass + " - " + aURL);
|
||||
#endif
|
||||
try {
|
||||
compile(this.tokens, new Scope(null ,{ compiler: this }), pass === 2 ? pass2 : pass1);
|
||||
}
|
||||
catch (e) {
|
||||
#ifdef BROWSER
|
||||
//console.log("Error: " + e + ", file content: " + aString);
|
||||
#else
|
||||
//print("Error: " + e + ", file content: " + aString);
|
||||
#endif
|
||||
throw e;
|
||||
}
|
||||
//var end = new Date().getTime();
|
||||
//var time = (end - start) / 1000;
|
||||
//print("Compile pass 1: " + aURL + " in " + time + " seconds");
|
||||
#ifdef BROWSER
|
||||
console.timeEnd("Compile pass " + pass + " - " + aURL);
|
||||
#endif
|
||||
// console.log("JS: " + this.jsBuffer);
|
||||
}
|
||||
|
||||
exports.ObjJAcornCompiler = ObjJAcornCompiler;
|
||||
|
||||
exports.ObjJAcornCompiler.compileToExecutable = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
ObjJAcornCompiler.currentCompileFile = aURL;
|
||||
return new ObjJAcornCompiler(aString, aURL, flags, 2).executable();
|
||||
}
|
||||
|
||||
exports.ObjJAcornCompiler.compileToIMBuffer = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
return new ObjJAcornCompiler(aString, aURL, flags, 2).IMBuffer();
|
||||
}
|
||||
|
||||
exports.ObjJAcornCompiler.compileFileDependencies = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
ObjJAcornCompiler.currentCompileFile = aURL;
|
||||
return new ObjJAcornCompiler(aString, aURL, flags, 1).executable();
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.compilePass2 = function()
|
||||
{
|
||||
ObjJAcornCompiler.currentCompileFile = this.URL;
|
||||
this.pass = 2;
|
||||
this.jsBuffer = new StringBuffer();
|
||||
this.warnings = [];
|
||||
//print("Start Compile2: " + this.URL);
|
||||
//var start = new Date().getTime();
|
||||
#ifdef BROWSER
|
||||
console.time("Compile pass 2" + this.pass + " - " + this.URL);
|
||||
#endif
|
||||
compile(this.tokens, new Scope(null ,{ compiler: this }), pass2);
|
||||
//var end = new Date().getTime();
|
||||
//var time = (end - start) / 1000;
|
||||
//print("Compile pass 2: " + this.URL + " in " + time + " seconds");
|
||||
#ifdef BROWSER
|
||||
console.timeEnd("Compile pass 2" + this.pass + " - " + this.URL);
|
||||
#endif
|
||||
//print("Compiled: \n" + this.jsBuffer.toString());
|
||||
|
||||
for (var i = 0; i < this.warnings.length; i++)
|
||||
{
|
||||
var message = this.prettifyMessage(this.warnings[i], "WARNING");
|
||||
#ifdef BROWSER
|
||||
console.log(message);
|
||||
#else
|
||||
print(message);
|
||||
#endif
|
||||
}
|
||||
|
||||
return this.jsBuffer.toString();
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.Flags = { };
|
||||
|
||||
ObjJAcornCompiler.Flags.IncludeDebugSymbols = 1 << 0;
|
||||
ObjJAcornCompiler.Flags.IncludeTypeSignatures = 1 << 1;
|
||||
|
||||
ObjJAcornCompiler.prototype.addWarning = function(/* Warning */ aWarning)
|
||||
{
|
||||
this.warnings.push(aWarning);
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.getIvarForClass = function(/* String */ ivarName, /* Scope */ scope)
|
||||
{
|
||||
var ivar = scope.getIvarForCurrentClass(ivarName);
|
||||
|
||||
if (ivar)
|
||||
return ivar;
|
||||
|
||||
var c = this.getClassDef(scope.currentClassName());
|
||||
|
||||
while (c)
|
||||
{
|
||||
var ivars = c.ivars;
|
||||
if (ivars)
|
||||
{
|
||||
var ivarDef = ivars[ivarName];
|
||||
if (ivarDef)
|
||||
return ivarDef;
|
||||
}
|
||||
c = this.getClassDef(c.superClassName);
|
||||
}
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.getClassDef = function(/* String */ aClassName)
|
||||
{
|
||||
if (!aClassName) return null;
|
||||
|
||||
var c = this.classDefs[aClassName];
|
||||
|
||||
if (c) return c;
|
||||
|
||||
if (objj_getClass)
|
||||
{
|
||||
var aClass = objj_getClass(aClassName);
|
||||
if (aClass)
|
||||
{
|
||||
var ivars = class_copyIvarList(aClass),
|
||||
ivarSize = ivars.length,
|
||||
myIvars = Object.create(null),
|
||||
superClass = aClass.super_class;
|
||||
|
||||
for (var i = 0; i < ivarSize; i++)
|
||||
{
|
||||
var ivar = ivars[i];
|
||||
|
||||
myIvars[ivar.name] = {"type": ivar.type, "name": ivar.name};
|
||||
}
|
||||
c = {"className": aClassName, "ivars": myIvars};
|
||||
|
||||
if (superClass)
|
||||
c.superClassName = superClass.name;
|
||||
this.classDefs[aClassName] = c;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
// classDef = {"className": className, "superClassName": superClassName, "ivars": Object.create(null), "methods": Object.create(null)};
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.executable = function()
|
||||
{
|
||||
if (!this._executable)
|
||||
this._executable = new Executable(this.jsBuffer ? this.jsBuffer.toString() : null, this.dependencies, this.URL, null, this);
|
||||
return this._executable;
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.IMBuffer = function()
|
||||
{
|
||||
return this.imBuffer;
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.JSBuffer = function()
|
||||
{
|
||||
return this.jsBuffer;
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.prettifyMessage = function(/* Message */ aMessage, /* String */ messageType)
|
||||
{
|
||||
var line = this.source.substring(aMessage.lineStart, aMessage.lineEnd);
|
||||
var message = "\n" + line;
|
||||
//print("e: " + e + ", e.lineStart: " + e.lineStart + ", e.lineEnd: " + e.lineEnd + ", e.column: " + e.column);
|
||||
|
||||
message += (new Array(aMessage.column + 1)).join(" ");
|
||||
message += (new Array(Math.min(1, line.length) + 1)).join("^") + "\n";
|
||||
message += messageType + " line " + aMessage.line + " in " + this.URL + ": " + aMessage.message;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.error_message = function(errorMessage, astNode)
|
||||
{
|
||||
return errorMessage + " <Context File: "+ this.URL +
|
||||
(this.currentClass ? " Class: "+this.currentClass : "") +
|
||||
(this.currentSelector ? " Method: "+this.currentSelector : "") +">";
|
||||
}
|
||||
|
||||
function createMessage(/* String */ aMessage, /* SpiderMonkey AST node */ node, /* String */ code)
|
||||
{
|
||||
var message = exports.acorn.getLineInfo(code, node.start);
|
||||
message.message = aMessage;
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
function compile(node, state, visitor) {
|
||||
function c(node, st, override) {
|
||||
visitor[override || node.type](node, st, c);
|
||||
}
|
||||
c(node, state);
|
||||
};
|
||||
|
||||
var pass1 = exports.acorn.walk.make({
|
||||
ImportStatement: function(node, st, c) {
|
||||
var urlString = node.filename.value;
|
||||
|
||||
st.compiler.dependencies.push(new FileDependency(new CFURL(urlString), node.localfilepath));
|
||||
}
|
||||
});
|
||||
|
||||
var pass2 = exports.acorn.walk.make({
|
||||
Program: function(node, st, c) {
|
||||
for (var i = 0; i < node.body.length; ++i) {
|
||||
c(node.body[i], st, "Statement");
|
||||
}
|
||||
CONCAT(st.compiler.jsBuffer,st.compiler.source.substring(st.compiler.lastPos, node.end));
|
||||
},
|
||||
Function: function(node, scope, c) {
|
||||
var inner = new Scope(scope);
|
||||
for (var i = 0; i < node.params.length; ++i)
|
||||
inner.vars[node.params[i].name] = {type: "argument", node: node.params[i]};
|
||||
if (node.id) {
|
||||
var decl = node.type == "FunctionDeclaration";
|
||||
(decl ? scope : inner).vars[node.id.name] =
|
||||
{type: decl ? "function" : "function name", node: node.id};
|
||||
CONCAT(scope.compiler.jsBuffer,scope.compiler.source.substring(scope.compiler.lastPos, node.start));
|
||||
CONCAT(scope.compiler.jsBuffer, node.id.name);
|
||||
CONCAT(scope.compiler.jsBuffer, " = function");
|
||||
scope.compiler.lastPos = node.id.end;
|
||||
}
|
||||
c(node.body, inner, "ScopeBody");
|
||||
},
|
||||
TryStatement: function(node, scope, c) {
|
||||
c(node.block, scope, "Statement");
|
||||
for (var i = 0; i < node.handlers.length; ++i) {
|
||||
var handler = node.handlers[i], inner = new Scope(scope);
|
||||
inner.vars[handler.param.name] = {type: "catch clause", node: handler.param};
|
||||
c(handler.body, inner, "ScopeBody");
|
||||
}
|
||||
if (node.finalizer) c(node.finalizer, scope, "Statement");
|
||||
},
|
||||
VariableDeclaration: function(node, scope, c) {
|
||||
for (var i = 0; i < node.declarations.length; ++i) {
|
||||
var decl = node.declarations[i];
|
||||
scope.vars[decl.id.name] = {type: "var", node: decl.id};
|
||||
if (decl.init) c(decl.init, scope, "Expression");
|
||||
}
|
||||
},
|
||||
MemberExpression: function(node, st, c) {
|
||||
c(node.object, st, "Expression");
|
||||
st.secondMemberExpression = !node.computed;
|
||||
c(node.property, st, "Expression");
|
||||
st.secondMemberExpression = false;
|
||||
},
|
||||
ImportStatement: function(node, st, c) {
|
||||
var buffer = st.compiler.jsBuffer;
|
||||
|
||||
if (!buffer) return;
|
||||
CONCAT(buffer,st.compiler.source.substring(st.compiler.lastPos, node.start));
|
||||
CONCAT(buffer, "objj_executeFile(\"");
|
||||
CONCAT(buffer, node.filename.value);
|
||||
CONCAT(buffer, node.localfilepath ? "\", YES);" : "\", NO);");
|
||||
st.compiler.lastPos = node.end;
|
||||
},
|
||||
ClassDeclarationStatement: function(node, st, c) {
|
||||
var classDef,
|
||||
saveJSBuffer = st.compiler.jsBuffer,
|
||||
className = node.classname.name,
|
||||
classScope = new Scope(st);
|
||||
|
||||
st.compiler.imBuffer = new StringBuffer();
|
||||
st.compiler.cmBuffer = new StringBuffer();
|
||||
st.compiler.classBodyBuffer = new StringBuffer(); // TODO: Check if this is needed
|
||||
|
||||
CONCAT(saveJSBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start));
|
||||
|
||||
// First we declare the class
|
||||
if (node.superclassname)
|
||||
{
|
||||
if (st.compiler.getClassDef(className))
|
||||
throw new SyntaxError(st.compiler.error_message("Duplicate class " + className, node.classname));
|
||||
if (!st.compiler.getClassDef(node.superclassname.name))
|
||||
throw new SyntaxError(st.compiler.error_message("Can't find superclass " + node.superclassname.name, node.superclassname));
|
||||
|
||||
classDef = {"className": className, "superClassName": node.superclassname.name, "ivars": Object.create(null), "methods": Object.create(null)};
|
||||
st.compiler.classDefs[className] = classDef;
|
||||
|
||||
CONCAT(saveJSBuffer, "{var the_class = objj_allocateClassPair(" + node.superclassname.name + ", \"" + className + "\"),\nmeta_class = the_class.isa;");
|
||||
}
|
||||
else if (node.categoryname)
|
||||
{
|
||||
classDef = st.compiler.getClassDef(className);
|
||||
if (!classDef)
|
||||
throw new SyntaxError(st.compiler.error_message("Class " + className + " not found ", node.classname));
|
||||
|
||||
CONCAT(saveJSBuffer, "{\nvar the_class = objj_getClass(\"" + className + "\")\n");
|
||||
CONCAT(saveJSBuffer, "if(!the_class) throw new SyntaxError(\"*** Could not find definition for class \\\"" + className + "\\\"\");\n");
|
||||
CONCAT(saveJSBuffer, "var meta_class = the_class.isa;");
|
||||
}
|
||||
else
|
||||
{
|
||||
classDef = {"className": className, "superClassName": null, "ivars": Object.create(null), "methods": Object.create(null)};
|
||||
st.compiler.classDefs[className] = classDef;
|
||||
|
||||
CONCAT(saveJSBuffer, "{var the_class = objj_allocateClassPair(Nil, \"" + className + "\"),\nmeta_class = the_class.isa;");
|
||||
}
|
||||
|
||||
classScope.classDef = classDef;
|
||||
st.compiler.currentSuperClass = "objj_getClass(\"" + className + "\").super_class";
|
||||
st.compiler.currentSuperMetaClass = "objj_getMetaClass(\"" + className + "\").super_class";
|
||||
|
||||
var firstIvarDeclaration = true,
|
||||
hasAccessors = false;
|
||||
|
||||
// Then we add all ivars
|
||||
if (node.ivardeclarations) for (var i = 0; i < node.ivardeclarations.length; ++i)
|
||||
{
|
||||
var ivarDecl = node.ivardeclarations[i],
|
||||
ivarType = ivarDecl.ivartype ? ivarDecl.ivartype.name : null,
|
||||
ivarName = ivarDecl.id.name,
|
||||
ivar = {"type": ivarType, "name": ivarName};
|
||||
|
||||
if (firstIvarDeclaration)
|
||||
{
|
||||
firstIvarDeclaration = false;
|
||||
CONCAT(saveJSBuffer, "class_addIvars(the_class, [");
|
||||
}
|
||||
else
|
||||
CONCAT(saveJSBuffer, ", ");
|
||||
|
||||
if (st.compiler.flags & ObjJAcornCompiler.Flags.IncludeTypeSignatures)
|
||||
CONCAT(saveJSBuffer, "new objj_ivar(\"" + ivarName + "\", \"" + ivarType + "\")");
|
||||
else
|
||||
CONCAT(saveJSBuffer, "new objj_ivar(\"" + ivarName + "\")");
|
||||
|
||||
if (ivarDecl.outlet)
|
||||
ivar.outlet = true;
|
||||
classDef.ivars[ivarName] = ivar;
|
||||
if (!classScope.ivars)
|
||||
classScope.ivars = Object.create(null);
|
||||
classScope.ivars[ivarName] = {type: "ivar", name: ivarName, node: ivarDecl.id, ivar: ivar};
|
||||
|
||||
if (!hasAccessors && ivarDecl.accessors)
|
||||
hasAccessors = true;
|
||||
}
|
||||
|
||||
if (!firstIvarDeclaration)
|
||||
CONCAT(saveJSBuffer, "]);");
|
||||
|
||||
// If we have accessors add get and set methods for them
|
||||
if (hasAccessors)
|
||||
{
|
||||
var getterSetterBuffer = new StringBuffer();
|
||||
|
||||
// Add the class declaration to compile accessors correctly
|
||||
CONCAT(getterSetterBuffer, st.compiler.source.substring(node.start, node.endOfIvars));
|
||||
CONCAT(getterSetterBuffer, "\n");
|
||||
|
||||
for (var i = 0; i < node.ivardeclarations.length; ++i)
|
||||
{
|
||||
var ivarDecl = node.ivardeclarations[i],
|
||||
ivarType = ivarDecl.ivartype ? ivarDecl.ivartype.name : null,
|
||||
ivarName = ivarDecl.id.name,
|
||||
accessors = ivarDecl.accessors;
|
||||
|
||||
if (!accessors)
|
||||
continue;
|
||||
|
||||
var property = (accessors.property && accessors.property.name) || ivarName,
|
||||
getterName = (accessors.getter && accessors.getter.name) || property,
|
||||
getterCode = "- (" + (ivarType ? ivarType : "id") + ")" + getterName + "\n{\nreturn " + ivarName + ";\n}\n";
|
||||
|
||||
CONCAT(getterSetterBuffer, getterCode);
|
||||
|
||||
if (accessors.readonly)
|
||||
continue;
|
||||
|
||||
var setterName = accessors.setter ? accessors.setter.name : null;
|
||||
|
||||
if (!setterName)
|
||||
{
|
||||
var start = property.charAt(0) == '_' ? 1 : 0;
|
||||
|
||||
setterName = (start ? "_" : "") + "set" + property.substr(start, 1).toUpperCase() + property.substring(start + 1) + ":";
|
||||
}
|
||||
|
||||
var setterCode = "- (void)" + setterName + "(" + (ivarType ? ivarType : "id") + ")newValue\n{\n";
|
||||
|
||||
if (accessors.copy)
|
||||
setterCode += "if (" + ivarName + " !== newValue)\n" + ivarName + " = [newValue copy];\n}\n";
|
||||
else
|
||||
setterCode += ivarName + " = newValue;\n}\n";
|
||||
|
||||
CONCAT(getterSetterBuffer, setterCode);
|
||||
}
|
||||
|
||||
CONCAT(getterSetterBuffer, "\n@end");
|
||||
|
||||
// Remove all @accessors or we will get a recursive loop in infinity
|
||||
var b = getterSetterBuffer.toString().replace(/@accessors(\(.*\))?/g, "");
|
||||
var imBuffer = ObjJAcornCompiler.compileToIMBuffer(b, "Accessors", st.compiler.flags);
|
||||
|
||||
// Add the accessors methods first to instance method buffer.
|
||||
// This will allow manually added set and get methods to override the compiler generated
|
||||
CONCAT(st.compiler.imBuffer, imBuffer);
|
||||
}
|
||||
|
||||
if (node.body.length > 0)
|
||||
{
|
||||
st.compiler.lastPos = node.body[0].start;
|
||||
|
||||
// And last add methods and other statements
|
||||
for (var i = 0; i < node.body.length; ++i) {
|
||||
var body = node.body[i];
|
||||
c(body, classScope, "Statement");
|
||||
}
|
||||
CONCAT(saveJSBuffer, st.compiler.source.substring(st.compiler.lastPos, body.end));
|
||||
}
|
||||
|
||||
// We must make a new class object for our class definition if it's not a category
|
||||
if (!node.categoryname) {
|
||||
CONCAT(saveJSBuffer, "objj_registerClassPair(the_class);\n");
|
||||
}
|
||||
|
||||
// Add instance methods
|
||||
if (IS_NOT_EMPTY(st.compiler.imBuffer))
|
||||
{
|
||||
CONCAT(saveJSBuffer, "class_addMethods(the_class, [");
|
||||
saveJSBuffer.atoms.push.apply(saveJSBuffer.atoms, st.compiler.imBuffer.atoms); // FIXME: Move this append to StringBuffer
|
||||
CONCAT(saveJSBuffer, "]);\n");
|
||||
}
|
||||
|
||||
// Add class methods
|
||||
if (IS_NOT_EMPTY(st.compiler.cmBuffer))
|
||||
{
|
||||
CONCAT(saveJSBuffer, "class_addMethods(meta_class, [");
|
||||
saveJSBuffer.atoms.push.apply(saveJSBuffer.atoms, st.compiler.cmBuffer.atoms); // FIXME: Move this append to StringBuffer
|
||||
CONCAT(saveJSBuffer, "]);\n");
|
||||
}
|
||||
|
||||
CONCAT(saveJSBuffer, "}");
|
||||
|
||||
st.compiler.jsBuffer = saveJSBuffer;
|
||||
|
||||
// Skip the "@end"
|
||||
st.compiler.lastPos = node.end;
|
||||
},
|
||||
MethodDeclarationStatement: function(node, st, c) {
|
||||
var saveJSBuffer = st.compiler.jsBuffer,
|
||||
methodScope = new Scope(st),
|
||||
selectors = node.selectors,
|
||||
arguments = node.arguments,
|
||||
types = [node.returntype ? node.returntype.name : "id"],
|
||||
selector = selectors[0].name; // There is always at least one selector
|
||||
|
||||
CONCAT(saveJSBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start));
|
||||
|
||||
st.compiler.jsBuffer = node.methodtype === '-' ? st.compiler.imBuffer : st.compiler.cmBuffer;
|
||||
|
||||
// Put together the selector. Maybe this should be done in the parser...
|
||||
for (var i = 0; i < arguments.length; i++) {
|
||||
if (i === 0)
|
||||
selector += ":";
|
||||
else
|
||||
selector += (selectors[i] ? selectors[i].name : "") + ":";
|
||||
}
|
||||
|
||||
if (IS_NOT_EMPTY(st.compiler.jsBuffer)) // Add comma separator if this is not first method in this buffer
|
||||
CONCAT(st.compiler.jsBuffer, ", ");
|
||||
CONCAT(st.compiler.jsBuffer, "new objj_method(sel_getUid(\"");
|
||||
CONCAT(st.compiler.jsBuffer, selector);
|
||||
CONCAT(st.compiler.jsBuffer, "\"), function");
|
||||
|
||||
// this.currentSelector = selector;
|
||||
|
||||
if (st.compiler.flags & ObjJAcornCompiler.Flags.IncludeDebugSymbols)
|
||||
{
|
||||
CONCAT(st.compiler.jsBuffer, " $" + st.currentClassName() + "__" + selector.replace(/:/g, "_"));
|
||||
}
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, "(self, _cmd");
|
||||
|
||||
methodScope.methodType = node.methodtype;
|
||||
if (arguments) for (var i = 0; i < arguments.length; i++)
|
||||
{
|
||||
var argument = arguments[i],
|
||||
argumentName = argument.identifier.name;
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, ", ");
|
||||
CONCAT(st.compiler.jsBuffer, argumentName);
|
||||
types.push(argument.type ? argument.type.name : null);
|
||||
methodScope.vars[argumentName] = {type: "method argument", node: argument};
|
||||
}
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, ")");
|
||||
|
||||
st.compiler.lastPos = node.startOfBody;
|
||||
c(node.body, methodScope, "Statement");
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.body.end));
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, "\n");
|
||||
if (st.compiler.flags & ObjJAcornCompiler.Flags.IncludeDebugSymbols) //flags.IncludeTypeSignatures)
|
||||
CONCAT(st.compiler.jsBuffer, ","+JSON.stringify(types));
|
||||
CONCAT(st.compiler.jsBuffer, ")");
|
||||
st.compiler.jsBuffer = saveJSBuffer;
|
||||
st.compiler.lastPos = node.end;
|
||||
},
|
||||
MessageSendExpression: function(node, st, c) {
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start));
|
||||
st.compiler.lastPos = node.object ? node.object.start : node.arguments.length ? node.arguments[0].start : node.end;
|
||||
if (node.superObject)
|
||||
{
|
||||
CONCAT(st.compiler.jsBuffer, "objj_msgSendSuper(");
|
||||
CONCAT(st.compiler.jsBuffer, "{ receiver:self, super_class:" + (st.currentMethodType() === "+" ? st.compiler.currentSuperMetaClass : st.compiler.currentSuperClass ) + " }");
|
||||
}
|
||||
else
|
||||
{
|
||||
CONCAT(st.compiler.jsBuffer, "objj_msgSend(");
|
||||
c(node.object, st, "Expression");
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.object.end));
|
||||
}
|
||||
|
||||
var selectors = node.selectors,
|
||||
arguments = node.arguments,
|
||||
selector = selectors[0].name; // There is always at least one selector
|
||||
|
||||
// Put together the selector. Maybe this should be done in the parser...
|
||||
for (var i = 0; i < arguments.length; i++)
|
||||
if (i === 0)
|
||||
selector += ":";
|
||||
else
|
||||
selector += (selectors[i] ? selectors[i].name : "") + ":";
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, ", \"");
|
||||
CONCAT(st.compiler.jsBuffer, selector); // FIXME: sel_getUid(selector + "") ? This FIXME is from the old preprocessor compiler
|
||||
CONCAT(st.compiler.jsBuffer, "\"");
|
||||
|
||||
if (node.arguments) for (var i = 0; i < node.arguments.length; i++)
|
||||
{
|
||||
var argument = node.arguments[i];
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, ", ");
|
||||
st.compiler.lastPos = argument.start;
|
||||
c(argument, st, "Expression");
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, argument.end));
|
||||
st.compiler.lastPos = argument.end;
|
||||
}
|
||||
|
||||
// TODO: Move this 'if' wtih body up inside the node.argument 'if'
|
||||
if (node.parameters) for (var i = 0; i < node.parameters.length; ++i)
|
||||
{
|
||||
var parameter = node.parameters[i];
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, ", ");
|
||||
st.compiler.lastPos = parameter.start;
|
||||
c(parameter, st, "Expression");
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, parameter.end));
|
||||
st.compiler.lastPos = parameter.end;
|
||||
}
|
||||
|
||||
CONCAT(st.compiler.jsBuffer, ")");
|
||||
st.compiler.lastPos = node.end;
|
||||
},
|
||||
Identifier: function(node, st, c) {
|
||||
if (!st.secondMemberExpression)
|
||||
{
|
||||
var identifier = node.name,
|
||||
lvar = st.getLvarForCurrentMethod(identifier),
|
||||
ivar = st.compiler.getIvarForClass(identifier, st);
|
||||
|
||||
if (ivar)
|
||||
{
|
||||
if (lvar)
|
||||
st.compiler.addWarning(createMessage("Local declaration of '" + identifier + "' hides instance variable", node, st.compiler.source));
|
||||
else
|
||||
{
|
||||
var nodeStart = node.start,
|
||||
compiler = st.compiler;
|
||||
|
||||
do { // The Spider Monkey AST tree includes any parentheses in start and end properties so we have to make sure we skip those
|
||||
CONCAT(compiler.jsBuffer, compiler.source.substring(compiler.lastPos, nodeStart));
|
||||
compiler.lastPos = nodeStart;
|
||||
} while (compiler.source.substr(nodeStart++, 1) === "(")
|
||||
CONCAT(compiler.jsBuffer, "self.");
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
SelectorLiteralExpression: function(node, st, c) {
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start));
|
||||
CONCAT(st.compiler.jsBuffer, "sel_getUid(\"");
|
||||
CONCAT(st.compiler.jsBuffer, node.selector);
|
||||
CONCAT(st.compiler.jsBuffer, "\")");
|
||||
st.compiler.lastPos = node.end;
|
||||
},
|
||||
Literal: function(node, st, c) {
|
||||
if (node.raw && node.raw.charAt(0) === "@")
|
||||
{
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, node.start));
|
||||
st.compiler.lastPos = node.start + 1;
|
||||
}
|
||||
},
|
||||
ObjectExpression: function(node, st, c) {
|
||||
for (var i = 0; i < node.properties.length; ++i)
|
||||
{
|
||||
var prop = node.properties[i];
|
||||
if (prop.key.raw && prop.key.raw.charAt(0) === "@")
|
||||
{
|
||||
CONCAT(st.compiler.jsBuffer, st.compiler.source.substring(st.compiler.lastPos, prop.key.start));
|
||||
st.compiler.lastPos = prop.key.start + 1;
|
||||
}
|
||||
c(prop.value, st, "Expression");
|
||||
}
|
||||
}
|
||||
});
|
||||
+23
-24
@@ -20,25 +20,7 @@
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
var ObjJCompiler = { },
|
||||
currentCompilerFlags = "";
|
||||
|
||||
exports.compileToExecutable = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
ObjJCompiler.currentCompileFile = aURL;
|
||||
return new ObjJCompiler(aString, aURL, flags, 2).executable();
|
||||
}
|
||||
|
||||
exports.compileToIMBuffer = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
return new ObjJCompiler(aString, aURL, flags, 2).IMBuffer();
|
||||
}
|
||||
|
||||
exports.compileFileDependencies = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
ObjJCompiler.currentCompileFile = aURL;
|
||||
return new ObjJCompiler(aString, aURL, flags, 1).executable();
|
||||
}
|
||||
var currentCompilerFlags = "";
|
||||
|
||||
var ObjJCompiler = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags, /*unsigned*/ pass)
|
||||
{
|
||||
@@ -91,6 +73,25 @@ var ObjJCompiler = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ fla
|
||||
// console.log("JS: " + this._jsBuffer);
|
||||
}
|
||||
|
||||
exports.ObjJCompiler = ObjJCompiler;
|
||||
|
||||
exports.ObjJCompiler.compileToExecutable = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
ObjJCompiler.currentCompileFile = aURL;
|
||||
return new ObjJCompiler(aString, aURL, flags, 2).executable();
|
||||
}
|
||||
|
||||
exports.ObjJCompiler.compileToIMBuffer = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
return new ObjJCompiler(aString, aURL, flags, 2).IMBuffer();
|
||||
}
|
||||
|
||||
exports.ObjJCompiler.compileFileDependencies = function(/*String*/ aString, /*CFURL*/ aURL, /*unsigned*/ flags)
|
||||
{
|
||||
ObjJCompiler.currentCompileFile = aURL;
|
||||
return new ObjJCompiler(aString, aURL, flags, 1).executable();
|
||||
}
|
||||
|
||||
ObjJCompiler.prototype.compilePass2 = function()
|
||||
{
|
||||
ObjJCompiler.currentCompileFile = this._URL;
|
||||
@@ -111,12 +112,11 @@ ObjJCompiler.prototype.compilePass2 = function()
|
||||
return this._jsBuffer.toString();
|
||||
}
|
||||
|
||||
exports.ObjJCompiler = ObjJCompiler;
|
||||
|
||||
// This will set the compiler version to use.
|
||||
// These version works:
|
||||
// "preprocessor" -> Old Cappuccino compiler
|
||||
// "objj_compiler2" -> New Cappuccino compiler
|
||||
// "acorn" -> New Cappuccino compiler with acorn parser
|
||||
|
||||
GLOBAL(ObjJCompilerSetUsedVersion) = function(version)
|
||||
{
|
||||
@@ -1400,7 +1400,7 @@ ObjJCompiler.prototype.nodeClassDeclationStatement = function(/*SyntaxNode*/ ast
|
||||
if (this.getClassDef(className))
|
||||
throw new SyntaxError(this.error_message("Duplicate class " + className, children[2]));
|
||||
if (!this.getClassDef(superClassName))
|
||||
throw new SyntaxError(this.error_message("Can't find superclass " + superClassName, child));
|
||||
throw new SyntaxError(this.error_message("Can't find superclass " + superClassName, child));
|
||||
|
||||
classDef = {"className": className, "superClassName": superClassName, "ivars": {}, "methods": {}};
|
||||
|
||||
@@ -1540,7 +1540,7 @@ ObjJCompiler.prototype.nodeClassDeclationStatement = function(/*SyntaxNode*/ ast
|
||||
CONCAT(getterSetterBuffer, "\n@end");
|
||||
// Remove all @accessors or we will get a recursive loop in infinity
|
||||
var b = getterSetterBuffer.toString().replace(/@accessors(\(.*\))?/g, "");
|
||||
var imBuffer = exports.compileToIMBuffer(b, "getter", this._flags);
|
||||
var imBuffer = ObjJCompiler.compileToIMBuffer(b, "getter", this._flags);
|
||||
|
||||
CONCAT(this._imBuffer, imBuffer);
|
||||
}
|
||||
@@ -4704,4 +4704,3 @@ ObjJCompiler.prototype.error_message = function(errorMessage, astNode)
|
||||
(this._currentClass ? " Class: "+this._currentClass : "") +
|
||||
(this._currentSelector ? " Method: "+this._currentSelector : "") +">";
|
||||
}
|
||||
//})(window, ObjJCompiler, { exports: ObjJCompiler });
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,23 @@
|
||||
Copyright (C) 2012 by Marijn Haverbeke <marijnh@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
Please note that some subdirectories of the CodeMirror distribution
|
||||
include their own LICENSE files, and are released under different
|
||||
licences.
|
||||
@@ -0,0 +1,254 @@
|
||||
// AST walker module for Mozilla Parser API compatible trees
|
||||
|
||||
if (!exports.acorn) {
|
||||
exports.acorn = {};
|
||||
exports.acorn.walk = {};
|
||||
}
|
||||
|
||||
(function(exports) {
|
||||
"use strict";
|
||||
|
||||
// A simple walk is one where you simply specify callbacks to be
|
||||
// called on specific nodes. The last two arguments are optional. A
|
||||
// simple use would be
|
||||
//
|
||||
// walk.simple(myTree, {
|
||||
// Expression: function(node) { ... }
|
||||
// });
|
||||
//
|
||||
// to do something with all expressions. All Parser API node types
|
||||
// can be used to identify node types, as well as Expression,
|
||||
// Statement, and ScopeBody, which denote categories of nodes.
|
||||
//
|
||||
// The base argument can be used to pass a custom (recursive)
|
||||
// walker, and state can be used to give this walked an initial
|
||||
// state.
|
||||
exports.simple = function(node, visitors, base, state) {
|
||||
if (!base) base = exports;
|
||||
function c(node, st, override) {
|
||||
var type = override || node.type, found = visitors[type];
|
||||
if (found) found(node, st);
|
||||
base[type](node, st, c);
|
||||
}
|
||||
c(node, state);
|
||||
};
|
||||
|
||||
// A recursive walk is one where your functions override the default
|
||||
// walkers. They can modify and replace the state parameter that's
|
||||
// threaded through the walk, and can opt how and whether to walk
|
||||
// their child nodes (by calling their third argument on these
|
||||
// nodes).
|
||||
exports.recursive = function(node, state, funcs, base) {
|
||||
var visitor = exports.make(funcs, base);
|
||||
function c(node, st, override) {
|
||||
visitor[override || node.type](node, st, c);
|
||||
}
|
||||
c(node, state);
|
||||
};
|
||||
|
||||
// Used to create a custom walker. Will fill in all missing node
|
||||
// type properties with the defaults.
|
||||
exports.make = function(funcs, base) {
|
||||
if (!base) base = exports;
|
||||
var visitor = {};
|
||||
for (var type in base) visitor[type] = base[type];
|
||||
for (var type in funcs) visitor[type] = funcs[type];
|
||||
return visitor;
|
||||
};
|
||||
|
||||
function skipThrough(node, st, c) { c(node, st); }
|
||||
function ignore(node, st, c) {}
|
||||
|
||||
// Node walkers.
|
||||
|
||||
exports.Program = exports.BlockStatement = function(node, st, c) {
|
||||
for (var i = 0; i < node.body.length; ++i) {
|
||||
c(node.body[i], st, "Statement");
|
||||
}
|
||||
};
|
||||
exports.Statement = skipThrough;
|
||||
exports.EmptyStatement = ignore;
|
||||
exports.ExpressionStatement = function(node, st, c) {
|
||||
c(node.expression, st, "Expression");
|
||||
};
|
||||
exports.IfStatement = function(node, st, c) {
|
||||
c(node.test, st, "Expression");
|
||||
c(node.consequent, st, "Statement");
|
||||
if (node.alternate) c(node.alternate, st, "Statement");
|
||||
};
|
||||
exports.LabeledStatement = function(node, st, c) {
|
||||
c(node.body, st, "Statement");
|
||||
};
|
||||
exports.BreakStatement = exports.ContinueStatement = ignore;
|
||||
exports.WithStatement = function(node, st, c) {
|
||||
c(node.object, st, "Expression");
|
||||
c(node.body, st, "Statement");
|
||||
};
|
||||
exports.SwitchStatement = function(node, st, c) {
|
||||
c(node.discriminant, st, "Expression");
|
||||
for (var i = 0; i < node.cases.length; ++i) {
|
||||
var cs = node.cases[i];
|
||||
if (cs.test) c(cs.test, st, "Expression");
|
||||
for (var j = 0; j < cs.consequent.length; ++j)
|
||||
c(cs.consequent[j], st, "Statement");
|
||||
}
|
||||
};
|
||||
exports.ReturnStatement = function(node, st, c) {
|
||||
if (node.argument) c(node.argument, st, "Expression");
|
||||
};
|
||||
exports.ThrowStatement = function(node, st, c) {
|
||||
c(node.argument, st, "Expression");
|
||||
};
|
||||
exports.TryStatement = function(node, st, c) {
|
||||
c(node.block, st, "Statement");
|
||||
for (var i = 0; i < node.handlers.length; ++i)
|
||||
c(node.handlers[i].body, st, "ScopeBody");
|
||||
if (node.finalizer) c(node.finalizer, st, "Statement");
|
||||
};
|
||||
exports.WhileStatement = function(node, st, c) {
|
||||
c(node.test, st, "Expression");
|
||||
c(node.body, st, "Statement");
|
||||
};
|
||||
exports.DoWhileStatement = function(node, st, c) {
|
||||
c(node.body, st, "Statement");
|
||||
c(node.test, st, "Expression");
|
||||
};
|
||||
exports.ForStatement = function(node, st, c) {
|
||||
if (node.init) c(node.init, st, "ForInit");
|
||||
if (node.test) c(node.test, st, "Expression");
|
||||
if (node.update) c(node.update, st, "Expression");
|
||||
c(node.body, st, "Statement");
|
||||
};
|
||||
exports.ForInStatement = function(node, st, c) {
|
||||
c(node.left, st, "ForInit");
|
||||
c(node.right, st, "Expression");
|
||||
c(node.body, st, "Statement");
|
||||
};
|
||||
exports.ForInit = function(node, st, c) {
|
||||
if (node.type == "VariableDeclaration") c(node, st);
|
||||
else c(node, st, "Expression");
|
||||
};
|
||||
exports.DebuggerStatement = ignore;
|
||||
|
||||
exports.FunctionDeclaration = function(node, st, c) {
|
||||
c(node, st, "Function");
|
||||
};
|
||||
exports.VariableDeclaration = function(node, st, c) {
|
||||
for (var i = 0; i < node.declarations.length; ++i) {
|
||||
var decl = node.declarations[i];
|
||||
if (decl.init) c(decl.init, st, "Expression");
|
||||
}
|
||||
};
|
||||
|
||||
exports.Function = function(node, st, c) {
|
||||
c(node.body, st, "ScopeBody");
|
||||
};
|
||||
exports.ScopeBody = function(node, st, c) {
|
||||
c(node, st, "Statement");
|
||||
};
|
||||
|
||||
exports.Expression = skipThrough;
|
||||
exports.ThisExpression = ignore;
|
||||
exports.ArrayExpression = function(node, st, c) {
|
||||
for (var i = 0; i < node.elements.length; ++i) {
|
||||
var elt = node.elements[i];
|
||||
if (elt) c(elt, st, "Expression");
|
||||
}
|
||||
};
|
||||
exports.ObjectExpression = function(node, st, c) {
|
||||
for (var i = 0; i < node.properties.length; ++i)
|
||||
c(node.properties[i].value, st, "Expression");
|
||||
};
|
||||
exports.FunctionExpression = exports.FunctionDeclaration;
|
||||
exports.SequenceExpression = function(node, st, c) {
|
||||
for (var i = 0; i < node.expressions.length; ++i)
|
||||
c(node.expressions[i], st, "Expression");
|
||||
};
|
||||
exports.UnaryExpression = exports.UpdateExpression = function(node, st, c) {
|
||||
c(node.argument, st, "Expression");
|
||||
};
|
||||
exports.BinaryExpression = exports.AssignmentExpression = exports.LogicalExpression = function(node, st, c) {
|
||||
c(node.left, st, "Expression");
|
||||
c(node.right, st, "Expression");
|
||||
};
|
||||
exports.ConditionalExpression = function(node, st, c) {
|
||||
c(node.test, st, "Expression");
|
||||
c(node.consequent, st, "Expression");
|
||||
c(node.alternate, st, "Expression");
|
||||
};
|
||||
exports.NewExpression = exports.CallExpression = function(node, st, c) {
|
||||
c(node.callee, st, "Expression");
|
||||
if (node.arguments) for (var i = 0; i < node.arguments.length; ++i)
|
||||
c(node.arguments[i], st, "Expression");
|
||||
};
|
||||
exports.MemberExpression = function(node, st, c) {
|
||||
c(node.object, st, "Expression");
|
||||
if (node.computed) c(node.property, st, "Expression");
|
||||
};
|
||||
exports.Identifier = exports.Literal = ignore;
|
||||
|
||||
exports.ClassDeclarationStatement = function(node, st, c) {
|
||||
if (node.ivardeclarations) for (var i = 0; i < node.ivardeclarations.length; ++i) {
|
||||
c(node.ivardeclarations[i], st, "IvarDeclaration");
|
||||
}
|
||||
for (var i = 0; i < node.body.length; ++i) {
|
||||
c(node.body[i], st, "Statement");
|
||||
}
|
||||
}
|
||||
|
||||
exports.ImportStatement = ignore;
|
||||
|
||||
exports.IvarDeclaration = ignore;
|
||||
|
||||
exports.MethodDeclarationStatement = ignore;
|
||||
|
||||
exports.MethodDeclarationStatement = function(node, st, c) {
|
||||
c(node.body, st, "Statement");
|
||||
}
|
||||
|
||||
exports.MessageSendExpression = function(node, st, c) {
|
||||
if (!node.superObject) c(node.object, st, "Expression");
|
||||
if (node.arguments) for (var i = 0; i < node.arguments.length; ++i)
|
||||
c(node.arguments[i], st, "Expression");
|
||||
if (node.parameters) for (var i = 0; i < node.parameters.length; ++i)
|
||||
c(node.parameters[i], st, "Expression");
|
||||
}
|
||||
|
||||
exports.SelectorLiteralExpression = ignore;
|
||||
|
||||
// A custom walker that keeps track of the scope chain and the
|
||||
// variables defined in it.
|
||||
function makeScope(prev) {
|
||||
return {vars: Object.create(null), prev: prev};
|
||||
}
|
||||
exports.scopeVisitor = exports.make({
|
||||
Function: function(node, scope, c) {
|
||||
var inner = makeScope(scope);
|
||||
for (var i = 0; i < node.params.length; ++i)
|
||||
inner.vars[node.params[i].name] = {type: "argument", node: node.params[i]};
|
||||
if (node.id) {
|
||||
var decl = node.type == "FunctionDeclaration";
|
||||
(decl ? scope : inner).vars[node.id.name] =
|
||||
{type: decl ? "function" : "function name", node: node.id};
|
||||
}
|
||||
c(node.body, inner, "ScopeBody");
|
||||
},
|
||||
TryStatement: function(node, scope, c) {
|
||||
c(node.block, scope, "Statement");
|
||||
for (var i = 0; i < node.handlers.length; ++i) {
|
||||
var handler = node.handlers[i], inner = makeScope(scope);
|
||||
inner.vars[handler.param.name] = {type: "catch clause", node: handler.param};
|
||||
c(handler.body, inner, "ScopeBody");
|
||||
}
|
||||
if (node.finalizer) c(node.finalizer, scope, "Statement");
|
||||
},
|
||||
VariableDeclaration: function(node, scope, c) {
|
||||
for (var i = 0; i < node.declarations.length; ++i) {
|
||||
var decl = node.declarations[i];
|
||||
scope.vars[decl.id.name] = {type: "var", node: decl.id};
|
||||
if (decl.init) c(decl.init, scope, "Expression");
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
})(typeof exports == "undefined" ? acorn.walk = {} : exports.acorn.walk);
|
||||
Reference in New Issue
Block a user