File manager - Edit - /opt/cpanel/ea-ruby27/root/usr/local/share/gems/gems/irb-1.18.0/lib/irb/nesting_parser.rb
Back
# frozen_string_literal: true require 'prism' module IRB module NestingParser NestingElem = Struct.new(:pos, :event, :tok) class NestingVisitor < Prism::Visitor def initialize # Array of [column, priority(+1/-1), NestingElem(open) or nil(close)] per line. # priority is +1 for open, -1 for close so that close comes before open when sorted. # Example: # if cond # else # end # `else` closes `if` at column 0 first and then opens `else` at column 0 next. @lines = [] # Array of open heredoc NestingElem per line @heredocs = [] end def nestings size = [@lines.size, @heredocs.size].max nesting = [] size.times.map do |line_index| @lines[line_index]&.sort_by { |col, pri| [col, pri] }&.each do |col, pri, elem| if elem nesting << elem else nesting.pop end end @heredocs[line_index]&.sort_by { |elem| elem.pos[1] }&.reverse_each do |elem| nesting << elem end nesting.dup end end def heredoc_open(node) elem = NestingElem.new([node.location.start_line, node.location.start_column], :on_heredoc_beg, node.opening) (@heredocs[node.location.start_line - 1] ||= []) << elem end def open(line, column, elem) (@lines[line - 1] ||= []) << [column, +1, elem] end def close(line, column) (@lines[line - 1] ||= []) << [column, -1] end # Checks if a node (if, while, etc) is a modifier form that does not need `end` closing. # modifier node: `a if b`, non-modifier node: `if a; b; end` def modifier_node?(node, keyword_loc) !(keyword_loc && node.location.start_line == keyword_loc.start_line && node.location.start_column == keyword_loc.start_column) end def open_location(location, type, tok) open(location.start_line, location.start_column, NestingElem.new([location.start_line, location.start_column], type, tok)) end def close_location(location) close(location.end_line, location.end_column) end def close_location_start(location) close(location.start_line, location.start_column) end def close_end_keyword_loc(node) close_location(node.end_keyword_loc) if node.end_keyword == 'end' end def close_closing_loc(node) close_location(node.closing_loc) if node.closing_loc && !node.closing.empty? end def visit_for_node(node) super open_location(node.location, :on_kw, 'for') close_end_keyword_loc(node) end def visit_while_node(node) super return if modifier_node?(node, node.keyword_loc) open_location(node.location, :on_kw, 'while') close_closing_loc(node) end def visit_until_node(node) super return if modifier_node?(node, node.keyword_loc) open_location(node.location, :on_kw, 'until') close_closing_loc(node) end def visit_if_node(node) super return if !node.if_keyword || modifier_node?(node, node.if_keyword_loc) open_location(node.location, :on_kw, node.if_keyword) if node.subsequent close_location_start(node.subsequent.location) else close_end_keyword_loc(node) end end def visit_unless_node(node) super return if modifier_node?(node, node.keyword_loc) open_location(node.location, :on_kw, 'unless') if node.else_clause close_location_start(node.else_clause.location) else close_end_keyword_loc(node) end end def visit_case_node(node) super open_location(node.location, :on_kw, 'case') if node.else_clause close_location_start(node.else_clause.location) else close_end_keyword_loc(node) end end alias visit_case_match_node visit_case_node def visit_when_node(node) super close_location_start(node.location) open_location(node.location, :on_kw, 'when') end def visit_in_node(node) super close_location_start(node.location) open_location(node.location, :on_kw, 'in') end def visit_else_node(node) super if node.else_keyword == 'else' open_location(node.location, :on_kw, 'else') close_end_keyword_loc(node) end end def visit_ensure_node(node) super return if modifier_node?(node, node.ensure_keyword_loc) close_location_start(node.location) open_location(node.location, :on_kw, 'ensure') end def visit_rescue_node(node) super return if modifier_node?(node, node.keyword_loc) close_location_start(node.location) open_location(node.location, :on_kw, 'rescue') end def visit_begin_node(node) super if node.begin_keyword open_location(node.location, :on_kw, 'begin') close_end_keyword_loc(node) end end def visit_block_node(node) super open_location(node.location, node.opening == '{' ? :on_lbrace : :on_kw, node.opening) close_closing_loc(node) end def visit_array_node(node) super type = case node.opening when nil # `x = 1, 2` doesn't have opening nil when '[' :bracket when /\A%W/ :on_words_beg when /\A%w/ :on_qwords_beg when /\A%I/ :on_symbols_beg when /\A%i/ :on_qsymbols_beg end if type open_location(node.location, type, node.opening) close_closing_loc(node) end end def visit_hash_node(node) super open_location(node.location, :on_lbrace, '{') close_closing_loc(node) end def heredoc_string_like(node, type) if node.opening&.start_with?('<<') heredoc_open(node) # Heredoc closing contains trailing newline. We need to exclude it close_location_start(node.closing_loc) if node.closing_loc && !node.closing.empty? elsif node.opening return if node.opening == '?' && node.closing.nil? # Character literal has no closing open_location(node.location, type, node.opening) if node.closing && node.closing != '' # Closing of `"#{\n` is "\n". We need to treat it as not-closed. close_location_start(node.closing_loc) if node.opening.match?(/\n\z/) || node.closing != "\n" end end end def visit_embedded_statements_node(node) super open_location(node.location, :on_embexpr_beg, '#{') close_closing_loc(node) end def visit_interpolated_string_node(node) super heredoc_string_like(node, :on_tstring_beg) end alias visit_string_node visit_interpolated_string_node def visit_interpolated_x_string_node(node) super heredoc_string_like(node, :on_backtick) end alias visit_x_string_node visit_interpolated_x_string_node def visit_symbol_node(node) super unless node.opening.nil? || node.opening.empty? || node.opening == ':' # :"sym" or %s[sym] open_location(node.location, :on_symbeg, node.opening) close_closing_loc(node) end end alias visit_interpolated_symbol_node visit_symbol_node def visit_regular_expression_node(node) super open_location(node.location, :on_regexp_beg, node.opening) close_closing_loc(node) end alias visit_interpolated_regular_expression_node visit_regular_expression_node def visit_parentheses_node(node) super open_location(node.location, :on_lparen, '(') close_closing_loc(node) end def visit_call_node(node) super type = case node.opening when '(' :on_lparen when '[' :on_lbracket end if type open_location(node.opening_loc, type, node.opening) close_closing_loc(node) end end def visit_block_parameters_node(node) super if node.opening == '(' open_location(node.location, :on_lparen, '(') close_closing_loc(node) end end def visit_lambda_node(node) super open_location(node.opening_loc, :on_tlambeg, node.opening) close_closing_loc(node) end def visit_super_node(node) super if node.lparen open_location(node.lparen_loc, :on_lparen, '(') close_location(node.rparen_loc) if node.rparen == ')' end end alias visit_yield_node visit_super_node alias visit_defined_node visit_super_node def visit_def_node(node) super open_location(node.location, :on_kw, 'def') if node.lparen == '(' open_location(node.lparen_loc, :on_lparen, '(') close_location(node.rparen_loc) if node.rparen == ')' end if node.equal close_location(node.equal_loc) else close_end_keyword_loc(node) end end def visit_class_node(node) super open_location(node.location, :on_kw, 'class') close_end_keyword_loc(node) end alias visit_singleton_class_node visit_class_node def visit_module_node(node) super open_location(node.location, :on_kw, 'module') close_end_keyword_loc(node) end end class << self # Return a list of open nesting elements at EOF position def open_nestings(parse_lex_result) parse_by_line(parse_lex_result).last[1] end # Calculates nesting information [prev_opens, next_opens, min_depth] for each line. # Example code # ["hello # world"+( # First line # prev_opens: [] # next_opens: [lbracket, tstring_beg] # min_depth: 0 (minimum at beginning of line) # Second line # prev_opens: [lbracket, tstring_beg] # next_opens: [lbracket, lparen] # min_depth: 1 (minimum just after tstring_end) def parse_by_line(parse_lex_result) visitor = NestingVisitor.new node, tokens = parse_lex_result.value node.accept(visitor) tokens.each do |token,| case token.type when :EMBDOC_BEGIN visitor.open_location(token.location, :on_embdoc_beg, '=begin') when :EMBDOC_END visitor.close_location_start(token.location) end end nestings = visitor.nestings last_nesting = nestings.last || [] num_lines = parse_lex_result.source.source.lines.size num_lines.times.map do |i| prev_opens = i == 0 ? [] : nestings[i - 1] || last_nesting opens = nestings[i] || last_nesting min_depth = prev_opens.zip(opens).take_while { |s, e| s == e }.size [prev_opens, opens, min_depth] end end end end end
| ver. 1.4 |
Github
|
.
| PHP 8.1.34 | Generation time: 0.02 |
proxy
|
phpinfo
|
Settings