Class: Parser::Diagnostic
- Inherits:
-
Object
- Object
- Parser::Diagnostic
- Defined in:
- lib/parser/diagnostic.rb
Defined Under Namespace
Classes: Engine
Constant Summary collapse
- LEVELS =
Collection of the available diagnostic levels.
[:note, :warning, :error, :fatal].freeze
Instance Attribute Summary collapse
-
#arguments ⇒ Symbol
readonly
Extended arguments that describe the error.
-
#highlights ⇒ Array<Parser::Source::Range>
readonly
Supplementary error-related source ranges.
-
#level ⇒ Symbol
readonly
Diagnostic level.
-
#location ⇒ Parser::Source::Range
readonly
Main error-related source range.
-
#message ⇒ String
readonly
The rendered message.
-
#reason ⇒ Symbol
readonly
Reason for error.
Instance Method Summary collapse
-
#initialize(level, reason, arguments, location, highlights = []) ⇒ Diagnostic
constructor
A new instance of Diagnostic.
-
#render ⇒ Array<String>
Renders the diagnostic message as a clang-like diagnostic.
Constructor Details
#initialize(level, reason, arguments, location, highlights = []) ⇒ Diagnostic
Returns a new instance of Diagnostic.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
# File 'lib/parser/diagnostic.rb', line 49 def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end |
Instance Attribute Details
#arguments ⇒ Symbol (readonly)
Returns extended arguments that describe the error.
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 158 159 160 161 162 |
# File 'lib/parser/diagnostic.rb', line 31 class Diagnostic ## # Collection of the available diagnostic levels. # # @return [Array] # LEVELS = [:note, :warning, :error, :fatal].freeze attr_reader :level, :reason, :arguments attr_reader :location, :highlights ## # @param [Symbol] level # @param [Symbol] reason # @param [Hash] arguments # @param [Parser::Source::Range] location # @param [Array<Parser::Source::Range>] highlights # def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end ## # @return [String] the rendered message. # def Messages.compile(@reason, @arguments) end ## # Renders the diagnostic message as a clang-like diagnostic. # # @example # diagnostic.render # => # # [ # # "(fragment:0):1:5: error: unexpected token $end", # # "foo +", # # " ^" # # ] # # @return [Array<String>] # def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end private ## # Renders one source line in clang diagnostic style, with highlights. # # @return [Array<String>] # def render_line(range, ellipsis=false, range_end=false) source_line = range.source_line highlight_line = ' ' * source_line.length @highlights.each do |highlight| line_range = range.source_buffer.line_range(range.line) if highlight = highlight.intersect(line_range) highlight_line[highlight.column_range] = '~' * highlight.size end end if range.is?("\n") highlight_line += "^" else if !range_end && range.size >= 1 highlight_line[range.column_range] = '^' + '~' * (range.size - 1) else highlight_line[range.column_range] = '~' * range.size end end highlight_line += '...' if ellipsis [source_line, highlight_line]. map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" } end ## # If necessary, shrink a `Range` so as to include only the first line. # # @return [Parser::Source::Range] # def first_line_only(range) if range.line != range.last_line range.resize(range.source =~ /\n/) else range end end ## # If necessary, shrink a `Range` so as to include only the last line. # # @return [Parser::Source::Range] # def last_line_only(range) if range.line != range.last_line range.adjust(begin_pos: range.source =~ /[^\n]*\z/) else range end end end |
#highlights ⇒ Array<Parser::Source::Range> (readonly)
Supplementary error-related source ranges.
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 158 159 160 161 162 |
# File 'lib/parser/diagnostic.rb', line 31 class Diagnostic ## # Collection of the available diagnostic levels. # # @return [Array] # LEVELS = [:note, :warning, :error, :fatal].freeze attr_reader :level, :reason, :arguments attr_reader :location, :highlights ## # @param [Symbol] level # @param [Symbol] reason # @param [Hash] arguments # @param [Parser::Source::Range] location # @param [Array<Parser::Source::Range>] highlights # def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end ## # @return [String] the rendered message. # def Messages.compile(@reason, @arguments) end ## # Renders the diagnostic message as a clang-like diagnostic. # # @example # diagnostic.render # => # # [ # # "(fragment:0):1:5: error: unexpected token $end", # # "foo +", # # " ^" # # ] # # @return [Array<String>] # def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end private ## # Renders one source line in clang diagnostic style, with highlights. # # @return [Array<String>] # def render_line(range, ellipsis=false, range_end=false) source_line = range.source_line highlight_line = ' ' * source_line.length @highlights.each do |highlight| line_range = range.source_buffer.line_range(range.line) if highlight = highlight.intersect(line_range) highlight_line[highlight.column_range] = '~' * highlight.size end end if range.is?("\n") highlight_line += "^" else if !range_end && range.size >= 1 highlight_line[range.column_range] = '^' + '~' * (range.size - 1) else highlight_line[range.column_range] = '~' * range.size end end highlight_line += '...' if ellipsis [source_line, highlight_line]. map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" } end ## # If necessary, shrink a `Range` so as to include only the first line. # # @return [Parser::Source::Range] # def first_line_only(range) if range.line != range.last_line range.resize(range.source =~ /\n/) else range end end ## # If necessary, shrink a `Range` so as to include only the last line. # # @return [Parser::Source::Range] # def last_line_only(range) if range.line != range.last_line range.adjust(begin_pos: range.source =~ /[^\n]*\z/) else range end end end |
#level ⇒ Symbol (readonly)
Returns diagnostic level.
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 158 159 160 161 162 |
# File 'lib/parser/diagnostic.rb', line 31 class Diagnostic ## # Collection of the available diagnostic levels. # # @return [Array] # LEVELS = [:note, :warning, :error, :fatal].freeze attr_reader :level, :reason, :arguments attr_reader :location, :highlights ## # @param [Symbol] level # @param [Symbol] reason # @param [Hash] arguments # @param [Parser::Source::Range] location # @param [Array<Parser::Source::Range>] highlights # def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end ## # @return [String] the rendered message. # def Messages.compile(@reason, @arguments) end ## # Renders the diagnostic message as a clang-like diagnostic. # # @example # diagnostic.render # => # # [ # # "(fragment:0):1:5: error: unexpected token $end", # # "foo +", # # " ^" # # ] # # @return [Array<String>] # def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end private ## # Renders one source line in clang diagnostic style, with highlights. # # @return [Array<String>] # def render_line(range, ellipsis=false, range_end=false) source_line = range.source_line highlight_line = ' ' * source_line.length @highlights.each do |highlight| line_range = range.source_buffer.line_range(range.line) if highlight = highlight.intersect(line_range) highlight_line[highlight.column_range] = '~' * highlight.size end end if range.is?("\n") highlight_line += "^" else if !range_end && range.size >= 1 highlight_line[range.column_range] = '^' + '~' * (range.size - 1) else highlight_line[range.column_range] = '~' * range.size end end highlight_line += '...' if ellipsis [source_line, highlight_line]. map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" } end ## # If necessary, shrink a `Range` so as to include only the first line. # # @return [Parser::Source::Range] # def first_line_only(range) if range.line != range.last_line range.resize(range.source =~ /\n/) else range end end ## # If necessary, shrink a `Range` so as to include only the last line. # # @return [Parser::Source::Range] # def last_line_only(range) if range.line != range.last_line range.adjust(begin_pos: range.source =~ /[^\n]*\z/) else range end end end |
#location ⇒ Parser::Source::Range (readonly)
Main error-related source range.
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 158 159 160 161 162 |
# File 'lib/parser/diagnostic.rb', line 31 class Diagnostic ## # Collection of the available diagnostic levels. # # @return [Array] # LEVELS = [:note, :warning, :error, :fatal].freeze attr_reader :level, :reason, :arguments attr_reader :location, :highlights ## # @param [Symbol] level # @param [Symbol] reason # @param [Hash] arguments # @param [Parser::Source::Range] location # @param [Array<Parser::Source::Range>] highlights # def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end ## # @return [String] the rendered message. # def Messages.compile(@reason, @arguments) end ## # Renders the diagnostic message as a clang-like diagnostic. # # @example # diagnostic.render # => # # [ # # "(fragment:0):1:5: error: unexpected token $end", # # "foo +", # # " ^" # # ] # # @return [Array<String>] # def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end private ## # Renders one source line in clang diagnostic style, with highlights. # # @return [Array<String>] # def render_line(range, ellipsis=false, range_end=false) source_line = range.source_line highlight_line = ' ' * source_line.length @highlights.each do |highlight| line_range = range.source_buffer.line_range(range.line) if highlight = highlight.intersect(line_range) highlight_line[highlight.column_range] = '~' * highlight.size end end if range.is?("\n") highlight_line += "^" else if !range_end && range.size >= 1 highlight_line[range.column_range] = '^' + '~' * (range.size - 1) else highlight_line[range.column_range] = '~' * range.size end end highlight_line += '...' if ellipsis [source_line, highlight_line]. map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" } end ## # If necessary, shrink a `Range` so as to include only the first line. # # @return [Parser::Source::Range] # def first_line_only(range) if range.line != range.last_line range.resize(range.source =~ /\n/) else range end end ## # If necessary, shrink a `Range` so as to include only the last line. # # @return [Parser::Source::Range] # def last_line_only(range) if range.line != range.last_line range.adjust(begin_pos: range.source =~ /[^\n]*\z/) else range end end end |
#message ⇒ String (readonly)
Returns the rendered message.
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 158 159 160 161 162 |
# File 'lib/parser/diagnostic.rb', line 31 class Diagnostic ## # Collection of the available diagnostic levels. # # @return [Array] # LEVELS = [:note, :warning, :error, :fatal].freeze attr_reader :level, :reason, :arguments attr_reader :location, :highlights ## # @param [Symbol] level # @param [Symbol] reason # @param [Hash] arguments # @param [Parser::Source::Range] location # @param [Array<Parser::Source::Range>] highlights # def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end ## # @return [String] the rendered message. # def Messages.compile(@reason, @arguments) end ## # Renders the diagnostic message as a clang-like diagnostic. # # @example # diagnostic.render # => # # [ # # "(fragment:0):1:5: error: unexpected token $end", # # "foo +", # # " ^" # # ] # # @return [Array<String>] # def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end private ## # Renders one source line in clang diagnostic style, with highlights. # # @return [Array<String>] # def render_line(range, ellipsis=false, range_end=false) source_line = range.source_line highlight_line = ' ' * source_line.length @highlights.each do |highlight| line_range = range.source_buffer.line_range(range.line) if highlight = highlight.intersect(line_range) highlight_line[highlight.column_range] = '~' * highlight.size end end if range.is?("\n") highlight_line += "^" else if !range_end && range.size >= 1 highlight_line[range.column_range] = '^' + '~' * (range.size - 1) else highlight_line[range.column_range] = '~' * range.size end end highlight_line += '...' if ellipsis [source_line, highlight_line]. map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" } end ## # If necessary, shrink a `Range` so as to include only the first line. # # @return [Parser::Source::Range] # def first_line_only(range) if range.line != range.last_line range.resize(range.source =~ /\n/) else range end end ## # If necessary, shrink a `Range` so as to include only the last line. # # @return [Parser::Source::Range] # def last_line_only(range) if range.line != range.last_line range.adjust(begin_pos: range.source =~ /[^\n]*\z/) else range end end end |
#reason ⇒ Symbol (readonly)
Returns reason for error.
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 158 159 160 161 162 |
# File 'lib/parser/diagnostic.rb', line 31 class Diagnostic ## # Collection of the available diagnostic levels. # # @return [Array] # LEVELS = [:note, :warning, :error, :fatal].freeze attr_reader :level, :reason, :arguments attr_reader :location, :highlights ## # @param [Symbol] level # @param [Symbol] reason # @param [Hash] arguments # @param [Parser::Source::Range] location # @param [Array<Parser::Source::Range>] highlights # def initialize(level, reason, arguments, location, highlights=[]) unless LEVELS.include?(level) raise ArgumentError, "Diagnostic#level must be one of #{LEVELS.join(', ')}; " \ "#{level.inspect} provided." end raise 'Expected a location' unless location @level = level @reason = reason @arguments = (arguments || {}).dup.freeze @location = location @highlights = highlights.dup.freeze freeze end ## # @return [String] the rendered message. # def Messages.compile(@reason, @arguments) end ## # Renders the diagnostic message as a clang-like diagnostic. # # @example # diagnostic.render # => # # [ # # "(fragment:0):1:5: error: unexpected token $end", # # "foo +", # # " ^" # # ] # # @return [Array<String>] # def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end private ## # Renders one source line in clang diagnostic style, with highlights. # # @return [Array<String>] # def render_line(range, ellipsis=false, range_end=false) source_line = range.source_line highlight_line = ' ' * source_line.length @highlights.each do |highlight| line_range = range.source_buffer.line_range(range.line) if highlight = highlight.intersect(line_range) highlight_line[highlight.column_range] = '~' * highlight.size end end if range.is?("\n") highlight_line += "^" else if !range_end && range.size >= 1 highlight_line[range.column_range] = '^' + '~' * (range.size - 1) else highlight_line[range.column_range] = '~' * range.size end end highlight_line += '...' if ellipsis [source_line, highlight_line]. map { |line| "#{range.source_buffer.name}:#{range.line}: #{line}" } end ## # If necessary, shrink a `Range` so as to include only the first line. # # @return [Parser::Source::Range] # def first_line_only(range) if range.line != range.last_line range.resize(range.source =~ /\n/) else range end end ## # If necessary, shrink a `Range` so as to include only the last line. # # @return [Parser::Source::Range] # def last_line_only(range) if range.line != range.last_line range.adjust(begin_pos: range.source =~ /[^\n]*\z/) else range end end end |
Instance Method Details
#render ⇒ Array<String>
Renders the diagnostic message as a clang-like diagnostic.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/parser/diagnostic.rb', line 86 def render if @location.line == @location.last_line || @location.is?("\n") ["#{@location}: #{@level}: #{}"] + render_line(@location) else # multi-line diagnostic first_line = first_line_only(@location) last_line = last_line_only(@location) num_lines = (@location.last_line - @location.line) + 1 buffer = @location.source_buffer last_lineno, last_column = buffer.decompose_position(@location.end_pos) ["#{@location}-#{last_lineno}:#{last_column}: #{@level}: #{}"] + render_line(first_line, num_lines > 2, false) + render_line(last_line, false, true) end end |