syntax_tree 6.0.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -792,9 +792,10 @@ module SyntaxTree
792
792
  private
793
793
 
794
794
  def trailing_comma?
795
+ arguments = self.arguments
795
796
  return false unless arguments.is_a?(Args)
796
- parts = arguments.parts
797
797
 
798
+ parts = arguments.parts
798
799
  if parts.last.is_a?(ArgBlock)
799
800
  # If the last argument is a block, then we can't put a trailing comma
800
801
  # after it without resulting in a syntax error.
@@ -1188,8 +1189,11 @@ module SyntaxTree
1188
1189
  end
1189
1190
 
1190
1191
  def format(q)
1191
- if lbracket.comments.empty? && contents && contents.comments.empty? &&
1192
- contents.parts.length > 1
1192
+ lbracket = self.lbracket
1193
+ contents = self.contents
1194
+
1195
+ if lbracket.is_a?(LBracket) && lbracket.comments.empty? && contents &&
1196
+ contents.comments.empty? && contents.parts.length > 1
1193
1197
  if qwords?
1194
1198
  QWordsFormatter.new(contents).format(q)
1195
1199
  return
@@ -2091,6 +2095,7 @@ module SyntaxTree
2091
2095
  end
2092
2096
 
2093
2097
  def format(q)
2098
+ left = self.left
2094
2099
  power = operator == :**
2095
2100
 
2096
2101
  q.group do
@@ -2307,6 +2312,8 @@ module SyntaxTree
2307
2312
  end
2308
2313
 
2309
2314
  def bind(parser, start_char, start_column, end_char, end_column)
2315
+ rescue_clause = self.rescue_clause
2316
+
2310
2317
  @location =
