func (p *parser) parseSong() (*songtools.Song, error) { song := &songtools.Song{} token, text, err := p.scanner.next() if err != nil { return nil, err } var section *songtools.Section var line *songtools.Line numNewLines := 0 for token != eofToken { switch token { case commentToken: comment := &songtools.Comment{ Text: text, Hidden: true, } if section != nil { section.Nodes = append(section.Nodes, comment) } else { song.Nodes = append(song.Nodes, comment) } case directiveToken: d, err := parseDirective(text) if err != nil { return nil, err } switch d.Name { case startOfChorusDirectiveName: section = &songtools.Section{ Kind: songtools.SectionKind("Chorus"), } song.Nodes = append(song.Nodes, section) case endOfChorusDirectiveName: section = nil case startOfBridgeDirectiveName: section = &songtools.Section{ Kind: songtools.SectionKind("Bridge"), } song.Nodes = append(song.Nodes, section) case endOfBridgeDirectiveName: section = nil case commentDirectiveName: if section == nil { la := 1 for { // we are going to look forward past all the comments until we find a non-comment nextToken, _, nextErr := p.scanner.la(la) if nextErr != nil { break } if nextToken == directiveToken { innerD, err := parseDirective(text) if err != nil { break } if innerD.Name != commentDirectiveName { break } la += 2 } else if nextToken == chordToken || nextToken == textToken { section = &songtools.Section{ Kind: songtools.SectionKind(d.Value), } song.Nodes = append(song.Nodes, section) break } else { break } } } else { comment := &songtools.Comment{ Text: d.Value, Hidden: false, } if section == nil { song.Nodes = append(song.Nodes, comment) } else { section.Nodes = append(section.Nodes, comment) } } case titleDirectiveName: song.Title = d.Value case subtitleDirectiveName: song.Subtitles = append(song.Subtitles, d.Value) case authorDirectiveName: song.Authors = append(song.Authors, d.Value) case keyDirectiveName: song.Key = songtools.Key(d.Value) default: // choruses and bridges have end tags, which means we can just wait until those show up // and not have to guess at the end of a section. if section != nil && numNewLines == 2 && section.Kind != "Chorus" && section.Kind != "Bridge" { section = nil } if section != nil { section.Nodes = append(section.Nodes, d) } else { song.Nodes = append(song.Nodes, d) } line = nil numNewLines = 0 } case chordToken: if section == nil { section = &songtools.Section{} song.Nodes = append(song.Nodes, section) } if line == nil { line = &songtools.Line{} section.Nodes = append(section.Nodes, line) } chord, ok := songtools.ParseChord(text) if !ok { return nil, fmt.Errorf("The text '%v' is not a chord.", text) } line.Chords = append(line.Chords, chord) line.ChordPositions = append(line.ChordPositions, len(line.Text)) case textToken: if section == nil { section = &songtools.Section{} song.Nodes = append(song.Nodes, section) } if line == nil { line = &songtools.Line{} section.Nodes = append(section.Nodes, line) } line.Text += text numNewLines = 0 case newLineToken: line = nil numNewLines++ if section != nil && numNewLines == 2 && section.Kind != "Chorus" && section.Kind != "Bridge" { section = nil numNewLines = 0 } break } token, text, err = p.scanner.next() if err != nil { return nil, err } } return song, nil }
func (p *parser) parseSong() (*songtools.Song, error) { song := &songtools.Song{} token, text, err := p.scanner.next() if err != nil { return nil, err } var section *songtools.Section var line *songtools.Line numNewLines := 0 for token != eofToken { switch token { case commentToken: comment := &songtools.Comment{ Text: text, Hidden: false, } if section != nil { section.Nodes = append(section.Nodes, comment) } else { song.Nodes = append(song.Nodes, comment) } case directiveToken: d, err := parseDirective(text) if err != nil { return nil, err } if numNewLines == 2 { section = nil } if section != nil { section.Nodes = append(section.Nodes, d) } else { switch d.Name { case titleDirectiveName: song.Title = d.Value case subtitleDirectiveName: song.Subtitles = append(song.Subtitles, d.Value) case authorDirectiveName: song.Authors = append(song.Authors, d.Value) case keyDirectiveName: song.Key = songtools.Key(d.Value) default: song.Nodes = append(song.Nodes, d) } } line = nil numNewLines = 0 case sectionToken: section = &songtools.Section{ Kind: songtools.SectionKind(text), } song.Nodes = append(song.Nodes, section) line = nil numNewLines = 0 case textToken: if section != nil && numNewLines == 0 { // we have text immediately following a section without a newline directive := &songtools.Comment{ Text: text, Hidden: false, } section.Nodes = append(section.Nodes, directive) break } if section == nil { section = &songtools.Section{} song.Nodes = append(song.Nodes, section) } chords, positions, isChordLine := parseTextForChords(text) if !isChordLine { if line != nil && line.Text == "" { line.Text = text } else { line = &songtools.Line{ Text: text, } section.Nodes = append(section.Nodes, line) } line = nil } else { line = &songtools.Line{ Chords: chords, ChordPositions: positions, } section.Nodes = append(section.Nodes, line) } numNewLines = 0 case newLineToken: numNewLines++ if numNewLines > 2 { section = nil line = nil numNewLines = 0 } break } token, text, err = p.scanner.next() if err != nil { return nil, err } } return song, nil }