Class: Solid::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/solid/parser.rb

Defined Under Namespace

Classes: ContextVariable, Literal, LiteralArray, LiteralHash, LiteralRange, MethodCall

Constant Summary collapse

KEYWORDS =
{
  'true' => Literal.new(true),
  'false' => Literal.new(false),
  'nil' => Literal.new(nil),
}

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(string) ⇒ Parser

Returns a new instance of Parser.



71
72
73
74
# File 'lib/solid/parser.rb', line 71

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

Class Method Details

.parse(string) ⇒ Object



65
66
67
# File 'lib/solid/parser.rb', line 65

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

Instance Method Details

#dive_inObject

Looks for a structure like

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

or

:program, [[:array, nil]]


85
86
87
88
# File 'lib/solid/parser.rb', line 85

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

#handle_array(array) ⇒ Object

# [1]

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


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

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]]]


107
108
109
# File 'lib/solid/parser.rb', line 107

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]


171
172
173
174
# File 'lib/solid/parser.rb', line 171

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]


122
123
124
125
126
# File 'lib/solid/parser.rb', line 122

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]



247
248
249
# File 'lib/solid/parser.rb', line 247

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]]


190
191
192
# File 'lib/solid/parser.rb', line 190

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]]


196
197
198
# File 'lib/solid/parser.rb', line 196

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



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

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]



259
260
261
# File 'lib/solid/parser.rb', line 259

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]]]]


113
114
115
# File 'lib/solid/parser.rb', line 113

def handle_hash(hash)
  handle_bare_assoc_hash(hash.last)
end

#handle_ident(identifier, lineno_column) ⇒ Object

# spam “spam”, [1, 23]



241
242
243
# File 'lib/solid/parser.rb', line 241

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

#handle_int(int, lineno_column) ⇒ Object

# 42 “42”, [1, 2]



253
254
255
# File 'lib/solid/parser.rb', line 253

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

#handle_kw(keyword, lineno_column) ⇒ Object

# true “true”, [1, 33]

Raises:



234
235
236
237
# File 'lib/solid/parser.rb', line 234

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]



265
266
267
# File 'lib/solid/parser.rb', line 265

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]]


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

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]]


184
185
186
# File 'lib/solid/parser.rb', line 184

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

#handle_regexp_literal(regexp_literal, lineno_column) ⇒ Object

# /bb|2/ [[:@tstring_content, “bb|2”, [1, 2]]].first.first TODO: handle regexp interpolation



223
224
225
# File 'lib/solid/parser.rb', line 223

def handle_regexp_literal(regexp_literal, lineno_column)
  Literal.new Regexp.new(regexp_literal.first[1])
end

#handle_string_content(*parts) ⇒ Object



207
208
209
# File 'lib/solid/parser.rb', line 207

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



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

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]


212
213
214
# File 'lib/solid/parser.rb', line 212

def handle_tstring_content(string_content, lineno_column)
  string_content
end

#handle_unary(operator, operand) ⇒ Object

# !true

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


165
166
167
# File 'lib/solid/parser.rb', line 165

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]


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

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]]


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

def handle_vcall(expression)
  parse_one(expression)
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


157
158
159
160
161
# File 'lib/solid/parser.rb', line 157

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



76
77
78
79
80
# File 'lib/solid/parser.rb', line 76

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

#parse_one(argument) ⇒ Object

Raises:



90
91
92
93
94
95
# File 'lib/solid/parser.rb', line 90

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