2311
2318
  Location.new(
2312
2319
  start_line: location.start_line,
@@ -2330,6 +2337,7 @@ module SyntaxTree
2330
2337
  # Next we're going to determine the rescue clause if there is one
2331
2338
  if rescue_clause
2332
2339
  consequent = else_clause || ensure_clause
2340
+
2333
2341
  rescue_clause.bind_end(
2334
2342
  consequent ? consequent.location.start_char : end_char,
2335
2343
  consequent ? consequent.location.start_column : end_column
@@ -2735,7 +2743,7 @@ module SyntaxTree
2735
2743
  children << receiver
2736
2744
  end
2737
2745
  when MethodAddBlock
2738
- if receiver.call.is_a?(CallNode) && !receiver.call.receiver.nil?
2746
+ if (call = receiver.call).is_a?(CallNode) && !call.receiver.nil?
2739
2747
  children << receiver
2740
2748
  else
2741
2749
  break
@@ -2744,8 +2752,8 @@ module SyntaxTree
2744
2752
  break
2745
2753
  end
2746
2754
  when MethodAddBlock
2747
- if child.call.is_a?(CallNode) && !child.call.receiver.nil?
2748
- children << child.call
2755
+ if (call = child.call).is_a?(CallNode) && !call.receiver.nil?
2756
+ children << call
2749
2757
  else
2750
2758
  break
2751
2759
  end
@@ -2767,8 +2775,8 @@ module SyntaxTree
2767
2775
  # of just Statements nodes.
2768
2776
  parent = parents[3] if parent.is_a?(BlockNode) && parent.keywords?
2769
2777
 
2770
- if parent.is_a?(MethodAddBlock) && parent.call.is_a?(CallNode) &&
2771
- parent.call.message.value == "sig"
2778
+ if parent.is_a?(MethodAddBlock) &&
2779
+ (call = parent.call).is_a?(CallNode) && call.message.value == "sig"
2772
2780
  threshold = 2
2773
2781
  end
2774
2782
  end
@@ -2813,10 +2821,10 @@ module SyntaxTree
2813
2821
 
2814
2822
  while (child = children.pop)
2815
2823
  if child.is_a?(CallNode)
2816
- if child.receiver.is_a?(CallNode) &&
2817
- (child.receiver.message != :call) &&
2818
- (child.receiver.message.value == "where") &&
2819
- (child.message.value == "not")
2824
+ if (receiver = child.receiver).is_a?(CallNode) &&
2825
+ (receiver.message != :call) &&
2826
+ (receiver.message.value == "where") &&
2827
+ (message.value == "not")
2820
2828
  # This is very specialized behavior wherein we group
2821
2829
  # .where.not calls together because it looks better. For more
2822
2830
  # information, see
@@ -2872,7 +2880,8 @@ module SyntaxTree
2872
2880
  when CallNode
2873
2881
  !node.receiver.nil?
2874
2882
  when MethodAddBlock
2875
- node.call.is_a?(CallNode) && !node.call.receiver.nil?
2883
+ call = node.call
2884
+ call.is_a?(CallNode) && !call.receiver.nil?
2876
2885
  else
2877
2886
  false
2878
2887
  end
@@ -3629,6 +3638,10 @@ module SyntaxTree
3629
3638
  end
3630
3639
 
3631
3640
  def format(q)
3641
+ message = self.message
3642
+ arguments = self.arguments
3643
+ block = self.block
3644
+
3632
3645
  q.group do
3633
3646
  doc =
3634
3647
  q.nest(0) do
@@ -3637,7 +3650,7 @@ module SyntaxTree
3637
3650
  # If there are leading comments on the message then we know we have
3638
3651
  # a newline in the source that is forcing these things apart. In
3639
3652
  # this case we will have to use a trailing operator.
3640
- if message.comments.any?(&:leading?)
3653
+ if message != :call && message.comments.any?(&:leading?)
3641
3654
  q.format(CallOperatorFormatter.new(operator), stackable: false)
3642
3655
  q.indent do
3643
3656
  q.breakable_empty
@@ -4153,6 +4166,9 @@ module SyntaxTree
4153
4166
  end
4154
4167
 
4155
4168
  def format(q)
4169
+ params = self.params
4170
+ bodystmt = self.bodystmt
4171
+
4156
4172
  q.group do
4157
4173
  q.group do
4158
4174
  q.text("def")
@@ -4209,6 +4225,8 @@ module SyntaxTree
4209
4225
  end
4210
4226
 
4211
4227
  def arity
4228
+ params = self.params
4229
+
4212
4230
  case params
4213
4231
  when Params
4214
4232
  params.arity
@@ -5293,6 +5311,7 @@ module SyntaxTree
5293
5311
  end
5294
5312
 
5295
5313
  def child_nodes
5314
+ operator = self.operator
5296
5315
  [parent, (operator if operator != :"::"), name]
5297
5316
  end
5298
5317
 
@@ -5674,7 +5693,7 @@ module SyntaxTree
5674
5693
  end
5675
5694
 
5676
5695
  def child_nodes
5677
- [lbrace] + assocs
5696
+ [lbrace].concat(assocs)
5678
5697
  end
5679
5698
 
5680
5699
  def copy(lbrace: nil, assocs: nil, location: nil)
@@ -5766,7 +5785,7 @@ module SyntaxTree
5766
5785
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
5767
5786
  attr_reader :comments
5768
5787
 
5769
- def initialize(beginning:, ending: nil, dedent: 0, parts: [], location:)
5788
+ def initialize(beginning:, location:, ending: nil, dedent: 0, parts: [])
5770
5789
  @beginning = beginning
5771
5790
  @ending = ending
5772
5791
  @dedent = dedent
@@ -6134,6 +6153,8 @@ module SyntaxTree
6134
6153
  private
6135
6154
 
6136
6155
  def format_contents(q, parts, nested)
6156
+ keyword_rest = self.keyword_rest
6157
+
6137
6158
  q.group { q.seplist(parts) { |part| q.format(part, stackable: false) } }
6138
6159
 
6139
6160
  # If there isn't a constant, and there's a blank keyword_rest, then we
@@ -6763,10 +6784,13 @@ module SyntaxTree
6763
6784
 
6764
6785
  def format(q)
6765
6786
  keyword = "in "
6787
+ pattern = self.pattern
6788
+ consequent = self.consequent
6766
6789
 
6767
6790
  q.group do
6768
6791
  q.text(keyword)
6769
6792
  q.nest(keyword.length) { q.format(pattern) }
6793
+ q.text(" then") if pattern.is_a?(RangeNode) && pattern.right.nil?
6770
6794
 
6771
6795
  unless statements.empty?
6772
6796
  q.indent do
@@ -7164,6 +7188,8 @@ module SyntaxTree
7164
7188
  end
7165
7189
 
7166
7190
  def format(q)
7191
+ params = self.params
7192
+
7167
7193
  q.text("->")
7168
7194
  q.group do
7169
7195
  if params.is_a?(Paren)
@@ -7642,7 +7668,7 @@ module SyntaxTree
7642
7668
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
7643
7669
  attr_reader :comments
7644
7670
 
7645
- def initialize(parts:, comma: false, location:)
7671
+ def initialize(parts:, location:, comma: false)
7646
7672
  @parts = parts
7647
7673
  @comma = comma
7648
7674
  @location = location
@@ -7703,7 +7729,7 @@ module SyntaxTree
7703
7729
  # [Array[ Comment | EmbDoc ]] the comments attached to this node
7704
7730
  attr_reader :comments
7705
7731
 
7706
- def initialize(contents:, comma: false, location:)
7732
+ def initialize(contents:, location:, comma: false)
7707
7733
  @contents = contents
7708
7734
  @comma = comma
7709
7735
  @location = location
@@ -8286,14 +8312,14 @@ module SyntaxTree
8286
8312
  attr_reader :comments
8287
8313
 
8288
8314
  def initialize(
8315
+ location:,
8289
8316
  requireds: [],
8290
8317
  optionals: [],
8291
8318
  rest: nil,
8292
8319
  posts: [],
8293
8320
  keywords: [],
8294
8321
  keyword_rest: nil,
8295
- block: nil,
8296
- location:
8322
+ block: nil
8297
8323
  )
8298
8324
  @requireds = requireds
8299
8325
  @optionals = optionals
@@ -8320,6 +8346,8 @@ module SyntaxTree
8320
8346
  end
8321
8347
 
8322
8348
  def child_nodes
8349
+ keyword_rest = self.keyword_rest
8350
+
8323
8351
  [
8324
8352
  *requireds,
8325
8353
  *optionals.flatten(1),
@@ -8374,16 +8402,19 @@ module SyntaxTree
8374
8402
  end
8375
8403
 
8376
8404
  def format(q)
8405
+ rest = self.rest
8406
+ keyword_rest = self.keyword_rest
8407
+
8377
8408
  parts = [
8378
8409
  *requireds,
8379
8410
  *optionals.map { |(name, value)| OptionalFormatter.new(name, value) }
8380
8411
  ]
8381
8412
 
8382
8413
  parts << rest if rest && !rest.is_a?(ExcessedComma)
8383
- parts += [
8384
- *posts,
8385
- *keywords.map { |(name, value)| KeywordFormatter.new(name, value) }
8386
- ]
8414
+ parts.concat(posts)
8415
+ parts.concat(
8416
+ keywords.map { |(name, value)| KeywordFormatter.new(name, value) }
8417
+ )
8387
8418
 
8388
8419
  parts << KeywordRestFormatter.new(keyword_rest) if keyword_rest
8389
8420
  parts << block if block
@@ -8510,6 +8541,8 @@ module SyntaxTree
8510
8541
  end
8511
8542
 
8512
8543
  def format(q)
8544
+ contents = self.contents
8545
+
8513
8546
  q.group do
8514
8547
  q.format(lparen)
8515
8548
 
@@ -9424,11 +9457,11 @@ module SyntaxTree
9424
9457
  end_column: end_column
9425
9458
  )
9426
9459
 
9427
- if consequent
9428
- consequent.bind_end(end_char, end_column)
9460
+ if (next_node = consequent)
9461
+ next_node.bind_end(end_char, end_column)
9429
9462
  statements.bind_end(
9430
- consequent.location.start_char,
9431
- consequent.location.start_column
9463
+ next_node.location.start_char,
9464
+ next_node.location.start_column
9432
9465
  )
9433
9466
  else
9434
9467
  statements.bind_end(end_char, end_column)
@@ -9871,8 +9904,8 @@ module SyntaxTree
9871
9904
  end_column: end_column
9872
9905
  )
9873
9906
 
9874
- if body[0].is_a?(VoidStmt)
9875
- location = body[0].location
9907
+ if (void_stmt = body[0]).is_a?(VoidStmt)
9908
+ location = void_stmt.location
9876
9909
  location =
9877
9910
  Location.new(
9878
9911
  start_line: location.start_line,
@@ -10351,7 +10384,7 @@ module SyntaxTree
10351
10384
  opening_quote, closing_quote =
10352
10385
  if !Quotes.locked?(self, q.quote)
10353
10386
  [q.quote, q.quote]
10354
- elsif quote.start_with?("%")
10387
+ elsif quote&.start_with?("%")
10355
10388
  [quote, Quotes.matching(quote[/%[qQ]?(.)/, 1])]
10356
10389
  else
10357
10390
  [quote, quote]
@@ -11520,7 +11553,7 @@ module SyntaxTree
11520
11553
  end
11521
11554
 
11522
11555
  def child_nodes
11523
- [value]
11556
+ value == :nil ? [] : [value]
11524
11557
  end
11525
11558
 
11526
11559
  def copy(value: nil, location: nil)
@@ -2132,13 +2132,20 @@ module SyntaxTree
2132
2132
  ending = consequent || consume_keyword(:end)
2133
2133
 
2134
2134
  statements_start = pattern
2135
- if (token = find_keyword(:then))
2135
+ if (token = find_keyword_between(:then, pattern, statements))
2136
2136
  tokens.delete(token)
2137
2137
  statements_start = token
2138
2138
  end
2139
2139
 
2140
2140
  start_char =
2141
2141
  find_next_statement_start((token || statements_start).location.end_char)
2142
+
2143
+ # Ripper ignores parentheses on patterns, so we need to do the same in
2144
+ # order to attach comments correctly to the pattern.
2145
+ if source[start_char] == ")"
2146
+ start_char = find_next_statement_start(start_char + 1)
2147
+ end
2148
+
2142
2149
  statements.bind(
2143
2150
  self,
2144
2151
  start_char,
@@ -2391,8 +2398,14 @@ module SyntaxTree
2391
2398
  }
2392
2399
  }
2393
2400
 
2401
+ parent_line = lineno - 1
2402
+ parent_column =
2403
+ consume_token(Semicolon).location.start_column - tokens[index][0][1]
2404
+
2394
2405
  tokens[(index + 1)..].each_with_object([]) do |token, locals|
2395
2406
  (lineno, column), type, value, = token
2407
+ column += parent_column if lineno == 1
2408
+ lineno += parent_line
2396
2409
 
2397
2410
  # Make the state transition for the parser. If there isn't a transition
2398
2411
  # from the current state to a new state for this type, then we're in a
@@ -138,12 +138,13 @@ module SyntaxTree
138
138
  # as a placeholder for collecting all of the various places that nodes are
139
139
  # used.
140
140
  class Node
141
- attr_reader :name, :comment, :attributes
141
+ attr_reader :name, :comment, :attributes, :visitor_method
142
142
 
143
- def initialize(name, comment, attributes)
143
+ def initialize(name, comment, attributes, visitor_method)
144
144
  @name = name
145
145
  @comment = comment
146
146
  @attributes = attributes
147
+ @visitor_method = visitor_method
147
148
  end
148
149
  end
149
150
 
@@ -176,16 +177,18 @@ module SyntaxTree
176
177
  program =
177
178
  SyntaxTree.parse(SyntaxTree.read(File.expand_path("node.rb", __dir__)))
178
179
 
179
- main_statements = program.statements.body.last.bodystmt.statements.body
180
+ program_statements = program.statements
181
+ main_statements = program_statements.body.last.bodystmt.statements.body
180
182
  main_statements.each_with_index do |main_statement, main_statement_index|
181
183
  # Ensure we are only looking at class declarations.
182
184
  next unless main_statement.is_a?(SyntaxTree::ClassDeclaration)
183
185
 
184
186
  # Ensure we're looking at class declarations with superclasses.
185
- next unless main_statement.superclass.is_a?(SyntaxTree::VarRef)
187
+ superclass = main_statement.superclass
188
+ next unless superclass.is_a?(SyntaxTree::VarRef)
186
189
 
187
190
  # Ensure we're looking at class declarations that inherit from Node.
188
- next unless main_statement.superclass.value.value == "Node"
191
+ next unless superclass.value.value == "Node"
189
192
 
190
193
  # All child nodes inherit the location attr_reader from Node, so we'll add
191
194
  # that to the list of attributes first.
@@ -194,6 +197,10 @@ module SyntaxTree
194
197
  Attribute.new(:location, "[Location] the location of this node")
195
198
  }
