Class: YARD::Parser::Ruby::RipperParser
Relationships & Source Files | |
Super Chains via Extension / Inclusion / Inheritance | |
Class Chain:
self,
Ripper
|
|
Instance Chain:
self,
Ripper
|
|
Inherits: |
Ripper
|
Defined in: | lib/yard/parser/ruby/ruby_parser.rb |
Overview
Internal parser class
Constant Summary
-
AST_TOKENS =
[:CHAR, :backref, :const, :cvar, :gvar, :heredoc_end, :ident, :int, :float, :ivar, :label, :period, :regexp_end, :tstring_content, :backtick]
-
COMMENT_SKIP_NODE_TYPES =
[ :comment, :void_stmt, :list ].freeze
-
MAPPINGS =
{ :BEGIN => "BEGIN", :END => "END", :alias => "alias", :array => :lbracket, :arg_paren => :lparen, :begin => "begin", :blockarg => "&", :brace_block => :lbrace, :break => "break", :case => "case", :class => "class", :def => "def", :defined => "defined?", :defs => "def", :do_block => "do", :else => "else", :elsif => "elsif", :ensure => "ensure", :for => "for", :hash => :lbrace, :if => "if", :lambda => [:tlambda, "lambda"], :module => "module", :next => "next", :paren => :lparen, :qwords_literal => :qwords_beg, :words_literal => :words_beg, :qsymbols_literal => :qsymbols_beg, :symbols_literal => :symbols_beg, :redo => "redo", :regexp_literal => :regexp_beg, :rescue => "rescue", :rest_param => "*", :retry => "retry", :return => "return", :return0 => "return", :sclass => "class", :string_embexpr => :embexpr_beg, :string_literal => [:tstring_beg, :heredoc_beg], :super => "super", :symbol => :symbeg, :top_const_ref => "::", :undef => "undef", :unless => "unless", :until => "until", :when => "when", :while => "while", :xstring_literal => :backtick, :yield => "yield", :yield0 => "yield", :zsuper => "super" }
-
REV_MAPPINGS =
{}
Class Method Summary
- .new(source, filename, *args) ⇒ RipperParser constructor
Instance Attribute Summary
- #ast (also: #root, #root) readonly
- #charno readonly
- #comments readonly
- #encoding_line readonly
- #file readonly
- #frozen_string_line readonly
-
#root
readonly
Alias for #ast.
- #shebang_line readonly
- #tokens readonly
Instance Method Summary
- #enumerator
- #file_encoding
- #initialize(source, filename, *args) ⇒ RipperParser constructor
- #parse
- #add_comment(line, node = nil, before_node = nil, into = false) private
- #add_token(token, data) private
- #comment_starts_line?(charno) ⇒ Boolean private
-
#compile_error(msg)
private
Alias for #on_parse_error.
- #freeze_tree(node = nil) private
- #insert_comments private
- #on_aref(*args) private
- #on_aref_field(*args) private
- #on_array(other) private
- #on_assoc_new(*args) private
- #on_assoclist_from_args(*args) private
- #on_bare_assoc_hash(*args) private
- #on_body_stmt(*args) (also: #on_bodystmt, #on_bodystmt) private
-
#on_bodystmt(*args)
private
Alias for #on_body_stmt.
- #on_comment(comment) private
- #on_const_path_ref(*args) private
- #on_dyna_symbol(sym) private
- #on_embdoc(text) private
- #on_embdoc_beg(text) private
- #on_embdoc_end(text) private
- #on_hash(*args) private
- #on_label(data) private
- #on_lambda(*args) private
- #on_lbracket(tok) private
- #on_params(*args) private
- #on_parse_error(msg) (also: #compile_error, #compile_error) private
- #on_program(*args) private
- #on_rbracket(tok) private
- #on_rescue(exc, *args) private
- #on_sp(tok) private
- #on_string_content(*args) private
- #on_string_literal(*args) private
- #on_top_const_ref(*args) private
- #on_unary(op, val) private
- #on_void_stmt private
- #visit_event(node) private
- #visit_event_arr(node) private
- #visit_ns_token(token, data, ast_token = false) private
Constructor Details
.new(source, filename, *args) ⇒ RipperParser
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 32
def initialize(source, filename, *args) super @last_ns_token = nil @file = filename @source = source @tokens = [] @comments = {} @comments_range = {} @comments_flags = {} @heredoc_tokens = nil @heredoc_state = nil @map = {} @ns_charno = 0 @list = [] @charno = 0 @shebang_line = nil @encoding_line = nil @frozen_string_line = nil @file_encoding = nil @newline = true @percent_ary = nil end
#initialize(source, filename, *args) ⇒ RipperParser
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 32
def initialize(source, filename, *args) super @last_ns_token = nil @file = filename @source = source @tokens = [] @comments = {} @comments_range = {} @comments_flags = {} @heredoc_tokens = nil @heredoc_state = nil @map = {} @ns_charno = 0 @list = [] @charno = 0 @shebang_line = nil @encoding_line = nil @frozen_string_line = nil @file_encoding = nil @newline = true @percent_ary = nil end
Instance Attribute Details
#ast (readonly) Also known as: #root, #root
#charno (readonly)
#comments (readonly)
#encoding_line (readonly)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 29
attr_reader :shebang_line, :encoding_line, :frozen_string_line
#file (readonly)
#frozen_string_line (readonly)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 29
attr_reader :shebang_line, :encoding_line, :frozen_string_line
#root (readonly)
Alias for #ast.
#shebang_line (readonly)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 29
attr_reader :shebang_line, :encoding_line, :frozen_string_line
#tokens (readonly)
Instance Method Details
#add_comment(line, node = nil, before_node = nil, into = false) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 667
def add_comment(line, node = nil, before_node = nil, into = false) comment = @comments[line] source_range = @comments_range[line] line_range = ((line - comment.count("\n"))..line) if node.nil? node = CommentNode.new(:comment, [comment], :line => line_range, :char => source_range) if into before_node.push(node) before_node.unfreeze node.parent = before_node elsif before_node parent_node = before_node.parent idx = parent_node.index(before_node) parent_node.insert(idx, node) parent_node.unfreeze node.parent = parent_node end end node.docstring = comment node.docstring_hash_flag = @comments_flags[line] node.docstring_range = line_range @comments.delete(line) @comments_range.delete(line) @comments_flags.delete(line) end
#add_token(token, data) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 271
def add_token(token, data) if @percent_ary if token == :words_sep && data !~ /\s\z/ rng = @percent_ary.source_range rng = Range.new(rng.first, rng.last + data.length) @percent_ary.source_range = rng @tokens << [token, data, [lineno, charno]] @percent_ary = nil return elsif token == :tstring_end && data =~ /\A\s/ rng = @percent_ary.source_range rng = Range.new(rng.first, rng.last + data.length) @percent_ary.source_range = rng @tokens << [token, data, [lineno, charno]] @percent_ary = nil return end end if @tokens.last && (@tokens.last[0] == :symbeg || (@tokens.last[0] == :symbol && token.to_s =~ /^tstring/)) @tokens[-1] = [:symbol, @tokens.last[1] + data, @tokens.last[2]] elsif @heredoc_state == :started @heredoc_tokens << [token, data, [lineno, charno]] # fix ripper encoding of heredoc bug # (see http://bugs.ruby-lang.org/issues/6200) data.force_encoding(file_encoding) if file_encoding @heredoc_state = :ended if token == :heredoc_end elsif (token == :nl || token == :comment) && @heredoc_state == :ended @heredoc_tokens.unshift([token, data, [lineno, charno]]) @tokens += @heredoc_tokens @heredoc_tokens = nil @heredoc_state = nil else @tokens << [token, data, [lineno, charno]] if token == :heredoc_beg @heredoc_state = :started @heredoc_tokens = [] end end end
#comment_starts_line?(charno) ⇒ Boolean
(private)
#compile_error(msg) (private)
Alias for #on_parse_error.
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 609
alias compile_error on_parse_error
#enumerator
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 64
def enumerator ast.children end
#file_encoding
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 68
def file_encoding return nil unless defined?(::Encoding) return @file_encoding if @file_encoding return Encoding.default_internal unless @encoding_line match = @encoding_line.match(SourceParser::ENCODING_LINE) @file_encoding = match.captures.last if match end
#freeze_tree(node = nil) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 693
def freeze_tree(node = nil) @tokens = @tokens.sort_by {|t| t.last } nodes = [node || root] until nodes.empty? p_node = nodes.shift p_node.children.each do |child| child.parent = p_node nodes << child end end end
#insert_comments (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 620
def insert_comments root.traverse do |node| next if COMMENT_SKIP_NODE_TYPES.include?(node.type) || node.parent.type != :list # never attach comments to if/unless mod nodes if node.type == :if_mod || node.type == :unless_mod node = node.then_block end # check upwards from line before node; check node's line at the end ((node.line - 1).downto(node.line - 2).to_a + [node.line]).each do |line| comment = @comments[line] if comment && !comment.empty? add_comment(line, node) break end end @comments.keys.each do |line| add_comment(line, nil, node) if node.line > line end end # insert any lone unadded comments before node root.traverse do |node| next if node.type == :list || node.parent.type != :list @comments.keys.each do |line| next unless node.line_range.include?(line) pick = nil node.traverse do |subnode| next unless subnode.type == :list pick ||= subnode next unless subnode.line_range.include?(line) pick = subnode end add_comment(line, nil, pick, true) if pick end end unless @comments.empty? # insert all remaining comments @comments.each do |line, _comment| add_comment(line, nil, root, true) end @comments = {} end
#on_aref(*args) (private)
#on_aref_field(*args) (private)
#on_array(other) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 391
def on_array(other) node = AstNode.node_class_for(:array).new(:array, [other]) map = @map[MAPPINGS[node.type]] if map && !map.empty? lstart, sstart = *map.pop node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) else sstart = other.source_range.begin lstart = other.line_range.begin node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) node.source_range = other.source_range node.line_range = other.line_range end node end
#on_assoc_new(*args) (private)
#on_assoclist_from_args(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 364
def on_assoclist_from_args(*args) args.first end
#on_bare_assoc_hash(*args) (private)
#on_body_stmt(*args) (private) Also known as: #on_bodystmt, #on_bodystmt
#on_bodystmt(*args) (private)
Alias for #on_body_stmt.
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 350
alias on_bodystmt on_body_stmt
#on_comment(comment) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 542
def on_comment(comment) not_comment = false if @last_ns_token.nil? || @last_ns_token.empty? if comment =~ SourceParser::SHEBANG_LINE && !@encoding_line @shebang_line = comment not_comment = true elsif comment =~ SourceParser::ENCODING_LINE @encoding_line = comment not_comment = true elsif comment =~ SourceParser::FROZEN_STRING_LINE @frozen_string_line = comment not_comment = true end end ch = charno visit_ns_token(:comment, comment) if not_comment @last_ns_token = nil return end source_range = ch..(charno - 1) comment = comment.gsub(/^(\#+)\s{0,1}/, '').chomp append_comment = @comments[lineno - 1] hash_flag = $1 == '##' ? true : false if append_comment && @comments_last_column && @comments_last_column == column && comment_starts_line?(ch) @comments.delete(lineno - 1) @comments_flags[lineno] = @comments_flags[lineno - 1] @comments_flags.delete(lineno - 1) range = @comments_range.delete(lineno - 1) source_range = range.first..source_range.last comment = append_comment + "\n" + comment end @comments[lineno] = comment @comments_range[lineno] = source_range @comments_flags[lineno] = hash_flag unless append_comment @comments_last_column = column end
#on_const_path_ref(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 441
def on_const_path_ref(*args) ReferenceNode.new(:const_path_ref, args, :listline => lineno..lineno, :listchar => charno..charno) end
#on_dyna_symbol(sym) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 419
def on_dyna_symbol(sym) rng = if sym.source_range.to_a.size == 0 # rubocop:disable Style/ZeroLengthPredicate (sym.source_range.begin - 3)...sym.source_range.end else (sym.source_range.begin - 2)..(sym.source_range.end + 1) end AstNode.new(:dyna_symbol, [sym], :line => lineno..lineno, :listline => lineno..lineno, :listchar => rng, :char => rng) end
#on_embdoc(text) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 592
def on_embdoc(text) visit_ns_token(:embdoc, text) @embdoc << text end
#on_embdoc_beg(text) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 586
def on_embdoc_beg(text) visit_ns_token(:embdoc_beg, text) @embdoc_start = charno - text.length @embdoc = String.new("") end
#on_embdoc_end(text) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 597
def on_embdoc_end(text) visit_ns_token(:embdoc_end, text) @comments_last_column = nil @comments[lineno] = @embdoc @comments_range[lineno] = @embdoc_start...charno @embdoc_start = nil @embdoc = nil end
#on_hash(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 356
def on_hash(*args) visit_event AstNode.new(:hash, args.first || []) end
#on_label(data) (private)
#on_lambda(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 497
def on_lambda(*args) visit_event_arr AstNode.new(:lambda, args) end
#on_lbracket(tok) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 409
def on_lbracket(tok) (@map[:lbracket] ||= []) << [lineno, charno] visit_ns_token(:lbracket, tok, false) end
#on_params(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 515
def on_params(*args) args.map! do |arg| next arg unless arg.class == Array if arg.first.class == Array arg.map! do |sub_arg| next sub_arg unless sub_arg.class == Array type = sub_arg[0].type == :label ? :named_arg : :unnamed_optional_arg AstNode.new(type, sub_arg, :listline => lineno..lineno, :listchar => charno..charno) end end AstNode.new(:list, arg, :listline => lineno..lineno, :listchar => charno..charno) end ParameterNode.new(:params, args, :listline => lineno..lineno, :listchar => charno..charno) end
#on_parse_error(msg) (private) Also known as: #compile_error, #compile_error
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 606
def on_parse_error(msg) raise ParserSyntaxError, "syntax error in `#{file}`:(#{lineno},#{column}): #{msg}" end
#on_program(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 343
def on_program(*args) args.first end
#on_rbracket(tok) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 414
def on_rbracket(tok) (@map[:aref] ||= []) << [lineno, charno] visit_ns_token(:rbracket, tok, false) end
#on_rescue(exc, *args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 506
def on_rescue(exc, *args) exc = AstNode.new(:list, exc) if exc visit_event AstNode.new(:rescue, [exc, *args]) end
#on_sp(tok) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 232
def on_sp(tok) add_token(:sp, tok) @charno += tok.length end
#on_string_content(*args) (private)
#on_string_literal(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 484
def on_string_literal(*args) node = visit_event_arr(LiteralNode.new(:string_literal, args)) if args.size == 1 r = args[0].source_range if node.source_range != Range.new(r.first - 1, r.last + 1) klass = AstNode.node_class_for(node[0].type) r = Range.new(node.source_range.first + 1, node.source_range.last - 1) node[0] = klass.new(node[0].type, [@source[r]], :line => node.line_range, :char => r) end end node end
#on_top_const_ref(*args) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 429
def on_top_const_ref(*args) type = :top_const_ref node = AstNode.node_class_for(type).new(type, args) mapping = @map[MAPPINGS[type]] extra_op = mapping.last[1] + 2 == charno ? mapping.pop : nil lstart, sstart = *mapping.pop node.source_range = Range.new(sstart, args.last.source_range.last) node.line_range = Range.new(lstart, args.last.line_range.last) mapping.push(extra_op) if extra_op node end
#on_unary(op, val) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 368
def on_unary(op, val) map = @map[op.to_s[0, 1]] lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1]) node = AstNode.node_class_for(:unary).new(:unary, [op, val]) node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) node end
#on_void_stmt (private)
#parse
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 55
def parse @ast = super @ast.full_source = @source @ast.file = @file freeze_tree insert_comments self end
#visit_event(node) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 237
def visit_event(node) map = @map[MAPPINGS[node.type]] lstart, sstart = *(map ? map.pop : [lineno, @ns_charno - 1]) node.source_range = Range.new(sstart, @ns_charno - 1) node.line_range = Range.new(lstart, lineno) if node.respond_to?(:block) sr = node.block.source_range lr = node.block.line_range node.block.source_range = Range.new(sr.first, @tokens.last[2][1] - 1) node.block.line_range = Range.new(lr.first, @tokens.last[2][0]) end node end
#visit_event_arr(node) (private)
#visit_ns_token(token, data, ast_token = false) (private)
# File 'lib/yard/parser/ruby/ruby_parser.rb', line 259
def visit_ns_token(token, data, ast_token = false) add_token(token, data) ch = charno @last_ns_token = [token, data] @charno += data.length @ns_charno = charno @newline = [:semicolon, :comment, :kw, :op, :lparen, :lbrace].include?(token) if ast_token AstNode.new(token, [data], :line => lineno..lineno, :char => ch..charno - 1, :token => true) end end