mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-05-03 03:00:14 -04:00
adding bound functions, with test
This commit is contained in:
@@ -14,63 +14,39 @@
|
|||||||
var arr = [];
|
var arr = [];
|
||||||
while (num--) arr.push(num);
|
while (num--) arr.push(num);
|
||||||
|
|
||||||
JSLitmus.test('current comprehensions', function() {
|
var f1 = function f1() {
|
||||||
__a = arr;
|
return arr;
|
||||||
__c = [];
|
};
|
||||||
for (__b in __a) {
|
|
||||||
if (__a.hasOwnProperty(__b)) {
|
JSLitmus.test('regular function', function() {
|
||||||
num = __a[__b];
|
f1();
|
||||||
__d = num;
|
|
||||||
__c.push(num);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
JSLitmus.test('raw for loop (best we can do)', function() {
|
var __this = this;
|
||||||
__a = arr;
|
|
||||||
__c = new Array(__a.length);
|
var f2 = function f2() {
|
||||||
for (__b=0; __b < __a.length; __b++) {
|
return (function() {
|
||||||
__c[__b] = __a[__b];
|
return arr;
|
||||||
}
|
}).apply(__this, arguments);
|
||||||
|
};
|
||||||
|
|
||||||
|
JSLitmus.test('bound function', function() {
|
||||||
|
f2();
|
||||||
});
|
});
|
||||||
|
|
||||||
JSLitmus.test('current without hasOwnProperty check', function() {
|
var f3 = (function() {
|
||||||
__a = arr;
|
__b = function() {
|
||||||
__c = [];
|
return arr;
|
||||||
for (__b in __a) {
|
|
||||||
num = __a[__b];
|
|
||||||
__d = num;
|
|
||||||
__c.push(num);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JSLitmus.test('raw for..in loop', function() {
|
|
||||||
__a = arr;
|
|
||||||
__c = new Array(__a.length);
|
|
||||||
for (__b in __a) {
|
|
||||||
__c[__b] = __a[__b];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
JSLitmus.test('weepy\'s comprehensions', function() {
|
|
||||||
__c = []; __a = arr;
|
|
||||||
__d = function(num, __b) {
|
|
||||||
__c.push(num);
|
|
||||||
};
|
};
|
||||||
if (__a instanceof Array) {
|
return (function f2() {
|
||||||
for (__b=0; __b<__a.length; __b++) __d(__a[__b], __b);
|
return __b.apply(__this, arguments);
|
||||||
} else {
|
});
|
||||||
for (__b in __a) { if (__a.hasOwnProperty(__b)) __d(__a[__b], __b); }
|
})();
|
||||||
}
|
|
||||||
|
JSLitmus.test('prebound function', function() {
|
||||||
|
f3();
|
||||||
});
|
});
|
||||||
|
|
||||||
JSLitmus.test('CoffeeScript 0.2.2 comprehensions', function() {
|
|
||||||
__c = []; __a = arr;
|
|
||||||
for (__b=0; __b<__a.length; __b++) {
|
|
||||||
num = __a[__b];
|
|
||||||
__c.push(num);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<key>comment</key>
|
<key>comment</key>
|
||||||
<string>match stuff like: funcName: => … </string>
|
<string>match stuff like: funcName: => … </string>
|
||||||
<key>match</key>
|
<key>match</key>
|
||||||
<string>([a-zA-Z0-9_?.$:*]*)\s*(=|:)\s*([\w,\s]*?)\s*(=>)</string>
|
<string>([a-zA-Z0-9_?.$:*]*?)\s*(=\b|:\b)\s*([\w,\s]*?)\s*(=+>)</string>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>meta.function.coffee</string>
|
<string>meta.function.coffee</string>
|
||||||
</dict>
|
</dict>
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
<key>comment</key>
|
<key>comment</key>
|
||||||
<string>match stuff like: a => … </string>
|
<string>match stuff like: a => … </string>
|
||||||
<key>match</key>
|
<key>match</key>
|
||||||
<string>([a-zA-Z0-9_?., $*]*)\s*(=>)</string>
|
<string>([a-zA-Z0-9_?., $*]*)\s*(=+>)</string>
|
||||||
<key>name</key>
|
<key>name</key>
|
||||||
<string>meta.inline.function.coffee</string>
|
<string>meta.inline.function.coffee</string>
|
||||||
</dict>
|
</dict>
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ prechigh
|
|||||||
left EXTENDS
|
left EXTENDS
|
||||||
left ASSIGN '||=' '&&='
|
left ASSIGN '||=' '&&='
|
||||||
right RETURN
|
right RETURN
|
||||||
right '=>' UNLESS IF ELSE WHILE
|
right '=>' '==>' UNLESS IF ELSE WHILE
|
||||||
preclow
|
preclow
|
||||||
|
|
||||||
rule
|
rule
|
||||||
@@ -198,8 +198,14 @@ rule
|
|||||||
|
|
||||||
# Function definition.
|
# Function definition.
|
||||||
Code:
|
Code:
|
||||||
ParamList "=>" Block { result = CodeNode.new(val[0], val[2]) }
|
ParamList FuncGlyph Block { result = CodeNode.new(val[0], val[2], val[1]) }
|
||||||
| "=>" Block { result = CodeNode.new([], val[1]) }
|
| FuncGlyph Block { result = CodeNode.new([], val[1], val[0]) }
|
||||||
|
;
|
||||||
|
|
||||||
|
# The symbols to signify functions, and bound functions.
|
||||||
|
FuncGlyph:
|
||||||
|
'=>' { result = :func }
|
||||||
|
| '==>' { result = :boundfunc }
|
||||||
;
|
;
|
||||||
|
|
||||||
# The parameters to a function definition.
|
# The parameters to a function definition.
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ module CoffeeScript
|
|||||||
OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/
|
OPERATOR = /\A([+\*&|\/\-%=<>:!]+)/
|
||||||
WHITESPACE = /\A([ \t]+)/
|
WHITESPACE = /\A([ \t]+)/
|
||||||
COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/
|
COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/
|
||||||
CODE = /\A(=>)/
|
CODE = /\A(=?=>)/
|
||||||
REGEX = /\A(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/
|
REGEX = /\A(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/
|
||||||
MULTI_DENT = /\A((\n([ \t]*))+)(\.)?/
|
MULTI_DENT = /\A((\n([ \t]*))+)(\.)?/
|
||||||
LAST_DENT = /\n([ \t]*)/
|
LAST_DENT = /\n([ \t]*)/
|
||||||
@@ -155,7 +155,7 @@ module CoffeeScript
|
|||||||
@line += indent.scan(MULTILINER).size
|
@line += indent.scan(MULTILINER).size
|
||||||
@i += indent.size
|
@i += indent.size
|
||||||
next_character = @chunk[MULTI_DENT, 4]
|
next_character = @chunk[MULTI_DENT, 4]
|
||||||
no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && last_value != "=>")
|
no_newlines = next_character == '.' || (last_value.to_s.match(NO_NEWLINE) && !last_value.match(CODE))
|
||||||
return suppress_newlines(indent) if no_newlines
|
return suppress_newlines(indent) if no_newlines
|
||||||
size = indent.scan(LAST_DENT).last.last.length
|
size = indent.scan(LAST_DENT).last.last.length
|
||||||
return newline_token(indent) if size == @indent
|
return newline_token(indent) if size == @indent
|
||||||
|
|||||||
@@ -546,14 +546,23 @@ module CoffeeScript
|
|||||||
|
|
||||||
# A function definition. The only node that creates a new Scope.
|
# A function definition. The only node that creates a new Scope.
|
||||||
class CodeNode < Node
|
class CodeNode < Node
|
||||||
attr_reader :params, :body
|
attr_reader :params, :body, :bound
|
||||||
|
|
||||||
def initialize(params, body)
|
def initialize(params, body, tag=nil)
|
||||||
@params = params
|
@params = params
|
||||||
@body = body
|
@body = body
|
||||||
|
@bound = tag == :boundfunc
|
||||||
|
end
|
||||||
|
|
||||||
|
def statement?
|
||||||
|
@bound
|
||||||
end
|
end
|
||||||
|
|
||||||
def compile_node(o)
|
def compile_node(o)
|
||||||
|
if @bound
|
||||||
|
o[:scope].assign("__this", "this")
|
||||||
|
fvar = o[:scope].free_variable
|
||||||
|
end
|
||||||
shared_scope = o.delete(:shared_scope)
|
shared_scope = o.delete(:shared_scope)
|
||||||
o[:scope] = shared_scope || Scope.new(o[:scope], @body)
|
o[:scope] = shared_scope || Scope.new(o[:scope], @body)
|
||||||
o[:return] = true
|
o[:return] = true
|
||||||
@@ -568,9 +577,11 @@ module CoffeeScript
|
|||||||
@body.unshift(splat)
|
@body.unshift(splat)
|
||||||
end
|
end
|
||||||
@params.each {|id| o[:scope].parameter(id.to_s) }
|
@params.each {|id| o[:scope].parameter(id.to_s) }
|
||||||
code = @body.compile_with_declarations(o)
|
code = "\n#{@body.compile_with_declarations(o)}\n"
|
||||||
name_part = name ? " #{name}" : ''
|
name_part = name ? " #{name}" : ''
|
||||||
write("function#{name_part}(#{@params.join(', ')}) {\n#{code}\n#{idt}}")
|
func = "function#{@bound ? '' : name_part}(#{@params.join(', ')}) {#{code}#{idt}}"
|
||||||
|
return write(func) unless @bound
|
||||||
|
write("#{idt}#{fvar} = #{func};\n#{idt}#{o[:return] ? 'return ' : ''}(function#{name_part}() {\n#{idt(1)}return #{fvar}.apply(__this, arguments);\n#{idt}});")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -726,7 +737,7 @@ module CoffeeScript
|
|||||||
body = Expressions.wrap(IfNode.new(@filter, body))
|
body = Expressions.wrap(IfNode.new(@filter, body))
|
||||||
end
|
end
|
||||||
if @object
|
if @object
|
||||||
o[:scope].top_level_assign("__hasProp", "Object.prototype.hasOwnProperty")
|
o[:scope].assign("__hasProp", "Object.prototype.hasOwnProperty", true)
|
||||||
body = Expressions.wrap(IfNode.new(
|
body = Expressions.wrap(IfNode.new(
|
||||||
CallNode.new(ValueNode.new(LiteralNode.wrap("__hasProp"), [AccessorNode.new(Value.new('call'))]), [LiteralNode.wrap(svar), LiteralNode.wrap(ivar)]),
|
CallNode.new(ValueNode.new(LiteralNode.wrap("__hasProp"), [AccessorNode.new(Value.new('call'))]), [LiteralNode.wrap(svar), LiteralNode.wrap(ivar)]),
|
||||||
Expressions.wrap(body),
|
Expressions.wrap(body),
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ module CoffeeScript
|
|||||||
|
|
||||||
# Single-line flavors of block expressions that have unclosed endings.
|
# Single-line flavors of block expressions that have unclosed endings.
|
||||||
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
# The grammar can't disambiguate them, so we insert the implicit indentation.
|
||||||
SINGLE_LINERS = [:ELSE, "=>", :TRY, :FINALLY, :THEN]
|
SINGLE_LINERS = [:ELSE, "=>", "==>", :TRY, :FINALLY, :THEN]
|
||||||
SINGLE_CLOSERS = ["\n", :CATCH, :FINALLY, :ELSE, :OUTDENT, :LEADING_WHEN]
|
SINGLE_CLOSERS = ["\n", :CATCH, :FINALLY, :ELSE, :OUTDENT, :LEADING_WHEN]
|
||||||
|
|
||||||
# Rewrite the token stream in multiple passes, one logical filter at
|
# Rewrite the token stream in multiple passes, one logical filter at
|
||||||
|
|||||||
@@ -47,10 +47,10 @@ module CoffeeScript
|
|||||||
@temp_variable.dup
|
@temp_variable.dup
|
||||||
end
|
end
|
||||||
|
|
||||||
# Ensure that an assignment is made at the top-level scope.
|
# Ensure that an assignment is made at the top of scope (or top-level
|
||||||
# Takes two strings.
|
# scope, if requested).
|
||||||
def top_level_assign(name, value)
|
def assign(name, value, top=false)
|
||||||
return @parent.top_level_assign(name, value) if @parent
|
return @parent.assign(name, value, top) if top && @parent
|
||||||
@variables[name.to_sym] = Value.new(value)
|
@variables[name.to_sym] = Value.new(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,10 @@ module CoffeeScript
|
|||||||
def hash
|
def hash
|
||||||
@value.hash
|
@value.hash
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def match(regex)
|
||||||
|
@value.match(regex)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
22
test/fixtures/execution/test_functions.coffee
vendored
Normal file
22
test/fixtures/execution/test_functions.coffee
vendored
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
x: 1
|
||||||
|
y: {}
|
||||||
|
y.x: => 3
|
||||||
|
|
||||||
|
print(x is 1)
|
||||||
|
print(typeof(y.x) is 'function')
|
||||||
|
print(y.x() is 3)
|
||||||
|
print(y.x.name is 'x')
|
||||||
|
|
||||||
|
|
||||||
|
obj: {
|
||||||
|
name: "Fred"
|
||||||
|
|
||||||
|
bound: =>
|
||||||
|
(==> print(this.name is "Fred"))()
|
||||||
|
|
||||||
|
unbound: =>
|
||||||
|
(=> print(!this.name?))()
|
||||||
|
}
|
||||||
|
|
||||||
|
obj.unbound()
|
||||||
|
obj.bound()
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
x: 1
|
|
||||||
y: {}
|
|
||||||
y.x: => 3
|
|
||||||
|
|
||||||
print(x is 1)
|
|
||||||
print(typeof(y.x) is 'function')
|
|
||||||
print(y.x() is 3)
|
|
||||||
print(y.x.name is 'x')
|
|
||||||
Reference in New Issue
Block a user