diff --git a/AppKit/Cib/CPCibControlConnector.j b/AppKit/Cib/CPCibControlConnector.j index ddb64d8c3..70b36e273 100644 --- a/AppKit/Cib/CPCibControlConnector.j +++ b/AppKit/Cib/CPCibControlConnector.j @@ -51,7 +51,7 @@ // Not being able to set the action is a fatal error. if ([_source respondsToSelector:@selector(setAction:)]) - objj_msgSend(_source, @selector(setAction:), selector); + [_source setAction:selector]; else [CPException @@ -60,7 +60,7 @@ // Not being able to set the target is a fatal error. if ([_source respondsToSelector:@selector(setTarget:)]) - objj_msgSend(_source, @selector(setTarget:), _destination); + [_source setTarget:_destination]; else [CPException diff --git a/Objective-J/ObjJAcornCompiler.js b/Objective-J/ObjJAcornCompiler.js index ed9cd62c7..83f61621b 100644 --- a/Objective-J/ObjJAcornCompiler.js +++ b/Objective-J/ObjJAcornCompiler.js @@ -1400,9 +1400,18 @@ AssignmentExpression: function(node, st, c) { return; } - var saveAssignment = st.assignment; + var saveAssignment = st.assignment, + nodeLeft = node.left; st.assignment = true; - (generate && nodePrecedence(node, node.left) ? surroundExpression(c) : c)(node.left, st, "Expression"); + if (nodeLeft.type === "Identifier" && nodeLeft.name === "self") { + var lVar = st.getLvar("self", true); + if (lVar) { + var lVarScope = lVar.scope; + if (lVarScope) + lVarScope.assignmentToSelf = true; + } + } + (generate && nodePrecedence(node, nodeLeft) ? surroundExpression(c) : c)(nodeLeft, st, "Expression"); if (generate) { buffer.concat(" "); buffer.concat(node.operator); @@ -1410,8 +1419,8 @@ AssignmentExpression: function(node, st, c) { } st.assignment = saveAssignment; (generate && nodePrecedence(node, node.right, true) ? surroundExpression(c) : c)(node.right, st, "Expression"); - if (st.isRootScope() && node.left.type === "Identifier" && !st.getLvar(node.left.name)) - st.vars[node.left.name] = {type: "global", node: node.left}; + if (st.isRootScope() && nodeLeft.type === "Identifier" && !st.getLvar(nodeLeft.name)) + st.vars[nodeLeft.name] = {type: "global", node: nodeLeft}; }, ConditionalExpression: function(node, st, c) { var compiler = st.compiler, @@ -1440,8 +1449,22 @@ NewExpression: function(node, st, c) { }, CallExpression: function(node, st, c) { var compiler = st.compiler, - generate = compiler.generate; - (generate && nodePrecedence(node, node.callee) ? surroundExpression(c) : c)(node.callee, st, "Expression"); + generate = compiler.generate, + callee = node.callee; + + // If call to function 'eval' we assume that 'self' can be altered and from this point + // we check if 'self' is null before 'objj_msgSend' is called with 'self' as receiver. + if (callee.type === "Identifier" && callee.name === "eval") { + var selfLvar = st.getLvar("self", true); + if (selfLvar) { + var selfScope = selfLvar.scope; + if (selfScope) { + selfScope.assignmentToSelf = true; + } + } + } + + (generate && nodePrecedence(node, callee) ? surroundExpression(c) : c)(callee, st, "Expression"); if (generate) compiler.jsBuffer.concat("("); if (node.arguments) { for (var i = 0; i < node.arguments.length; ++i) { @@ -2026,6 +2049,9 @@ MethodDeclarationStatement: function(node, st, c) { compiler.jsBuffer.concat("(self, _cmd"); methodScope.methodType = node.methodtype; + methodScope.vars["self"] = {type: "method base", scope: methodScope}; + methodScope.vars["_cmd"] = {type: "method base", scope: methodScope}; + if (nodeArguments) for (var i = 0; i < nodeArguments.length; i++) { var argument = nodeArguments[i], @@ -2125,10 +2151,11 @@ MethodDeclarationStatement: function(node, st, c) { MessageSendExpression: function(node, st, c) { var compiler = st.compiler, generate = compiler.generate, - buffer = compiler.jsBuffer; + buffer = compiler.jsBuffer, + nodeObject = node.object; if (!generate) { buffer.concat(compiler.source.substring(compiler.lastPos, node.start)); - compiler.lastPos = node.object ? node.object.start : node.arguments.length ? node.arguments[0].start : node.end; + compiler.lastPos = nodeObject ? nodeObject.start : node.arguments.length ? node.arguments[0].start : node.end; } if (node.superObject) { @@ -2138,20 +2165,49 @@ MessageSendExpression: function(node, st, c) { } else { - if (!st.receiverLevel) st.receiverLevel = 0; - if (!generate) buffer.concat(" "); // Add an extra space if it looks something like this: "return()". No space between return and expression. - buffer.concat("((___r"); - buffer.concat(++st.receiverLevel + ""); - buffer.concat(" = "); - c(node.object, st, "Expression"); - buffer.concat("), ___r"); - buffer.concat(st.receiverLevel + ""); - buffer.concat(" == null ? null : ___r"); - buffer.concat(st.receiverLevel + ""); - buffer.concat(".isa.objj_msgSend"); - if (!generate) buffer.concat(compiler.source.substring(compiler.lastPos, node.object.end)); - if (!(st.maxReceiverLevel >= st.receiverLevel)) - st.maxReceiverLevel = st.receiverLevel; + if (generate) { + // If the recevier is not an identifier or an ivar that should have 'self.' infront we need to assign it to a temporary variable + // If it is 'self' we assume it will never be nil and remove that test + var receiverIsIdentifier = nodeObject.type === "Identifier" && !(st.currentMethodType() === "-" && compiler.getIvarForClass(nodeObject.name, st) && !st.getLvar(nodeObject.name, true)), + selfLvar, + receiverIsNotSelf; + + if (receiverIsIdentifier) { + var name = nodeObject.name, + selfLvar = st.getLvar(name); + + if (name === "self") { + receiverIsNotSelf = !selfLvar || !selfLvar.scope || selfLvar.scope.assignmentToSelf; + } else { + receiverIsNotSelf = !!selfLvar || !compiler.getClassDef(name); + } + + if (receiverIsNotSelf) { + buffer.concat("("); + c(nodeObject, st, "Expression"); + buffer.concat(" == null ? null : "); + } + c(nodeObject, st, "Expression"); + } else { + receiverIsNotSelf = true; + if (!st.receiverLevel) st.receiverLevel = 0; + buffer.concat("((___r"); + buffer.concat(++st.receiverLevel + ""); + buffer.concat(" = "); + c(nodeObject, st, "Expression"); + buffer.concat("), ___r"); + buffer.concat(st.receiverLevel + ""); + buffer.concat(" == null ? null : ___r"); + buffer.concat(st.receiverLevel + ""); + if (!(st.maxReceiverLevel >= st.receiverLevel)) + st.maxReceiverLevel = st.receiverLevel; + } + buffer.concat(".isa.objj_msgSend"); + } else { + buffer.concat(" "); // Add an extra space if it looks something like this: "return()". No space between return and expression. + buffer.concat("objj_msgSend("); + buffer.concat(compiler.source.substring(compiler.lastPos, nodeObject.end)); + } } var selectors = node.selectors, @@ -2160,7 +2216,7 @@ MessageSendExpression: function(node, st, c) { firstSelector = selectors[0], selector = firstSelector ? firstSelector.name : ""; // There is always at least one selector - if (!node.superObject) { + if (generate && !node.superObject) { var totalNoOfParameters = argumentsLength; if (node.parameters) @@ -2169,8 +2225,13 @@ MessageSendExpression: function(node, st, c) { buffer.concat("" + totalNoOfParameters); } - buffer.concat("(___r"); - buffer.concat(st.receiverLevel + ""); + if (receiverIsIdentifier) { + buffer.concat("("); + c(nodeObject, st, "Expression"); + } else { + buffer.concat("(___r"); + buffer.concat(st.receiverLevel + ""); + } } // Put together the selector. Maybe this should be done in the parser... @@ -2213,9 +2274,11 @@ MessageSendExpression: function(node, st, c) { } } - if (!node.superObject) { - buffer.concat(")"); - st.receiverLevel--; + if (generate && !node.superObject) { + if (receiverIsNotSelf) + buffer.concat(")"); + if (!receiverIsIdentifier) + st.receiverLevel--; } buffer.concat(")"); diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/colon-selector.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/colon-selector.js index 07ce0e2ee..1104fd603 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/colon-selector.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/colon-selector.js @@ -1,2 +1,2 @@ -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend1(___r1,":",argument)); +(object==null?null:object.isa.objj_msgSend1(object,":",argument)); \ No newline at end of file diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/keyword-in-selector.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/keyword-in-selector.js index 35a123ac4..8e4bc3bda 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/keyword-in-selector.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/keyword-in-selector.js @@ -1 +1 @@ -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend3(___r1,"for:in:nil:",a,b,nil)); \ No newline at end of file +(object==null?null:object.isa.objj_msgSend3(object,"for:in:nil:",a,b,nil)); \ No newline at end of file diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/multiple-parameters.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/multiple-parameters.js index bd35709fe..4c55b7aef 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/multiple-parameters.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/multiple-parameters.js @@ -1,2 +1,2 @@ -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend(___r1,"label:label2:label3:label4:",argument,argument2,argument3,argument4)); +(object==null?null:object.isa.objj_msgSend(object,"label:label2:label3:label4:",argument,argument2,argument3,argument4)); diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.j b/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.j index 3292fea80..dc4f82b03 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.j +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.j @@ -1,2 +1,2 @@ - +[CPArray new]; [object message]; diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.js index b96b0c15d..023c09bdf 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/no-parameters.js @@ -1,2 +1,2 @@ - -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend0(___r1,"message")); +CPArray.isa.objj_msgSend0(CPArray,"new"); +(object==null?null:object.isa.objj_msgSend0(object,"message")); \ No newline at end of file diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.j b/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.j index dee678fde..8e01d2bab 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.j +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.j @@ -1,2 +1,2 @@ - +[CPArray arrayWithArray:[]]; [object label:argument]; diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.js index a69f22f5e..b8795333c 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/one-parameter.js @@ -1,2 +1,2 @@ - -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend1(___r1,"label:",argument)); +CPArray.isa.objj_msgSend1(CPArray,"arrayWithArray:",[]); +(object==null?null:object.isa.objj_msgSend1(object,"label:",argument)); \ No newline at end of file diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/self-as-receiver.j b/Tests/Objective-J/Preprocessor/OutputTests/Messages/self-as-receiver.j new file mode 100644 index 000000000..1d339fcc3 --- /dev/null +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/self-as-receiver.j @@ -0,0 +1,15 @@ +@implementation MyClass + +- (id)mySelector { + [self init]; + self = nil; + [self init]; +} + +- (id)mySelector2 { + [self init]; + eval("self = null;"); + [self init]; +} + +@end diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/self-as-receiver.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/self-as-receiver.js new file mode 100644 index 000000000..561ad60cb --- /dev/null +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/self-as-receiver.js @@ -0,0 +1,11 @@ +var the_class=objj_allocateClassPair(Nil,"MyClass"),meta_class=the_class.isa; +objj_registerClassPair(the_class); +class_addMethods(the_class,[new objj_method(sel_getUid("mySelector"),function $MyClass__mySelector(_1,_2){ +_1.isa.objj_msgSend0(_1,"init"); +_1=nil; +(_1==null?null:_1.isa.objj_msgSend0(_1,"init")); +},["id"]),new objj_method(sel_getUid("mySelector2"),function $MyClass__mySelector2(_3,_4){ +_3.isa.objj_msgSend0(_3,"init"); +eval("self = null;"); +(_3==null?null:_3.isa.objj_msgSend0(_3,"init")); +},["id"])]); \ No newline at end of file diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Messages/ternary-operator-argument.js b/Tests/Objective-J/Preprocessor/OutputTests/Messages/ternary-operator-argument.js index f5d8ca3e7..f879e332c 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Messages/ternary-operator-argument.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Messages/ternary-operator-argument.js @@ -1,4 +1,4 @@ -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend1(___r1,"label:",condition?true:false)); -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend1(___r1,"label:",condition?true:false)); -((___r1=object),___r1==null?null:___r1.isa.objj_msgSend1(___r1,"label:",condition?true:false)); +(object==null?null:object.isa.objj_msgSend1(object,"label:",condition?true:false)); +(object==null?null:object.isa.objj_msgSend1(object,"label:",condition?true:false)); +(object==null?null:object.isa.objj_msgSend1(object,"label:",condition?true:false)); diff --git a/Tests/Objective-J/Preprocessor/OutputTests/Misc/parenthesis-return.js b/Tests/Objective-J/Preprocessor/OutputTests/Misc/parenthesis-return.js index d09cbb0de..4b3da9ec7 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/Misc/parenthesis-return.js +++ b/Tests/Objective-J/Preprocessor/OutputTests/Misc/parenthesis-return.js @@ -1,4 +1,3 @@ x=function(){ -return ((_1=someIval),_1==null?null:_1.isa.objj_msgSend0(_1,"someMethod")); -var _1; -}; \ No newline at end of file +return (someIval==null?null:someIval.isa.objj_msgSend0(someIval,"someMethod")); +}; diff --git a/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j b/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j index 302ce7823..776b75d09 100644 --- a/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j +++ b/Tests/Objective-J/Preprocessor/OutputTests/OutputTest.j @@ -13,6 +13,7 @@ var FILENAMES = [ "Messages/ternary-operator-argument", "Messages/keyword-in-selector", "Messages/colon-selector", + "Messages/self-as-receiver", "Misc/parenthesis-return", "Misc/preprocess-if-directives",