196
199
 
200
+ # This is the name of the method tha gets called on the given visitor when
201
+ # the accept method is called on this node.
202
+ visitor_method = nil
203
+
197
204
  statements = main_statement.bodystmt.statements.body
198
205
  statements.each_with_index do |statement, statement_index|
199
206
  case statement
@@ -223,16 +230,25 @@ module SyntaxTree
223
230
  end
224
231
 
225
232
  attributes[attribute.name] = attribute
233
+ when SyntaxTree::DefNode
234
+ if statement.name.value == "accept"
235
+ call_node = statement.bodystmt.statements.body.first
236
+ visitor_method = call_node.message.value.to_sym
237
+ end
226
238
  end
227
239
  end
228
240
 
241
+ # If we never found a visitor method, then we have an error.
242
+ raise if visitor_method.nil?
243
+
229
244
  # Finally, set it up in the hash of nodes so that we can use it later.
230
245
  comments = parse_comments(main_statements, main_statement_index)
231
246
  node =
232
247
  Node.new(
233
248
  main_statement.constant.constant.value.to_sym,
234
249
  "#{comments.join("\n")}\n",
235
- attributes
250
+ attributes,
251
+ visitor_method
236
252
  )
237
253
 
238
254
  @nodes[node.name] = node
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SyntaxTree
4
- VERSION = "6.0.1"
4
+ VERSION = "6.1.0"
5
5
  end
