summaryrefslogtreecommitdiff
path: root/ast.rb
blob: 34fa645671de3aa755460196a130b913a28247e4 (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
136
137
138
139
140
141
142
143
144
145
146
# for ast.c

class RubyVM

  # AbstractSyntaxTree provides methods to parse Ruby code into
  # abstract syntax trees. The nodes in the tree
  # are instances of RubyVM::AbstractSyntaxTree::Node.
  #
  # This module is MRI specific as it exposes implementation details
  # of the MRI abstract syntax tree.
  #
  # This module is experimental and its API is not stable, therefore it might
  # change without notice. As examples, the order of children nodes is not
  # guaranteed, the number of children nodes might change, there is no way to
  # access children nodes by name, etc.
  #
  # If you are looking for a stable API or an API working under multiple Ruby
  # implementations, consider using the _parser_ gem or Ripper. If you would
  # like to make RubyVM::AbstractSyntaxTree stable, please join the discussion
  # at https://bugs.ruby-lang.org/issues/14844.
  #
  module AbstractSyntaxTree

    #  call-seq:
    #     RubyVM::AbstractSyntaxTree.parse(string) -> RubyVM::AbstractSyntaxTree::Node
    #
    #  Parses the given _string_ into an abstract syntax tree,
    #  returning the root node of that tree.
    #
    #  SyntaxError is raised if the given _string_ is invalid syntax.
    #
    #    RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
    #    # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-1:9>
    def self.parse string
      Primitive.ast_s_parse string
    end

    #  call-seq:
    #     RubyVM::AbstractSyntaxTree.parse_file(pathname) -> RubyVM::AbstractSyntaxTree::Node
    #
    #   Reads the file from _pathname_, then parses it like ::parse,
    #   returning the root node of the abstract syntax tree.
    #
    #   SyntaxError is raised if _pathname_'s contents are not
    #   valid Ruby syntax.
    #
    #     RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
    #     # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
    def self.parse_file pathname
      Primitive.ast_s_parse_file pathname
    end

    #  call-seq:
    #     RubyVM::AbstractSyntaxTree.of(proc)   -> RubyVM::AbstractSyntaxTree::Node
    #     RubyVM::AbstractSyntaxTree.of(method) -> RubyVM::AbstractSyntaxTree::Node
    #
    #   Returns AST nodes of the given _proc_ or _method_.
    #
    #     RubyVM::AbstractSyntaxTree.of(proc {1 + 2})
    #     # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:35-1:42>
    #
    #     def hello
    #       puts "hello, world"
    #     end
    #
    #     RubyVM::AbstractSyntaxTree.of(method(:hello))
    #     # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
    def self.of body
      Primitive.ast_s_of body
    end

    # RubyVM::AbstractSyntaxTree::Node instances are created by parse methods in
    # RubyVM::AbstractSyntaxTree.
    #
    # This class is MRI specific.
    #
    class Node

      #  call-seq:
      #     node.type -> symbol
      #
      #  Returns the type of this node as a symbol.
      #
      #    root = RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
      #    root.type # => :SCOPE
      #    lasgn = root.children[2]
      #    lasgn.type # => :LASGN
      #    call = lasgn.children[1]
      #    call.type # => :OPCALL
      def type
        Primitive.ast_node_type
      end

      #  call-seq:
      #     node.first_lineno -> integer
      #
      #  The line number in the source code where this AST's text began.
      def first_lineno
        Primitive.ast_node_first_lineno
      end

      #  call-seq:
      #     node.first_column -> integer
      #
      #  The column number in the source code where this AST's text began.
      def first_column
        Primitive.ast_node_first_column
      end

      #  call-seq:
      #     node.last_lineno -> integer
      #
      #  The line number in the source code where this AST's text ended.
      def last_lineno
        Primitive.ast_node_last_lineno
      end

      #  call-seq:
      #     node.last_column -> integer
      #
      #  The column number in the source code where this AST's text ended.
      def last_column
        Primitive.ast_node_last_column
      end

      #  call-seq:
      #     node.children -> array
      #
      #  Returns AST nodes under this one.  Each kind of node
      #  has different children, depending on what kind of node it is.
      #
      #  The returned array may contain other nodes or <code>nil</code>.
      def children
        Primitive.ast_node_children
      end

      #  call-seq:
      #     node.inspect -> string
      #
      #  Returns debugging information about this node as a string.
      def inspect
        Primitive.ast_node_inspect
      end
    end
  end
end