Class: Kumi::Parser::Source
- Inherits:
-
Object
- Object
- Kumi::Parser::Source
- Defined in:
- lib/kumi/parser/source.rb
Overview
The text being parsed, plus the bookkeeping needed to turn a byte offset into a 1-based line/column and to render a caret-annotated code frame for error messages. Owning this here keeps location math in one place instead of being recomputed in the lexer and the parser.
Instance Attribute Summary collapse
-
#file ⇒ Object
readonly
Returns the value of attribute file.
-
#text ⇒ Object
readonly
Returns the value of attribute text.
Instance Method Summary collapse
-
#code_frame(offset, context: 2) ⇒ Object
A two-line-of-context code frame with a caret under the offending column, in the same shape kumi-core’s text frontend already renders.
-
#initialize(text, file: 'schema') ⇒ Source
constructor
A new instance of Source.
-
#line_col(offset) ⇒ Object
1-based [line, column] for a 0-based byte offset.
- #location(offset) ⇒ Object
Constructor Details
#initialize(text, file: 'schema') ⇒ Source
Returns a new instance of Source.
12 13 14 15 16 |
# File 'lib/kumi/parser/source.rb', line 12 def initialize(text, file: 'schema') @text = text @file = file @line_starts = compute_line_starts(text) end |
Instance Attribute Details
#file ⇒ Object (readonly)
Returns the value of attribute file.
10 11 12 |
# File 'lib/kumi/parser/source.rb', line 10 def file @file end |
#text ⇒ Object (readonly)
Returns the value of attribute text.
10 11 12 |
# File 'lib/kumi/parser/source.rb', line 10 def text @text end |
Instance Method Details
#code_frame(offset, context: 2) ⇒ Object
A two-line-of-context code frame with a caret under the offending column, in the same shape kumi-core’s text frontend already renders.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/kumi/parser/source.rb', line 33 def code_frame(offset, context: 2) line, col = line_col(offset) lines = text.lines from = [line - 1 - context, 0].max to = [line - 1 + context, lines.length - 1].min return '' if lines.empty? out = [] (from..to).each do |i| marker = i + 1 == line ? '➤' : ' ' out << format('%s %4d | %s', marker, i + 1, lines[i].to_s.chomp) out << format(' | %s^', ' ' * (col - 1)) if i + 1 == line end out.join("\n") end |
#line_col(offset) ⇒ Object
1-based [line, column] for a 0-based byte offset.
19 20 21 22 23 24 |
# File 'lib/kumi/parser/source.rb', line 19 def line_col(offset) offset = text.length if offset > text.length line = upper_bound(@line_starts, offset) - 1 col = offset - @line_starts[line] + 1 [line + 1, col] end |
#location(offset) ⇒ Object
26 27 28 29 |
# File 'lib/kumi/parser/source.rb', line 26 def location(offset) line, col = line_col(offset) Kumi::Syntax::Location.new(file: file, line: line, column: col) end |