mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 21:17:03 +00:00
225 lines
8.0 KiB
JavaScript
225 lines
8.0 KiB
JavaScript
var FILE = require("file"),
|
|
FileList = require("jake").FileList,
|
|
OS = require("os"),
|
|
stream = require("narwhal/term").stream;
|
|
|
|
var cPreprocessedFileContents = function(aFilePath)
|
|
{
|
|
var INCLUDES = new FileList(FILE.join(FILE.dirname(aFilePath), "**", "*.h")).map(function(aFilename)
|
|
{
|
|
return "--include \"" + aFilename + "\"";
|
|
}).join(" ");
|
|
var gcc = OS.popen("gcc -E -x c -P -DPLATFORM_COMMONJS " + INCLUDES + " " + OS.enquote(aFilePath), { charset:"UTF-8" }),
|
|
chunk,
|
|
fileContents = "";
|
|
|
|
while (chunk = gcc.stdout.read())
|
|
fileContents += chunk;
|
|
|
|
return fileContents;
|
|
};
|
|
|
|
var checkImportsForFile = function (fileName)
|
|
{
|
|
var classNames = [],
|
|
errorMessageHashSet = {},
|
|
matches = fileName.match(new RegExp("([^\\/]+)\\/([^\\/]+)\\.j$"));
|
|
|
|
if (!FILE.exists(fileName) ||
|
|
FILE.isDirectory(fileName) ||
|
|
fileName.indexOf("+") !== -1 ||
|
|
(matches && matches[1] === matches[2]))
|
|
return;
|
|
|
|
// this is a hackish way to clear the previous file's @imports
|
|
for (var g in global)
|
|
if (g !== "SyntaxError")
|
|
delete global[g];
|
|
|
|
// reload Objective-J and get a reference to its StaticResource export at
|
|
// the same time
|
|
global.StaticResource = require.force("objective-j").StaticResource;
|
|
|
|
ObjectiveJ.OBJJ_INCLUDE_PATHS = [FILE.canonical(".")];
|
|
|
|
var og_resolveResourceAtURL = StaticResource.resolveResourceAtURL;
|
|
|
|
// this function gets called for all "File.j" imports
|
|
// in case the import can't be resolved, use JAKE.FileList to try and find
|
|
// it.
|
|
StaticResource.resolveResourceAtURL = function(/*CFURL|String*/ aURL, /*BOOL*/ isDirectory, /*Function*/ aCallback)
|
|
{
|
|
var og_callback = arguments[2];
|
|
arguments[2] = function (resource)
|
|
{
|
|
if (!resource)
|
|
{
|
|
var basename = FILE.basename(aURL.toString()),
|
|
newURL = (new FileList("Foundation/**/" + basename)).include("AppKit/**/" + basename).items()[0];
|
|
|
|
|
|
if (newURL)
|
|
return og_resolveResourceAtURL(FILE.canonical(newURL), isDirectory, og_callback)
|
|
else
|
|
og_callback(resource);
|
|
}
|
|
else
|
|
og_callback(resource);
|
|
|
|
};
|
|
|
|
og_resolveResourceAtURL.apply(this, arguments);
|
|
};
|
|
|
|
// this function gets called for <Framework/File.j> imports
|
|
// since this script looks at the un-compiled frameworks,
|
|
// some trickery for finding the correct file is sometimes necessary
|
|
var resolveResourceAtURLSearchingIncludeURLs = function (/*CFURL*/ aURL, /*Number*/ anIndex, /*Function*/ aCallback)
|
|
{
|
|
var includeURLs = StaticResource.includeURLs(),
|
|
searchURL = new CFURL(aURL, includeURLs[anIndex]).absoluteURL();
|
|
|
|
og_resolveResourceAtURL(searchURL, NO, function(/*StaticResource*/ aStaticResource)
|
|
{
|
|
if (!aStaticResource)
|
|
{
|
|
if (anIndex + 1 < includeURLs.length)
|
|
resolveResourceAtURLSearchingIncludeURLs(aURL, anIndex + 1, aCallback);
|
|
else
|
|
{
|
|
var basename = FILE.basename(aURL),
|
|
newURL = (new FileList("Foundation/**/" + basename)).include("AppKit/**/" + basename).items()[0];
|
|
|
|
if (newURL)
|
|
resolveResourceAtURLSearchingIncludeURLS(FILE.canonical(newURL), anIndex, aCallback);
|
|
else
|
|
aCallback(NULL);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
aCallback(aStaticResource);
|
|
});
|
|
}
|
|
StaticResource.resolveResourceAtURLSearchingIncludeURLs = function(/*CFURL*/ aURL, /*Function*/ aCallback)
|
|
{
|
|
resolveResourceAtURLSearchingIncludeURLs(aURL, 0, aCallback);
|
|
};
|
|
|
|
// find all the @implementations by running through the CPP and then
|
|
// calling ObjectiveJ.preprocess with a decorated @implementation handler
|
|
// on the Preprocessor
|
|
var fileNameContents = cPreprocessedFileContents(fileName);
|
|
var og_objj_implementation = ObjectiveJ.Preprocessor.prototype.implementation;
|
|
ObjectiveJ.Preprocessor.prototype.implementation = function (tokens)
|
|
{
|
|
var className = tokens.skip_whitespace();
|
|
if (classNames.indexOf(className) === -1)
|
|
classNames.push(className);
|
|
|
|
tokens.skip_whitespace(YES);
|
|
|
|
og_objj_implementation.apply(this, arguments);
|
|
};
|
|
|
|
ObjectiveJ.preprocess(fileNameContents);
|
|
|
|
// reset the preprocessor's @implementation handler
|
|
ObjectiveJ.Preprocessor.prototype.implementation = og_objj_implementation;
|
|
|
|
// do automatic CPP runs on @imported files
|
|
// to resolve #includes and conditional compilation
|
|
CFHTTPRequest.prototype.responseText = function ()
|
|
{
|
|
if (this._URL.slice(-2) === ".j")
|
|
{
|
|
var tmpFile = FILE.canonical(FILE.join(FILE.dirname(this._URL.split(":")[1]), ".detect_missing_imports"));
|
|
|
|
// hackishly give the file a window object
|
|
FILE.write(tmpFile, "window = {};\n" + this._nativeRequest.responseText);
|
|
var result = cPreprocessedFileContents(tmpFile);
|
|
FILE.remove(tmpFile);
|
|
}
|
|
else
|
|
result = this._nativeRequest.responseText;
|
|
return result;
|
|
};
|
|
|
|
try
|
|
{
|
|
objj_importFile(FILE.canonical(fileName), YES);
|
|
}
|
|
catch (e)
|
|
{
|
|
if (e.name === "ReferenceError")
|
|
stream.print("\0yellow(Detected missing @import in \"" + fileName + "\": " + e.message + "\0)");
|
|
else
|
|
throw e;
|
|
}
|
|
|
|
for(var j = 0, jj = classNames.length; j < jj; ++j)
|
|
{
|
|
var className = classNames[j],
|
|
cls = objj_getClass(className);
|
|
if (cls && cls.super_class)
|
|
{
|
|
// instance methods
|
|
var method_dtable = cls.method_dtable;
|
|
for (var methodName in method_dtable)
|
|
{
|
|
if (method_dtable.hasOwnProperty(methodName))
|
|
{
|
|
try
|
|
{
|
|
var instance = objj_msgSend(cls, "alloc");
|
|
objj_msgSend(instance, methodName, method_dtable[methodName].types.slice(1));
|
|
}
|
|
catch (e)
|
|
{
|
|
if (e.name === "ReferenceError")
|
|
{
|
|
var hashKey = fileName + e.message;
|
|
if (!errorMessageHashSet[hashKey])
|
|
{
|
|
stream.print("\0yellow(Detected missing @import in \"" + fileName + "\": " + e.message + " (Context: [" + className + " " + methodName + "])\0)");
|
|
errorMessageHashSet[hashKey] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// class methods
|
|
method_dtable = cls.isa.method_dtable;
|
|
for (var methodName in method_dtable)
|
|
{
|
|
if (method_dtable.hasOwnProperty(methodName))
|
|
{
|
|
try
|
|
{
|
|
objj_msgSend(cls, methodName);
|
|
}
|
|
catch (e)
|
|
{
|
|
if (e.name === "ReferenceError")
|
|
{
|
|
var hashKey = fileName + e.message;
|
|
if (!errorMessageHashSet[hashKey])
|
|
{
|
|
stream.print("\0yellow(Detected missing @import in \"" + fileName + "\": " + e.message + " (Context: [" + className + " " + methodName + "])\0)");
|
|
errorMessageHashSet[hashKey] = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
(new FileList("Foundation/**.j").include("AppKit/**.j")).forEach(function (aFile)
|
|
{
|
|
checkImportsForFile(aFile);
|
|
});
|