summaryrefslogtreecommitdiff
path: root/test/ripper/test_sexp.rb
blob: 064c0f1536cbdaade408e90950a6d1127a636e5f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# frozen_string_literal: true
begin
  require 'ripper'
  require 'test/unit'
  ripper_test = true
  module TestRipper; end
rescue LoadError
end

class TestRipper::Sexp < Test::Unit::TestCase
  def test_compile_error
    assert_nil Ripper.sexp("/")
    assert_nil Ripper.sexp("-")
    assert_nil Ripper.sexp("+")
    assert_nil Ripper.sexp("*")
    assert_nil Ripper.sexp("end")
    assert_nil Ripper.sexp("end 1")
    assert_nil Ripper.sexp("/*")
    assert_nil Ripper.sexp("/*/")
    assert_nil Ripper.sexp("/+/")
  end

  def test_regexp_content
    sexp = Ripper.sexp('//')
    assert_nil search_sexp(:@tstring_content, search_sexp(:regexp_literal, sexp))

    sexp = Ripper.sexp('/foo/')
    assert_equal 'foo', search_sexp(:@tstring_content, search_sexp(:regexp_literal, sexp))[1]

    sexp = Ripper.sexp("/foo\nbar/")
    assert_equal "foo\nbar", search_sexp(:@tstring_content, search_sexp(:regexp_literal, sexp))[1]

    sexp = Ripper.sexp('/(?<n>a(b|\g<n>))/')
    assert_equal '(?<n>a(b|\g<n>))', search_sexp(:@tstring_content, search_sexp(:regexp_literal, sexp))[1]
  end

  def test_heredoc_content
    sexp = Ripper.sexp("<<E\nfoo\nE")
    assert_equal "foo\n", search_sexp(:@tstring_content, sexp)[1]
  end

  def test_squiggly_heredoc
    sexp = Ripper.sexp("<<~eot\n      asdf\neot")
    assert_equal "asdf\n", search_sexp(:@tstring_content, sexp)[1]
  end

  def test_squiggly_heredoc_with_interpolated_expression
    sexp1 = Ripper.sexp(<<-eos)
<<-eot
a\#{1}z
eot
    eos

    sexp2 = Ripper.sexp(<<-eos)
<<~eot
  a\#{1}z
eot
    eos

    assert_equal clear_pos(sexp1), clear_pos(sexp2)
  end

  def test_params_mlhs
    sexp = Ripper.sexp("proc {|(w, *x, y), z|}")
    _, ((mlhs, w, (rest, x), y), z) = search_sexp(:params, sexp)
    assert_equal(:mlhs, mlhs)
    assert_equal(:@ident, w[0])
    assert_equal("w", w[1])
    assert_equal(:rest_param, rest)
    assert_equal(:@ident, x[0])
    assert_equal("x", x[1])
    assert_equal(:@ident, y[0])
    assert_equal("y", y[1])
    assert_equal(:@ident, z[0])
    assert_equal("z", z[1])
  end

  def test_def_fname
    sexp = Ripper.sexp("def t; end")
    _, (type, fname,) = search_sexp(:def, sexp)
    assert_equal(:@ident, type)
    assert_equal("t", fname)

    sexp = Ripper.sexp("def <<; end")
    _, (type, fname,) = search_sexp(:def, sexp)
    assert_equal(:@op, type)
    assert_equal("<<", fname)
  end

  def test_defs_fname
    sexp = Ripper.sexp("def self.t; end")
    _, recv, _, (type, fname) = search_sexp(:defs, sexp)
    assert_equal(:var_ref, recv[0], recv)
    assert_equal([:@kw, "self", [1, 4]], recv[1], recv)
    assert_equal(:@ident, type)
    assert_equal("t", fname)
  end

  def test_named_with_default
    sexp = Ripper.sexp("def hello(bln: true, int: 1, str: 'str', sym: :sym) end")
    named = String.new
    search_sexp(:params, sexp)[5].each { |i| named << "#{i}\n" }  # join flattens
    exp = "#{<<-"{#"}#{<<~'};'}"
    {#
      [[:@label, "bln:", [1, 10]], [:var_ref, [:@kw, "true", [1, 15]]]]
      [[:@label, "int:", [1, 21]], [:@int, "1", [1, 26]]]
      [[:@label, "str:", [1, 29]], [:string_literal, [:string_content, [:@tstring_content, "str", [1, 35]]]]]
      [[:@label, "sym:", [1, 41]], [:symbol_literal, [:symbol, [:@ident, "sym", [1, 47]]]]]
    };
    assert_equal(exp, named)
  end

  def search_sexp(sym, sexp)
    return sexp if !sexp or sexp[0] == sym
    sexp.find do |e|
      if Array === e and e = search_sexp(sym, e)
        return e
      end
    end
  end

  def clear_pos(sexp)
    return sexp if !sexp
    sexp.each do |e|
      if Array === e
        if e.size == 3 and Array === (last = e.last) and
          last.size == 2 and Integer === last[0] and Integer === last[1]
          last.clear
        else
          clear_pos(e)
        end
      end
    end
  end
end if ripper_test