mirror of
https://github.com/cappuccino/cappuccino.git
synced 2026-08-25 21:17:03 +00:00
New: We now support source maps when compiling both from command line and in browsers.
To add source maps add the ”-S” flag to the Jake file when compiling from command line. In the browser you need to add the compiler option into your index.html file. It should look something like this: OBJJ_COMPILER_FLAGS = [... , "SourceMap"]; All browsers has support for source maps but currently Chrome works best.
This commit is contained in:
@@ -772,6 +772,7 @@ var STATIC_MAGIC_NUMBER = "@STATIC",
|
||||
MARKER_TEXT = "t",
|
||||
MARKER_IMPORT_STD = 'I',
|
||||
MARKER_IMPORT_LOCAL = 'i';
|
||||
MARKER_SOURCE_MAP = 'S';
|
||||
|
||||
function decompileStaticFile(/*Bundle*/ aBundle, /*String*/ aString, /*String*/ aPath)
|
||||
{
|
||||
|
||||
+25
-11
@@ -27,7 +27,7 @@ var ExecutableUnloadedFileDependencies = 0,
|
||||
ExecutableCantStartLoadYetFileDependencies = 3,
|
||||
AnonymousExecutableCount = 0;
|
||||
|
||||
function Executable(/*String*/ aCode, /*Array*/ fileDependencies, /*CFURL|String*/ aURL, /*Function*/ aFunction, /*ObjJCompiler*/aCompiler, /*Dictionary*/ aFilenameTranslateDictionary)
|
||||
function Executable(/*String*/ aCode, /*Array*/ fileDependencies, /*CFURL|String*/ aURL, /*Function*/ aFunction, /*ObjJCompiler*/aCompiler, /*Dictionary*/ aFilenameTranslateDictionary, /* Base64 String */ sourceMap)
|
||||
{
|
||||
if (arguments.length === 0)
|
||||
return this;
|
||||
@@ -41,6 +41,9 @@ function Executable(/*String*/ aCode, /*Array*/ fileDependencies, /*CFURL|String
|
||||
this._fileDependencies = fileDependencies;
|
||||
this._filenameTranslateDictionary = aFilenameTranslateDictionary;
|
||||
|
||||
if (sourceMap)
|
||||
this._base64EncodedSourceMap = sourceMap;
|
||||
|
||||
// This is a little hacky but if fileDependencies is null we can start loading file dependencies yet
|
||||
if (!fileDependencies)
|
||||
{
|
||||
@@ -148,6 +151,12 @@ Executable.prototype.toMarkedString = function()
|
||||
for (; index < count; ++index)
|
||||
markedString += dependencies[index].toMarkedString();
|
||||
|
||||
var sourceMap = this._base64EncodedSourceMap;
|
||||
|
||||
if (sourceMap) {
|
||||
markedString += MARKER_SOURCE_MAP + ";" + sourceMap.length + ";" + sourceMap;
|
||||
}
|
||||
|
||||
var code = this.code();
|
||||
|
||||
return markedString + MARKER_TEXT + ";" + code.length + ";" + code;
|
||||
@@ -179,7 +188,7 @@ Executable.prototype.execute = function()
|
||||
|
||||
this.setCode(this._compiler.compilePass2(), this._compiler.map());
|
||||
|
||||
if (FileExecutable.printWarningsAndErrors(this._compiler, exports.messageOutputFormatInXML))
|
||||
if (FileExecutable.printWarningsAndErrors(this._compiler, exports.messageOutputFormatInXML))
|
||||
throw "Compilation error";
|
||||
|
||||
this._compiler = null;
|
||||
@@ -211,6 +220,7 @@ Executable.prototype.setCode = function(code, sourceMap)
|
||||
this._code = code;
|
||||
|
||||
var parameters = this.functionParameters().join(",");
|
||||
var sourceMapBase64;
|
||||
|
||||
#if COMMONJS
|
||||
if (typeof system !== "undefined" && system.engine === "rhino")
|
||||
@@ -222,6 +232,9 @@ Executable.prototype.setCode = function(code, sourceMap)
|
||||
{
|
||||
#endif
|
||||
#if DEBUG
|
||||
// Check if base64 source map is available
|
||||
sourceMapBase64 = this._base64EncodedSourceMap;
|
||||
|
||||
// "//# sourceURL=" at the end lets us name our eval'd files for debuggers, etc.
|
||||
// * WebKit: http://pmuellr.blogspot.com/2009/06/debugger-friendly.html
|
||||
// * Firebug: http://blog.getfirebug.com/2009/08/11/give-your-eval-a-name-with-sourceurl/
|
||||
@@ -229,22 +242,23 @@ Executable.prototype.setCode = function(code, sourceMap)
|
||||
var absoluteString = this.URL().absoluteString();
|
||||
|
||||
code += "/**/\n//# sourceURL=" + absoluteString + "s";
|
||||
|
||||
if (sourceMap)
|
||||
{
|
||||
// The new Function constructor will add a function header before the first line
|
||||
// The compiler adds a new line as the first character to the code to get the spurce
|
||||
// mapping correct. We have to remove it here
|
||||
code = code.substring(2);
|
||||
|
||||
var sourceMapBase64;
|
||||
|
||||
if (typeof btoa === 'function')
|
||||
sourceMapBase64 = btoa(UTF16ToUTF8(sourceMap));
|
||||
else if (typeof Buffer === 'function')
|
||||
sourceMapBase64 = new Buffer(sourceMap).toString("base64");
|
||||
}
|
||||
|
||||
if (sourceMapBase64)
|
||||
code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + sourceMapBase64;
|
||||
if (sourceMapBase64) {
|
||||
// The new Function constructor will add a function header before the first line
|
||||
// The compiler adds two newlines as the first character to the code to get the source
|
||||
// mapping correct. We have to remove it here. As Javascript engines adds diffentent
|
||||
// amount of lines at the top we need to calculate how many.
|
||||
code = code.substring(exports.ObjJCompiler.numberOfLinesAtTopOfFunction());
|
||||
this._base64EncodedSourceMap = sourceMapBase64;
|
||||
code += "\n//# sourceMappingURL=data:application/json;charset=utf-8;base64," + sourceMapBase64;
|
||||
}
|
||||
//} else {
|
||||
// // Firebug only does it for "eval()", not "new Function()". Ugh. Slower.
|
||||
|
||||
@@ -248,7 +248,8 @@ function decompile(/*String*/ aString, /*CFURL*/ aURL)
|
||||
*/
|
||||
var marker = NULL,
|
||||
code = "",
|
||||
dependencies = [];
|
||||
dependencies = [],
|
||||
sourceMap;
|
||||
|
||||
while (marker = stream.getMarker())
|
||||
{
|
||||
@@ -262,14 +263,17 @@ function decompile(/*String*/ aString, /*CFURL*/ aURL)
|
||||
|
||||
else if (marker === MARKER_IMPORT_LOCAL)
|
||||
dependencies.push(new FileDependency(new CFURL(text), YES));
|
||||
|
||||
else if (marker === MARKER_SOURCE_MAP)
|
||||
sourceMap = text;
|
||||
}
|
||||
|
||||
var fn = FileExecutable._lookupCachedFunction(aURL);
|
||||
|
||||
if (fn)
|
||||
return new Executable(code, dependencies, aURL, fn);
|
||||
return new Executable(code, dependencies, aURL, fn, null, null, sourceMap);
|
||||
|
||||
return new Executable(code, dependencies, aURL);
|
||||
return new Executable(code, dependencies, aURL, null, null, null, sourceMap);
|
||||
}
|
||||
|
||||
var FunctionCache = { };
|
||||
|
||||
@@ -46,6 +46,7 @@
|
||||
#include "CFBundle.js"
|
||||
#include "StaticResource.js"
|
||||
#include "Preprocessor.js"
|
||||
#include "source-map.js"
|
||||
#include "acorn.js"
|
||||
#include "acornwalk.js"
|
||||
#include "ObjJAcornCompiler.js"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
(function(mod)
|
||||
{
|
||||
mod(exports.ObjJCompiler || (exports.ObjJCompiler = {}), exports.acorn || acorn, (exports.acorn || acorn).walk, typeof sourceMap != "undefined" ? sourceMap : null); // Plain browser env
|
||||
mod(exports.ObjJCompiler || (exports.ObjJCompiler = {}), exports.acorn || acorn, (exports.acorn || acorn).walk, typeof exports.sourceMap != "undefined" ? exports.sourceMap : (typeof module != "undefined" && typeof module.exports === "object" ? module.exports : null)); // Plain browser env
|
||||
})(function(exports, acorn, walk, sourceMap)
|
||||
{
|
||||
"use strict";
|
||||
@@ -821,6 +821,28 @@ exports.compileFileDependencies = function(/*String*/ aString, /*CFURL*/ aURL, o
|
||||
return new ObjJAcornCompiler(aString, aURL, options);
|
||||
}
|
||||
|
||||
/*!
|
||||
This function is used to calculate the number of lines that is added when a 'new Function(...) call is used.
|
||||
This is used to make sure source maps are correct
|
||||
Currently Safari is adding one line and Chrome and Firefox is adding two lines.
|
||||
|
||||
We calculate this by creating a function and counts the number of new lines at the top of the function
|
||||
The result is cached so we only need to make the calculation once.
|
||||
*/
|
||||
exports.numberOfLinesAtTopOfFunction = function() {
|
||||
var f = new Function("x", "return x;");
|
||||
var fString = f.toString();
|
||||
var index = fString.indexOf("return x;");
|
||||
var firstPart = fString.substring(0, index);
|
||||
var numberOfLines = (firstPart.match(/\n/g) || []).length;
|
||||
|
||||
ObjJAcornCompiler.numberOfLinesAtTopOfFunction = function() {
|
||||
return numberOfLines;
|
||||
}
|
||||
|
||||
return numberOfLines;
|
||||
}
|
||||
|
||||
ObjJAcornCompiler.prototype.compilePass2 = function()
|
||||
{
|
||||
var options = this.options;
|
||||
@@ -1427,7 +1449,7 @@ ExpressionStatement: function(node, st, c, format) {
|
||||
generate = compiler.generate && !format;
|
||||
if (generate) compiler.jsBuffer.concat(indentation);
|
||||
c(node.expression, st, "Expression");
|
||||
if (generate) compiler.jsBuffer.concat(";\n");
|
||||
if (generate) compiler.jsBuffer.concat(";\n", node);
|
||||
},
|
||||
IfStatement: function(node, st, c, format) {
|
||||
var compiler = st.compiler,
|
||||
@@ -1994,7 +2016,7 @@ VariableDeclaration: function(node, st, c, format) {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (generate && !format && !st.isFor) buffer.concat(";\n"); // Don't add ';' if this is a for statement but do it if this is a statement
|
||||
if (generate && !format && !st.isFor) buffer.concat(";\n", node); // Don't add ';' if this is a for statement but do it if this is a statement
|
||||
},
|
||||
ThisExpression: function(node, st, c) {
|
||||
var compiler = st.compiler;
|
||||
@@ -2149,7 +2171,7 @@ BinaryExpression: function(node, st, c, format) {
|
||||
if (generate) {
|
||||
var buffer = compiler.jsBuffer;
|
||||
buffer.concatFormat(format ? format.beforeOperator : " ");
|
||||
buffer.concat(node.operator);
|
||||
buffer.concat(node.operator, node);
|
||||
buffer.concatFormat(format ? format.afterOperator : " ");
|
||||
}
|
||||
(generate && nodePrecedence(node, node.right, true) ? surroundExpression(c) : c)(node.right, st, "Expression");
|
||||
@@ -2315,7 +2337,7 @@ MemberExpression: function(node, st, c) {
|
||||
if (generate)
|
||||
compiler.jsBuffer.concat(computed ? "[" : ".", node);
|
||||
st.secondMemberExpression = !computed;
|
||||
// No parentheses when it is computed, '[' amd ']' are the same thing.
|
||||
// No parentheses when it is computed, '[' and ']' are the same thing.
|
||||
(generate && !computed && nodePrecedence(node, node.property) ? surroundExpression(c) : c)(node.property, st, "Expression");
|
||||
st.secondMemberExpression = false;
|
||||
if (generate && computed)
|
||||
@@ -3315,7 +3337,8 @@ MessageSendExpression: function(node, st, c) {
|
||||
firstSelector = selectors[0],
|
||||
selector = firstSelector ? firstSelector.name : "", // There is always at least one selector
|
||||
parameters = node.parameters,
|
||||
generateObjJ = compiler.options.generateObjJ;
|
||||
options = compiler.options,
|
||||
generateObjJ = options.generateObjJ;
|
||||
|
||||
// Put together the selector. Maybe this should be done in the parser...
|
||||
for (var i = 0; i < argumentsLength; i++) {
|
||||
@@ -3438,10 +3461,12 @@ MessageSendExpression: function(node, st, c) {
|
||||
}
|
||||
buffer.concat("]");
|
||||
} else {
|
||||
var selectorJSPath;
|
||||
|
||||
if (generate && !node.superObject) {
|
||||
if (!inlineMsgSend) {
|
||||
if (totalNoOfParameters < 4) {
|
||||
buffer.concat("" + totalNoOfParameters, null);
|
||||
buffer.concat("" + totalNoOfParameters, node);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3451,12 +3476,35 @@ MessageSendExpression: function(node, st, c) {
|
||||
} else {
|
||||
buffer.concat("(___r" + st.receiverLevel, node);
|
||||
}
|
||||
|
||||
// Only do this if source map is enabled and we have an identifier
|
||||
if (options.sourceMap && nodeObject.type === "Identifier") {
|
||||
// Get target expression for sourcemap to allow hovering selector to show method function. Create new buffer to write in.
|
||||
compiler.jsBuffer = new StringBuffer();
|
||||
c(nodeObject, st, "Expression");
|
||||
var aTarget = compiler.jsBuffer.toString();
|
||||
selectorJSPath = aTarget + ".isa.method_dtable[\"" + selector + "\"]"
|
||||
// Restored buffer so everything will continue as usually.
|
||||
compiler.jsBuffer = buffer;
|
||||
}
|
||||
}
|
||||
|
||||
buffer.concat(", \"", node);
|
||||
buffer.concat(selector); // FIXME: sel_getUid(selector + "") ? This FIXME is from the old preprocessor compiler
|
||||
buffer.concat(", ", node);
|
||||
if (selectorJSPath) {
|
||||
buffer.concat("(", node);
|
||||
for (var i = 0; i < selectors.length; i++) {
|
||||
var nextSelector = selectors[i];
|
||||
if (nextSelector) {
|
||||
buffer.concat(selectorJSPath, nextSelector);
|
||||
buffer.concat(", ", node);
|
||||
}
|
||||
}
|
||||
}
|
||||
buffer.concat("\"", node);
|
||||
|
||||
buffer.concat(selector, node); // FIXME: sel_getUid(selector + "") ? This FIXME is from the old preprocessor compiler
|
||||
buffer.concat(selectorJSPath ? "\")" : "\"", node);
|
||||
|
||||
if (nodeArguments) for (var i = 0; i < nodeArguments.length; i++)
|
||||
{
|
||||
var argument = nodeArguments[i];
|
||||
|
||||
+14
-20
@@ -738,13 +738,13 @@
|
||||
if (macroCurrentLine) this.line += macroCurrentLine;
|
||||
var macroCurrentLineStart = locationOffset.column;
|
||||
// Only add column offset if we are on the first line
|
||||
if (macroCurrentLineStart) this.column += tokPosMacroOffset - (tokCurLine === 0 ? macroCurrentLineStart : 0);
|
||||
if (macroCurrentLineStart) this.column += tokPosMacroOffset - (tokCurLine === 1 ? macroCurrentLineStart : 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function PositionOffset(line, column) {
|
||||
this.line = line;
|
||||
this.line = line - 1; // Line start on one so we have to convert it to an offset
|
||||
this.column = column;
|
||||
if (preprocessStackLastItem) {
|
||||
var macro = preprocessStackLastItem.macro;
|
||||
@@ -893,10 +893,6 @@
|
||||
last = ch;
|
||||
ch = input.charCodeAt(++tokPos);
|
||||
}
|
||||
if (options.locations) {
|
||||
++tokCurLine;
|
||||
tokLineStart = tokPos;
|
||||
}
|
||||
}
|
||||
|
||||
// Called at the start of the parse and after every token. Skips
|
||||
@@ -1320,6 +1316,8 @@
|
||||
// We don't want to concatenate tokens when creating macros
|
||||
preprocessDontConcatenate = true;
|
||||
|
||||
// Get position offset now as ´tokCurLine´ and ´tokLineStart´ points to next token.
|
||||
var positionOffset = options.locations && new PositionOffset(tokCurLine, tokLineStart);
|
||||
var macroIdentifier = preprocessGetIdent();
|
||||
// '(' Must follow directly after identifier to be a valid macro with parameters
|
||||
if (input.charCodeAt(macroIdentifierEnd) === 40) { // '('
|
||||
@@ -1332,10 +1330,12 @@
|
||||
if (!first) preprocessExpect(_comma, "Expected ',' between macro parameters"); else first = false;
|
||||
parameters.push(preprocessEat(_dotdotdot) ? variadic = true && "__VA_ARGS__" : preprocessGetIdent());
|
||||
if (preprocessEat(_dotdotdot)) variadic = true;
|
||||
// Get a new position offset as macro has parameters. This is needed if line has escaped (backslash) newline
|
||||
positionOffset = options.locations && new PositionOffset(tokCurLine, tokLineStart);
|
||||
}
|
||||
}
|
||||
var start = preTokStart;
|
||||
var positionOffset = options.locations && new PositionOffset(tokCurLine, tokLineStart);
|
||||
|
||||
while(preTokType !== _eol && preTokType !== _eof)
|
||||
preprocessReadToken();
|
||||
|
||||
@@ -1532,18 +1532,13 @@
|
||||
|
||||
if (allowEndOfLineToken) {
|
||||
var r;
|
||||
if (code === 13) {
|
||||
r = finishOp(_eol, input.charCodeAt(tokPos+1) === 10 ? 2 : 1, finisher);
|
||||
} else if (code === 10 || code === 8232 || code === 8233) {
|
||||
r = finishOp(_eol, 1, finisher);
|
||||
} else {
|
||||
return false;
|
||||
if (code === 13 || code === 10 || code === 8232 || code === 8233) {
|
||||
if (options.locations) {
|
||||
++tokCurLine;
|
||||
tokLineStart = tokPos;
|
||||
}
|
||||
return finishOp(_eol, (code === 13 && input.charCodeAt(tokPos+1) === 10) ? 2 : 1, finisher);
|
||||
}
|
||||
if (options.locations) {
|
||||
++tokCurLine;
|
||||
tokLineStart = tokPos;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
return false;
|
||||
@@ -2426,7 +2421,7 @@
|
||||
inputLen = macroString.length;
|
||||
tokPosMacroOffset = macro.start;
|
||||
tokPos = 0;
|
||||
tokCurLine = 0;
|
||||
tokCurLine = 1;
|
||||
tokLineStart = 0;
|
||||
firstTokEnd = 0;
|
||||
localLastEnd = 0;
|
||||
@@ -2634,7 +2629,6 @@
|
||||
// Test whether a semicolon can be inserted at the current position.
|
||||
|
||||
function canInsertSemicolon() {
|
||||
//if (lastEnd !== localLastEnd) print("lastEnd: " + lastEnd + ", localLastEnd: " + localLastEnd);
|
||||
return !options.strictSemicolons &&
|
||||
(tokType === _eof || tokType === _braceR || newline.test(lastEndInput.slice(lastEnd, lastEndOfFile || tokFirstStart)) ||
|
||||
(nodeMessageSendObjectExpression && options.objj) || lastEndOfFile != null);
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user