Class: HeadMusic::Notation::LilyPond::DocumentReader
- Inherits:
-
Object
- Object
- HeadMusic::Notation::LilyPond::DocumentReader
- Defined in:
- lib/head_music/notation/lily_pond/document_reader.rb
Overview
Reads a token list into a Document.
This reader is the envelope the Writer emits plus the common hand-written shapes around it: an optional \version, \header, and \score wrapper, and \layout and \midi blocks, which are skipped. The one music expression the document holds is read by the MusicReader.
Constant Summary collapse
- HEADER_FIELDS =
%w[title composer].freeze
- SCORE_SKIPPED_COMMANDS =
%w[layout midi].freeze
Instance Attribute Summary collapse
-
#cursor ⇒ Object
readonly
private
Returns the value of attribute cursor.
Instance Method Summary collapse
- #document ⇒ Object
-
#initialize(tokens) ⇒ DocumentReader
constructor
A new instance of DocumentReader.
- #read ⇒ Object private
- #read_document(context) ⇒ Object private
- #read_envelope_command(context) ⇒ Object private
- #read_header ⇒ Object private
- #read_score(context) ⇒ Object private
- #read_score_item(context) ⇒ Object private
- #read_top_level_music(context) ⇒ Object private
- #read_version ⇒ Object private
Constructor Details
#initialize(tokens) ⇒ DocumentReader
Returns a new instance of DocumentReader.
13 14 15 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 13 def initialize(tokens) @cursor = TokenCursor.new(tokens) end |
Instance Attribute Details
#cursor ⇒ Object (readonly, private)
Returns the value of attribute cursor.
23 24 25 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 23 def cursor @cursor end |
Instance Method Details
#document ⇒ Object
17 18 19 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 17 def document @document ||= read end |
#read ⇒ Object (private)
25 26 27 28 29 30 31 32 33 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 25 def read @building = Document.new @music = MusicReader.new(cursor, @building) @music_read = false root = VoiceContext.new(@building, nil, explicit: false) read_document(root) root.close @building end |
#read_document(context) ⇒ Object (private)
35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 35 def read_document(context) until cursor.eos? token = cursor.peek if token.type == :command && ENVELOPE_COMMANDS.include?(token.lexeme) read_envelope_command(context) elsif token.type == :word && cursor.peek(1)&.type == :equals raise cursor.unsupported(%(Variable assignments such as "#{token.lexeme} =" are not supported), token) else read_top_level_music(context) end end end |
#read_envelope_command(context) ⇒ Object (private)
48 49 50 51 52 53 54 55 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 48 def read_envelope_command(context) case cursor.peek.lexeme when "version" then read_version when "header" then read_header when "score" then read_score(context) else cursor.skip_block end end |
#read_header ⇒ Object (private)
72 73 74 75 76 77 78 79 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 72 def read_header cursor.advance cursor.expect(:open_brace, "\\header expects a block") AssignmentReader.new(cursor, "\\header", HEADER_FIELDS).read do |name, value| @building.title = value if name == "title" @building.composer = value if name == "composer" end end |
#read_score(context) ⇒ Object (private)
81 82 83 84 85 86 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 81 def read_score(context) cursor.advance cursor.expect(:open_brace, "\\score expects a block") read_score_item(context) until cursor.peek.type == :close_brace cursor.advance end |
#read_score_item(context) ⇒ Object (private)
88 89 90 91 92 93 94 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 88 def read_score_item(context) token = cursor.peek return cursor.skip_block if token.type == :command && SCORE_SKIPPED_COMMANDS.include?(token.lexeme) return read_header if token.type == :command && token.lexeme == "header" read_top_level_music(context) end |
#read_top_level_music(context) ⇒ Object (private)
57 58 59 60 61 62 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 57 def read_top_level_music(context) raise cursor.unsupported("Only one \\score or top-level music expression is supported", cursor.peek) if @music_read @music_read = true @music.read_expression(context) end |
#read_version ⇒ Object (private)
64 65 66 67 68 69 70 |
# File 'lib/head_music/notation/lily_pond/document_reader.rb', line 64 def read_version version = cursor.advance token = cursor.advance return if token&.type == :string raise cursor.error("\\version expects a quoted version string", token || version) end |