Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: utkarshkukreti/calvin
base: 6ceb572ccd31a4e5ddbb8b36c0eb87ff5e415195
...
head fork: utkarshkukreti/calvin
compare: a1fa2ff60abe8af7487e614b48f32f98ffe5e832
  • 1 commit
  • 4 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 26, 2012
@utkarshkukreti Make a custom AST::Range class, for a range that supports negative step.
Heavy use of modules and duck typing.
a1fa2ff
View
3  lib/calvin.rb
@@ -4,7 +4,10 @@
require "calvin/core"
require "calvin/parser"
require "calvin/transform"
+
require "calvin/ast"
+require "calvin/ast/range"
+
require "calvin/evaluator"
require "calvin/helpers"
View
30 lib/calvin/ast/range.rb
@@ -0,0 +1,30 @@
+module Calvin
+ class AST
+ class Range
+ include Enumerable
+
+ attr_accessor :first, :last
+
+ def initialize(first, last)
+ @first = first
+ @last = last
+ end
+
+ def each
+ method = @first > @last ? :downto : :upto
+ @first.send(method, @last) do |i|
+ yield i
+ end
+ end
+
+ def size
+ 1 + (@first - @last).abs
+ end
+
+ def ==(other)
+ other.respond_to?(:first) && other.first == @first &&
+ other.respond_to?(:last) && other.last == @last
+ end
+ end
+ end
+end
View
18 lib/calvin/evaluator.rb
@@ -17,16 +17,12 @@ def initialize
rule range: { first: simple(:first), last: simple(:last) } do
if first
- if last >= first
- first..last
- else
- raise ArgumentError.new "`first` should be less than or equal to `last`. You passed in #{first} and #{last}."
- end
+ AST::Range.new first, last
else
if last >= 0
- 0..(last - 1)
+ AST::Range.new 0, last - 1
else
- raise ArgumentError.new "`last` should be greater than 0. You passed in #{last}."
+ raise ArgumentError.new "`last` should be greater than 0 when `first` isn't specified. You passed in #{last}."
end
end
end
@@ -71,8 +67,7 @@ module Helpers
extend self
def apply(fn, object)
- object = object.to_a if object.respond_to?(:to_a)
- if object.is_a?(Array)
+ if object.respond_to?(:map)
object.map { |el| apply(fn, el) }
else
fn.call object
@@ -95,10 +90,7 @@ def apply_dyad(fn, left, right)
end
def apply_each(fn, left, right)
- left = left.to_a if left.respond_to?(:to_a)
- right = right.to_a if right.respond_to?(:to_a)
-
- if left.is_a?(Array) && right.is_a?(Array)
+ if left.respond_to?(:map) && right.respond_to?(:map)
if left.size == right.size
left.zip(right).map do |l, r|
apply_each(fn, l, r)
View
6 spec/evaluator_spec.rb
@@ -171,14 +171,18 @@ def e(num); Math::E ** num; end
eval1("-10..10").should eq -10..10
end
+ it "should parse reverse ranges" do
+ eval1("5..-5").should eq 5..-5
+ end
+
it "should not parse invalid ranges" do
- expect { eval1("5..-5") }.to raise_exception
expect { eval1("..-5") }.to raise_exception
end
it "should treat ranges as arrays when required" do
eval1("1..4 + 5 6 7 8 - 2..5").should eq [4, 5, 6, 7]
eval1("..100 - ..100").should eq [0] * 100
+ eval1("10..-10 - 20..0").should eq [-10] * 21
end
end

No commit comments for this range

Something went wrong with that request. Please try again.