Class: YARD::Parser::Ruby::AstNode

Inherits:
Array
  • Object
show all
Defined in:
lib/yard/parser/ruby/ast_node.rb

Overview

An AST node is characterized by a type and a list of children. It is most easily represented by the s-expression #s such as:

# AST for "if true; 5 end":
s(s(:if, s(:var_ref, s(:kw, "true")), s(s(:int, "5")), nil))

The node type is not considered part of the list, only its children. So ast[0] does not refer to the type, but rather the first child (or object). Items that are not AstNode objects can be part of the list, like Strings or Symbols representing names. To return only the AstNode children of the node, use #children.

Constant Summary collapse

KEYWORDS =

List of all known keywords

Returns:

{:class => true, :alias => true, :lambda => true, :do_block => true,
:def => true, :defs => true, :begin => true, :rescue => true, :rescue_mod => true,
:if => true, :if_mod => true, :else => true, :elsif => true, :case => true,
:when => true, :next => true, :break => true, :retry => true, :redo => true,
:return => true, :throw => true, :catch => true, :until => true, :until_mod => true,
:while => true, :while_mod => true, :yield => true, :yield0 => true, :zsuper => true,
:unless => true, :unless_mod => true, :for => true, :super => true, :return0 => true}

Instance Attribute Summary collapse

Creating an AstNode collapse

Traversing a Node collapse

Node Meta Types collapse

Getting Line Information collapse

Printing a Node collapse

Managing node state collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, arr, opts = {}) ⇒ AstNode

Creates a new AST node

Parameters:

  • type (Symbol)

    the type of node being created

  • arr (Array<AstNode>)

    the child nodes

  • opts (Hash) (defaults to: {})

    any extra line options

Options Hash (opts):

  • :line (Fixnum) — default: nil

    the line the node starts on in source

  • :char (String) — default: nil

    the character number the node starts on in source

  • :listline (Fixnum) — default: nil

    a special key like :line but for list nodes

  • :listchar (Fixnum) — default: nil

    a special key like :char but for list nodes

  • :token (Boolean) — default: nil

    whether the node represents a token



153
154
155
156
157
158
159
160
161
162
# File 'lib/yard/parser/ruby/ast_node.rb', line 153

def initialize(type, arr, opts = {})
  super(arr)
  self.type = type
  self.line_range = opts[:line]
  self.source_range = opts[:char]
  @fallback_line = opts[:listline]
  @fallback_source = opts[:listchar]
  @token = true if opts[:token]
  @docstring = nil
end

Instance Attribute Details

#docstringObject Also known as: comments

Returns the value of attribute docstring.



43
44
45
# File 'lib/yard/parser/ruby/ast_node.rb', line 43

def docstring
  @docstring
end

#docstring_hash_flagObject Also known as: comments_hash_flag

Returns the value of attribute docstring_hash_flag.



42
43
44
# File 'lib/yard/parser/ruby/ast_node.rb', line 42

def docstring_hash_flag
  @docstring_hash_flag
end

#docstring_rangeObject Also known as: comments_range

Returns the value of attribute docstring_range.



43
44
45
# File 'lib/yard/parser/ruby/ast_node.rb', line 43

def docstring_range
  @docstring_range
end

#fileString

Returns the filename the node was parsed from.

Returns:

  • (String)

    the filename the node was parsed from



76
77
78
79
# File 'lib/yard/parser/ruby/ast_node.rb', line 76

def file
  return parent.file if parent
  @file
end

#full_sourceString

Returns the full source that the node was parsed from.

Returns:

  • (String)

    the full source that the node was parsed from



82
83
84
85
86
# File 'lib/yard/parser/ruby/ast_node.rb', line 82

def full_source
  return parent.full_source if parent
  return @full_source if @full_source
  return IO.read(@file) if file && File.exist?(file)
end

#groupObject

Deprecated.

Groups are now defined by directives



47
48
49
# File 'lib/yard/parser/ruby/ast_node.rb', line 47

def group
  @group
end

#line_rangeRange

Returns the line range in #full_source represented by the node.

Returns:

  • (Range)

    the line range in #full_source represented by the node



70
71
72
73
# File 'lib/yard/parser/ruby/ast_node.rb', line 70

def line_range
  reset_line_info unless @line_range
  @line_range
end

