Skip to content
This repository was archived by the owner on Apr 12, 2024. It is now read-only.

Commit 39b3297

Browse files
committed
fix($parse): get rid of $unboundFn
Closes #731
1 parent 1268fc1 commit 39b3297

File tree

5 files changed

+72
-17
lines changed

5 files changed

+72
-17
lines changed

src/Angular.js

-1
Original file line numberDiff line numberDiff line change
@@ -686,7 +686,6 @@ function equals(o1, o2) {
686686
return true;
687687
}
688688
}
689-
if (t1 == 'function' && o1.$unboundFn) return o1.$unboundFn === o2.$unboundFn;
690689
}
691690
return false;
692691
}

src/service/parse.js

+50-13
Original file line numberDiff line numberDiff line change
@@ -144,18 +144,40 @@ function lex(text){
144144
fn:function() {return number;}});
145145
}
146146
function readIdent() {
147-
var ident = "";
148-
var start = index;
149-
var fn;
147+
var ident = "",
148+
start = index,
149+
fn, lastDot, peekIndex, methodName;
150+
150151
while (index < text.length) {
151152
var ch = text.charAt(index);
152153
if (ch == '.' || isIdent(ch) || isNumber(ch)) {
154+
if (ch == '.') lastDot = index;
153155
ident += ch;
154156
} else {
155157
break;
156158
}
157159
index++;
158160
}
161+
162+
//check if this is not a method invocation and if it is back out to last dot
163+
if (lastDot) {
164+
peekIndex = index
165+
while(peekIndex < text.length) {
166+
var ch = text.charAt(peekIndex);
167+
if (ch == '(') {
168+
methodName = ident.substr(lastDot - start + 1);
169+
ident = ident.substr(0, lastDot - start);
170+
index = peekIndex;
171+
break;
172+
}
173+
if(isWhitespace(ch)) {
174+
peekIndex++;
175+
} else {
176+
break;
177+
}
178+
}
179+
}
180+
159181
fn = OPERATORS[ident];
160182
tokens.push({
161183
index:start,
@@ -167,6 +189,19 @@ function lex(text){
167189
}
168190
})
169191
});
192+
193+
if (methodName) {
194+
tokens.push({
195+
index:lastDot,
196+
text: '.',
197+
json: false
198+
});
199+
tokens.push({
200+
index: lastDot + 1,
201+
text: methodName,
202+
json: false
203+
});
204+
}
170205
}
171206

172207
function readString(quote) {
@@ -490,13 +525,17 @@ function parser(text, json, $filter){
490525
throwError("not a primary expression", token);
491526
}
492527
}
493-
var next;
528+
529+
var next, context;
494530
while ((next = expect('(', '[', '.'))) {
495531
if (next.text === '(') {
496-
primary = functionCall(primary);
532+
primary = functionCall(primary, context);
533+
context = null;
497534
} else if (next.text === '[') {
535+
context = primary;
498536
primary = objectIndex(primary);
499537
} else if (next.text === '.') {
538+
context = primary;
500539
primary = fieldAccess(primary);
501540
} else {
502541
throwError("IMPOSSIBLE");
@@ -544,7 +583,7 @@ function parser(text, json, $filter){
544583
});
545584
}
546585

