From a9f016e2926df0afb67649fdab372d4e0db18a12 Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Tue, 26 Jan 2010 10:52:05 -0500 Subject: [PATCH] trying out new arrows for function literals -> is a function, => is a bound function --- documentation/coffee/arguments.coffee | 2 +- documentation/coffee/blocks.coffee | 4 +- documentation/coffee/expressions.coffee | 2 +- documentation/coffee/functions.coffee | 4 +- documentation/coffee/long_arrow.coffee | 4 +- .../coffee/multiple_return_values.coffee | 2 +- documentation/coffee/overview.coffee | 6 +- .../coffee/range_comprehensions.coffee | 2 +- documentation/coffee/scope.coffee | 2 +- documentation/coffee/splats.coffee | 2 +- documentation/coffee/super.coffee | 12 +- documentation/index.html.erb | 8 +- examples/beautiful_code/binary_search.coffee | 2 +- .../beautiful_code/quicksort_runtime.coffee | 2 +- .../regular_expression_matcher.coffee | 6 +- examples/code.coffee | 34 ++-- .../computer_science/binary_search.coffee | 2 +- examples/computer_science/bubble_sort.coffee | 2 +- examples/computer_science/linked_list.coffee | 14 +- .../computer_science/luhn_algorithm.coffee | 2 +- examples/computer_science/merge_sort.coffee | 2 +- .../computer_science/selection_sort.coffee | 2 +- examples/poignant.coffee | 30 +-- examples/potion.coffee | 22 +-- examples/underscore.coffee | 186 +++++++++--------- extras/coffee.vim | 2 +- index.html | 8 +- lib/coffee_script/grammar.y | 6 +- lib/coffee_script/lexer.rb | 2 +- .../narwhal/coffee-script.coffee | 12 +- lib/coffee_script/narwhal/loader.coffee | 6 +- lib/coffee_script/parser.rb | 6 +- lib/coffee_script/rewriter.rb | 6 +- test/fixtures/execution/test_arguments.coffee | 6 +- .../execution/test_array_comprehension.coffee | 2 +- .../fixtures/execution/test_assignment.coffee | 2 +- test/fixtures/execution/test_blocks.coffee | 2 +- .../execution/test_calling_super.coffee | 22 +-- .../execution/test_chained_calls.coffee | 4 +- .../fixtures/execution/test_everything.coffee | 4 +- test/fixtures/execution/test_existence.coffee | 2 +- .../execution/test_expressions.coffee | 4 +- test/fixtures/execution/test_functions.coffee | 26 +-- .../execution/test_funky_comments.coffee | 4 +- test/fixtures/execution/test_literals.coffee | 4 +- .../fixtures/execution/test_operations.coffee | 2 +- test/fixtures/execution/test_splats.coffee | 4 +- test/fixtures/execution/test_switch.coffee | 2 +- test/fixtures/generation/each.coffee | 2 +- test/fixtures/generation/each.tokens | 2 +- .../statements_as_expressions.coffee | 2 +- test/fixtures/generation/whitespace.coffee | 12 +- test/unit/test_lexer.rb | 4 +- test/unit/test_parser.rb | 2 +- 54 files changed, 259 insertions(+), 259 deletions(-) diff --git a/documentation/coffee/arguments.coffee b/documentation/coffee/arguments.coffee index afee3741..ac548c12 100644 --- a/documentation/coffee/arguments.coffee +++ b/documentation/coffee/arguments.coffee @@ -1,4 +1,4 @@ -backwards: => +backwards: -> alert arguments.reverse() backwards "stairway", "to", "heaven" \ No newline at end of file diff --git a/documentation/coffee/blocks.coffee b/documentation/coffee/blocks.coffee index a80196b3..16d9bc07 100644 --- a/documentation/coffee/blocks.coffee +++ b/documentation/coffee/blocks.coffee @@ -1,4 +1,4 @@ -$('table.list').each (table) => - $('tr.account', table).each (row) => +$('table.list').each (table) -> + $('tr.account', table).each (row) -> row.show() row.highlight() diff --git a/documentation/coffee/expressions.coffee b/documentation/coffee/expressions.coffee index f74f8442..74a02466 100644 --- a/documentation/coffee/expressions.coffee +++ b/documentation/coffee/expressions.coffee @@ -1,4 +1,4 @@ -grade: (student) => +grade: (student) -> if student.excellent_work "A+" else if student.okay_stuff diff --git a/documentation/coffee/functions.coffee b/documentation/coffee/functions.coffee index 3d00c8f1..4fd48d32 100644 --- a/documentation/coffee/functions.coffee +++ b/documentation/coffee/functions.coffee @@ -1,2 +1,2 @@ -square: (x) => x * x -cube: (x) => square(x) * x +square: (x) -> x * x +cube: (x) -> square(x) * x diff --git a/documentation/coffee/long_arrow.coffee b/documentation/coffee/long_arrow.coffee index 33356a17..4b7759d3 100644 --- a/documentation/coffee/long_arrow.coffee +++ b/documentation/coffee/long_arrow.coffee @@ -1,6 +1,6 @@ -Account: (customer, cart) => +Account: (customer, cart) -> this.customer: customer this.cart: cart - $('.shopping_cart').bind 'click', (event) ==> + $('.shopping_cart').bind 'click', (event) => this.customer.purchase this.cart \ No newline at end of file diff --git a/documentation/coffee/multiple_return_values.coffee b/documentation/coffee/multiple_return_values.coffee index 116f8b53..3fe572b1 100644 --- a/documentation/coffee/multiple_return_values.coffee +++ b/documentation/coffee/multiple_return_values.coffee @@ -1,4 +1,4 @@ -weather_report: (location) => +weather_report: (location) -> # Make an Ajax request to fetch the weather... [location, 72, "Mostly Sunny"] diff --git a/documentation/coffee/overview.coffee b/documentation/coffee/overview.coffee index 0d8cd4d5..3156f840 100644 --- a/documentation/coffee/overview.coffee +++ b/documentation/coffee/overview.coffee @@ -6,7 +6,7 @@ opposite_day: true number: -42 if opposite_day # Functions: -square: (x) => x * x +square: (x) -> x * x # Arrays: list: [1, 2, 3, 4, 5] @@ -15,11 +15,11 @@ list: [1, 2, 3, 4, 5] math: { root: Math.sqrt square: square - cube: (x) => x * square x + cube: (x) -> x * square x } # Splats: -race: (winner, runners...) => +race: (winner, runners...) -> print winner, runners # Existence: diff --git a/documentation/coffee/range_comprehensions.coffee b/documentation/coffee/range_comprehensions.coffee index 8baa2e87..33790f5a 100644 --- a/documentation/coffee/range_comprehensions.coffee +++ b/documentation/coffee/range_comprehensions.coffee @@ -1,6 +1,6 @@ countdown: num for num in [10..1] -egg_delivery: => +egg_delivery: -> for i in [0...eggs.length] by 12 dozen_eggs: eggs[i...i+12] deliver new egg_carton(dozen) diff --git a/documentation/coffee/scope.coffee b/documentation/coffee/scope.coffee index b074dad2..30eedacf 100644 --- a/documentation/coffee/scope.coffee +++ b/documentation/coffee/scope.coffee @@ -1,5 +1,5 @@ num: 1 -change_numbers: => +change_numbers: -> new_num: -1 num: 10 new_num: change_numbers() \ No newline at end of file diff --git a/documentation/coffee/splats.coffee b/documentation/coffee/splats.coffee index ad919a5c..ea27d0c1 100644 --- a/documentation/coffee/splats.coffee +++ b/documentation/coffee/splats.coffee @@ -1,6 +1,6 @@ gold: silver: the_field: "unknown" -medalists: (first, second, rest...) => +medalists: (first, second, rest...) -> gold: first silver: second the_field: rest diff --git a/documentation/coffee/super.coffee b/documentation/coffee/super.coffee index 9dc4d5a2..b45faff0 100644 --- a/documentation/coffee/super.coffee +++ b/documentation/coffee/super.coffee @@ -1,16 +1,16 @@ -Animal: => -Animal::move: (meters) => +Animal: -> +Animal::move: (meters) -> alert this.name + " moved " + meters + "m." -Snake: (name) => this.name: name +Snake: (name) -> this.name: name Snake extends Animal -Snake::move: => +Snake::move: -> alert "Slithering..." super 5 -Horse: (name) => this.name: name +Horse: (name) -> this.name: name Horse extends Animal -Horse::move: => +Horse::move: -> alert "Galloping..." super 45 diff --git a/documentation/index.html.erb b/documentation/index.html.erb index 34f23c02..6b91505e 100644 --- a/documentation/index.html.erb +++ b/documentation/index.html.erb @@ -174,7 +174,7 @@ gem install coffee-script -e, --eval Compile and print a little snippet of CoffeeScript directly from the - command line (or from stdin). For example:
coffee -e "square: (x) => x * x" + command line (or from stdin). For example:
coffee -e "square: (x) -> x * x" @@ -256,13 +256,13 @@ coffee --print app/scripts/*.coffee > concatenation.js

Functions and Invocation Functions are defined by a list of parameters, an arrow, and the - function body. The empty function looks like this: =>. All + function body. The empty function looks like this: ->. All functions in CoffeeScript are named by default, for easier debugging.

<%= code_for('functions', 'cube(5)') %>

If you'd like to create an anonymous function, just wrap it in parentheses: - ((x) => x * x) + ((x) -> x * x)

@@ -547,7 +547,7 @@ coffee --print app/scripts/*.coffee > concatenation.js

Function binding - The long arrow ==> can be used to both define a function, and to bind + The long arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot. This is helpful when using callback-based libraries like Prototype or jQuery, for creating iterator functions to pass to each, or event-handler functions diff --git a/examples/beautiful_code/binary_search.coffee b/examples/beautiful_code/binary_search.coffee index 2c659825..9c6e02d1 100644 --- a/examples/beautiful_code/binary_search.coffee +++ b/examples/beautiful_code/binary_search.coffee @@ -2,7 +2,7 @@ # The implementation of binary search that is tested. # Return the index of an element in a sorted list. (or -1, if not present) -index: (list, target) => +index: (list, target) -> [low, high]: [0, list.length] while low < high mid: (low + high) >> 1 diff --git a/examples/beautiful_code/quicksort_runtime.coffee b/examples/beautiful_code/quicksort_runtime.coffee index 2d1dc0b6..affd775a 100644 --- a/examples/beautiful_code/quicksort_runtime.coffee +++ b/examples/beautiful_code/quicksort_runtime.coffee @@ -1,7 +1,7 @@ # Beautiful Code, Chapter 3. # Produces the expected runtime of Quicksort, for every integer from 1 to N. -runtime: (N) => +runtime: (N) -> [sum, t]: [0, 0] for n in [1..N] sum += 2 * t diff --git a/examples/beautiful_code/regular_expression_matcher.coffee b/examples/beautiful_code/regular_expression_matcher.coffee index 7f678402..4ef8237e 100644 --- a/examples/beautiful_code/regular_expression_matcher.coffee +++ b/examples/beautiful_code/regular_expression_matcher.coffee @@ -3,7 +3,7 @@ # '.', '^', '$', and '*'. # Search for the regexp anywhere in the text. -match: (regexp, text) => +match: (regexp, text) -> return match_here(regexp.slice(1), text) if regexp[0] is '^' while text return true if match_here(regexp, text) @@ -11,7 +11,7 @@ match: (regexp, text) => false # Search for the regexp at the beginning of the text. -match_here: (regexp, text) => +match_here: (regexp, text) -> [cur, next]: [regexp[0], regexp[1]] if regexp.length is 0 then return true if next is '*' then return match_star(cur, regexp.slice(2), text) @@ -20,7 +20,7 @@ match_here: (regexp, text) => false # Search for a kleene star match at the beginning of the text. -match_star: (c, regexp, text) => +match_star: (c, regexp, text) -> while true return true if match_here(regexp, text) return false unless text and (text[0] is c or c is '.') diff --git a/examples/code.coffee b/examples/code.coffee index 105bdbe0..85b75169 100644 --- a/examples/code.coffee +++ b/examples/code.coffee @@ -1,14 +1,14 @@ # Functions: -square: (x) => x * x +square: (x) -> x * x -sum: (x, y) => x + y +sum: (x, y) -> x + y -odd: (x) => x % 2 isnt 0 +odd: (x) -> x % 2 isnt 0 -even: (x) => x % 2 is 0 +even: (x) -> x % 2 is 0 -run_loop: => - fire_events((e) => e.stopPropagation()) +run_loop: -> + fire_events((e) -> e.stopPropagation()) listen() wait() @@ -22,14 +22,14 @@ spaced_out_multiline_object: { three: new Idea() inner_obj: { - freedom: => _.freedom() + freedom: -> _.freedom() } } # Arrays: stooges: [{moe: 45}, {curly: 43}, {larry: 46}] -exponents: [(x) => x, (x) => x * x, (x) => x * x * x] +exponents: [(x) -> x, (x) -> x * x, (x) -> x * x * x] empty: [] @@ -54,7 +54,7 @@ decoration: medal_of_honor if war_hero go_to_sleep() unless coffee # Returning early: -race: => +race: -> run() walk() crawl() @@ -103,7 +103,7 @@ while true # Lexical scoping. v_1: 5 -change_a_and_set_b: => +change_a_and_set_b: -> v_1: 10 v_2: 15 v_2: 20 @@ -128,7 +128,7 @@ activity: switch day else go_to_work() # Semicolons can optionally be used instead of newlines. -wednesday: => eat_breakfast(); go_to_work(); eat_dinner() +wednesday: -> eat_breakfast(); go_to_work(); eat_dinner() # Array slice literals. zero_to_nine: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9] @@ -140,19 +140,19 @@ sed diam nonummy nibh euismod tincidunt ut laoreet dolore magna aliquam erat volutpat. Ut wisi enim ad." # Inheritance and calling super. -Animal: => -Animal::move: (meters) => +Animal: -> +Animal::move: (meters) -> alert(this.name + " moved " + meters + "m.") -Snake: (name) => this.name: name +Snake: (name) -> this.name: name Snake extends Animal -Snake::move: => +Snake::move: -> alert('Slithering...') super(5) -Horse: (name) => this.name: name +Horse: (name) -> this.name: name Horse extends Animal -Horse::move: => +Horse::move: -> alert('Galloping...') super(45) diff --git a/examples/computer_science/binary_search.coffee b/examples/computer_science/binary_search.coffee index 8b07f7a5..443eaaa0 100644 --- a/examples/computer_science/binary_search.coffee +++ b/examples/computer_science/binary_search.coffee @@ -1,5 +1,5 @@ # Uses a binary search algorithm to locate a value in the specified array. -binary_search: (items, value) => +binary_search: (items, value) -> start: 0 stop: items.length - 1 diff --git a/examples/computer_science/bubble_sort.coffee b/examples/computer_science/bubble_sort.coffee index 0d9a3aca..f671bedd 100644 --- a/examples/computer_science/bubble_sort.coffee +++ b/examples/computer_science/bubble_sort.coffee @@ -1,5 +1,5 @@ # A bubble sort implementation, sorting the given array in-place. -bubble_sort: (list) => +bubble_sort: (list) -> for i in [0...list.length] for j in [0...list.length - i] [list[j], list[j+1]]: [list[j+1], list[j]] if list[j] > list[j+1] diff --git a/examples/computer_science/linked_list.coffee b/examples/computer_science/linked_list.coffee index 8071f869..6af3fddf 100644 --- a/examples/computer_science/linked_list.coffee +++ b/examples/computer_science/linked_list.coffee @@ -1,11 +1,11 @@ # "Classic" linked list implementation that doesn't keep track of its size. -LinkedList: => +LinkedList: -> this._head: null # Pointer to the first item in the list. # Appends some data to the end of the list. This method traverses the existing # list and places the value at the end in a new node. -LinkedList::add: (data) => +LinkedList::add: (data) -> # Create a new node object to wrap the data. node: {data: data, next: null} @@ -20,7 +20,7 @@ LinkedList::add: (data) => # Retrieves the data at the given position in the list. -LinkedList::item: (index) => +LinkedList::item: (index) -> # Check for out-of-bounds values. return null if index < 0 @@ -36,7 +36,7 @@ LinkedList::item: (index) => # Remove the item from the given location in the list. -LinkedList::remove: (index) => +LinkedList::remove: (index) -> # Check for out-of-bounds values. return null if index < 0 @@ -60,7 +60,7 @@ LinkedList::remove: (index) => # Calculate the number of items in the list. -LinkedList::size: => +LinkedList::size: -> current: this._head count: 0 @@ -72,7 +72,7 @@ LinkedList::size: => # Convert the list into an array. -LinkedList::toArray: => +LinkedList::toArray: -> result: [] current: this._head @@ -84,7 +84,7 @@ LinkedList::toArray: => # The string representation of the linked list. -LinkedList::toString: => this.toArray().toString() +LinkedList::toString: -> this.toArray().toString() # Tests. diff --git a/examples/computer_science/luhn_algorithm.coffee b/examples/computer_science/luhn_algorithm.coffee index ce3a78da..042b249d 100644 --- a/examples/computer_science/luhn_algorithm.coffee +++ b/examples/computer_science/luhn_algorithm.coffee @@ -2,7 +2,7 @@ # numbers, national insurance numbers, etc. # See: http://en.wikipedia.org/wiki/Luhn_algorithm -is_valid_identifier: (identifier) => +is_valid_identifier: (identifier) -> sum: 0 alt: false diff --git a/examples/computer_science/merge_sort.coffee b/examples/computer_science/merge_sort.coffee index 4df0a59d..fb3f8ce8 100644 --- a/examples/computer_science/merge_sort.coffee +++ b/examples/computer_science/merge_sort.coffee @@ -1,5 +1,5 @@ # Sorts an array in ascending natural order using merge sort. -merge_sort: (list) => +merge_sort: (list) -> return list if list.length is 1 diff --git a/examples/computer_science/selection_sort.coffee b/examples/computer_science/selection_sort.coffee index c134b225..f4b970a1 100644 --- a/examples/computer_science/selection_sort.coffee +++ b/examples/computer_science/selection_sort.coffee @@ -1,5 +1,5 @@ # An in-place selection sort. -selection_sort: (list) => +selection_sort: (list) -> len: list.length # For each item in the list. diff --git a/examples/poignant.coffee b/examples/poignant.coffee index 4347daea..0754284a 100644 --- a/examples/poignant.coffee +++ b/examples/poignant.coffee @@ -2,7 +2,7 @@ # ['toast', 'cheese', 'wine'].each { |food| print food.capitalize } -['toast', 'wine', 'cheese'].each (food) => print(food.capitalize()) +['toast', 'wine', 'cheese'].each (food) -> print(food.capitalize()) @@ -14,10 +14,10 @@ # end LotteryTicket: { - get_picks: => this.picks - set_picks: (nums) => this.picks: nums - get_purchase: => this.purchase - set_purchase: (amount) => this.purchase: amount + get_picks: -> this.picks + set_picks: (nums) -> this.picks: nums + get_purchase: -> this.purchase + set_purchase: (amount) -> this.purchase: amount } @@ -40,11 +40,11 @@ LotteryTicket: { # end LotteryDraw: { - play: => + play: -> result: LotteryTicket.new_random() winners: {} - this.tickets.each (buyer, ticket_list) => - ticket_list.each (ticket) => + this.tickets.each (buyer, ticket_list) -> + ticket_list.each (ticket) -> score: ticket.score(result) return if score is 0 winners[buyer] ||= [] @@ -65,8 +65,8 @@ LotteryDraw: { # end WishScanner: { - scan_for_a_wish: => - wish: this.read().detect((thought) => thought.index('wish: ') is 0) + scan_for_a_wish: -> + wish: this.read().detect((thought) -> thought.index('wish: ') is 0) wish.replace('wish: ', '') } @@ -111,7 +111,7 @@ WishScanner: { Creature : { # This method applies a hit taken during a fight. - hit: (damage) => + hit: (damage) -> p_up: Math.rand(this.charisma) if p_up % 9 is 7 this.life += p_up / 4 @@ -120,7 +120,7 @@ Creature : { if this.life <= 0 then puts("[" + this.name + " has died.]") # This method takes one turn in a fight. - fight: (enemy, weapon) => + fight: (enemy, weapon) -> if this.life <= 0 then return puts("[" + this.name + "is too dead to fight!]") # Attack the opponent. @@ -156,12 +156,12 @@ Creature : { # Get evil idea and swap in code words print("Enter your new idea: ") idea: gets() -code_words.each((real, code) => idea.replace(real, code)) +code_words.each((real, code) -> idea.replace(real, code)) # Save the jibberish to a new file print("File encoded. Please enter a name for this idea: ") idea_name: gets().strip() -File.open("idea-" + idea_name + '.txt', 'w', (file) => file.write(idea)) +File.open("idea-" + idea_name + '.txt', 'w', (file) -> file.write(idea)) @@ -177,7 +177,7 @@ File.open("idea-" + idea_name + '.txt', 'w', (file) => file.write(idea)) # end # end -wipe_mutterings_from: (sentence) => +wipe_mutterings_from: (sentence) -> throw new Error("cannot wipe mutterings") unless sentence.indexOf while sentence.indexOf('(') >= 0 open: sentence.indexOf('(') - 1 diff --git a/examples/potion.coffee b/examples/potion.coffee index ef9ac898..c8c5ddf9 100644 --- a/examples/potion.coffee +++ b/examples/potion.coffee @@ -8,7 +8,7 @@ print("Odelay!") for i in [1..5] # add = (x, y): x + y. # add(2, 4) string print -add: (x, y) => x + y +add: (x, y) -> x + y print(add(2, 4)) @@ -31,7 +31,7 @@ print({language: 'Potion', pointless: true}['language']) # minus = (x, y): x - y. # minus (y=10, x=6) -minus: (x, y) => x - y +minus: (x, y) -> x - y minus(6, 10) @@ -53,8 +53,8 @@ for key, val of {dog: 'canine', cat: 'feline', fox: 'vulpine'} # Person print = (): # ('My name is ', /name, '.') join print. -Person: => -Person::print: => +Person: -> +Person::print: -> print('My name is ' + this.name + '.') @@ -71,9 +71,9 @@ print(p.name) # # Policeman ('Constable') print -Policeman: (rank) => this.rank: rank +Policeman: (rank) -> this.rank: rank Policeman extends Person -Policeman::print: => +Policeman::print: -> print('My name is ' + this.name + " and I'm a " + this.rank + '.') print(new Policeman('Constable')) @@ -115,13 +115,13 @@ table: { # String length = (): 10. # this foul business... -String::length: => 10 +String::length: -> 10 # block = : # 'potion' print. -block: => +block: -> print('potion') @@ -178,7 +178,7 @@ if (3).gender? # HomePage get = (url): # session = url query ? at ('session'). -HomePage::get: (url) => +HomePage::get: (url) -> session: url.query.session if url.query? @@ -187,7 +187,7 @@ HomePage::get: (url) => # b /left = BTree () # b /right = BTree () -BTree: => +BTree: -> b: new BTree() b.left: new BTree() b.right: new BTree() @@ -199,7 +199,7 @@ b.right: new BTree() # if (b ? /left): # 'left path found!' print. -BTree: => +BTree: -> b: new BTree() print('left path found!') if b.left? diff --git a/examples/underscore.coffee b/examples/underscore.coffee index db879723..7dbb763a 100644 --- a/examples/underscore.coffee +++ b/examples/underscore.coffee @@ -21,7 +21,7 @@ # If Underscore is called as a function, it returns a wrapped object that # can be used OO-style. This wrapper holds altered versions of all the # underscore functions. Wrapped objects may be chained. - wrapper: (obj) => + wrapper: (obj) -> this._wrapped: obj this @@ -31,7 +31,7 @@ # Create a safe reference to the Underscore object forreference below. - _: root._: (obj) => new wrapper(obj) + _: root._: (obj) -> new wrapper(obj) # Export the Underscore object for CommonJS. @@ -54,7 +54,7 @@ # The cornerstone, an each implementation. # Handles objects implementing forEach, arrays, and raw objects. - _.each: (obj, iterator, context) => + _.each: (obj, iterator, context) -> index: 0 try return obj.forEach(iterator, context) if obj.forEach @@ -68,36 +68,36 @@ # Return the results of applying the iterator to each element. Use JavaScript # 1.6's version of map, if possible. - _.map: (obj, iterator, context) => + _.map: (obj, iterator, context) -> return obj.map(iterator, context) if (obj and _.isFunction(obj.map)) results: [] - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> results.push(iterator.call(context, value, index, list)) results # Reduce builds up a single result from a list of values. Also known as # inject, or foldl. Uses JavaScript 1.8's version of reduce, if possible. - _.reduce: (obj, memo, iterator, context) => + _.reduce: (obj, memo, iterator, context) -> return obj.reduce(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduce)) - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> memo: iterator.call(context, memo, value, index, list) memo # The right-associative version of reduce, also known as foldr. Uses # JavaScript 1.8's version of reduceRight, if available. - _.reduceRight: (obj, memo, iterator, context) => + _.reduceRight: (obj, memo, iterator, context) -> return obj.reduceRight(_.bind(iterator, context), memo) if (obj and _.isFunction(obj.reduceRight)) - _.each _.clone(_.toArray(obj)).reverse(), (value, index) => + _.each _.clone(_.toArray(obj)).reverse(), (value, index) -> memo: iterator.call(context, memo, value, index, obj) memo # Return the first value which passes a truth test. - _.detect: (obj, iterator, context) => + _.detect: (obj, iterator, context) -> result: null - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> if iterator.call(context, value, index, list) result: value _.breakLoop() @@ -106,47 +106,47 @@ # Return all the elements that pass a truth test. Use JavaScript 1.6's # filter(), if it exists. - _.select: (obj, iterator, context) => + _.select: (obj, iterator, context) -> if obj and _.isFunction(obj.filter) then return obj.filter(iterator, context) results: [] - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> results.push(value) if iterator.call(context, value, index, list) results # Return all the elements for which a truth test fails. - _.reject: (obj, iterator, context) => + _.reject: (obj, iterator, context) -> results: [] - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> results.push(value) if not iterator.call(context, value, index, list) results # Determine whether all of the elements match a truth test. Delegate to # JavaScript 1.6's every(), if it is present. - _.all: (obj, iterator, context) => + _.all: (obj, iterator, context) -> iterator ||= _.identity return obj.every(iterator, context) if obj and _.isFunction(obj.every) result: true - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> _.breakLoop() unless (result: result and iterator.call(context, value, index, list)) result # Determine if at least one element in the object matches a truth test. Use # JavaScript 1.6's some(), if it exists. - _.any: (obj, iterator, context) => + _.any: (obj, iterator, context) -> iterator ||= _.identity return obj.some(iterator, context) if obj and _.isFunction(obj.some) result: false - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> _.breakLoop() if (result: iterator.call(context, value, index, list)) result # Determine if a given value is included in the array or object, # based on '==='. - _.include: (obj, target) => + _.include: (obj, target) -> return _.indexOf(obj, target) isnt -1 if _.isArray(obj) for key, val of obj return true if val is target @@ -154,41 +154,41 @@ # Invoke a method with arguments on every item in a collection. - _.invoke: (obj, method) => + _.invoke: (obj, method) -> args: _.rest(arguments, 2) (if method then val[method] else val).apply(val, args) for val in obj # Convenience version of a common use case of map: fetching a property. - _.pluck: (obj, key) => - _.map(obj, ((val) => val[key])) + _.pluck: (obj, key) -> + _.map(obj, ((val) -> val[key])) # Return the maximum item or (item-based computation). - _.max: (obj, iterator, context) => + _.max: (obj, iterator, context) -> return Math.max.apply(Math, obj) if not iterator and _.isArray(obj) result: {computed: -Infinity} - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> computed: if iterator then iterator.call(context, value, index, list) else value computed >= result.computed and (result: {value: value, computed: computed}) result.value # Return the minimum element (or element-based computation). - _.min: (obj, iterator, context) => + _.min: (obj, iterator, context) -> return Math.min.apply(Math, obj) if not iterator and _.isArray(obj) result: {computed: Infinity} - _.each obj, (value, index, list) => + _.each obj, (value, index, list) -> computed: if iterator then iterator.call(context, value, index, list) else value computed < result.computed and (result: {value: value, computed: computed}) result.value # Sort the object's values by a criteria produced by an iterator. - _.sortBy: (obj, iterator, context) => - _.pluck(((_.map obj, (value, index, list) => + _.sortBy: (obj, iterator, context) -> + _.pluck(((_.map obj, (value, index, list) -> {value: value, criteria: iterator.call(context, value, index, list)} - ).sort((left, right) => + ).sort((left, right) -> a: left.criteria; b: right.criteria if a < b then -1 else if a > b then 1 else 0 )), 'value') @@ -196,7 +196,7 @@ # Use a comparator function to figure out at what index an object should # be inserted so as to maintain order. Uses binary search. - _.sortedIndex: (array, obj, iterator) => + _.sortedIndex: (array, obj, iterator) -> iterator ||= _.identity low: 0; high: array.length while low < high @@ -206,7 +206,7 @@ # Convert anything iterable into a real, live array. - _.toArray: (iterable) => + _.toArray: (iterable) -> return [] if (!iterable) return iterable.toArray() if (iterable.toArray) return iterable if (_.isArray(iterable)) @@ -215,7 +215,7 @@ # Return the number of elements in an object. - _.size: (obj) => _.toArray(obj).length + _.size: (obj) -> _.toArray(obj).length # -------------------------- Array Functions: ------------------------------ @@ -223,7 +223,7 @@ # Get the first element of an array. Passing "n" will return the first N # values in the array. Aliased as "head". The "guard" check allows it to work # with _.map. - _.first: (array, n, guard) => + _.first: (array, n, guard) -> if n and not guard then slice.call(array, 0, n) else array[0] @@ -231,35 +231,35 @@ # Especially useful on the arguments object. Passing an "index" will return # the rest of the values in the array from that index onward. The "guard" # check allows it to work with _.map. - _.rest: (array, index, guard) => + _.rest: (array, index, guard) -> slice.call(array, if _.isUndefined(index) or guard then 1 else index) # Get the last element of an array. - _.last: (array) => array[array.length - 1] + _.last: (array) -> array[array.length - 1] # Trim out all falsy values from an array. - _.compact: (array) => array[i] for i in [0...array.length] when array[i] + _.compact: (array) -> array[i] for i in [0...array.length] when array[i] # Return a completely flattened version of an array. - _.flatten: (array) => - _.reduce array, [], (memo, value) => + _.flatten: (array) -> + _.reduce array, [], (memo, value) -> return memo.concat(_.flatten(value)) if _.isArray(value) memo.push(value) memo # Return a version of the array that does not contain the specified value(s). - _.without: (array) => + _.without: (array) -> values: _.rest(arguments) val for val in _.toArray(array) when not _.include(values, val) # Produce a duplicate-free version of the array. If the array has already # been sorted, you have the option of using a faster algorithm. - _.uniq: (array, isSorted) => + _.uniq: (array, isSorted) -> memo: [] for el, i in _.toArray(array) memo.push(el) if i is 0 || (if isSorted is true then _.last(memo) isnt el else not _.include(memo, el)) @@ -268,16 +268,16 @@ # Produce an array that contains every item shared between all the # passed-in arrays. - _.intersect: (array) => + _.intersect: (array) -> rest: _.rest(arguments) - _.select _.uniq(array), (item) => - _.all rest, (other) => + _.select _.uniq(array), (item) -> + _.all rest, (other) -> _.indexOf(other, item) >= 0 # Zip together multiple lists into a single array -- elements that share # an index go together. - _.zip: => + _.zip: -> length: _.max(_.pluck(arguments, 'length')) results: new Array(length) for i in [0...length] @@ -288,7 +288,7 @@ # If the browser doesn't supply us with indexOf (I'm looking at you, MSIE), # we need this function. Return the position of the first occurence of an # item in an array, or -1 if the item is not included in the array. - _.indexOf: (array, item) => + _.indexOf: (array, item) -> return array.indexOf(item) if array.indexOf i: 0; l: array.length while l - i @@ -298,7 +298,7 @@ # Provide JavaScript 1.6's lastIndexOf, delegating to the native function, # if possible. - _.lastIndexOf: (array, item) => + _.lastIndexOf: (array, item) -> return array.lastIndexOf(item) if array.lastIndexOf i: array.length while i @@ -309,7 +309,7 @@ # Generate an integer Array containing an arithmetic progression. A port of # the native Python range() function. See: # http://docs.python.org/library/functions.html#range - _.range: (start, stop, step) => + _.range: (start, stop, step) -> a: arguments solo: a.length <= 1 i: start: if solo then 0 else a[0]; @@ -330,44 +330,44 @@ # Create a function bound to a given object (assigning 'this', and arguments, # optionally). Binding with arguments is also known as 'curry'. - _.bind: (func, obj) => + _.bind: (func, obj) -> args: _.rest(arguments, 2) - => func.apply(obj or root, args.concat(arguments)) + -> func.apply(obj or root, args.concat(arguments)) # Bind all of an object's methods to that object. Useful for ensuring that # all callbacks defined on an object belong to it. - _.bindAll: (obj) => + _.bindAll: (obj) -> funcs: if arguments.length > 1 then _.rest(arguments) else _.functions(obj) - _.each(funcs, (f) => obj[f]: _.bind(obj[f], obj)) + _.each(funcs, (f) -> obj[f]: _.bind(obj[f], obj)) obj # Delays a function for the given number of milliseconds, and then calls # it with the arguments supplied. - _.delay: (func, wait) => + _.delay: (func, wait) -> args: _.rest(arguments, 2) - setTimeout((=> func.apply(func, args)), wait) + setTimeout((-> func.apply(func, args)), wait) # Defers a function, scheduling it to run after the current call stack has # cleared. - _.defer: (func) => + _.defer: (func) -> _.delay.apply(_, [func, 1].concat(_.rest(arguments))) # Returns the first function passed as an argument to the second, # allowing you to adjust arguments, run code before and after, and # conditionally execute the original function. - _.wrap: (func, wrapper) => - => wrapper.apply(wrapper, [func].concat(arguments)) + _.wrap: (func, wrapper) -> + -> wrapper.apply(wrapper, [func].concat(arguments)) # Returns a function that is the composition of a list of functions, each # consuming the return value of the function that follows. - _.compose: => + _.compose: -> funcs: arguments - => + -> args: arguments for i in [(funcs.length - 1)..0] args: [funcs[i].apply(this, args)] @@ -377,43 +377,43 @@ # ------------------------- Object Functions: ---------------------------- # Retrieve the names of an object's properties. - _.keys: (obj) => + _.keys: (obj) -> return _.range(0, obj.length) if _.isArray(obj) key for key, val of obj # Retrieve the values of an object's properties. - _.values: (obj) => + _.values: (obj) -> _.map(obj, _.identity) # Return a sorted list of the function names available in Underscore. - _.functions: (obj) => - _.select(_.keys(obj), (key) => _.isFunction(obj[key])).sort() + _.functions: (obj) -> + _.select(_.keys(obj), (key) -> _.isFunction(obj[key])).sort() # Extend a given object with all of the properties in a source object. - _.extend: (destination, source) => + _.extend: (destination, source) -> for key, val of source destination[key]: val destination # Create a (shallow-cloned) duplicate of an object. - _.clone: (obj) => + _.clone: (obj) -> return obj.slice(0) if _.isArray(obj) _.extend({}, obj) # Invokes interceptor with the obj, and then returns obj. # The primary purpose of this method is to "tap into" a method chain, in order to perform operations on intermediate results within the chain. - _.tap: (obj, interceptor) => + _.tap: (obj, interceptor) -> interceptor(obj) obj # Perform a deep comparison to check if two objects are equal. - _.isEqual: (a, b) => + _.isEqual: (a, b) -> # Check object identity. return true if a is b # Different types? @@ -449,81 +449,81 @@ # Is a given array or object empty? - _.isEmpty: (obj) => _.keys(obj).length is 0 + _.isEmpty: (obj) -> _.keys(obj).length is 0 # Is a given value a DOM element? - _.isElement: (obj) => obj and obj.nodeType is 1 + _.isElement: (obj) -> obj and obj.nodeType is 1 # Is a given value an array? - _.isArray: (obj) => !!(obj and obj.concat and obj.unshift) + _.isArray: (obj) -> !!(obj and obj.concat and obj.unshift) # Is a given variable an arguments object? - _.isArguments: (obj) => obj and _.isNumber(obj.length) and !_.isArray(obj) and !propertyIsEnumerable.call(obj, 'length') + _.isArguments: (obj) -> obj and _.isNumber(obj.length) and !_.isArray(obj) and !propertyIsEnumerable.call(obj, 'length') # Is the given value a function? - _.isFunction: (obj) => !!(obj and obj.constructor and obj.call and obj.apply) + _.isFunction: (obj) -> !!(obj and obj.constructor and obj.call and obj.apply) # Is the given value a string? - _.isString: (obj) => !!(obj is '' or (obj and obj.charCodeAt and obj.substr)) + _.isString: (obj) -> !!(obj is '' or (obj and obj.charCodeAt and obj.substr)) # Is a given value a number? - _.isNumber: (obj) => toString.call(obj) is '[object Number]' + _.isNumber: (obj) -> toString.call(obj) is '[object Number]' # Is a given value a Date? - _.isDate: (obj) => !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear) + _.isDate: (obj) -> !!(obj and obj.getTimezoneOffset and obj.setUTCFullYear) # Is the given value a regular expression? - _.isRegExp: (obj) => !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false)) + _.isRegExp: (obj) -> !!(obj and obj.exec and (obj.ignoreCase or obj.ignoreCase is false)) # Is the given value NaN -- this one is interesting. NaN != NaN, and # isNaN(undefined) == true, so we make sure it's a number first. - _.isNaN: (obj) => _.isNumber(obj) and window.isNaN(obj) + _.isNaN: (obj) -> _.isNumber(obj) and window.isNaN(obj) # Is a given value equal to null? - _.isNull: (obj) => obj is null + _.isNull: (obj) -> obj is null # Is a given variable undefined? - _.isUndefined: (obj) => typeof obj is 'undefined' + _.isUndefined: (obj) -> typeof obj is 'undefined' # -------------------------- Utility Functions: -------------------------- # Run Underscore.js in noConflict mode, returning the '_' variable to its # previous owner. Returns a reference to the Underscore object. - _.noConflict: => + _.noConflict: -> root._: previousUnderscore this # Keep the identity function around for default iterators. - _.identity: (value) => value + _.identity: (value) -> value # Break out of the middle of an iteration. - _.breakLoop: => throw breaker + _.breakLoop: -> throw breaker # Generate a unique integer id (unique within the entire client session). # Useful for temporary DOM ids. idCounter: 0 - _.uniqueId: (prefix) => + _.uniqueId: (prefix) -> (prefix or '') + idCounter++ # JavaScript templating a-la ERB, pilfered from John Resig's # "Secrets of the JavaScript Ninja", page 83. - _.template: (str, data) => + _.template: (str, data) -> `var fn = new Function('obj', 'var p=[],print=function(){p.push.apply(p,arguments);};' + 'with(obj){p.push(\'' + @@ -555,38 +555,38 @@ # /*------------------------ Setup the OOP Wrapper: --------------------------*/ # Helper function to continue chaining intermediate results. - result: (obj, chain) => + result: (obj, chain) -> if chain then _(obj).chain() else obj # Add all of the Underscore functions to the wrapper object. - _.each _.functions(_), (name) => + _.each _.functions(_), (name) -> method: _[name] - wrapper.prototype[name]: => + wrapper.prototype[name]: -> unshift.call(arguments, this._wrapped) result(method.apply(_, args), this._chain) # Add all mutator Array functions to the wrapper. - _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift']) (name) => + _.each(['pop', 'push', 'reverse', 'shift', 'sort', 'splice', 'unshift']) (name) -> method: Array.prototype[name] - wrapper.prototype[name]: => + wrapper.prototype[name]: -> method.apply(this._wrapped, arguments) result(this._wrapped, this._chain) # Add all accessor Array functions to the wrapper. - _.each(['concat', 'join', 'slice']) (name) => + _.each(['concat', 'join', 'slice']) (name) -> method: Array.prototype[name] - wrapper.prototype[name]: => + wrapper.prototype[name]: -> result(method.apply(this._wrapped, arguments), this._chain) # Start chaining a wrapped Underscore object. - wrapper::chain: => + wrapper::chain: -> this._chain: true this # Extracts the result from a wrapped and chained object. - wrapper::value: => this._wrapped + wrapper::value: -> this._wrapped diff --git a/extras/coffee.vim b/extras/coffee.vim index e0999d89..5235d3cb 100644 --- a/extras/coffee.vim +++ b/extras/coffee.vim @@ -29,7 +29,7 @@ syn match coffeeNumber "-\=\<\d\+L\=\>\|0[xX][0-9a-fA-F]\+\>" syn region coffeeRegexpString start=+/[^/*]+me=e-1 skip=+\\\\\|\\/+ end=+/[gi]\{0,2\}\s*$+ end=+/[gi]\{0,2\}\s*[;.,)\]}]+me=e-1 contains=@htmlPreproc oneline syn match coffeePrototypeAccess "::" -syn match coffeeFunction "=>" +syn match coffeeFunction "->" syn keyword coffeeExtends extends syn keyword coffeeConditional if else switch then diff --git a/index.html b/index.html index 5c8c1eff..1447e18e 100644 --- a/index.html +++ b/index.html @@ -271,7 +271,7 @@ gem install coffee-script -e, --eval Compile and print a little snippet of CoffeeScript directly from the - command line (or from stdin). For example:
coffee -e "square: (x) => x * x" + command line (or from stdin). For example:
coffee -e "square: (x) -> x * x" @@ -353,7 +353,7 @@ coffee --print app/scripts/*.coffee > concatenation.js

Functions and Invocation Functions are defined by a list of parameters, an arrow, and the - function body. The empty function looks like this: =>. All + function body. The empty function looks like this: ->. All functions in CoffeeScript are named by default, for easier debugging.

square: (x) => x * x
@@ -375,7 +375,7 @@ cube = function cube(x) {
 ;alert(cube(5));'>run: cube(5)

If you'd like to create an anonymous function, just wrap it in parentheses: - ((x) => x * x) + ((x) -> x * x)

@@ -1304,7 +1304,7 @@ city = __c[1];

Function binding - The long arrow ==> can be used to both define a function, and to bind + The long arrow => can be used to both define a function, and to bind it to the current value of this, right on the spot. This is helpful when using callback-based libraries like Prototype or jQuery, for creating iterator functions to pass to each, or event-handler functions diff --git a/lib/coffee_script/grammar.y b/lib/coffee_script/grammar.y index 427a1564..06f8f984 100644 --- a/lib/coffee_script/grammar.y +++ b/lib/coffee_script/grammar.y @@ -39,7 +39,7 @@ prechigh left EXTENDS left '||=' '&&=' '?=' right ASSIGN RETURN - right '=>' '==>' UNLESS IF ELSE WHILE + right '->' '=>' UNLESS IF ELSE WHILE preclow rule @@ -207,8 +207,8 @@ rule # The symbols to signify functions, and bound functions. FuncGlyph: - '=>' { result = :func } - | '==>' { result = :boundfunc } + '->' { result = :func } + | '=>' { result = :boundfunc } ; # The parameters to a function definition. diff --git a/lib/coffee_script/lexer.rb b/lib/coffee_script/lexer.rb index df14f0a5..dfda26a9 100644 --- a/lib/coffee_script/lexer.rb +++ b/lib/coffee_script/lexer.rb @@ -27,7 +27,7 @@ module CoffeeScript OPERATOR = /\A([+\*&|\/\-%=<>:!?]+)/ WHITESPACE = /\A([ \t]+)/ COMMENT = /\A(((\n?[ \t]*)?#.*$)+)/ - CODE = /\A(=?=>)/ + CODE = /\A((-|=)>)/ REGEX = /\A(\/(.*?)([^\\]|\\\\)\/[imgy]{0,4})/ MULTI_DENT = /\A((\n([ \t]*))+)(\.)?/ LAST_DENT = /\n([ \t]*)/ diff --git a/lib/coffee_script/narwhal/coffee-script.coffee b/lib/coffee_script/narwhal/coffee-script.coffee index ce0ba011..e9f49649 100644 --- a/lib/coffee_script/narwhal/coffee-script.coffee +++ b/lib/coffee_script/narwhal/coffee-script.coffee @@ -12,14 +12,14 @@ Readline: require('readline') coffeePath: File.path(module.path).dirname().dirname().dirname().dirname().dirname().join('bin', 'coffee') # Our general-purpose error handler. -checkForErrors: (coffeeProcess) => +checkForErrors: (coffeeProcess) -> return true if coffeeProcess.wait() is 0 system.stderr.print(coffeeProcess.stderr.read()) throw new Error("CoffeeScript compile error") # Run a simple REPL, round-tripping to the CoffeeScript compiler for every # command. -exports.run: (args) => +exports.run: (args) -> if args.length for path, i in args exports.evalCS(File.read(path)) @@ -35,24 +35,24 @@ exports.run: (args) => print(e) # Compile a given CoffeeScript file into JavaScript. -exports.compileFile: (path) => +exports.compileFile: (path) -> coffee: OS.popen([coffeePath, "--print", "--no-wrap", path]) checkForErrors(coffee) coffee.stdout.read() # Compile a string of CoffeeScript into JavaScript. -exports.compile: (source, flags) => +exports.compile: (source, flags) -> coffee: OS.popen([coffeePath, "--eval", "--no-wrap"].concat(flags or [])) coffee.stdin.write(source).flush().close() checkForErrors(coffee) coffee.stdout.read() # Evaluating a string of CoffeeScript first compiles it externally. -exports.evalCS: (source, flags) => +exports.evalCS: (source, flags) -> eval(exports.compile(source, flags)) # Make a factory for the CoffeeScript environment. -exports.makeNarwhalFactory: (path) => +exports.makeNarwhalFactory: (path) -> code: exports.compileFile(path) factoryText: "function(require,exports,module,system,print){" + code + "/**/\n}" if system.engine is "rhino" diff --git a/lib/coffee_script/narwhal/loader.coffee b/lib/coffee_script/narwhal/loader.coffee index 6f793a73..5b80e733 100644 --- a/lib/coffee_script/narwhal/loader.coffee +++ b/lib/coffee_script/narwhal/loader.coffee @@ -6,12 +6,12 @@ factories: {} loader: { # Reload the coffee-script environment from source. - reload: (topId, path) => + reload: (topId, path) -> coffeescript ||= require('coffee-script') - factories[topId]: => coffeescript.makeNarwhalFactory(path) + factories[topId]: -> coffeescript.makeNarwhalFactory(path) # Ensure that the coffee-script environment is loaded. - load: (topId, path) => + load: (topId, path) -> factories[topId] ||= this.reload(topId, path) } diff --git a/lib/coffee_script/parser.rb b/lib/coffee_script/parser.rb index cf5821ee..68ae61f8 100644 --- a/lib/coffee_script/parser.rb +++ b/lib/coffee_script/parser.rb @@ -1141,8 +1141,8 @@ racc_token_table = { "&&=" => 87, "?=" => 88, :ASSIGN => 89, - "=>" => 90, - "==>" => 91, + "->" => 90, + "=>" => 91, "\n" => 92, ";" => 93, "," => 94, @@ -1264,8 +1264,8 @@ Racc_token_to_s_table = [ "\"&&=\"", "\"?=\"", "ASSIGN", + "\"->\"", "\"=>\"", - "\"==>\"", "\"\\n\"", "\";\"", "\",\"", diff --git a/lib/coffee_script/rewriter.rb b/lib/coffee_script/rewriter.rb index b3d37338..6c5d60ce 100644 --- a/lib/coffee_script/rewriter.rb +++ b/lib/coffee_script/rewriter.rb @@ -22,7 +22,7 @@ module CoffeeScript IMPLICIT_END = [:IF, :UNLESS, :FOR, :WHILE, "\n", :PARAM_START, :OUTDENT] IMPLICIT_CALL = [:IDENTIFIER, :NUMBER, :STRING, :JS, :REGEX, :NEW, :PARAM_START, :TRY, :DELETE, :INSTANCEOF, :TYPEOF, :SWITCH, :ARGUMENTS, - :TRUE, :FALSE, :YES, :NO, :ON, :OFF, '!', '!!', :NOT, '=>', '==>'] + :TRUE, :FALSE, :YES, :NO, :ON, :OFF, '!', '!!', :NOT, '->', '=>'] # The inverse mappings of token pairs we're trying to fix up. INVERSES = BALANCED_PAIRS.inject({}) do |memo, pair| @@ -33,7 +33,7 @@ module CoffeeScript # Single-line flavors of block expressions that have unclosed endings. # 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, :PARAM_START] # Rewrite the token stream in multiple passes, one logical filter at @@ -193,7 +193,7 @@ module CoffeeScript end # We'd like to support syntax like this: - # el.click((event) => + # el.click((event) -> # el.hide()) # In order to accomplish this, move outdents that follow closing parens # inwards, safely. The steps to accomplish this are: diff --git a/test/fixtures/execution/test_arguments.coffee b/test/fixtures/execution/test_arguments.coffee index 3a3156a9..71a6c9c7 100644 --- a/test/fixtures/execution/test_arguments.coffee +++ b/test/fixtures/execution/test_arguments.coffee @@ -1,4 +1,4 @@ -area: (x, y, x1, y1) => +area: (x, y, x1, y1) -> (x - x1) * (x - y1) x: y: 10 @@ -18,14 +18,14 @@ print(area( # Arguments are turned into arrays. -curried: => +curried: -> print area.apply(this, arguments.concat(20, 20)) is 100 curried 10, 10 # Arguments is not a special keyword -- it can be assigned to: -func: => +func: -> arguments: 25 arguments diff --git a/test/fixtures/execution/test_array_comprehension.coffee b/test/fixtures/execution/test_array_comprehension.coffee index b5005bd6..03c1e1f7 100644 --- a/test/fixtures/execution/test_array_comprehension.coffee +++ b/test/fixtures/execution/test_array_comprehension.coffee @@ -34,7 +34,7 @@ methods: ['one', 'two', 'three'] for method in methods name: method - obj[name]: => + obj[name]: -> "I'm " + name print obj.one() is "I'm one" diff --git a/test/fixtures/execution/test_assignment.coffee b/test/fixtures/execution/test_assignment.coffee index c1b5d127..3fd42dd8 100644 --- a/test/fixtures/execution/test_assignment.coffee +++ b/test/fixtures/execution/test_assignment.coffee @@ -12,7 +12,7 @@ print result is true and result2 is true # Assign to conditional. -get_x: => 10 +get_x: -> 10 if x: get_x() then 100 diff --git a/test/fixtures/execution/test_blocks.coffee b/test/fixtures/execution/test_blocks.coffee index 29ac5296..2efd8aa8 100644 --- a/test/fixtures/execution/test_blocks.coffee +++ b/test/fixtures/execution/test_blocks.coffee @@ -1,4 +1,4 @@ -results: [1, 2, 3].map (x) => +results: [1, 2, 3].map (x) -> x * x print results.join(' ') is '1 4 9' \ No newline at end of file diff --git a/test/fixtures/execution/test_calling_super.coffee b/test/fixtures/execution/test_calling_super.coffee index 61ac4dac..546744b2 100644 --- a/test/fixtures/execution/test_calling_super.coffee +++ b/test/fixtures/execution/test_calling_super.coffee @@ -1,21 +1,21 @@ -Base: => -Base::func: (string) => +Base: -> +Base::func: (string) -> 'zero/' + string -FirstChild: => +FirstChild: -> FirstChild extends Base -FirstChild::func: (string) => +FirstChild::func: (string) -> super('one/') + string -SecondChild: => +SecondChild: -> SecondChild extends FirstChild -SecondChild::func: (string) => +SecondChild::func: (string) -> super('two/') + string -ThirdChild: => +ThirdChild: -> this.array: [1, 2, 3] ThirdChild extends SecondChild -ThirdChild::func: (string) => +ThirdChild::func: (string) -> super('three/') + string result: (new ThirdChild()).func 'four' @@ -23,13 +23,13 @@ result: (new ThirdChild()).func 'four' print result is 'zero/one/two/three/four' -TopClass: (arg) => +TopClass: (arg) -> this.prop: 'top-' + arg -SuperClass: (arg) => +SuperClass: (arg) -> super 'super-' + arg -SubClass: => +SubClass: -> super 'sub' SuperClass extends TopClass diff --git a/test/fixtures/execution/test_chained_calls.coffee b/test/fixtures/execution/test_chained_calls.coffee index e3aab11d..8f0b7043 100644 --- a/test/fixtures/execution/test_chained_calls.coffee +++ b/test/fixtures/execution/test_chained_calls.coffee @@ -1,5 +1,5 @@ -identity_wrap: (x) => - => x +identity_wrap: (x) -> + -> x result: identity_wrap(identity_wrap(true))()() diff --git a/test/fixtures/execution/test_everything.coffee b/test/fixtures/execution/test_everything.coffee index fd5231e4..c6b54b95 100644 --- a/test/fixtures/execution/test_everything.coffee +++ b/test/fixtures/execution/test_everything.coffee @@ -1,4 +1,4 @@ -func: => +func: -> a: 3 b: [] @@ -9,7 +9,7 @@ func: => c: { "text": b other: null - something_else: (x) => x + 5 + something_else: (x) -> x + 5 } c: 'error' unless 42 > 41 diff --git a/test/fixtures/execution/test_existence.coffee b/test/fixtures/execution/test_existence.coffee index 16c64c74..253a8bf2 100644 --- a/test/fixtures/execution/test_existence.coffee +++ b/test/fixtures/execution/test_existence.coffee @@ -26,7 +26,7 @@ print z is null and x is "EX" # Only evaluate once. counter: 0 -get_next_node: => +get_next_node: -> throw "up" if counter counter++ diff --git a/test/fixtures/execution/test_expressions.coffee b/test/fixtures/execution/test_expressions.coffee index e8dea0c5..9686d1a4 100644 --- a/test/fixtures/execution/test_expressions.coffee +++ b/test/fixtures/execution/test_expressions.coffee @@ -5,7 +5,7 @@ items: [1, 2, 3, "bacon", 4, 5] for item in items break if item is "bacon" -findit: (items) => +findit: (items) -> for item in items return item if item is "bacon" @@ -17,7 +17,7 @@ print findit(items) is "bacon" obj: { num: 5 - func: => + func: -> this.result: if false 10 else diff --git a/test/fixtures/execution/test_functions.coffee b/test/fixtures/execution/test_functions.coffee index 79eeb6e4..ecc2ea56 100644 --- a/test/fixtures/execution/test_functions.coffee +++ b/test/fixtures/execution/test_functions.coffee @@ -1,6 +1,6 @@ x: 1 y: {} -y.x: => 3 +y.x: -> 3 print x is 1 print typeof(y.x) is 'function' @@ -9,17 +9,17 @@ print y.x.name is 'x' # The empty function should not cause a syntax error. -=> +-> obj: { name: "Fred" - bound: => - (==> print(this.name is "Fred"))() + bound: -> + (=> print(this.name is "Fred"))() - unbound: => - (=> print(!this.name?))() + unbound: -> + (-> print(!this.name?))() } obj.unbound() @@ -29,18 +29,18 @@ obj.bound() # The named function should be cleared out before a call occurs: # Python decorator style wrapper that memoizes any function -memoize: (fn) => +memoize: (fn) -> cache: {} self: this - (args...) => + (args...) -> key: args.toString() return cache[key] if cache[key] cache[key] = fn.apply(self, args) Math: { - Add: (a, b) => a + b - AnonymousAdd: ((a, b) => a + b) - FastAdd: memoize (a, b) => a + b + Add: (a, b) -> a + b + AnonymousAdd: ((a, b) -> a + b) + FastAdd: memoize (a, b) -> a + b } print Math.Add(5, 5) is 10 @@ -53,5 +53,5 @@ print 100 > 1 if 1 > 0 print true unless false print true for i in [1..3] -print_func: (f) => print(f()) -print_func => true \ No newline at end of file +print_func: (f) -> print(f()) +print_func -> true \ No newline at end of file diff --git a/test/fixtures/execution/test_funky_comments.coffee b/test/fixtures/execution/test_funky_comments.coffee index 8acaafd8..9fbc030e 100644 --- a/test/fixtures/execution/test_funky_comments.coffee +++ b/test/fixtures/execution/test_funky_comments.coffee @@ -1,5 +1,5 @@ # comment -func: => +func: -> # comment false false # comment @@ -14,7 +14,7 @@ switch 'string' when null something_else() -=> +-> code() # comment diff --git a/test/fixtures/execution/test_literals.coffee b/test/fixtures/execution/test_literals.coffee index 3f92a584..c462b565 100644 --- a/test/fixtures/execution/test_literals.coffee +++ b/test/fixtures/execution/test_literals.coffee @@ -1,4 +1,4 @@ -a: [(x) => x, (x) => x * x] +a: [(x) -> x, (x) -> x * x] print a.length is 2 @@ -14,7 +14,7 @@ neg: (3 -4) print neg is -1 -func: => +func: -> return if true print func() is null diff --git a/test/fixtures/execution/test_operations.coffee b/test/fixtures/execution/test_operations.coffee index 9f0d51db..86332804 100644 --- a/test/fixtures/execution/test_operations.coffee +++ b/test/fixtures/execution/test_operations.coffee @@ -13,6 +13,6 @@ print 50 > 10 > 5 is parseInt('5', 10) # more than once. i: 0 -func: => i++ +func: -> i++ print 1 > func() < 1 diff --git a/test/fixtures/execution/test_splats.coffee b/test/fixtures/execution/test_splats.coffee index 58338adc..18083d89 100644 --- a/test/fixtures/execution/test_splats.coffee +++ b/test/fixtures/execution/test_splats.coffee @@ -1,4 +1,4 @@ -func: (first, second, rest...) => +func: (first, second, rest...) -> rest.join ' ' result: func 1, 2, 3, 4, 5 @@ -8,7 +8,7 @@ print result is "3 4 5" gold: silver: bronze: the_field: null -medalists: (first, second, third, rest...) => +medalists: (first, second, third, rest...) -> gold: first silver: second bronze: third diff --git a/test/fixtures/execution/test_switch.coffee b/test/fixtures/execution/test_switch.coffee index a978faf9..3911f043 100644 --- a/test/fixtures/execution/test_switch.coffee +++ b/test/fixtures/execution/test_switch.coffee @@ -16,7 +16,7 @@ result: switch num print result -func: (num) => +func: (num) -> switch num when 2, 4, 6 true diff --git a/test/fixtures/generation/each.coffee b/test/fixtures/generation/each.coffee index 544f96ed..9b76b976 100644 --- a/test/fixtures/generation/each.coffee +++ b/test/fixtures/generation/each.coffee @@ -1,6 +1,6 @@ # The cornerstone, an each implementation. # Handles objects implementing forEach, arrays, and raw objects. -_.each: (obj, iterator, context) => +_.each: (obj, iterator, context) -> index: 0 try if obj.forEach diff --git a/test/fixtures/generation/each.tokens b/test/fixtures/generation/each.tokens index 9244f37d..1f5761c4 100644 --- a/test/fixtures/generation/each.tokens +++ b/test/fixtures/generation/each.tokens @@ -1 +1 @@ -[[:COMMENT, [" The cornerstone, an each implementation.", " Handles objects implementing forEach, arrays, and raw objects."]], ["\n", "\n"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "each"], [:ASSIGN, ":"], [:PARAM_START, "("], [:PARAM, "obj"], [",", ","], [:PARAM, "iterator"], [",", ","], [:PARAM, "context"], [:PARAM_END, ")"], ["=>", "=>"], [:INDENT, 2], [:IDENTIFIER, "index"], [:ASSIGN, ":"], [:NUMBER, "0"], ["\n", "\n"], [:TRY, "try"], [:INDENT, 2], [:IF, "if"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], [:INDENT, 2], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], ["(", "("], [:IDENTIFIER, "iterator"], [",", ","], [:IDENTIFIER, "context"], [")", ")"], [:OUTDENT, 2], [:ELSE, "else"], [:IF, "if"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArray"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:OR, "or"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArguments"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:INDENT, 2], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [:IN, "in"], [:IDENTIFIER, "obj"], [:OUTDENT, 2], [:ELSE, "else"], [:INDENT, 2], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "obj"], ["[", "["], [:IDENTIFIER, "key"], ["]", "]"], [",", ","], [:IDENTIFIER, "key"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "key"], [:IN, "in"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "keys"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:OUTDENT, 2], [:OUTDENT, 2], [:CATCH, "catch"], [:IDENTIFIER, "e"], [:INDENT, 2], [:THROW, "throw"], [:IDENTIFIER, "e"], [:IF, "if"], [:IDENTIFIER, "e"], [:ISNT, "isnt"], [:IDENTIFIER, "breaker"], [:OUTDENT, 2], ["\n", "\n"], [:IDENTIFIER, "obj"], [:OUTDENT, 2], ["\n", "\n"]] \ No newline at end of file +[[:COMMENT, [" The cornerstone, an each implementation.", " Handles objects implementing forEach, arrays, and raw objects."]], ["\n", "\n"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "each"], [:ASSIGN, ":"], [:PARAM_START, "("], [:PARAM, "obj"], [",", ","], [:PARAM, "iterator"], [",", ","], [:PARAM, "context"], [:PARAM_END, ")"], ["->", "->"], [:INDENT, 2], [:IDENTIFIER, "index"], [:ASSIGN, ":"], [:NUMBER, "0"], ["\n", "\n"], [:TRY, "try"], [:INDENT, 2], [:IF, "if"], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], [:INDENT, 2], [:IDENTIFIER, "obj"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "forEach"], ["(", "("], [:IDENTIFIER, "iterator"], [",", ","], [:IDENTIFIER, "context"], [")", ")"], [:OUTDENT, 2], [:ELSE, "else"], [:IF, "if"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArray"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:OR, "or"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "isArguments"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:INDENT, 2], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "item"], [",", ","], [:IDENTIFIER, "i"], [:IN, "in"], [:IDENTIFIER, "obj"], [:OUTDENT, 2], [:ELSE, "else"], [:INDENT, 2], [:IDENTIFIER, "iterator"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "call"], ["(", "("], [:IDENTIFIER, "context"], [",", ","], [:IDENTIFIER, "obj"], ["[", "["], [:IDENTIFIER, "key"], ["]", "]"], [",", ","], [:IDENTIFIER, "key"], [",", ","], [:IDENTIFIER, "obj"], [")", ")"], [:FOR, "for"], [:IDENTIFIER, "key"], [:IN, "in"], [:IDENTIFIER, "_"], [:PROPERTY_ACCESS, "."], [:IDENTIFIER, "keys"], ["(", "("], [:IDENTIFIER, "obj"], [")", ")"], [:OUTDENT, 2], [:OUTDENT, 2], [:CATCH, "catch"], [:IDENTIFIER, "e"], [:INDENT, 2], [:THROW, "throw"], [:IDENTIFIER, "e"], [:IF, "if"], [:IDENTIFIER, "e"], [:ISNT, "isnt"], [:IDENTIFIER, "breaker"], [:OUTDENT, 2], ["\n", "\n"], [:IDENTIFIER, "obj"], [:OUTDENT, 2], ["\n", "\n"]] \ No newline at end of file diff --git a/test/fixtures/generation/statements_as_expressions.coffee b/test/fixtures/generation/statements_as_expressions.coffee index a9ddccb0..56baa374 100644 --- a/test/fixtures/generation/statements_as_expressions.coffee +++ b/test/fixtures/generation/statements_as_expressions.coffee @@ -10,7 +10,7 @@ catch error 3 ) -func: (x) => +func: (x) -> return throw x print(x * x for x in [1..100]) \ No newline at end of file diff --git a/test/fixtures/generation/whitespace.coffee b/test/fixtures/generation/whitespace.coffee index 94f816d4..781af19b 100644 --- a/test/fixtures/generation/whitespace.coffee +++ b/test/fixtures/generation/whitespace.coffee @@ -1,20 +1,20 @@ # test -f1: (x) => +f1: (x) -> x * x - f2: (y) => + f2: (y) -> y * x f3: 3 # Parens can close on the proper level. -elements.each((el) => - el.click((event) => +elements.each((el) -> + el.click((event) -> el.reset() el.show() if event.active ) ) # Or, parens can close blocks early. -elements.each((el) => - el.click((event) => +elements.each((el) -> + el.click((event) -> el.reset() el.show() if event.active)) \ No newline at end of file diff --git a/test/unit/test_lexer.rb b/test/unit/test_lexer.rb index e9f10ac9..568d2986 100644 --- a/test/unit/test_lexer.rb +++ b/test/unit/test_lexer.rb @@ -25,10 +25,10 @@ class LexerTest < Test::Unit::TestCase end def test_lexing_function_definition - code = "(x, y) => x * y" + code = "(x, y) -> x * y" assert @lex.tokenize(code) == [[:PARAM_START, "("], [:PARAM, "x"], [",", ","], [:PARAM, "y"], [:PARAM_END, ")"], - ["=>", "=>"], [:INDENT, 2], [:IDENTIFIER, "x"], ["*", "*"], + ["->", "->"], [:INDENT, 2], [:IDENTIFIER, "x"], ["*", "*"], [:IDENTIFIER, "y"], [:OUTDENT, 2], ["\n", "\n"]] end diff --git a/test/unit/test_parser.rb b/test/unit/test_parser.rb index 8e8738ff..1a95ae84 100644 --- a/test/unit/test_parser.rb +++ b/test/unit/test_parser.rb @@ -29,7 +29,7 @@ class ParserTest < Test::Unit::TestCase end def test_parsing_an_function_definition - code = @par.parse("(x, y) => x * y").expressions.first + code = @par.parse("(x, y) -> x * y").expressions.first assert code.params == ['x', 'y'] body = code.body.expressions.first assert body.is_a?(OpNode)