From 817e8deb2704b89d5e7106f81188e68be6ae900c Mon Sep 17 00:00:00 2001 From: Jeremy Ashkenas Date: Sun, 24 Jan 2010 12:52:15 -0500 Subject: [PATCH] adding soaked method calls, with caching --- examples/computer_science/README | 4 +++ .../computer_science/binary_search.coffee | 25 +++++++++++++++++++ examples/computer_science/bubble_sort.coffee | 11 ++++++++ lib/coffee_script/nodes.rb | 12 +++++++-- test/fixtures/execution/test_existence.coffee | 12 ++++++++- test/unit/test_execution.rb | 3 ++- 6 files changed, 63 insertions(+), 4 deletions(-) create mode 100644 examples/computer_science/README create mode 100644 examples/computer_science/binary_search.coffee create mode 100644 examples/computer_science/bubble_sort.coffee diff --git a/examples/computer_science/README b/examples/computer_science/README new file mode 100644 index 00000000..1046f9f9 --- /dev/null +++ b/examples/computer_science/README @@ -0,0 +1,4 @@ +Ported from Nicholas Zakas' collection of computer science fundamentals, written +in JavaScript. Originals available here: + +http://github.com/nzakas/computer-science-in-javascript diff --git a/examples/computer_science/binary_search.coffee b/examples/computer_science/binary_search.coffee new file mode 100644 index 00000000..e5447fa4 --- /dev/null +++ b/examples/computer_science/binary_search.coffee @@ -0,0 +1,25 @@ +# Uses a binary search algorithm to locate a value in the specified array. +binary_search: items, value => + + start: 0 + stop: items.length - 1 + pivot: Math.floor((start + stop) / 2) + + while items[pivot] isnt value and start < stop + + # Adjust the search area. + stop: pivot - 1 if value < items[pivot] + start: pivot + 1 if value > items[pivot] + + # Recalculate the pivot. + pivot: Math.floor((stop + start) / 2) + + # Make sure we've found the correct value. + if items[pivot] is value then pivot else -1 + + +# Test the function. +print(2 is binary_search([10, 20, 30, 40, 50], 30)) +print(4 is binary_search([-97, 35, 67, 88, 1200], 1200)) +print(0 is binary_search([0, 45, 70], 0)) +print(-1 is binary_search([0, 45, 70], 10)) \ No newline at end of file diff --git a/examples/computer_science/bubble_sort.coffee b/examples/computer_science/bubble_sort.coffee new file mode 100644 index 00000000..f5578780 --- /dev/null +++ b/examples/computer_science/bubble_sort.coffee @@ -0,0 +1,11 @@ +# A bubble sort implementation, sorting the given array in-place. +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] + list + + +# Test the function. +print(bubble_sort([3, 2, 1]).join(' ') is '1 2 3') +print(bubble_sort([9, 2, 7, 0, 1]).join(' ') is '0 1 2 7 9') \ No newline at end of file diff --git a/lib/coffee_script/nodes.rb b/lib/coffee_script/nodes.rb index 8f7cb20f..77016db4 100644 --- a/lib/coffee_script/nodes.rb +++ b/lib/coffee_script/nodes.rb @@ -332,6 +332,9 @@ module CoffeeScript children :base, :properties attr_reader :last, :source + # Soak up undefined properties and call attempts. + SOAK = " == undefined ? undefined : " + def initialize(base, properties=[]) @base, @properties = base, [properties].flatten end @@ -375,14 +378,19 @@ module CoffeeScript props.each do |prop| if prop.is_a?(AccessorNode) && prop.soak soaked = true - parts[-1] << " == undefined ? undefined : #{baseline += prop.compile(o)}" + if @base.is_a?(CallNode) && prop == props.first + temp = o[:scope].free_variable + parts[-1] = "(#{temp} = #{baseline})#{SOAK}#{baseline = temp.to_s + prop.compile(o)}" + else + parts[-1] << "#{SOAK}#{baseline += prop.compile(o)}" + end else parts << prop.compile(o) end end @last = parts.last @source = parts.length > 1 ? parts[0...-1].join('') : nil - code = parts.join('') + code = parts.join('').gsub(')())', '()))') write(soaked ? "(#{code})" : code) end end diff --git a/test/fixtures/execution/test_existence.coffee b/test/fixtures/execution/test_existence.coffee index 22720631..a532b8e7 100644 --- a/test/fixtures/execution/test_existence.coffee +++ b/test/fixtures/execution/test_existence.coffee @@ -41,4 +41,14 @@ obj: { print(obj?.prop is "hello") -print(obj?.prop?.non?.existent?.property is undefined) \ No newline at end of file +print(obj?.prop?.non?.existent?.property is undefined) + + +# Soaks and caches method calls as well. + +arr: ["--", "----"] + +print(arr.pop()?.length is 4) +print(arr.pop()?.length is 2) +print(arr.pop()?.length is undefined) +print(arr.pop()?.length?.non?.existent()?.property is undefined) diff --git a/test/unit/test_execution.rb b/test/unit/test_execution.rb index 81db6a6d..8eea7479 100644 --- a/test/unit/test_execution.rb +++ b/test/unit/test_execution.rb @@ -6,7 +6,8 @@ class ExecutionTest < Test::Unit::TestCase SOURCES = [ 'test/fixtures/execution/*.coffee', - 'examples/beautiful_code/*.coffee' + 'examples/beautiful_code/*.coffee', + 'examples/computer_science/*.coffee' ] # This is by far the most important test. It evaluates all of the