yaparc 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README +1 -11
- data/lib/yaparc.rb +253 -89
- data/tests/abc20bnf.txt +264 -0
- data/tests/test_abc.rb +113 -0
- data/tests/test_calc.rb +10 -5
- data/tests/test_owl.rb +68 -0
- data/tests/test_parser.rb +89 -25
- data/tests/test_sql.rb +10 -10
- data/tests/test_uri.rb +752 -0
- metadata +9 -2
data/tests/abc20bnf.txt
ADDED
@@ -0,0 +1,264 @@
|
|
1
|
+
; ABC notation 2.0 - BNF specification.
|
2
|
+
; This is a specification of the draft ABC 2.0 standard in BNF.
|
3
|
+
; This BNF specification is not finished yet - it needs to be elaborated in some places.
|
4
|
+
; It uses ABNF as defined in http://www.ietf.org/rfc/rfc2234.txt.
|
5
|
+
; This file written by Henrik Norbeck.
|
6
|
+
; --------------------------------------------------------------------------------
|
7
|
+
abc-file ::= *(abc-tune / comment / xcommand / file-field / text-line / tex)
|
8
|
+
file-field ::= field-area / field-book / field-composer / field-discography / field-file / field-group / field-history / field-length / field-meter / field-notes / field-origin / field-parts / field-tempo / field-rhythm / field-source / field-userdef-print / field-userdef-play / field-words / field-transcription / field-key / unused-field ; Default values for the whole file - all fields except number, title and voice
|
9
|
+
text-line ::= [non-comment-char tex-text] eol ; Free text between tunes. This is a catch-all rule - check for fields first!
|
10
|
+
|
11
|
+
; --------------------------------------------------------------------------------
|
12
|
+
abc-tune ::= abc-header abc-music eol
|
13
|
+
abc-header ::= [field-number] title-fields *other-field field-key ; note that field-number is optional.
|
14
|
+
field-number ::= %x58.3A *WSP 1*DIGIT header-eol ; X:
|
15
|
+
title-fields ::= *(comment / xcommand / tex) 1*(field-title *(comment / xcommand / tex))
|
16
|
+
field-title ::= %x54.3A *WSP tex-text header-eol ; T:
|
17
|
+
other-field ::= field-area / field-book / field-composer / field-discography / field-file / field-group / field-history / field-length / field-meter / field-notes / field-origin / field-parts / field-tempo / field-rhythm / field-source / field-userdef-print / field-userdef-play / field-voice / field-words / field-transcription / field-macro / unused-field / comment / xcommand / tex
|
18
|
+
field-area ::= %x41.3A *WSP tex-text header-eol ; A:
|
19
|
+
field-book ::= %x42.3A *WSP tex-text header-eol ; B:
|
20
|
+
field-composer ::= %x43.3A *WSP tex-text header-eol ; C:
|
21
|
+
field-discography ::= %x44.3A *WSP tex-text header-eol ; D:
|
22
|
+
field-file ::= %x46.3A *WSP tex-text header-eol ; F:
|
23
|
+
field-group ::= %x47.3A *WSP tex-text header-eol ; G:
|
24
|
+
field-history ::= %x48.3A *WSP 1*(tex-text header-eol) ; H: field contents may extend over many lines, which is deprecated (maybe not allowed any longer?)
|
25
|
+
field-length ::= %x4C.3A *WSP note-length-strict header-eol ; L: default note length
|
26
|
+
field-meter ::= %x4D.3A *WSP time-signature header-eol ; M:
|
27
|
+
field-notes ::= %x4E.3A *WSP tex-text header-eol ; N:
|
28
|
+
field-origin ::= %x4F.3A *WSP tex-text header-eol ; O:
|
29
|
+
field-parts ::= %x50.3A *WSP parts-play-order header-eol ; P: in header defines in which order parts should be played
|
30
|
+
field-tempo ::= %x51.3A *WSP tempo header-eol ; Q:
|
31
|
+
field-rhythm ::= %x52.3A *WSP tex-text header-eol ; R:
|
32
|
+
field-source ::= %x53.3A *WSP tex-text header-eol ; S:
|
33
|
+
field-userdef-print ::= %x55.3A *WSP userdef header-eol ; U:
|
34
|
+
field-userdef-play ::= %x75.3A *WSP userdef header-eol ; u:
|
35
|
+
field-voice ::= %x56.3A *WSP voice header-eol ; V: options should be better defined
|
36
|
+
field-words ::= %x57.3A *WSP tex-text header-eol ; W: unformatted words, printed after the tune
|
37
|
+
field-transcription ::= %x5A.3A *WSP tex-text header-eol ; Z:
|
38
|
+
field-macro ::= %x6D.3A *WSP 1*(WSP / VCHAR) header-eol ; m: BarFly-style macros - do be defined better
|
39
|
+
field-key ::= %x4B.3A *WSP key header-eol ; K:
|
40
|
+
unused-field ::= (%x45 / %x49 / %4A / %59 / %61-6c / %6e-%74 / %76 / %78-7A) %3A *(WSP / VCHAR) eol ; E: I: J: Y: a:-l: n:-t: v: x: y: z: ignore - but for backward and forward compatibility
|
41
|
+
|
42
|
+
; --------------------------------------------------------------------------------
|
43
|
+
time-signature ::= %x43 / %x43.7C / "none" / meter-num / 1*DIGIT ; C, C|, none or numeric
|
44
|
+
meter-num ::= (1*DIGIT *("+" 1*DIGIT) "/" 1*DIGIT) [1*SP meter-num]
|
45
|
+
; e.g. 2/4 , 6/8 , 2+2+3/16 , 11/8 , 2/4 3/4 , 2+2+3/8 2+2+3+2+2+2/8
|
46
|
+
tempo ::= (note-length-strict "=" 1*DIGIT) / (%x43 [note-length] "=" 1*DIGIT) / 1*DIGIT ; 1*DIGIT is deprecated, kept for compatibility
|
47
|
+
note-length-strict ::= 1*DIGIT "/" 1*DIGIT
|
48
|
+
key ::= (key-def [1*WSP clef]) / clef / "HP" / "Hp"
|
49
|
+
key-def ::= basenote ["#" / "b"] [mode] *(1*WSP global-accidental)
|
50
|
+
mode ::= minor / major / lydian / ionian / mixolydian / dorian / aeolian / phrygian / locrian
|
51
|
+
minor ::= "m" ["in" ["o" ["r"]]] ; m, min, mino, minor - all modes are case insensitive
|
52
|
+
major ::= "maj" ["o" ["r"]]
|
53
|
+
lydian ::= "lyd" ["i" ["a" ["n"]]] ; major with sharp 4th
|
54
|
+
ionian ::= "ion" ["i" ["a" ["n"]]] ; =major
|
55
|
+
mixolydian ::= "mix" ["o" ["l" ["y" ["d" ["i" ["a" ["n"]]]]]]] ; major with flat 7th
|
56
|
+
dorian ::= "dor" ["i" ["a" ["n"]]] ; minor with sharp 6th
|
57
|
+
aeolian ::= "aeo" ["l" ["i" ["a" ["n"]]]] ; =minor
|
58
|
+
phrygian ::= "phr" ["y" ["g" ["i" ["a" ["n"]]]]] ; minor with flat 2nd
|
59
|
+
locrian ::= "loc" ["r" ["i" ["a" ["n"]]]] ; minor with flat 2nd and 5th
|
60
|
+
global-accidental ::= accidental basenote ; e.g. ^f =c _b
|
61
|
+
parts-play-order ::= 1*( ALPHA / ( "(" parts-play-order ")" ) *DIGIT) / "." ; dots are ignored - for legibility only
|
62
|
+
|
63
|
+
; --------------------------------------------------------------------------------
|
64
|
+
voice ::= 1*(ALPHA / DIGIT) *(1*WSP (clef / voice-name / voice-subname / voice-transpose / "merge" / "up" / "down")) ; maybe "stems=up" / "stems=down" / "stems=normal" instead?
|
65
|
+
voice-name ::= ("name=" / "nm=") %x22 *non-quote %x22 ; \n in name = linefeed
|
66
|
+
voice-subname ::= ("subname=" / "snm=") %x22 *non-quote %x22 ; \n in name = linefeed
|
67
|
+
voice-transpose ::= "transpose=" ["-"] 1*DIGIT
|
68
|
+
|
69
|
+
; --------------------------------------------------------------------------------
|
70
|
+
clef ::= ( ("clef=" (clef-note / clef-name)) / clef-name) clef-line ["+8" / "-8"] [1*WSP clef-middle]
|
71
|
+
clef-note ::= "G" / "C" / "F" / "P"
|
72
|
+
clef-name ::= "treble" / "alto" / "tenor" / "baritone" / "bass" / "mezzo" / "soprano" / "perc" / "none" ; Maybe also Doh1-4, Fa1-4
|
73
|
+
clef-line ::= "1" / "2" / "3" / "4" / "5"
|
74
|
+
cleff-middle ::= "middle=" basenote [octave]
|
75
|
+
|
76
|
+
; --------------------------------------------------------------------------------
|
77
|
+
userdef ::= userdef-symbol *WSP "=" *WSP (long-gracing / chord-or-text)
|
78
|
+
header-eol ::= *WSP (comment / eol) ; there may be comments at the end of header lines
|
79
|
+
|
80
|
+
; --------------------------------------------------------------------------------
|
81
|
+
abc-music ::= *(abc-line / comment / xcommand / tune-field / tex)
|
82
|
+
abc-line ::= barline / ([barline] 1*element *(barline 1*element) [barline]) abc-eol
|
83
|
+
barline ::= ( *":" *"[" 1*"|" *"]" ( *":" / nth-repeat-num ) ) / invisible-barline / dashed-barline ; e.g. :| | |:: |2 :||:
|
84
|
+
invisible-barline ::= "[|]" | "[]"
|
85
|
+
dashed-barline ::= ":"
|
86
|
+
element ::= stem / WSP / chord-or-text / gracing / grace-notes / broken-rhythm / tuplet / slur-begin / slur-end / rollback / multi-measure-rest / measure-repeat / nth-repeat / end-nth-repeat / inline-field / unused-char
|
87
|
+
|
88
|
+
; --------------------------------------------------------------------------------
|
89
|
+
stem ::= note / ( "[" 2*note "]" ) ; stem
|
90
|
+
note ::= pitch [note-length] [tie] ; note
|
91
|
+
pitch ::= [accidental] basenote [octave]
|
92
|
+
rest ::= (normal-rest / invisible-rest / inaudible-rest) [note-length]
|
93
|
+
normal-rest ::= %x7A ; z = normal rest
|
94
|
+
invisible-rest ::= %x78 ; x = invisible rest
|
95
|
+
inaudible-rest ::= %x79 ; y = inaudible and invisible rest, for spacing
|
96
|
+
accidental ::= "^" / "^^" / "_" / "__" / "="
|
97
|
+
basenote ::= %x43 / %x44 / %x45 / %x46 / %x47 / %x41 / %x42 / %x63 / %x64 / %x65 / %x66 / %x67 / %x61 / %x62 ; CDEFGABcdefgab
|
98
|
+
octave ::= 1*"'" / 1*","
|
99
|
+
note-length ::= (*DIGIT ["/" *DIGIT]) / 1*"/"
|
100
|
+
tie ::= "-" ; tie
|
101
|
+
|
102
|
+
; --------------------------------------------------------------------------------
|
103
|
+
broken-rhythm ::= stem *b-elem (1*"<" / 1*">") *b-elem stem
|
104
|
+
b-elem ::= WSP / chord-or-text / gracing / grace-notes / slur-begin / slur-end
|
105
|
+
tuplet ::= "("1*DIGIT [":" [1*DIGIT] ":" [1*DIGIT]] 2*(*t-elem stem)
|
106
|
+
t-elem ::= WSP / chord-or-text / gracing / grace-notes / broken-rhythm / slur-begin / slur-end
|
107
|
+
|
108
|
+
; --------------------------------------------------------------------------------
|
109
|
+
gracing ::= "." / userdef-symbol / long-gracing ; gracings
|
110
|
+
userdef-symbol ::= "~" / %x48-59 / %x68-77 ; user definable symbols ~ H-Y, h-w
|
111
|
+
grace-notes ::= "{" acciaccatura 1*( grace-note-stem ) "}" ; grace notes can have length
|
112
|
+
grace-note-stem ::= grace-note / ( "[" 2*grace-note "]" )
|
113
|
+
grace-note ::= pitch [note-length] ; as note, but without tie
|
114
|
+
acciaccatura ::= "/"
|
115
|
+
|
116
|
+
; --------------------------------------------------------------------------------
|
117
|
+
chord-or-text ::= %x22 (chord / text-expression) *(chord-newline (chord / text-expression)) %x22 ; ".."
|
118
|
+
chord ::= basenote [chord-accidental] [chord-type] ["/" basenote [chord-accidental]] *non-quote
|
119
|
+
chord-accidental ::= "#" / "b" / "="
|
120
|
+
chord-type ::= 1*( ALPHA / DIGIT / "+" / "-" ) ; e.g. m, 7, m7, +, mb5, sus, sus4, maj7, mmaj7, 7sus4, dim
|
121
|
+
text-expression ::= [ "^" / "<" / ">" / "_" / "@" ] 1*non-quote ; above, left, right, below, anywhere
|
122
|
+
non-quote ::= SP / %x21 / %x23-7E ; all characters except quote
|
123
|
+
chord-newline ::= "\n" / ";"
|
124
|
+
|
125
|
+
; --------------------------------------------------------------------------------
|
126
|
+
slur-begin ::= "("
|
127
|
+
slur-end ::= ")"
|
128
|
+
rollback ::= "&"
|
129
|
+
measure-repeat ::= "/" ["/"] ; repeat whole measure
|
130
|
+
multi-measure-rest ::= %5A *DIGIT ; e.g. Z4
|
131
|
+
nth-repeat ::= "[" ( nth-repeat-num / nth-repeat-text )
|
132
|
+
nth-repeat-num ::= 1*DIGIT *(("," / "-") 1*DIGIT)
|
133
|
+
nth-repeat-text ::= %x22 *non-quote %x22
|
134
|
+
end-nth-repeat ::= "]"
|
135
|
+
unused-char ::= "#" / "$" / "*" / "+" / ";" / "?" / "@" / "`" ; ignore for backward and forward compatibility, but maybe warn about them
|
136
|
+
|
137
|
+
; --------------------------------------------------------------------------------
|
138
|
+
inline-field ::= ifield-area / ifield-book / ifield-composer / ifield-discography / ifield-group / ifield-history / ifield-length / ifield-meter / ifield-notes / ifield-origin / ifield-part / ifield-tempo / ifield-rhythm / ifield-source / ifield-title / ifield-voice / ifield-words / ifield-lyrics / ifield-transcription / ifield-key
|
139
|
+
ifield-area ::= %5B.%41.%3A tex-text-ifield %5D ; [A:..]
|
140
|
+
ifield-book ::= %5B.%42.%3A *WSP tex-text-ifield %5D ; [B:..]
|
141
|
+
ifield-composer ::= %5B.%43.%3A *WSP tex-text-ifield %5D ; [C:..]
|
142
|
+
ifield-discography ::= %5B.%44.%3A *WSP tex-text-ifield %5D ; [D:..]
|
143
|
+
ifield-group ::= %5B.%47.%3A *WSP tex-text-ifield %5D ; [G:..]
|
144
|
+
ifield-history ::= %5B.%48.%3A *WSP tex-text-ifield %5D ; [H:..]
|
145
|
+
ifield-length ::= %5B.4C.3A *WSP note-length-strict %5D ; e.g. [L:1/8]
|
146
|
+
ifield-meter ::= %5B.4D.3A *WSP meter %5D ; e.g. [M:C|] [M: 2+3/8]
|
147
|
+
ifield-notes ::= %5B.%4E.%3A *WSP tex-text-ifield %5D ; [N:..]
|
148
|
+
ifield-origin ::= %5B.%4F.%3A *WSP tex-text-ifield %5D ; [O:..]
|
149
|
+
ifield-part ::= %5B.%50.%3A *WSP (ALPHA / tex-text-ifield) %5D ; e.g. [P:A]
|
150
|
+
ifield-tempo ::= %5B.%51.%3A *WSP tempo %5D ; e.g. [Q:1/4=120]
|
151
|
+
ifield-rhythm ::= %5B.%52.%3A *WSP tex-text-ifield %5D ; e.g. [R:reel]
|
152
|
+
ifield-source ::= %5B.%53.%3A *WSP tex-text-ifield %5D ; [S:..]
|
153
|
+
ifield-title ::= %5B.%54.%3A *WSP tex-text-ifield %5D ; e.g. [T:second version]
|
154
|
+
ifield-voice ::= %5B.%56.%3A *WSP voice %5D ; [V:..] options should be better defined
|
155
|
+
ifield-words ::= %5B.%57.%3A *WSP tex-text-ifield %5D ; [W:..]
|
156
|
+
ifield-lyrics ::= %5B.%77.%3A *WSP tex-text-ifield %5D ; [w:..]
|
157
|
+
ifield-transcription ::= %5B.%5A.%3A *WSP tex-text-ifield %5D ; [Z:..]
|
158
|
+
ifield-key ::= %5B.4B.3A *WSP key %5D ; e.g. [K:Ador] [K: Bphr ^d]
|
159
|
+
unused-ifield ::= %5B (%x45 / %x49 / %4A / %59 / %61-6c / %6e-%74 / %76 / %78-7A) %3A *(WSP / VCHAR) %5D ; E: I: J: Y: a:-l: n:-t: v: x: y: z: ignore - but for backward and forward compatibility
|
160
|
+
non-bracket-char ::= *(WSP / %21-%5C / %5E-7E) ; all except ]
|
161
|
+
|
162
|
+
; --------------------------------------------------------------------------------
|
163
|
+
abc-eol ::= comment / ([line-continuation / hard-line-break] *WSP eol)
|
164
|
+
line-continuation ::= "\"
|
165
|
+
hard-line-break ::= "!" ; kept for compatibility with abc2win
|
166
|
+
|
167
|
+
; --------------------------------------------------------------------------------
|
168
|
+
tune-field ::= field-area / field-book / field-composer / field-discography / field-group / field-history / field-length / field-meter / field-notes / field-origin / field-part / field-tempo / field-rhythm / field-source / field-title / field-voice / field-words / field-lyrics / field-transcription / field-key / unused-field
|
169
|
+
field-part ::= %x50.3A *WSP (ALPHA / tex-text) header-eol ; P:
|
170
|
+
field-lyrics ::= %x56.3A *WSP lyrics header-eol ; w: formatted lyrics printed under staff
|
171
|
+
|
172
|
+
; --------------------------------------------------------------------------------
|
173
|
+
long-gracing ::= gracing-grace / gracing-vol / gracing-style / gracing-finger / gracing-phrase / gracing-exec / gracing-other
|
174
|
+
gracing-grace ::= "!trill!" / "!mordent!" / "!lowermordent!" / "!pralltriller!" / "!uppermordent!" / "!turn!" / "!roll!" / "!turnx!" / "!invertedturn!" / "!invertedturnx!" / "!trill(!" / "!trill)!"
|
175
|
+
gracing-vol ::= "!accent!" / "!emphasis!" / "!crescendo(!" / "!crescendo)!" / "!diminuendo(!" / "!diminuendo)!" / "!p!" / "!pp!" / "!ppp!" / "!pppp!" / "!mp!" / "!mf!" / "!fp!" / "!f!" / "!ff!" / "!fff!" / "!ffff!" / "!sfz!" / "!cresc!" / "!decresc!" / "!dimin!"
|
176
|
+
gracing-style ::= "!+!" / "!open!" / "!snap!" / "!upbow!" / "!downbow!" / "!slide!" / "!arpeggio!"
|
177
|
+
gracing-len ::= "!fermata!" / "!invertedfermata!" / "!tenuto!"
|
178
|
+
gracing-finger ::= "!0!" / "!1!" / "!2!" / "!3!" / "!4!" / "!5!"
|
179
|
+
gracing-phrase ::= "!shortphrase!" / "!mediumphrase!" / "!longphrase!"
|
180
|
+
gracing-exec ::= "!segno!" / "!coda!" / "!D.S.!" / "!D.C.!" / "!fine!" / ("!repeatbar" *DIGIT "!")
|
181
|
+
gracing-other ::= "!wedge!" / "!thumb!" / "!breath!" / ("!" 1*(SP / %x22-x7E) "!") ; any text between !! is allowed
|
182
|
+
|
183
|
+
; --------------------------------------------------------------------------------
|
184
|
+
comment ::= "%" ([non-comment-char *(VCHAR / WSP)]) eol
|
185
|
+
non-comment-char ::= %x20-24 / %x26-%x7E / HTAB ; all characters except %
|
186
|
+
xcommand ::= "%%" xcom eol
|
187
|
+
xcom ::= xcom-staff / xcom-measurenb / xcom-text / xcom-layout / xcom-margins / xcom-midi / xcom-other ; more need to be defined
|
188
|
+
xcom-staff ::= xcom-staffbreak / xcom-multicol / xcom-staves / xcom-indent
|
189
|
+
xcom-staffbreak ::= "staffbreak" 1*WSP xcom-number xcom-unit
|
190
|
+
xcom-multicol ::= "multicol" 1*WSP ("start" / "new" / "end")
|
191
|
+
xcom-staves ::= "staves" 1*WSP stave-voice *( bar-staves stave-voice)
|
192
|
+
stave-voice ::= single-voice / bracketed-voice / braced-voice / paren-voice
|
193
|
+
bracketed-voice ::= "[" *WSP (single-voice / braced-voice / paren-voice) 1*(bar-staves (single-voice / braced-voice / paren-voice)) *WSP "]" ; staves joined by bracket
|
194
|
+
braced-voice ::= "{" *WSP (single-voice / paren-voice) 1*(bar-staves (single-voice / paren-voice)) *WSP "}" ; staves joined by brace
|
195
|
+
paren-voice ::= "(" single-voice 1*( 1*WSP single-voice) ")" ; on same staff
|
196
|
+
single-voice ::= 1*(ALPHA / DIGIT)
|
197
|
+
bar-staves ::= (*WSP "|" *WSP) / 1*WSP ; | to not bar
|
198
|
+
xcom-indent ::= "indent" 1*WSP xcom-number xcom-unit
|
199
|
+
xcom-measurenb ::= "measurenb" / "measurebox" / "measurefirst" / ("setbarnb" 1*WSP 1*DIGIT)
|
200
|
+
xcom-text ::= xcom-textline / xcom-textcenter / xcom-textblock
|
201
|
+
xcom-textline ::= "text" 1*WSP tex-text
|
202
|
+
xcom-textcenter ::= "center" 1*WSP tex-text
|
203
|
+
xcom-textblock ::= "begintext" [textblock-param] eol *(["%%"] tex-text) "%%endtext"
|
204
|
+
textblock-param ::= "obeylines" / ("fill" / "ragged") / ("align" / "justify") / "skip"
|
205
|
+
xcom-layout ::= xcom-sep / xcom-vskip / xcom-newpage
|
206
|
+
xcom-sep ::= "sep" [3(1*WSP xcom-number xcom-unit)] ; space-above, space-below, width
|
207
|
+
xcom-vskip ::= "vskip" 1*WSP xcom-number xcom-unit
|
208
|
+
xcom-newpage ::= "newpage" [1*WSP 1*DIGIT] ; optionally restart page numbering at n
|
209
|
+
xcom-margins ::= ("botmargin" / "topmargin" / "leftmargin" / "rightmargin") 1*WSP xcom-number xcom-unit
|
210
|
+
xcom-midi ::= "midi" 1*WSP (midi-channel / midi-program / midi-transpose)
|
211
|
+
midi-channel ::= "channel" 1*WSP midi-channel-number
|
212
|
+
midi-program ::= "program" 1*WSP [midi-channel-number 1*WSP] midi-program-number
|
213
|
+
midi-channel-number ::= %x31-39 / (%x31 %x30-36) ; channels 1-16
|
214
|
+
midi-program-number ::= %x31-39 / (%x31-39 %x30-39) / (%x31 %x30-31 %x30-39) / (%x31.32 %x30-38) ; programs 1-128
|
215
|
+
midi-transpose ::= "transpose" 1*WSP ["-"] 1*DIGIT
|
216
|
+
xcom-other ::= *(VCHAR / WSP)
|
217
|
+
xcom-number ::= 1*DIGIT ["." 1*DIGIT]
|
218
|
+
xcom-unit ::= ["cm" / "pt" / "in"]
|
219
|
+
|
220
|
+
; --------------------------------------------------------------------------------
|
221
|
+
lyrics ::= *(lyrics-char / lyrics-syllable-break / lyrics-next-bar / lyrics-hold / lyrics-skip-note / lyrics-nbsp / lyrics-dash / tex-escape)
|
222
|
+
lyrics-ifield ::= *(lyrics-char-ifield / lyrics-syllable-break / lyrics-next-bar / lyrics-hold / lyrics-skip-note / lyrics-nbsp / lyrics-dash / tex-escape)
|
223
|
+
lyrics-syllable-break ::= "-" ; break between syllables in a word
|
224
|
+
lyrics-next-bar ::= "|" ; advance to next bar
|
225
|
+
lyrics-hold ::= "_" ; hold syllable for one more note
|
226
|
+
lyrics-skip-note ::= "*" ; =blank syllable
|
227
|
+
lyrics-nbsp ::= "~" ; non-breaking space = words on same note
|
228
|
+
lyrics-dash ::= "\-" ; printed as a -
|
229
|
+
lyrics-char ::= WSP / DIGIT / ALPHA / %x21-29 / %x2B-2C / %x2E-2F / %x3A-40 / %x5B / %x5D / %x5E / %x60 / %x7B-7D ; all characters without special meaning
|
230
|
+
lyrics-char-ifield ::= WSP / DIGIT / ALPHA / %x21-29 / %x2B-2C / %x2E-2F / %x3A-40 / %x5B / %x5E / %x60 / %x7B-7D ; all characters without special meaning and except ]
|
231
|
+
|
232
|
+
; --------------------------------------------------------------------------------
|
233
|
+
tex-text ::= *(WSP / %21-%5B / %5D-7E / tex-escape) ; text that may contain TeX escapes
|
234
|
+
tex-text-ifield ::= *(WSP / %21-%5B / %5E-7E / tex-escape) ; as above, but except ]
|
235
|
+
tex-escape ::= "\" 1*(VCHAR) ; to be defined better
|
236
|
+
|
237
|
+
; --------------------------------------------------------------------------------
|
238
|
+
tex ::= "\" *(VCHAR / WSP) eol ; deprecated - kept only for backward compatibility with abc2mtex
|
239
|
+
eol ::= CRLF / LF / CR ; only one version should occur in the whole file - win / *nix / mac line breaks
|
240
|
+
|
241
|
+
; --------------------------------------------------------------------------------
|
242
|
+
; Core rules in ABNF:
|
243
|
+
; ALPHA ::= %x41-5A / %x61-7A ; A-Z / a-z
|
244
|
+
; CR ::= %x0D ; carriage return
|
245
|
+
; CRLF ::= %x0D.0A ; CR+LF
|
246
|
+
; DIGIT ::= %x30-39 ; 0-9
|
247
|
+
; DQUOTE ::= %x22 ; "
|
248
|
+
; HTAB ::= %x09 ; tab
|
249
|
+
; LF ::= %x0A ; linefeed
|
250
|
+
; SP ::= %x20 ; space
|
251
|
+
; VCHAR ::= %x21-7e ; printing chars
|
252
|
+
; WSP ::= SP / HTAB ; whitespace
|
253
|
+
; %xDD means a hexadecimal code for a character
|
254
|
+
; %xCC-DD means any character in that range
|
255
|
+
; %xCC.DD means two characters
|
256
|
+
; / means or
|
257
|
+
; * means 0 or more occurences of
|
258
|
+
; 1* means 1 or more occurences of
|
259
|
+
; 2* means 2 or more occurences of
|
260
|
+
; [ ] means optional
|
261
|
+
; ( ) used for grouping
|
262
|
+
; " " is a literal string (note that it is case insensitive)
|
263
|
+
; ; starts a comment to end of line
|
264
|
+
; read more about ABNF at http://www.ietf.org/rfc/rfc2234.txt.
|
data/tests/test_abc.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
|
2
|
+
require 'lib/yaparc.rb'
|
3
|
+
require 'test/unit'
|
4
|
+
|
5
|
+
### c.f. http://www.norbeck.nu/abc/bnf/abc20bnf.htm###
|
6
|
+
|
7
|
+
module ABC
|
8
|
+
|
9
|
+
# KEYWORDS = %w{NOT AND OR ALL IN select from where EXISTS}
|
10
|
+
|
11
|
+
# abc-file ::= *(abc-tune / comment / xcommand / file-field / text-line / tex)
|
12
|
+
class AbcFile
|
13
|
+
include Yaparc::Parsable
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@parser = lambda do
|
17
|
+
Yaparc::ManyParser.new(
|
18
|
+
Yaparc::AltParser.new(AbcTune.new,
|
19
|
+
Comment.new,
|
20
|
+
Xcommand.new,
|
21
|
+
FileField.new,
|
22
|
+
TextLine.new,
|
23
|
+
Tex.new))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# file-field ::= field-area / field-book / field-composer / field-discography / field-file / field-group / field-history / field-length / field-meter / field-notes / field-origin / field-parts / field-tempo / field-rhythm / field-source / field-userdef-print / field-userdef-play / field-words / field-transcription / field-key / unused-field ; Default values for the whole file - all fields except number, title and voice
|
29
|
+
class FileField
|
30
|
+
include Yaparc::Parsable
|
31
|
+
|
32
|
+
def initialize
|
33
|
+
@parser = lambda do
|
34
|
+
Yaparc::AltParser.new(
|
35
|
+
FieldArea.new,
|
36
|
+
FieldBook.new,
|
37
|
+
FieldComposer.new,
|
38
|
+
FieldDiscography.new,
|
39
|
+
FieldFile.new,
|
40
|
+
FieldGroup.new,
|
41
|
+
FieldHistory.new,
|
42
|
+
FieldLength.new,
|
43
|
+
FieldMeter.new,
|
44
|
+
FieldNotes.new,
|
45
|
+
FieldOrigin.new,
|
46
|
+
FieldParts.new,
|
47
|
+
FieldTempo.new,
|
48
|
+
FieldRhythm.new,
|
49
|
+
FieldSource.new,
|
50
|
+
FieldUserdefPrint.new,
|
51
|
+
FieldUserdefPlay.new,
|
52
|
+
FieldWords.new,
|
53
|
+
FieldTranscription.new,
|
54
|
+
FieldKey.new,
|
55
|
+
UnusedField.new)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# abc-tune ::= abc-header abc-music eol
|
61
|
+
class AbcTune
|
62
|
+
include Yaparc::Parsable
|
63
|
+
|
64
|
+
def initialize
|
65
|
+
@parser = lambda do
|
66
|
+
Yaparc::SeqParser.new(AbcHeader.new,
|
67
|
+
AbcMusic.new,
|
68
|
+
Eol.new)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# abc-header ::= [field-number] title-fields *other-field field-key ; note that field-number is optional.
|
74
|
+
class AbcTune
|
75
|
+
include Yaparc::Parsable
|
76
|
+
|
77
|
+
def initialize
|
78
|
+
@parser = lambda do
|
79
|
+
Yaparc::SeqParser.new(
|
80
|
+
ZeroOneParser.new(FieldNumber.new)
|
81
|
+
TitleFields.new,
|
82
|
+
ManyParser.new(OtherField.new),
|
83
|
+
FieldKey.new)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
# field-number ::= %x58.3A *WSP 1*DIGIT header-eol ; X:
|
89
|
+
class FieldNumber
|
90
|
+
include Yaparc::Parsable
|
91
|
+
|
92
|
+
def initialize
|
93
|
+
@parser = lambda do
|
94
|
+
Yaparc::SeqParser.new(
|
95
|
+
|
96
|
+
|
97
|
+
%x58.3A *WSP 1*DIGIT header-eol ; X:
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
### eol ::= CRLF / LF / CR ; only one version should occur in the whole file - win / *nix / mac line breaks
|
103
|
+
class Eol
|
104
|
+
include Yaparc::Parsable
|
105
|
+
|
106
|
+
def initialize
|
107
|
+
@parser = lambda do
|
108
|
+
Yaparc::AltParser.new(RegexParser.new(/\n/))
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
data/tests/test_calc.rb
CHANGED
@@ -3,8 +3,10 @@ require 'test/unit'
|
|
3
3
|
|
4
4
|
module Calc
|
5
5
|
|
6
|
-
class Expr < Yaparc::AbstractParser
|
7
|
-
|
6
|
+
# class Expr < Yaparc::AbstractParser
|
7
|
+
class Expr
|
8
|
+
include Yaparc::Parsable
|
9
|
+
|
8
10
|
def initialize
|
9
11
|
@parser = lambda do
|
10
12
|
Yaparc::AltParser.new(
|
@@ -43,7 +45,9 @@ module Calc
|
|
43
45
|
end
|
44
46
|
end
|
45
47
|
|
46
|
-
class Term < Yaparc::AbstractParser
|
48
|
+
# class Term < Yaparc::AbstractParser
|
49
|
+
class Term
|
50
|
+
include Yaparc::Parsable
|
47
51
|
|
48
52
|
def initialize
|
49
53
|
@parser = lambda do
|
@@ -59,8 +63,9 @@ module Calc
|
|
59
63
|
end
|
60
64
|
end
|
61
65
|
|
62
|
-
class Factor < Yaparc::AbstractParser
|
63
|
-
|
66
|
+
# class Factor < Yaparc::AbstractParser
|
67
|
+
class Factor
|
68
|
+
include Yaparc::Parsable
|
64
69
|
|
65
70
|
def initialize
|
66
71
|
@parser = lambda do
|
data/tests/test_owl.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
ontology ::= 'Ontology(' [ ontologyID ] { directive } ')'
|
2
|
+
directive ::= 'Annotation(' ontologyPropertyID ontologyID ')'
|
3
|
+
| 'Annotation(' annotationPropertyID URIreference ')'
|
4
|
+
| 'Annotation(' annotationPropertyID dataLiteral ')'
|
5
|
+
| 'Annotation(' annotationPropertyID individual ')'
|
6
|
+
| axiom
|
7
|
+
| fact
|
8
|
+
datatypeID ::= URIreference
|
9
|
+
classID ::= URIreference
|
10
|
+
individualID ::= URIreference
|
11
|
+
ontologyID ::= URIreference
|
12
|
+
datavaluedPropertyID ::= URIreference
|
13
|
+
individualvaluedPropertyID ::= URIreference
|
14
|
+
annotationPropertyID ::= URIreference
|
15
|
+
ontologyPropertyID ::= URIreference
|
16
|
+
annotation ::= 'annotation(' annotationPropertyID URIreference ')'
|
17
|
+
| 'annotation(' annotationPropertyID dataLiteral ')'
|
18
|
+
| 'annotation(' annotationPropertyID individual ')'
|
19
|
+
|
20
|
+
fact ::= individual
|
21
|
+
individual ::= 'Individual(' [ individualID ] { annotation } { 'type(' type ')' } { value } ')'
|
22
|
+
value ::= 'value(' individualvaluedPropertyID individualID ')'
|
23
|
+
| 'value(' individualvaluedPropertyID individual ')'
|
24
|
+
| 'value(' datavaluedPropertyID dataLiteral ')'
|
25
|
+
type ::= description
|
26
|
+
|
27
|
+
axiom ::= 'Class(' classID ['Deprecated'] modality { annotation } { description } ')'
|
28
|
+
| 'EnumeratedClass(' classID ['Deprecated'] { annotation } { individualID } ')'
|
29
|
+
| 'DisjointClasses(' description description { description } ')'
|
30
|
+
| 'EquivalentClasses(' description { description } ')'
|
31
|
+
| 'SubClassOf(' description description ')'
|
32
|
+
| 'Datatype(' datatypeID ['Deprecated'] { annotation } )'
|
33
|
+
| 'DatatypeProperty(' datavaluedPropertyID ['Deprecated'] { annotation } { 'super(' datavaluedPropertyID ')'} ['Functional'] { 'domain(' description ')' } { 'range(' dataRange ')' } ')'
|
34
|
+
| 'ObjectProperty(' individualvaluedPropertyID ['Deprecated'] { annotation } { 'super(' individualvaluedPropertyID ')' } [ 'inverseOf(' individualvaluedPropertyID ')' ] [ 'Symmetric' ] [ 'Functional' | 'InverseFunctional' | 'Functional' 'InverseFunctional' | 'Transitive' ] { 'domain(' description ')' } { 'range(' description ')' } ')'
|
35
|
+
| 'AnnotationProperty(' annotationPropertyID { annotation } ')'
|
36
|
+
| 'OntologyProperty(' ontologyPropertyID { annotation } ')'
|
37
|
+
| 'EquivalentProperties(' datavaluedPropertyID datavaluedPropertyID { datavaluedPropertyID } ')'
|
38
|
+
| 'SubPropertyOf(' datavaluedPropertyID datavaluedPropertyID ')'
|
39
|
+
| 'EquivalentProperties(' individualvaluedPropertyID individualvaluedPropertyID { individualvaluedPropertyID } ')'
|
40
|
+
| 'SubPropertyOf(' individualvaluedPropertyID individualvaluedPropertyID ')'
|
41
|
+
|
42
|
+
modality ::= 'complete' | 'partial'
|
43
|
+
|
44
|
+
description ::= classID
|
45
|
+
| restriction
|
46
|
+
| 'unionOf(' { description } ')'
|
47
|
+
| 'intersectionOf(' { description } ')'
|
48
|
+
| 'complementOf(' description ')'
|
49
|
+
| 'oneOf(' { individualID } ')'
|
50
|
+
|
51
|
+
restriction ::= 'restriction(' datavaluedPropertyID dataRestrictionComponent { dataRestrictionComponent } ')'
|
52
|
+
| 'restriction(' individualvaluedPropertyID individualRestrictionComponent { individualRestrictionComponent } ')'
|
53
|
+
|
54
|
+
dataRestrictionComponent ::= 'allValuesFrom(' dataRange ')'
|
55
|
+
| 'someValuesFrom(' dataRange ')'
|
56
|
+
| 'value(' dataLiteral ')'
|
57
|
+
| cardinality
|
58
|
+
|
59
|
+
individualRestrictionComponent ::= 'allValuesFrom(' description ')'
|
60
|
+
| 'someValuesFrom(' description ')'
|
61
|
+
| 'value(' individualID ')'
|
62
|
+
| cardinality
|
63
|
+
cardinality ::= 'minCardinality(' non-negative-integer ')'
|
64
|
+
| 'maxCardinality(' non-negative-integer ')'
|
65
|
+
| 'cardinality(' non-negative-integer ')'
|
66
|
+
dataRange ::= datatypeID | 'rdfs:Literal'
|
67
|
+
| 'oneOf(' { dataLiteral } ')'
|
68
|
+
|
data/tests/test_parser.rb
CHANGED
@@ -5,12 +5,15 @@ require 'pp'
|
|
5
5
|
class YaparcTest < Test::Unit::TestCase
|
6
6
|
include ::Yaparc
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
8
|
+
def test_seq_alt_parse
|
9
|
+
parser = Yaparc::SeqParser.new(Yaparc::Symbol.new('scheme'),
|
10
|
+
Yaparc::Symbol.new(':'),
|
11
|
+
Yaparc::AltParser.new(Natural.new,
|
12
|
+
Identifier.new))
|
13
|
+
result = parser.parse("scheme:124")
|
14
|
+
assert_instance_of Result::OK, result
|
15
|
+
result = parser.parse("scheme:identifier")
|
16
|
+
assert_instance_of Result::OK, result
|
14
17
|
end
|
15
18
|
|
16
19
|
def test_succeed_parse
|
@@ -116,6 +119,17 @@ class YaparcTest < Test::Unit::TestCase
|
|
116
119
|
parser = AltParser.new(FailParser.new, FailParser.new)
|
117
120
|
result = parser.parse("abc")
|
118
121
|
assert_instance_of Result::Fail, result
|
122
|
+
|
123
|
+
parser = AltParser.new(Natural.new, Ident.new)
|
124
|
+
result = parser.parse("abc")
|
125
|
+
assert_instance_of Result::OK, result
|
126
|
+
result = parser.parse("124")
|
127
|
+
assert_instance_of Result::OK, result
|
128
|
+
result = parser.parse("ABC124")
|
129
|
+
assert_instance_of Result::Fail, result
|
130
|
+
result = parser.parse("abc124")
|
131
|
+
assert_instance_of Result::OK, result
|
132
|
+
assert_equal 'abc124', result.value
|
119
133
|
end
|
120
134
|
|
121
135
|
def test_apply_parse
|
@@ -172,6 +186,17 @@ class YaparcTest < Test::Unit::TestCase
|
|
172
186
|
Integer(match)
|
173
187
|
end
|
174
188
|
assert_equal 1234, result.value
|
189
|
+
|
190
|
+
parser = RegexParser.new(/([0-9]+):([a-z]+)/)
|
191
|
+
result = parser.parse_with_parameter("1234:ab") do |match1, match2|
|
192
|
+
assert_equal 'ab', match2
|
193
|
+
end
|
194
|
+
|
195
|
+
parser = RegexParser.new(/([0-9]+):([a-z]+)/) do |match1, match2|
|
196
|
+
[match2,match1]
|
197
|
+
end
|
198
|
+
result = parser.parse("1234:ab")
|
199
|
+
assert_equal ["ab", "1234"], result.value
|
175
200
|
end
|
176
201
|
|
177
202
|
def test_zero_one_parse
|
@@ -197,6 +222,18 @@ class YaparcTest < Test::Unit::TestCase
|
|
197
222
|
assert_equal "abcdef", result.input
|
198
223
|
end
|
199
224
|
|
225
|
+
def test_many_one_parse
|
226
|
+
is_digit = SatisfyParser.new(lambda {|i| i >= '0' and i <= '9'})
|
227
|
+
parser = ManyOneParser.new(is_digit,"")
|
228
|
+
result = parser.parse("123abc")
|
229
|
+
assert_equal "123", result.value
|
230
|
+
assert_equal "abc", result.input
|
231
|
+
|
232
|
+
result = parser.parse("abcdef")
|
233
|
+
assert_instance_of Result::Fail, result
|
234
|
+
assert_equal "abcdef", result.input
|
235
|
+
end
|
236
|
+
|
200
237
|
def test_ident
|
201
238
|
parser = Ident.new
|
202
239
|
result = parser.parse("abc def")
|
@@ -220,19 +257,19 @@ class YaparcTest < Test::Unit::TestCase
|
|
220
257
|
assert_equal "", result.input
|
221
258
|
end
|
222
259
|
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
260
|
+
# def test_space
|
261
|
+
# parser = Space.new
|
262
|
+
# result = parser.parse(" abc")
|
263
|
+
# assert_instance_of Result::OK, result
|
264
|
+
# assert_equal "abc", result.input
|
265
|
+
# end
|
229
266
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
267
|
+
# def test_whitespace
|
268
|
+
# parser = WhiteSpace.new
|
269
|
+
# result = parser.parse(" \n abc")
|
270
|
+
# assert_instance_of Result::OK, result
|
271
|
+
# assert_equal "abc", result.input
|
272
|
+
# end
|
236
273
|
|
237
274
|
# def test_token
|
238
275
|
# parser = Token.new
|
@@ -241,10 +278,10 @@ class YaparcTest < Test::Unit::TestCase
|
|
241
278
|
# assert_equal "abc", result.input
|
242
279
|
# end
|
243
280
|
|
244
|
-
def
|
245
|
-
parser =
|
246
|
-
tokenize.prefix =
|
247
|
-
tokenize.postfix =
|
281
|
+
def test_tokenize_with_block
|
282
|
+
parser = TokenizeParser.new(Ident.new) do |tokenize|
|
283
|
+
tokenize.prefix = SpaceParser.new
|
284
|
+
tokenize.postfix = SpaceParser.new
|
248
285
|
end
|
249
286
|
|
250
287
|
result = parser.parse(" abc")
|
@@ -256,9 +293,9 @@ class YaparcTest < Test::Unit::TestCase
|
|
256
293
|
assert_instance_of Result::Fail, result
|
257
294
|
assert_equal "\n abc", result.input
|
258
295
|
|
259
|
-
parser =
|
260
|
-
tokenize.prefix =
|
261
|
-
tokenize.postfix =
|
296
|
+
parser = TokenizeParser.new(Ident.new) do |tokenize|
|
297
|
+
tokenize.prefix = WhiteSpaceParser.new
|
298
|
+
tokenize.postfix = WhiteSpaceParser.new
|
262
299
|
end
|
263
300
|
|
264
301
|
result = parser.parse(" \n abc")
|
@@ -267,11 +304,31 @@ class YaparcTest < Test::Unit::TestCase
|
|
267
304
|
assert_equal "", result.input
|
268
305
|
end
|
269
306
|
|
307
|
+
def test_tokenize_without_block
|
308
|
+
parser = TokenizeParser.new(Ident.new, :prefix => WhiteSpaceParser.new, :postfix => WhiteSpaceParser.new)
|
309
|
+
|
310
|
+
result = parser.parse(" abc")
|
311
|
+
assert_instance_of Result::OK, result
|
312
|
+
assert_equal "abc", result.value
|
313
|
+
assert_equal "", result.input
|
314
|
+
|
315
|
+
parser = TokenizeParser.new(Ident.new, :prefix => SpaceParser.new, :postfix => SpaceParser.new)
|
316
|
+
result = parser.parse(" \n abc")
|
317
|
+
assert_instance_of Result::Fail, result
|
318
|
+
assert_equal "\n abc", result.input
|
319
|
+
end
|
320
|
+
|
270
321
|
def test_identifier
|
271
322
|
parser = Identifier.new
|
272
323
|
result = parser.parse(" abc ")
|
273
324
|
assert_equal "abc", result.value
|
274
325
|
assert_equal "", result.input
|
326
|
+
result = parser.parse(" _abc ")
|
327
|
+
assert_instance_of Result::OK, result
|
328
|
+
result = parser.parse(" 0_abc ")
|
329
|
+
assert_instance_of Result::Fail, result
|
330
|
+
result = parser.parse(" _00abc ")
|
331
|
+
assert_instance_of Result::OK, result
|
275
332
|
|
276
333
|
parser_with_keyword = Identifier.new("abc","efg")
|
277
334
|
result = parser_with_keyword.parse("abc")
|
@@ -294,5 +351,12 @@ class YaparcTest < Test::Unit::TestCase
|
|
294
351
|
assert_equal "%", result.value
|
295
352
|
assert_equal "", result.input
|
296
353
|
end
|
354
|
+
|
355
|
+
def test_literal_parser
|
356
|
+
parser = LiteralParser.new('%')
|
357
|
+
result = parser.parse(" % ")
|
358
|
+
assert_equal "%", result.value
|
359
|
+
assert_equal "", result.input
|
360
|
+
end
|
297
361
|
end
|
298
362
|
|