#parentAstNode?

Returns the node’s parent or nil if it is a root node.

Returns:

  • (AstNode, nil)

    the node’s parent or nil if it is a root node.



59
60
61
# File 'lib/yard/parser/ruby/ast_node.rb', line 59

def parent
  @parent
end

#sourceString

Returns the parse of #full_source that the node represents.

Returns:



89
90
91
# File 'lib/yard/parser/ruby/ast_node.rb', line 89

def source
  @source
end

#source_rangeRange

Returns the character range in #full_source represented by the node.

Returns:

  • (Range)

    the character range in #full_source represented by the node



63
64
65
66
# File 'lib/yard/parser/ruby/ast_node.rb', line 63

def source_range
  reset_line_info unless @source_range
  @source_range
end

#typeSymbol

Returns the node’s unique symbolic type.

Returns:

  • (Symbol)

    the node’s unique symbolic type



56
57
58
# File 'lib/yard/parser/ruby/ast_node.rb', line 56

def type
  @type
end

Class Method Details

.node_class_for(type) ⇒ Class

Finds the node subclass that should be instantiated for a specific node type

Parameters:

  • type (Symbol)

    the node type to find a subclass for

Returns:

  • (Class)

    a subclass of AstNode to instantiate the node with.



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
136
137
138
# File 'lib/yard/parser/ruby/ast_node.rb', line 111

def self.node_class_for(type)
  case type
  when :params
    ParameterNode
  when :call, :fcall, :vcall, :command, :command_call
    MethodCallNode
  when :if, :elsif, :if_mod, :unless, :unless_mod
    ConditionalNode
  when :for, :while, :while_mod, :until, :until_mod
    LoopNode
  when :def, :defs
    MethodDefinitionNode
  when :class, :sclass
    ClassNode
  when :module
    ModuleNode
  else
    if type.to_s =~ /_ref\Z/
      ReferenceNode
    elsif type.to_s =~ /_literal\Z/
      LiteralNode
    elsif KEYWORDS.key?(type)
      KeywordNode
    else
      AstNode
    end
  end
end

Instance Method Details

#block?Boolean

Returns whether the node has a block.

Returns:

  • (Boolean)

    whether the node has a block



261
262
263
# File 'lib/yard/parser/ruby/ast_node.rb', line 261

def block?
  respond_to?(:block) || condition?
end

#call?Boolean

Returns whether the node is a method call.

Returns:

  • (Boolean)

    whether the node is a method call



241
242
243
# File 'lib/yard/parser/ruby/ast_node.rb', line 241

def call?
  false
end

#childrenArray<AstNode>

Returns the YARD::Parser::Ruby::AstNode children inside the node.

Returns:



199
200
201
# File 'lib/yard/parser/ruby/ast_node.rb', line 199

def children
  @children ||= select {|e| AstNode === e }
end

#condition?Boolean

Returns whether the node is a if/elsif/else condition.

Returns:

  • (Boolean)

    whether the node is a if/elsif/else condition



251
252
253
# File 'lib/yard/parser/ruby/ast_node.rb', line 251

def condition?
  false
end

#def?Boolean

Returns whether the node is a method definition.

Returns:

  • (Boolean)

    whether the node is a method definition



246
247
248
# File 'lib/yard/parser/ruby/ast_node.rb', line 246

def def?
  false
end

#first_lineString

Returns the first line of source represented by the node.

Returns:

  • (String)

    the first line of source represented by the node.



278
279
280
# File 'lib/yard/parser/ruby/ast_node.rb', line 278

def first_line
  full_source.split(/\r?\n/)[line - 1].strip
end

#has_line?Boolean

Returns whether the node has a #line_range set.

Returns:



268
269
270
# File 'lib/yard/parser/ruby/ast_node.rb', line 268

def has_line?
  @line_range ? true : false
end

#inspectString

Returns inspects the object.

Returns:

  • (String)

    inspects the object



323
324
325
326
# File 'lib/yard/parser/ruby/ast_node.rb', line 323

def inspect
  typeinfo = type && type != :list ? ':' + type.to_s + ', ' : ''
  's(' + typeinfo + map(&:inspect).join(", ") + ')'
end

#jump(*node_types) ⇒ AstNode, self

Searches through the node and all descendants and returns the first node with a type matching any of node_types, otherwise returns the original node (self).

