diff --git a/AppKit/Rakefile b/AppKit/Rakefile
index f4f3d30cc..a93beb55c 100644
--- a/AppKit/Rakefile
+++ b/AppKit/Rakefile
@@ -53,6 +53,7 @@ file_d $THEME_PRODUCT => ThemeFiles << $ENVIRONMENT_PRODUCT do
puts str
end
end
+ rake abort if ($? != 0)
end
task :build => [:build_subprojects, :AppKit, $ENVIRONMENT_PRODUCT, $THEME_PRODUCT, $ENVIRONMENT_THEME_PRODUCT]
diff --git a/Objective-J/Rakefile b/Objective-J/Rakefile
index c57bb8edc..7debf3b85 100644
--- a/Objective-J/Rakefile
+++ b/Objective-J/Rakefile
@@ -48,9 +48,7 @@ def platform_flags(*platforms)
end
def build_product(path, flags)
-
IO.popen("gcc #{flags} -E -x c -P -", "w+") do |preprocessor|
-
Files.select { |name| name.match(/\.js$/) }.each do |fileName|
preprocessor.puts IO.read(fileName)
end
@@ -60,8 +58,8 @@ def build_product(path, flags)
File.open(path, "w") do |file|
file.write(IO.read("header.txt") + preprocessor.read)
end
-
end
+ rake abort if ($? != 0)
end
task :build => [:Products, $ENVIRONMENT_PRODUCT, :build_subprojects]
diff --git a/Objective-J/debug.js b/Objective-J/debug.js
index cbc5fd447..2c7624464 100644
--- a/Objective-J/debug.js
+++ b/Objective-J/debug.js
@@ -1,173 +1,184 @@
-function objj_backtrace_format(aReceiver, aSelector)
+// formatting helpers
+
+function objj_debug_object_format(aReceiver)
{
- return "[<" + GETMETA(aReceiver).name + " " + (typeof sprintf == "function" ? sprintf("%#08x", aReceiver.__address) : aReceiver.__address.toString(16)) + "> " + aSelector + "]";
+ return (aReceiver && aReceiver.isa) ? sprintf("<%s %#08x>", GETMETA(aReceiver).name, aReceiver.__address) : String(aReceiver);
}
-function objj_msgSend_Backtrace(/*id*/ aReceiver, /*SEL*/ aSelector)
+function objj_debug_message_format(aReceiver, aSelector)
{
- if (aReceiver == nil)
- return nil;
-
- objj_debug_backtrace.push(objj_backtrace_format(aReceiver, aSelector));
-
- try
- {
- var result = class_getMethodImplementation(aReceiver.isa, aSelector).apply(aReceiver, arguments);
- }
- catch (anException)
- {
- CPLog.error("Exception " + anException + " in " + objj_backtrace_format(aReceiver, aSelector));
- objj_debug_print_backtrace();
- }
-
- objj_debug_backtrace.pop();
-
- return result;
+ return sprintf("[%s %s]", objj_debug_object_format(aReceiver), aSelector);
}
-function objj_msgSendSuper_Backtrace(/*id*/ aSuper, /*SEL*/ aSelector)
+
+// save the original msgSend implementations so we can restore them later
+var objj_msgSend_original = objj_msgSend,
+ objj_msgSendSuper_original = objj_msgSendSuper;
+
+
+// decorator management functions
+
+// reset to default objj_msgSend* implementations
+function objj_msgSend_reset()
{
- objj_debug_backtrace.push(objj_backtrace_format(aSuper.receiver, aSelector));
- var super_class = aSuper.super_class;
-
- arguments[0] = aSuper.receiver;
-
- try
- {
- var result = class_getMethodImplementation(super_class, aSelector).apply(aSuper.receiver, arguments);
- }
- catch (anException)
- {
- CPLog.error("Exception " + anException + " in " + objj_backtrace_format(aSuper.receiver, aSelector));
- objj_debug_print_backtrace();
- }
-
- objj_debug_backtrace.pop();
-
- return result;
+ objj_msgSend = objj_msgSend_original;
+ objj_msgSendSuper = objj_msgSendSuper_original;
}
-function objj_msgSend_Profile(/*id*/ aReceiver, /*SEL*/ aSelector)
+// decorate both objj_msgSend and objj_msgSendSuper
+function objj_msgSend_decorate()
{
- if (aReceiver == nil)
- return nil;
-
- // profiling book keeping
- var profileRecord = {
- parent : objj_debug_profile,
- receiver : GETMETA(aReceiver).name,
- selector : aSelector,
- calls : []
- }
- objj_debug_profile.calls.push(profileRecord);
- objj_debug_profile = profileRecord;
- profileRecord.start = new Date();
-
- var result = class_getMethodImplementation(aReceiver.isa, aSelector).apply(aReceiver, arguments);
-
- profileRecord.end = new Date();
- objj_debug_profile = profileRecord.parent;
-
- return result;
-}
-
-function objj_msgSendSuper_Profile(/*id*/ aSuper, /*SEL*/ aSelector)
-{
- // profiling book keeping
- var profileRecord = {
- parent : objj_debug_profile,
- receiver : GETMETA(aReceiver).name,
- selector : aSelector,
- calls : []
- }
- objj_debug_profile.calls.push(profileRecord);
- objj_debug_profile = profileRecord;
- profileRecord.start = new Date();
-
- var super_class = aSuper.super_class;
-
- arguments[0] = aSuper.receiver;
-
- var result = class_getMethodImplementation(super_class, aSelector).apply(aSuper.receiver, arguments);
-
- profileRecord.end = new Date();
- objj_debug_profile = profileRecord.parent;
-
- return result;
-}
-
-var objj_msgSend_Standard = objj_msgSend,
- objj_msgSendSuper_Standard = objj_msgSendSuper;
-
-// FIXME: This could be much better.
-var objj_debug_backtrace;
-
-function objj_backtrace_set_enabled(enabled)
-{
- if (enabled)
+ for (var i = 0; i < arguments.length; i++)
{
- objj_debug_backtrace = [];
- objj_msgSend = objj_msgSend_Backtrace;
- objj_msgSendSuper = objj_msgSendSuper_Backtrace;
+ objj_msgSend = arguments[i](objj_msgSend);
+ objj_msgSendSuper = arguments[i](objj_msgSendSuper);
+ }
+}
+
+// reset then decorate both objj_msgSend and objj_msgSendSuper
+function objj_msgSend_set_decorators()
+{
+ objj_msgSend_reset();
+ objj_msgSend_decorate.apply(null, arguments);
+}
+
+
+// backtrace decorator
+
+var objj_backtrace = [];
+
+function objj_backtrace_print(stream) {
+ for (var i = 0; i < objj_backtrace.length; i++)
+ objj_fprintf(stream, objj_debug_message_format(objj_backtrace[i].receiver, objj_backtrace[i].selector));
+}
+
+function objj_backtrace_decorator(msgSend)
+{
+ return function(aReceiverOrSuper, aSelector)
+ {
+ var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
+
+ // push the receiver and selector onto the backtrace stack
+ objj_backtrace.push({ receiver: aReceiver, selector : aSelector });
+ try
+ {
+ return msgSend.apply(null, arguments);
+ }
+ catch (anException)
+ {
+ // print the exception and backtrace
+ objj_fprintf(warning_stream, "Exception " + anException + " in " + objj_debug_message_format(aReceiver, aSelector));
+ objj_backtrace_print(warning_stream);
+ }
+ finally
+ {
+ // make sure to always pop
+ objj_backtrace.pop();
+ }
+ }
+}
+
+// type checking decorator
+
+var objj_typechecks_reported = {},
+ objj_typecheck_prints_backtrace = false;
+
+function objj_typecheck_decorator(msgSend)
+{
+ return function(aReceiverOrSuper, aSelector)
+ {
+ var aReceiver = aReceiverOrSuper && (aReceiverOrSuper.receiver || aReceiverOrSuper);
+
+ if (!aReceiver)
+ return msgSend.apply(null, arguments);
+
+ var types = aReceiver.isa.method_dtable[aSelector].types;
+ for (var i = 2; i < arguments.length; i++)
+ {
+ try
+ {
+ objj_debug_typecheck(types[i-1], arguments[i]);
+ }
+ catch (e)
+ {
+ var key = [GETMETA(aReceiver).name, aSelector, i, e].join(";");
+ if (!objj_typechecks_reported[key]) {
+ objj_typechecks_reported[key] = true;
+ objj_fprintf(warning_stream, "Type check failed on argument " + (i-2) + " of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
+ if (objj_typecheck_prints_backtrace)
+ objj_backtrace_print(warning_stream);
+ }
+ }
+ }
+
+ var result = msgSend.apply(null, arguments);
+
+ try
+ {
+ objj_debug_typecheck(types[0], result);
+ }
+ catch (e)
+ {
+ var key = [GETMETA(aReceiver).name, aSelector, "ret", e].join(";");
+ if (!objj_typechecks_reported[key]) {
+ objj_typechecks_reported[key] = true;
+ objj_fprintf(warning_stream, "Type check failed on return val of " + objj_debug_message_format(aReceiver, aSelector) + ": " + e);
+ if (objj_typecheck_prints_backtrace)
+ objj_backtrace_print(warning_stream);
+ }
+ }
+
+ return result;
+ }
+}
+
+// type checking logic:
+function objj_debug_typecheck(expectedType, object)
+{
+ var objjClass;
+
+ if (!expectedType)
+ {
+ return;
+ }
+ else if (expectedType === "id")
+ {
+ if (object !== undefined)
+ return;
+ }
+ else if (expectedType === "void")
+ {
+ if (object === undefined)
+ return;
+ }
+ else if (objjClass = objj_getClass(expectedType))
+ {
+ if (object === nil)
+ {
+ return;
+ }
+ else if (object && object.isa)
+ {
+ var theClass = object.isa;
+ for (; theClass; theClass = theClass.super_class)
+ if (theClass === objjClass)
+ return;
+ }
}
else
{
- objj_msgSend = objj_msgSend_Standard;
- objj_msgSendSuper = objj_msgSendSuper_Standard;
- }
-}
-
-function objj_debug_print_backtrace()
-{
- alert(objj_debug_backtrace_string());
-}
-
-function objj_debug_backtrace_string()
-{
- return objj_debug_backtrace ? objj_debug_backtrace.join("\n") : "";
-}
-
-var objj_debug_profile = null,
- objj_currently_profiling = false,
- objj_profile_cleanup;
-
-function objj_profile(title)
-{
- if (objj_currently_profiling)
return;
-
- var objj_msgSend_profile_saved = objj_msgSend,
- objj_msgSendSuper_profile_saved = objj_msgSendSuper;
-
- objj_msgSend = objj_msgSend_Profile;
- objj_msgSendSuper = objj_msgSendSuper_Profile;
-
- var root = { calls: [] };
- objj_debug_profile = root;
-
- var context = {
- start : new Date(),
- title : title,
- profile : root
- };
-
- objj_profile_cleanup = function() {
- objj_msgSend = objj_msgSend_profile_saved;
- objj_msgSendSuper = objj_msgSendSuper_profile_saved;
- context.end = new Date();
- return context;
}
- objj_currently_profiling = true;
-}
-
-function objj_profileEnd()
-{
- if (!objj_currently_profiling)
- return;
-
- objj_debug_profile = null;
- objj_currently_profiling = false;
-
- return objj_profile_cleanup();
+ var actualType;
+ if (object === null)
+ actualType = "null";
+ else if (object === undefined)
+ actualType = "void";
+ else if (object.isa)
+ actualType = GETMETA(object).name;
+ else
+ actualType = typeof object;
+
+ throw ("expected=" + expectedType + ", actual=" + actualType);
}
diff --git a/Objective-J/preprocess.js b/Objective-J/preprocess.js
index 47218a9ca..ad96215f9 100644
--- a/Objective-J/preprocess.js
+++ b/Objective-J/preprocess.js
@@ -20,7 +20,8 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0;
+var OBJJ_PREPROCESSOR_DEBUG_SYMBOLS = 1 << 0,
+ OBJJ_PREPROCESSOR_TYPE_SIGNATURES = 1 << 1;
function objj_preprocess(/*String*/ aString, /*objj_bundle*/ aBundle, /*objj_file*/ aSourceFile, /*unsigned*/ flags)
{
@@ -592,12 +593,15 @@ objj_preprocessor.prototype.method = function(tokens)
var buffer = new objj_stringBuffer(),
token,
selector = "",
- parameters = [];
+ parameters = [],
+ types = [null];
while((token = tokens.skip_whitespace()) && token != TOKEN_OPEN_BRACE)
{
if (token == TOKEN_COLON)
{
+ var type = "";
+
// Colons are part of the selector name
selector += token;
@@ -606,18 +610,30 @@ objj_preprocessor.prototype.method = function(tokens)
if (token == TOKEN_OPEN_PARENTHESIS)
{
// Swallow parameter/return type. Perhaps later we can use this for debugging?
- while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) ;
+ while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS)
+ type += token;
token = tokens.skip_whitespace();
}
+ // Add the type. If it's empty, add null instead.
+ types[parameters.length+1] = type || null;
+
// Since this follows a colon, this must be the parameter name.
parameters[parameters.length] = token;
}
else if (token == TOKEN_OPEN_PARENTHESIS)
+ {
+ var type = "";
+
// Since :( is handled above, this must be the return type, just swallow it.
- while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS) ;
+ while((token = tokens.skip_whitespace()) && token != TOKEN_CLOSE_PARENTHESIS)
+ type += token;
+
+ // types[0] is the return argument
+ types[0] = type || null;
+ }
// Argument list ", ..."
else if (token == TOKEN_COMMA)
@@ -654,7 +670,11 @@ objj_preprocessor.prototype.method = function(tokens)
CONCAT(buffer, ")\n{ with(self)\n{");
CONCAT(buffer, this.preprocess(tokens, NULL, TOKEN_CLOSE_BRACE, TOKEN_OPEN_BRACE));
- CONCAT(buffer, "}\n})");
+ CONCAT(buffer, "}\n}");
+ // TODO: actually use OBJJ_PREPROCESSOR_TYPE_SIGNATURES flag instead of tying to OBJJ_PREPROCESSOR_DEBUG_SYMBOLS
+ if (this._flags & OBJJ_PREPROCESSOR_DEBUG_SYMBOLS) //OBJJ_PREPROCESSOR_TYPE_SIGNATURES)
+ CONCAT(buffer, ","+JSON.stringify(types));
+ CONCAT(buffer, ")");
return buffer;
}
diff --git a/Rakefile b/Rakefile
index 4f0a3da62..e06fdf743 100644
--- a/Rakefile
+++ b/Rakefile
@@ -86,7 +86,9 @@ file_d $STARTER_DOWNLOAD_APPLICATION => [$TOOLS_DOWNLOAD_ENV] do
rm_rf($STARTER_DOWNLOAD_APPLICATION)
mkdir_p($STARTER_DOWNLOAD)
+
system %{capp gen #{$STARTER_DOWNLOAD_APPLICATION} -t Application --noconfig }
+ rake abort if ($? != 0)
# No tools means no objective-j gem
rm(File.join($STARTER_DOWNLOAD_APPLICATION, 'Rakefile'))
@@ -103,7 +105,9 @@ task :install => [:tools_download] do
else
prefix = ''
end
+
system %{cd #{$TOOLS_DOWNLOAD} && sudo sh ./install-tools #{prefix} }
+ rake abort if ($? != 0)
end
task :test => [:build] do
@@ -122,6 +126,8 @@ end
task :docs do
if executable_exists? "doxygen"
system %{doxygen #{$DOXYGEN_CONFIG} }
+ rake abort if ($? != 0)
+
rm_rf $DOCUMENTATION_BUILD
mv "debug.txt", "Documentation"
mv "Documentation", $DOCUMENTATION_BUILD
@@ -133,6 +139,7 @@ end
task :submodules do
if executable_exists? "git"
system %{git submodule init && git submodule update}
+ rake abort if ($? != 0)
else
puts "Git not installed"
rake abort
diff --git a/Tools/Rake/lib/objective-j/bundletask.rb b/Tools/Rake/lib/objective-j/bundletask.rb
index eeee33003..95b77e138 100644
--- a/Tools/Rake/lib/objective-j/bundletask.rb
+++ b/Tools/Rake/lib/objective-j/bundletask.rb
@@ -390,6 +390,7 @@ module ObjectiveJ
puts str
end
end
+ #rake abort if ($? != 0)
end
{ 'copy' => include_nibs, 'copied_resources' => [copied_resource] }
@@ -424,6 +425,7 @@ module ObjectiveJ
puts str
end
end
+ rake abort if ($? != 0)
end
enhance([frameworks_path])
@@ -510,6 +512,7 @@ module ObjectiveJ
puts str
end
end
+ rake abort if ($? != 0)
end
BundleTask.compact(build_path) if needs_compact
diff --git a/Tools/capp/Templates/Application/index-debug.html b/Tools/capp/Templates/Application/index-debug.html
index 5ebc00c9a..54b8f7fbe 100644
--- a/Tools/capp/Templates/Application/index-debug.html
+++ b/Tools/capp/Templates/Application/index-debug.html
@@ -21,7 +21,22 @@
-
+
+
+