Class: Parser::Source::Map
- Inherits:
-
Object
- Object
- Parser::Source::Map
- Defined in:
- lib/parser/source/map.rb
Overview
Map relates AST nodes to the source code they were parsed from. More specifically, a Map or its subclass contains a set of ranges:
* `expression`: smallest range which includes all source corresponding
to the node and all `expression` ranges of its children.
* other ranges (`begin`, `end`, `operator`, ...): node-specific ranges
pointing to various interesting tokens corresponding to the node.
Note that the Heredoc map is the only one whose ‘expression` does not include other ranges. It only covers the heredoc marker (`<<HERE`), not the here document itself.
All ranges except ‘expression` are defined by Map subclasses.
Ranges (except ‘expression`) can be `nil` if the corresponding token is not present in source. For example, a hash may not have opening/closing braces, and so would its source map.
p Parser::CurrentRuby.parse('[1 => 2]').children[0].loc
# => <Parser::Source::Map::Collection:0x007f5492b547d8
# @end=nil, @begin=nil,
# @expression=#<Source::Range (string) 1...7>>
The AST_FORMAT document describes how ranges associated to source code tokens. For example, the entry
(array (int 1) (int 2))
"[1, 2]"
^ begin
^ end
~~~~~~ expression
means that if ‘node` is an AST::Node `(array (int 1) (int 2))`, then `node.loc` responds to `begin`, `end` and `expression`, and `node.loc.begin` returns a range pointing at the opening bracket, and so on.
If you want to write code polymorphic by the source map (i.e. accepting several subclasses of Map), use ‘respond_to?` instead of `is_a?` to check whether the map features the range you need. Concrete Map subclasses may not be preserved between versions, but their interfaces will be kept compatible.
You can visualize the source maps with ‘ruby-parse -E` command-line tool.
Direct Known Subclasses
Collection, Condition, Constant, Definition, For, Heredoc, Index, Keyword, MethodDefinition, ObjcKwarg, Operator, RescueBody, Send, Ternary, Variable
Defined Under Namespace
Classes: Collection, Condition, Constant, Definition, For, Heredoc, Index, Keyword, MethodDefinition, ObjcKwarg, Operator, RescueBody, Send, Ternary, Variable
Instance Attribute Summary collapse
- #expression ⇒ Range readonly
-
#node ⇒ Parser::AST::Node
The node that is described by this map.
Instance Method Summary collapse
-
#==(other) ⇒ Boolean
Compares source maps.
-
#column ⇒ Integer
A shortcut for ‘self.expression.column`.
-
#initialize(expression) ⇒ Map
constructor
A new instance of Map.
- #initialize_copy(other) ⇒ Object private
-
#last_column ⇒ Integer
A shortcut for ‘self.expression.last_column`.
-
#last_line ⇒ Integer
A shortcut for ‘self.expression.last_line`.
-
#line ⇒ Integer
(also: #first_line)
A shortcut for ‘self.expression.line`.
-
#to_hash ⇒ Hash<Symbol, Parser::Source::Range>
Converts this source map to a hash with keys corresponding to ranges.
- #with_expression(expression_l) ⇒ Object private
Constructor Details
#initialize(expression) ⇒ Map
Returns a new instance of Map.
76 77 78 |
# File 'lib/parser/source/map.rb', line 76 def initialize(expression) @expression = expression end |
Instance Attribute Details
#expression ⇒ Range (readonly)
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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/parser/source/map.rb', line 70 class Map attr_reader :node attr_reader :expression ## # @param [Range] expression def initialize(expression) @expression = expression end ## # @api private def initialize_copy(other) super @node = nil end ## # @api private def node=(node) @node = node freeze @node end ## # A shortcut for `self.expression.line`. # @return [Integer] # def line @expression.line end alias_method :first_line, :line ## # A shortcut for `self.expression.column`. # @return [Integer] # def column @expression.column end ## # A shortcut for `self.expression.last_line`. # @return [Integer] # def last_line @expression.last_line end ## # A shortcut for `self.expression.last_column`. # @return [Integer] # def last_column @expression.last_column end ## # @api private # def with_expression(expression_l) with { |map| map.update_expression(expression_l) } end ## # Compares source maps. # @return [Boolean] # def ==(other) other.class == self.class && instance_variables.map do |ivar| instance_variable_get(ivar) == other.send(:instance_variable_get, ivar) end.reduce(:&) end ## # Converts this source map to a hash with keys corresponding to # ranges. For example, if called on an instance of {Collection}, # which adds the `begin` and `end` ranges, the resulting hash # will contain keys `:expression`, `:begin` and `:end`. # # @example # require 'parser/current' # # p Parser::CurrentRuby.parse('[1, 2]').loc.to_hash # # => { # # :begin => #<Source::Range (string) 0...1>, # # :end => #<Source::Range (string) 5...6>, # # :expression => #<Source::Range (string) 0...6> # # } # # @return [Hash<Symbol, Parser::Source::Range>] # def to_hash instance_variables.inject({}) do |hash, ivar| next hash if ivar.to_sym == :@node hash[ivar[1..-1].to_sym] = instance_variable_get(ivar) hash end end protected def with(&block) dup.tap(&block) end def update_expression(expression_l) @expression = expression_l end end |
#node ⇒ Parser::AST::Node
The node that is described by this map. Nodes and maps have 1:1 correspondence.
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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
# File 'lib/parser/source/map.rb', line 70 class Map attr_reader :node attr_reader :expression ## # @param [Range] expression def initialize(expression) @expression = expression end ## # @api private def initialize_copy(other) super @node = nil end ## # @api private def node=(node) @node = node freeze @node end ## # A shortcut for `self.expression.line`. # @return [Integer] # def line @expression.line end alias_method :first_line, :line ## # A shortcut for `self.expression.column`. # @return [Integer] # def column @expression.column end ## # A shortcut for `self.expression.last_line`. # @return [Integer] # def last_line @expression.last_line end ## # A shortcut for `self.expression.last_column`. # @return [Integer] # def last_column @expression.last_column end ## # @api private # def with_expression(expression_l) with { |map| map.update_expression(expression_l) } end ## # Compares source maps. # @return [Boolean] # def ==(other) other.class == self.class && instance_variables.map do |ivar| instance_variable_get(ivar) == other.send(:instance_variable_get, ivar) end.reduce(:&) end ## # Converts this source map to a hash with keys corresponding to # ranges. For example, if called on an instance of {Collection}, # which adds the `begin` and `end` ranges, the resulting hash # will contain keys `:expression`, `:begin` and `:end`. # # @example # require 'parser/current' # # p Parser::CurrentRuby.parse('[1, 2]').loc.to_hash # # => { # # :begin => #<Source::Range (string) 0...1>, # # :end => #<Source::Range (string) 5...6>, # # :expression => #<Source::Range (string) 0...6> # # } # # @return [Hash<Symbol, Parser::Source::Range>] # def to_hash instance_variables.inject({}) do |hash, ivar| next hash if ivar.to_sym == :@node hash[ivar[1..-1].to_sym] = instance_variable_get(ivar) hash end end protected def with(&block) dup.tap(&block) end def update_expression(expression_l) @expression = expression_l end end |
Instance Method Details
#==(other) ⇒ Boolean
Compares source maps.
140 141 142 143 144 145 146 |
# File 'lib/parser/source/map.rb', line 140 def ==(other) other.class == self.class && instance_variables.map do |ivar| instance_variable_get(ivar) == other.send(:instance_variable_get, ivar) end.reduce(:&) end |
#column ⇒ Integer
A shortcut for ‘self.expression.column`.
109 110 111 |
# File 'lib/parser/source/map.rb', line 109 def column @expression.column end |
#initialize_copy(other) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
82 83 84 85 |
# File 'lib/parser/source/map.rb', line 82 def initialize_copy(other) super @node = nil end |
#last_column ⇒ Integer
A shortcut for ‘self.expression.last_column`.
125 126 127 |
# File 'lib/parser/source/map.rb', line 125 def last_column @expression.last_column end |
#last_line ⇒ Integer
A shortcut for ‘self.expression.last_line`.
117 118 119 |
# File 'lib/parser/source/map.rb', line 117 def last_line @expression.last_line end |
#line ⇒ Integer Also known as: first_line
A shortcut for ‘self.expression.line`.
99 100 101 |
# File 'lib/parser/source/map.rb', line 99 def line @expression.line end |
#to_hash ⇒ Hash<Symbol, Parser::Source::Range>
Converts this source map to a hash with keys corresponding to ranges. For example, if called on an instance of Collection, which adds the ‘begin` and `end` ranges, the resulting hash will contain keys `:expression`, `:begin` and `:end`.
166 167 168 169 170 171 172 |
# File 'lib/parser/source/map.rb', line 166 def to_hash instance_variables.inject({}) do |hash, ivar| next hash if ivar.to_sym == :@node hash[ivar[1..-1].to_sym] = instance_variable_get(ivar) hash end end |
#with_expression(expression_l) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
132 133 134 |
# File 'lib/parser/source/map.rb', line 132 def with_expression(expression_l) with { |map| map.update_expression(expression_l) } end |