Examples:

Returns the first method definition in a block of code

ast = YARD.parse_string("if true; def x; end end").ast
ast.jump(:def)
# => s(:def, s(:ident, "x"), s(:params, nil, nil, nil, nil,
#      nil), s(s(:void_stmt, )))

Returns first ‘def’ or ‘class’ statement

ast = YARD.parse_string("class X; def y; end end")
ast.jump(:def, :class).first
# =>

If the node types are not present in the AST

ast = YARD.parse("def x; end")
ast.jump(:def)

Parameters:

  • node_types (Array<Symbol>)

    a set of node types to match

Returns:

  • (AstNode)

    the matching node, if one was found

  • (self)

    if no node was found



193
194
195
196
# File 'lib/yard/parser/ruby/ast_node.rb', line 193

def jump(*node_types)
  traverse {|child| return(child) if node_types.include?(child.type) }
  self
end

#kw?Boolean

Returns whether the node is a keyword.

Returns:

  • (Boolean)

    whether the node is a keyword



236
237
238
# File 'lib/yard/parser/ruby/ast_node.rb', line 236

def kw?
  false
end

#lineFixnum

Returns the starting line number of the node.

Returns:

  • (Fixnum)

    the starting line number of the node



273
274
275
# File 'lib/yard/parser/ruby/ast_node.rb', line 273

def line
  line_range && line_range.first
end

#literal?Boolean

Returns whether the node is a literal value.

Returns:

  • (Boolean)

    whether the node is a literal value



231
232
233
# File 'lib/yard/parser/ruby/ast_node.rb', line 231

def literal?
  false
end

#loop?Boolean

Returns whether the node is a loop.

Returns:

  • (Boolean)

    whether the node is a loop



256
257
258
# File 'lib/yard/parser/ruby/ast_node.rb', line 256

def loop?
  false
end

#pretty_print(q) ⇒ nil

Returns pretty prints the node.

Returns:

  • (nil)

    pretty prints the node



290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/yard/parser/ruby/ast_node.rb', line 290

def pretty_print(q)
  objs = dup + [:__last__]
  objs.unshift(type) if type && type != :list

  options = []
  options << ['docstring', docstring] if @docstring
  if @source_range || @line_range
    options << ['line', line_range]
    options << ['source', source_range]
  end
  objs.pop if options.empty?

  q.group(3, 's(', ')') do
    q.seplist(objs, nil, :each) do |v|
      if v == :__last__
        q.seplist(options, nil, :each) do |arr|
          k, v2 = *arr
          q.group(3) do
            q.text k
            q.group(3) do
              q.text ': '
              q.pp v2
            end
          end
        end
      else
        q.pp v
      end
    end
  end
end

#ref?Boolean

Returns whether the node is a reference (variable, constant name).

Returns:

  • (Boolean)

    whether the node is a reference (variable, constant name)



226
227
228
# File 'lib/yard/parser/ruby/ast_node.rb', line 226

def ref?
  false
end

#showString

Returns the first line of source the node represents.

Returns:

  • (String)

    the first line of source the node represents



285
286
287
# File 'lib/yard/parser/ruby/ast_node.rb', line 285

def show
  "\t#{line}: #{first_line}"
end

#to_sObject

Returns the value of attribute source.



53
54
55
# File 'lib/yard/parser/ruby/ast_node.rb', line 53

def source
  @source
end

#token?Boolean

Returns whether the node is a token.

Returns:

  • (Boolean)

    whether the node is a token



220
221
222
# File 'lib/yard/parser/ruby/ast_node.rb', line 220

def token?
  @token
end

#traverse {|self,| ... } ⇒ void

This method returns an undefined value.

Traverses the object and yields each node (including descendants) in order.

Yields:

  • each descendant node in order

Yield Parameters:

  • self, (AstNode)

    or a child/descendant node



208
209
210
211
212
213
214
215
# File 'lib/yard/parser/ruby/ast_node.rb', line 208

def traverse
  nodes = [self]
  until nodes.empty?
    node = nodes.pop
    yield node
    nodes += node.children.reverse unless node.children.empty?
  end
end

#unfreezeObject

Resets node state in tree



331
332
333
# File 'lib/yard/parser/ruby/ast_node.rb', line 331

def unfreeze
  @children = nil
end