Coerce elements which respond to #to_ary for Array#flatten
[rbx.git] / spec / parser / sexp_spec.rb
blobfa99dafd8d1f5df6aea8d1e8655a26f001c13785
1 require File.dirname(__FILE__) + '/../spec_helper'
2 require File.dirname(__FILE__) + '/fixtures/sexp_expectations'
4 class String
5   alias :old_to_sexp :to_sexp
6   def to_sexp
7     old_to_sexp('test', 1, false)
8   end
9 end
11 describe "Shotgun" do
12   it "converts a number to an sexp" do
13     "834234".to_sexp.should == [:lit, 834234]
14   end
16   it "converts a regexp to an sexp" do
17     "/blah/".to_sexp.should == [:regex, "blah", 0]
18     "/blah/i".to_sexp.should == [:regex, "blah", 1]
19     "/blah/u".to_sexp.should == [:regex, "blah", 64]
20   end
22   it "converts a string to an sexp" do
23     "\"hello\"".to_sexp.should == [:str, "hello"]
24   end
26   it "converts a local var to an sexp" do
27     "a = 1; a".to_sexp.should ==
28       [:block, [:lasgn, :a, [:lit, 1]], [:lvar, :a, 0]]
29   end
31   it "converts an instance variable to an sexp" do
32     "@blah".to_sexp.should == [:ivar, :@blah]
33   end
35   it "converts an instance variable assignment to an sexp" do
36     "@blah = 1".to_sexp.should == [:iasgn, :@blah, [:lit, 1]]
37   end
39   it "converts a global variable to an sexp" do
40     "$blah".to_sexp.should == [:gvar, :$blah]
41   end
43   it "converts a global variable assignment to an sexp" do
44     "$blah = 1".to_sexp.should == [:gasgn, :$blah, [:lit, 1]]
45   end
47   it "converts a symbol to an sexp" do
48     ":blah".to_sexp.should == [:lit, :blah]
49   end
51   it "converts a string expansion to an sexp" do
52     'a = 1; "hello #{a}, you rock."'.to_sexp.should ==
53       [:block,
54         [:lasgn, :a, [:lit, 1]],
55         [:dstr, "hello ", [:evstr, [:lvar, :a, 0]],
56         [:str, ", you rock."]]]
57   end
59   it "converts a pathological string expansion to an sexp" do
60     '@thing = 5; "hello #@thing, you are crazy."'.to_sexp.should ==
61       [:block,
62         [:iasgn, :@thing, [:lit, 5]],
63         [:dstr, "hello ", [:evstr, [:ivar, :@thing]],
64         [:str, ", you are crazy."]]]
65   end
67   it "converts a method definition without arguments to an sexp" do
68     "def name; 1; end".to_sexp.should == [:defn, :name, [:scope, [:block, [:args], [:lit, 1]], []]]
69   end
71   it "converts a method definition with arguments to an sexp" do
72     "def name(a, b); 1; end".to_sexp.should ==
73       [:defn, :name,
74         [:scope, [:block, [:args, [:a, :b], [], nil, nil], [:lit, 1]], [:a, :b]]]
75   end
77   it "converts a class definition to an sexp" do
78     "class Blah < A::B; end".to_sexp.should ==
79       [:class,
80         [:colon2, :Blah], [:colon2, [:const, :A], :B], [:scope, []]]
81   end
83   it "converts a heredoc to an sexp" do
84       "a = <<-BLAH
85       hello
86       BLAH
87       ".to_sexp.should == [:lasgn, :a, [:str, "      hello\n"]]
88   end
89 end
91 def rewrite_expected array
92   case array.first
93   when :alias, :undef then
94     array[1..-1] = array[1..-1].map { |lit| lit.last }
95   when :dasgn_curr then
96     array[0] = :lasgn
97   when :dasgn then
98     array[0] = :lasgn
99   when :dvar then
100     array[0] = :lvar
101   when :class, :module then
102     name = array[1]
103     name = [:colon2, name] unless Array === name and name[0] == :colon2
104     array[1] = name
105     array[-1] << []      # no clue
106   when :lit then
107     case array[1]
108     when Regexp then
109       regexp = array[1]
110       offset = /./.options
111       array[0..-1] = [:regex, regexp.source] # FIX: add options
112     when Range then
113       range = array[1]
114       type = range.exclude_end? ? :dot3 : :dot2
115       array[0..-1] = [type, [:lit, range.begin], [:lit, range.end]] # FIX
116     end
117   when :yield then
118     array << true
119   when :resbody then
120     until array.size >= 3 do
121       array << nil << nil
122     end
123   end
125   array = array.map { |item|
126     if Array === item then
127       rewrite_expected(item)
128     else
129       item
130     end
131   }
133   array
136 def rewrite_actual array
137   case array.first
138   when :alias then
139     array[-2..-1] = array[-2..-1].reverse
140   when :args then
141     array = array.flatten.compact.map { |o| o == true ? :* : o }
142   when :back_ref then
143     array[-1] = array[-1].chr.to_sym
144   when :block then
145     array = array[2] if array.size == 3 and array[1][0] == :dasgn_curr
146   when :defn, :defs then
147     array[-1].pop # remove local vars list
148   when :lvar then
149     array.pop # remove index
150   when :negate then
151     array = array[1]
152     array[-1] = -array[-1]
153   when :regex then
154     array.pop # TODO: add options
155   when :dasgn then
156     array[0] = :lasgn
157   when :fixnum then
158     array[0] = :lit
159   when :match then
160     array = [:match, [:regex, *array[1..-1]]]
161   end
163   array = array.map { |item|
164     if Array === item then
165       rewrite_actual(item)
166     else
167       item
168     end
169   }
171   array
174 describe "String#to_sexp" do
175   SEXP_EXPECTATIONS.each do |node, hash|
176     it "parses :#{node}" do
177       expected = rewrite_expected(hash['ParseTree'])
178       actual = rewrite_actual(hash['Ruby'].to_sexp)
179       expected.should == actual
180     end
181   end