547-
function _functionCall(fn) {
586+
function _functionCall(fn, contextGetter) {
548587
var argsFn = [];
549588
if (peekToken().text != ')') {
550589
do {
@@ -553,14 +592,16 @@ function parser(text, json, $filter){
553592
}
554593
consume(')');
555594
return function(self){
556-
var args = [];
595+
var args = [],
596+
context = contextGetter ? contextGetter(self) : self;
597+
557598
for ( var i = 0; i < argsFn.length; i++) {
558599
args.push(argsFn[i](self));
559600
}
560601
var fnPtr = fn(self) || noop;
561602
// IE stupidity!
562603
return fnPtr.apply
563-
? fnPtr.apply(self, args)
604+
? fnPtr.apply(context, args)
564605
: fnPtr(args[0], args[1], args[2], args[3], args[4]);
565606
};
566607
}
@@ -691,11 +732,7 @@ function getterFn(path) {
691732
code += 'if(!s) return s;\n' +
692733
'l=s;\n' +
693734
's=s' + key + ';\n' +
694-
'if(typeof s=="function" && !(s instanceof RegExp)) {\n' +
695-
' fn=function(){ return l' + key + '.apply(l, arguments); };\n' +
696-
' fn.$unboundFn=s;\n' +
697-
' s=fn;\n' +
698-
'} else if (s && s.then) {\n' +
735+
'if (s && s.then) {\n' +
699736
' if (!("$$v" in s)) {\n' +
700737
' p=s;\n' +
701738
' p.$$v = undefined;\n' +

src/widget/input.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -741,7 +741,7 @@ var inputDirective = ['$defer', '$formFactory', function($defer, $formFactory) {
741741

742742
type = lowercase(type);
743743
TypeController = (loadFromScope
744-
? (assertArgFn(modelScope.$eval(loadFromScope[1]), loadFromScope[1])).$unboundFn
744+
? assertArgFn(modelScope.$eval(loadFromScope[1]), loadFromScope[1])
745745
: angularInputType(type)) || noop;
746746

747747
if (!HTML5_INPUTS_TYPES[type]) {

test/service/parseSpec.js

+20-1
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,17 @@ describe('parser', function() {
110110
expect(tokens[3].text).toEqual(';');
111111
});
112112

113+
it('should tokenize function invocation', function() {
114+
var tokens = lex("a()")
115+
expect(map(tokens, function(t) { return t.text;})).toEqual(['a', '(', ')']);
116+
});
117+
118+
it('should tokenize method invocation', function() {
119+
var tokens = lex("a.b.c (d) - e.f()");
120+
expect(map(tokens, function(t) { return t.text;})).
121+
toEqual(['a.b', '.', 'c', '(', 'd', ')', '-', 'e', '.', 'f', '(', ')']);
122+
});
123+
113124
it('should tokenize number', function() {
114125
var tokens = lex("0.5");
115126
expect(tokens[0].text).toEqual(0.5);
@@ -244,6 +255,12 @@ describe('parser', function() {
244255
expect(scope.$eval("add(1,2)")).toEqual(3);
245256
});
246257

258+
it('should evaluate function call from a return value', function() {
259+
scope.val = 33;
260+
scope.getter = function() { return function() { return this.val; }};
261+
expect(scope.$eval("getter()()")).toBe(33);
262+
});
263+
247264
it('should evaluate multiplication and division', function() {
248265
scope.taxRate = 8;
249266
scope.subTotal = 100;
@@ -281,7 +298,7 @@ describe('parser', function() {
281298
expect(toJson(scope.$eval("[{a:[]}, {b:1}]"))).toEqual('[{"a":[]},{"b":1}]');
282299
});
283300

284-
it('should evaluate multipple statements', function() {
301+
it('should evaluate multiple statements', function() {
285302
expect(scope.$eval("a=1;b=3;a+b")).toEqual(4);
286303
expect(scope.$eval(";;1;;")).toEqual(1);
287304
});
@@ -296,6 +313,7 @@ describe('parser', function() {
296313

297314
scope.obj = new C();
298315
expect(scope.$eval("obj.getA()")).toEqual(123);
316+
expect(scope.$eval("obj['getA']()")).toEqual(123);
299317
});
300318

301319
it('should evaluate methods in correct context (this) in argument', function() {
@@ -311,6 +329,7 @@ describe('parser', function() {
311329

312330
scope.obj = new C();
313331
expect(scope.$eval("obj.sum(obj.getA())")).toEqual(246);
332+
expect(scope.$eval("obj['sum'](obj.getA())")).toEqual(246);
314333
});
315334

316335
it('should evaluate objects on scope context', function() {

test/service/scopeSpec.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ describe('Scope', function() {
252252
module(provideLog);
253253
inject(function($rootScope, log) {
254254
$rootScope.fn = function() {return 'a'};
255-
$rootScope.$watch('fn', function(scope, fn) {
255+
$rootScope.$watch('fn', function(fn) {
256256
log(fn());
257257
});
258258
$rootScope.$digest();

0 commit comments

Comments
 (0)