Class: Solid::Parser::Ripper

Inherits:
Solid::Parser show all
Defined in:
lib/solid/parser/ripper.rb

Constant Summary collapse

REGEXP_FLAGS =
{
  'i' => Regexp::IGNORECASE,
  'x' => Regexp::EXTENDED,
  'm' => Regexp::MULTILINE,
  'n' => Regexp::NOENCODING
}

Constants inherited from Solid::Parser

BASE_PATH, KEYWORDS

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(string) ⇒ Ripper

Returns a new instance of Ripper.



7
8
9
10
# File 'lib/solid/parser/ripper.rb', line 7

def initialize(string)
  @string = string
  @sexp = nil
end

Class Method Details

.parse(string) ⇒ Object



3
4
5
# File 'lib/solid/parser/ripper.rb', line 3

def self.parse(string)
  new(string).parse
end

Instance Method Details

#dive_inObject

Looks for a structure like

:program, [[:array, [#stuff#]]]

or

:program, [[:array, nil]]


21
22
23
24
# File 'lib/solid/parser/ripper.rb', line 21

def dive_in
  @sexp = @sexp[1]
  @sexp = @sexp.first
end

#handle_array(array) ⇒ Object

# [1]

[:@int, “1”, [1, 1]


115
116
117
# File 'lib/solid/parser/ripper.rb', line 115

def handle_array(array)
  LiteralArray.new((array || []).map(&method(:parse_one)))
end

#handle_bare_assoc_hash(assoc_hash) ⇒ Object

# foo: 42

[:assoc_new, [:@label, “foo:”, [1, 1]], [:@int, “42”, [1, 5]]]


43
44
45
# File 'lib/solid/parser/ripper.rb', line 43

def handle_bare_assoc_hash(assoc_hash)
  LiteralHash.new assoc_hash.map {|(_, *key_value)| key_value.map(&method(:parse_one)) }
end

#handle_binary(left_operand, operator, right_operand) ⇒ Object

# 1 + 2

:@int, “1”, [1, 0]], :*, [:@int, “2”, [1, 4]


108
109
110
111
# File 'lib/solid/parser/ripper.rb', line 108

def handle_binary(left_operand, operator, right_operand)
  receiver = parse_one(left_operand)
  MethodCall.new(receiver, operator, [parse_one(right_operand)])
end

#handle_call(receiver_sexp, method_call, method_sexp) ⇒ Object

# myvar.length

:var_ref, [:@ident, “myvar”, [1, 1]]

:“.”

:@ident, “length”, [1, 7]


59
60
61
62
63
# File 'lib/solid/parser/ripper.rb', line 59

def handle_call(receiver_sexp, method_call, method_sexp)
  receiver = parse_one(receiver_sexp)
  method = method_sexp[1]
  MethodCall.new receiver, method, []
end

#handle_const(constant, lineno_column) ⇒ Object

# Spam “Spam”, [1, 23]



198
199
200
# File 'lib/solid/parser/ripper.rb', line 198

def handle_const(constant, lineno_column)
  ContextVariable.new constant
end

#handle_dot2(start_value, end_value) ⇒ Object

# 1..10

[:@int, “1”, [1, 0]], [:@int, “10”, [1, 4]]


127
128
129
# File 'lib/solid/parser/ripper.rb', line 127

def handle_dot2(start_value, end_value)
  LiteralRange.new(parse_one(start_value), parse_one(end_value), false)
end

#handle_dot3(start_value, end_value) ⇒ Object

# 1…10

[:@int, “1”, [1, 0]], [:@int, “10”, [1, 4]]


133
134
135
# File 'lib/solid/parser/ripper.rb', line 133

def handle_dot3(start_value, end_value)
  LiteralRange.new(parse_one(start_value), parse_one(end_value), true)
end

#handle_dyna_symbol(string_content) ⇒ Object



153
154
155
# File 'lib/solid/parser/ripper.rb', line 153

def handle_dyna_symbol(string_content)
  Literal.new(string_content.first[1])
end

#handle_float(float, lineno_column) ⇒ Object

# 4.2 “4.2”, [1, 2]



210
211
212
# File 'lib/solid/parser/ripper.rb', line 210

def handle_float(float, lineno_column)
  Literal.new float.to_f
end

#handle_hash(hash) ⇒ Object

# 42

:assoclist_from_args, [[:assoc_new, [:@label, “foo:”, [1, 2]], [:@int, “42”, [1, 7]]]]


49
50
51
52
# File 'lib/solid/parser/ripper.rb', line 49

def handle_hash(hash)
  return LiteralHash.new({}) unless hash
  handle_bare_assoc_hash(hash.last)
end

#handle_ident(identifier, lineno_column) ⇒ Object

# spam “spam”, [1, 23]



192
193
194
# File 'lib/solid/parser/ripper.rb', line 192

def handle_ident(identifier, lineno_column)
  ContextVariable.new identifier
end

#handle_int(int, lineno_column) ⇒ Object

# 42 “42”, [1, 2]



204
205
206
# File 'lib/solid/parser/ripper.rb', line 204

def handle_int(int, lineno_column)
  Literal.new int.to_i
end

#handle_kw(keyword, lineno_column) ⇒ Object

# true “true”, [1, 33]

Raises:



185
186
187
188
# File 'lib/solid/parser/ripper.rb', line 185

def handle_kw(keyword, lineno_column)
  raise Solid::SyntaxError, 'unknown Ripper sexp' unless KEYWORDS.has_key? keyword
  KEYWORDS[keyword]
end

#handle_label(label, lineno_column) ⇒ Object

# foo: “foo:”, [1, 2]



216
217
218
# File 'lib/solid/parser/ripper.rb', line 216

def handle_label(label, lineno_column)
  Literal.new label[0..-2].to_sym
end

#handle_method_add_arg(call_sexp, args_sexp) ⇒ Object

# myvar.split(‘,’, 2)

:call, [:var_ref, [:@ident, “myvar”, [1, 1]]], :“.”, [:@ident, “split”, [1, 7]]

[:arg_paren, [:args_add_block, [

  [:string_literal, [:string_content, [:@tstring_content, ",", [1, 14]]]],
  [:@int, "2", [1, 18]]
], false]]


80
81
82
83
84
# File 'lib/solid/parser/ripper.rb', line 80

def handle_method_add_arg(call_sexp, args_sexp)
  method_call = parse_one(call_sexp)
  method_call.arguments = method_call_args(args_sexp)
  method_call
end

#handle_paren(content) ⇒ Object

# (1)

[:@int, “42”, [1, 2]]


121
122
123
# File 'lib/solid/parser/ripper.rb', line 121

def handle_paren(content)
  parse_one(content.first)
end

#handle_regexp_literal(regexp_content, regexp_end) ⇒ Object

TODO: handle regexp interpolation



179
180
181
# File 'lib/solid/parser/ripper.rb', line 179

def handle_regexp_literal(regexp_content, regexp_end)
  Literal.new instanciate_regexp(regexp_content.first[1], regexp_end[1][1..-1])
end

#handle_string_content(*parts) ⇒ Object



144
145
146
# File 'lib/solid/parser/ripper.rb', line 144

def handle_string_content(*parts)
  parts.map(&method(:parse_one)).join
end

#handle_string_literal(string_content) ⇒ Object

# ‘mystring’

:string_content, [:@tstring_content, “mystring”, [1, 14]]

TODO: handle string interpolation



140
141
142
# File 'lib/solid/parser/ripper.rb', line 140

def handle_string_literal(string_content)
  Literal.new(parse_one(string_content))
end

#handle_tstring_content(string_content, lineno_column) ⇒ Object

:@tstring_content, “mystring”, [1, 14]


149
150
151
# File 'lib/solid/parser/ripper.rb', line 149

def handle_tstring_content(string_content, lineno_column)
  string_content
end

#handle_unary(operator, operand) ⇒ Object

# !true

:!, [:var_ref, [:@kw, “true”, [1, 1]]]


102
103
104
# File 'lib/solid/parser/ripper.rb', line 102

def handle_unary(operator, operand)
  MethodCall.new(parse_one(operand), operator, [])
end

#handle_var_ref(var_ref) ⇒ Object

# spam

:@ident, “spam”, [1, 33]

or

# true

:@kw, “true”, [1, 23]


37
38
39
# File 'lib/solid/parser/ripper.rb', line 37

def handle_var_ref(var_ref)
  parse_one(var_ref)
end

#handle_vcall(expression) ⇒ Object

# myvar

since 1.9.3

:vcall, [:@ident, “myvar”, [1, 0]]


69
70
71
# File 'lib/solid/parser/ripper.rb', line 69

def handle_vcall(expression)
  parse_one(expression)
end

#instanciate_regexp(content, flags) ⇒ Object



164
165
166
167
168
169
170
# File 'lib/solid/parser/ripper.rb', line 164

def instanciate_regexp(content, flags)
  mode = 0
  flags.each_char do |flag|
    mode |= REGEXP_FLAGS[flag] || 0
  end
  Regexp.new(content, mode)
end

#method_call_args(args_sexp) ⇒ Object

# args list: (‘,’, 2) [:arg_paren, [:args_add_block, [

  [:string_literal, [:string_content, [:@tstring_content, ",", [1, 14]]]],
  [:@int, "2", [1, 18]]
], false]]

1 args list: ()

:arg_paren, nil


94
95
96
97
98
# File 'lib/solid/parser/ripper.rb', line 94

def method_call_args(args_sexp)
  return [] if args_sexp[1].nil?
  args_sexp = args_sexp.last[1]
  args_sexp.map(&method(:parse_one))
end

#parseObject



12
13
14
15
16
# File 'lib/solid/parser/ripper.rb', line 12

def parse
  @sexp = ::Ripper.sexp(@string)
  dive_in or raise 'Ripper changed?'
  parse_one(@sexp)
end

#parse_one(argument) ⇒ Object

Raises:



26
27
28
29
30
31
# File 'lib/solid/parser/ripper.rb', line 26

def parse_one(argument)
  type = argument.shift
  handler = "handle_#{type.to_s.sub('@', '')}"
  raise Solid::SyntaxError, "unknown Ripper type: #{type.inspect}" unless respond_to?(handler)
  public_send handler, *argument
end