@@ -189,6 +189,15 @@ module SyntaxTree
189
189
  super
190
190
  end
191
191
 
192
+ def visit_block_var(node)
193
+ node.locals.each do |local|
194
+ current_scope.add_local_definition(local, :variable)
195
+ end
196
+
197
+ super
198
+ end
199
+ alias visit_lambda_var visit_block_var
200
+
192
201
  # Visit for keeping track of local variable definitions
193
202
  def visit_var_field(node)
194
203
  value = node.value
@@ -217,11 +226,72 @@ module SyntaxTree
217
226
  super
218
227
  end
219
228
 
229
+ # When using regex named capture groups, vcalls might actually be a variable
230
+ def visit_vcall(node)
231
+ value = node.value
232
+ definition = current_scope.find_local(value.value)
233
+ current_scope.add_local_usage(value, definition.type) if definition
234
+
235
+ super
236
+ end
237
+
238
+ # Visit for capturing local variables defined in regex named capture groups
239
+ def visit_binary(node)
240
+ if node.operator == :=~
241
+ left = node.left
242
+
243
+ if left.is_a?(RegexpLiteral) && left.parts.length == 1 &&
244
+ left.parts.first.is_a?(TStringContent)
245
+ content = left.parts.first
246
+
247
+ value = content.value
248
+ location = content.location
249
+ start_line = location.start_line
250
+
251
+ Regexp
252
+ .new(value, Regexp::FIXEDENCODING)
253
+ .names
254
+ .each do |name|
255
+ offset = value.index(/\(\?<#{Regexp.escape(name)}>/)
256
+ line = start_line + value[0...offset].count("\n")
257
+
258
+ # We need to add 3 to account for these three characters
259
+ # prefixing a named capture (?<
260
+ column = location.start_column + offset + 3
261
+ if value[0...offset].include?("\n")
262
+ column =
263
+ value[0...offset].length - value[0...offset].rindex("\n") +
264
+ 3 - 1
265
+ end
266
+
267
+ ident_location =
268
+ Location.new(
269
+ start_line: line,
270
+ start_char: location.start_char + offset,
271
+ start_column: column,
272
+ end_line: line,
273
+ end_char: location.start_char + offset + name.length,
274
+ end_column: column + name.length
275
+ )
276
+
277
+ identifier = Ident.new(value: name, location: ident_location)
278
+ current_scope.add_local_definition(identifier, :variable)
279
+ end
280
+ end
281
+ end
282
+
283
+ super
284
+ end
285
+
220
286
  private
221
287
 
222
288
  def add_argument_definitions(list)
223
289
  list.each do |param|
224
- if param.is_a?(SyntaxTree::MLHSParen)
290
+ case param
291
+ when ArgStar
292
+ value = param.value
293
+ current_scope.add_local_definition(value, :argument) if value
294
+ when MLHSParen
225
295
  add_argument_definitions(param.contents.parts)
226
296
  else
227
297
  current_scope.add_local_definition(param, :argument)
@@ -875,8 +875,7 @@ module SyntaxTree
875
875
  when Ident
876
876
  iseq.putobject("local-variable")
877
877
  when IVar
878
- iseq.putnil
879
- iseq.defined(Defined::TYPE_IVAR, name, "instance-variable")
878
+ iseq.definedivar(name, iseq.inline_storage, "instance-variable")
880
879
  when Kw
881
880
  case name
882
881
  when :false
@@ -50,7 +50,7 @@ module SyntaxTree
50
50
  @tail_node = nil
51
51
  end
52
52
 
53
- def each
53
+ def each(&_blk)
54
54
  return to_enum(__method__) unless block_given?
55
55
  each_node { |node| yield node.value }
56
56
  end
@@ -673,12 +673,21 @@ module SyntaxTree
673
673
  push(ConcatStrings.new(number))
674
674
  end
675
675
 
676
+ def defineclass(name, class_iseq, flags)
677
+ push(DefineClass.new(name, class_iseq, flags))
678
+ end
679
+
676
680
  def defined(type, name, message)
677
681
  push(Defined.new(type, name, message))
678
682
  end
679
683
 
680
- def defineclass(name, class_iseq, flags)
681
- push(DefineClass.new(name, class_iseq, flags))
684
+ def definedivar(name, cache, message)
685
+ if RUBY_VERSION < "3.3"
686
+ push(PutNil.new)
687
+ push(Defined.new(Defined::TYPE_IVAR, name, message))
688
+ else
689
+ push(DefinedIVar.new(name, cache, message))
690
+ end
682
691
  end
683
692
 
684
693
  def definemethod(name, method_iseq)
@@ -1058,6 +1067,8 @@ module SyntaxTree
1058
1067
  iseq.defineclass(opnds[0], from(opnds[1], options, iseq), opnds[2])
1059
1068
  when :defined
1060
1069
  iseq.defined(opnds[0], opnds[1], opnds[2])
1070
+ when :definedivar
1071
+ iseq.definedivar(opnds[0], opnds[1], opnds[2])
1061
1072
  when :definemethod
1062
1073
  iseq.definemethod(opnds[0], from(opnds[1], options, iseq))
1063
1074
  when :definesmethod
@@ -994,6 +994,64 @@ module SyntaxTree
994
994
  end
995
995
  end
996
996
 
997
+ # ### Summary
998
+ #
999
+ # `definedivar` checks if an instance variable is defined. It is a
1000
+ # specialization of the `defined` instruction. It accepts three arguments:
1001
+ # the name of the instance variable, an inline cache, and the string that
1002
+ # should be pushed onto the stack in the event that the instance variable
1003
+ # is defined.
1004
+ #
1005
+ # ### Usage
1006
+ #
1007
+ # ~~~ruby
1008
+ # defined?(@value)
1009
+ # ~~~
1010
+ #
1011
+ class DefinedIVar < Instruction
1012
+ attr_reader :name, :cache, :message
1013
+
1014
+ def initialize(name, cache, message)
1015
+ @name = name
1016
+ @cache = cache
1017
+ @message = message
1018
+ end
1019
+
1020
+ def disasm(fmt)
1021
+ fmt.instruction(
1022
+ "definedivar",
1023
+ [fmt.object(name), fmt.inline_storage(cache), fmt.object(message)]
1024
+ )
1025
+ end
1026
+
1027
+ def to_a(_iseq)
1028
+ [:definedivar, name, cache, message]
1029
+ end
1030
+
1031
+ def deconstruct_keys(_keys)
1032
+ { name: name, cache: cache, message: message }
1033
+ end
1034
+
1035
+ def ==(other)
1036
+ other.is_a?(DefinedIVar) && other.name == name &&
1037
+ other.cache == cache && other.message == message
1038
+ end
1039
+
1040
+ def length
1041
+ 4
1042
+ end
1043
+
1044
+ def pushes
1045
+ 1
1046
+ end
1047
+
1048
+ def call(vm)
1049
+ result = (message if vm.frame._self.instance_variable_defined?(name))
1050
+
1051
+ vm.push(result)
1052
+ end
1053
+ end
1054
+
997
1055
  # ### Summary
998
1056
  #
999
1057
  # `definemethod` defines a method on the class of the current value of
data/lib/syntax_tree.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "prettier_print"
4
+ require "pp"
4
5
  require "ripper"
5
6
 
6
7
  require_relative "syntax_tree/node"