Class: HeadMusic::Notation::LilyPond::TokenCursor
- Inherits:
-
Object
- Object
- HeadMusic::Notation::LilyPond::TokenCursor
- Defined in:
- lib/head_music/notation/lily_pond/token_cursor.rb
Overview
The readers’ shared place in the token list, and the errors they raise from there. Every ParseError carries the line, column, and lexeme of the token it was raised at, so the cursor builds them rather than each reader that navigates with it.
Instance Method Summary collapse
-
#advance ⇒ Object
-
#eos? ⇒ Boolean
-
#error(message, token) ⇒ Object
-
#expect(type, message, unsupported: false) ⇒ Object
-
#initialize(tokens) ⇒ TokenCursor
constructor
A new instance of TokenCursor.
-
#peek(offset = 0) ⇒ Object
-
#skip_block ⇒ Object
Consumes a command and the balanced block that follows it.
-
#unsupported(message, token) ⇒ Object
-
#unsupported_command(token) ⇒ Object
-
#unsupported_token(token) ⇒ Object
A construct the lexer could name but the model cannot hold.
Constructor Details
#initialize(tokens) ⇒ TokenCursor
Returns a new instance of TokenCursor.
8 9 10 11 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 8 def initialize(tokens) @tokens = tokens @index = 0 end |
Instance Method Details
#advance ⇒ Object
17 18 19 20 21 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 17 def advance token = @tokens[@index] @index += 1 if token token end |
#eos? ⇒ Boolean
23 24 25 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 23 def eos? @index >= @tokens.length end |
#error(message, token) ⇒ Object
46 47 48 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 46 def error(, token) ParseError.new(, line_number: token&.line, column: token&.column, snippet: token&.lexeme) end |
#expect(type, message, unsupported: false) ⇒ Object
27 28 29 30 31 32 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 27 def expect(type, , unsupported: false) token = advance return token if token&.type == type raise(unsupported ? unsupported(, token || peek(-1)) : error(, token || peek(-1))) end |
#peek(offset = 0) ⇒ Object
13 14 15 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 13 def peek(offset = 0) @tokens[@index + offset] end |
#skip_block ⇒ Object
Consumes a command and the balanced block that follows it.
35 36 37 38 39 40 41 42 43 44 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 35 def skip_block advance expect(:open_brace, "Expected a block") depth = 1 while depth.positive? token = advance depth += 1 if token.type == :open_brace depth -= 1 if token.type == :close_brace end end |
#unsupported(message, token) ⇒ Object
50 51 52 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 50 def unsupported(, token) UnsupportedFeatureError.new(, line_number: token&.line, column: token&.column, snippet: token&.lexeme) end |
#unsupported_command(token) ⇒ Object
54 55 56 57 58 59 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 54 def unsupported_command(token) UnsupportedFeatureError.new( %(Unsupported LilyPond feature "\\#{token.lexeme}"), line_number: token.line, column: token.column, snippet: "\\#{token.lexeme}" ) end |
#unsupported_token(token) ⇒ Object
A construct the lexer could name but the model cannot hold. It is reported where the reader meets it, so the same construct inside a block the reader skips costs nothing.
64 65 66 |
# File 'lib/head_music/notation/lily_pond/token_cursor.rb', line 64 def unsupported_token(token) unsupported(%(Unsupported LilyPond feature "#{token.lexeme}"), token) end |