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 147 148 149 150 151 152 153 154 155 156 157
|
# frozen_string_literal: true
require_relative '../runner'
require_relative '../color'
require_relative '../lexer/explanation'
require 'json'
module Parser
class Runner::RubyParse < Parser::Runner
class LocationProcessor < Parser::AST::Processor
def process(node)
if node
p node
source_line_no = nil
source_line = ''
hilight_line = ''
print_line = lambda do
unless hilight_line.empty?
puts hilight_line.
gsub(/[a-z_]+/) { |m| Color.yellow(m, bold: true) }.
gsub(/[~.]+/) { |m| Color.magenta(m, bold: true) }
hilight_line = ''
end
end
print_source = lambda do |range|
source_line = range.source_line
puts Color.green(source_line)
source_line
end
(node.loc || {}).to_hash.
sort_by do |name, range|
[(range ? range.line : 0),
(name == :expression ? 1 : 0)]
end.
each do |name, range|
next if range.nil?
if source_line_no != range.line
print_line.call()
source_line = print_source.call(range)
source_line_no = range.line
end
beg_col = range.begin.column
if beg_col + range.length > source_line.length
multiline = true
range_length = source_line.length - beg_col + 3
else
multiline = false
range_length = range.length
end
length = range_length + 1 + name.length
end_col = beg_col + length
if beg_col > 0
col_range = (beg_col - 1)...end_col
else
col_range = beg_col...end_col
end
if hilight_line.length < end_col
hilight_line = hilight_line.ljust(end_col)
end
if hilight_line[col_range] =~ /^\s*$/
if multiline
tail = ('~' * (source_line.length - beg_col)) + '...'
else
tail = '~' * range_length
end
tail = ' ' + tail if beg_col > 0
hilight_line[col_range] = tail + " #{name}"
else
print_line.call
redo
end
end
print_line.call
end
super
end
end
def initialize
super
@locate = false
@emit_ruby = false
@emit_json = false
end
private
def runner_name
'ruby-parse'
end
def setup_option_parsing(opts)
super(opts)
opts.on '-L', '--locate', 'Explain how source maps for AST nodes are laid out' do |v|
@locate = v
end
opts.on '-E', '--explain', 'Explain how the source is tokenized' do
ENV['RACC_DEBUG'] = '1'
Lexer.send :include, Lexer::Explanation
end
opts.on '--emit-ruby', 'Emit S-expressions as valid Ruby code' do
@emit_ruby = true
end
opts.on '--emit-json', 'Emit S-expressions as valid JSON' do
@emit_json = true
end
end
def process_all_input
if input_size > 1
puts "Using #{@parser_class} to parse #{input_size} files."
end
super
end
def process(buffer)
ast = @parser.parse(buffer)
if @locate
LocationProcessor.new.process(ast)
elsif !@benchmark
if @emit_ruby
puts ast.inspect
elsif @emit_json
puts(ast ? JSON.generate(ast.to_sexp_array) : nil)
else
puts ast.to_s
end
end
end
end
end
|