jsgf 0.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +4 -0
- data/README.md +19 -12
- data/jsgf.gemspec +1 -1
- data/lib/jsgf/alternation.rb +1 -1
- data/lib/jsgf/grammar.rb +46 -1
- data/lib/jsgf/optional.rb +2 -0
- data/lib/jsgf/parser.rb +115 -90
- data/lib/jsgf/tokenizer.rb +6 -0
- data/test/jsgf/grammar.rb +66 -0
- data/test/jsgf/parser.rb +65 -29
- data/test/jsgf/tokenizer.rb +6 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fdf13c6642d0aa9a9faaa005d72563af8151ac68
|
4
|
+
data.tar.gz: 3014db9c26234c9744262e9c50a0198c9c81b466
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 140f2abe3f92727e630bf4aab4e4f33ba92afa09fc57e38f2e50d6669769a60fdc23ef0aa6c2565fa68b925874bffbec645507f6fd4afdc10500c3272293e907
|
7
|
+
data.tar.gz: aae7b624c87f88c923a2d6db6bb8e63ea6963860d50178cfb0b5128a74b4aee223abef8754343db1e725af6bff5ba93a6c124bbae0b08a0cad070d0069154825
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -1,8 +1,22 @@
|
|
1
|
-
|
1
|
+
Jsgf
|
2
|
+
====
|
2
3
|
|
4
|
+
[](https://travis-ci.org/bfoz/jsgf-ruby)
|
3
5
|
[](http://badge.fury.io/rb/jsgf)
|
4
6
|
|
5
|
-
|
7
|
+
For all of your [Java Speech Grammar Format](http://www.w3.org/TR/jsgf/) parsing needs.
|
8
|
+
|
9
|
+
Usage
|
10
|
+
-----
|
11
|
+
|
12
|
+
```ruby
|
13
|
+
require 'jsgf'
|
14
|
+
|
15
|
+
grammar = JSGF.read('example.gram')
|
16
|
+
```
|
17
|
+
|
18
|
+
Installation
|
19
|
+
------------
|
6
20
|
|
7
21
|
Add this line to your application's Gemfile:
|
8
22
|
|
@@ -18,14 +32,7 @@ Or install it yourself as:
|
|
18
32
|
|
19
33
|
$ gem install jsgf
|
20
34
|
|
21
|
-
|
22
|
-
|
23
|
-
TODO: Write usage instructions here
|
24
|
-
|
25
|
-
## Contributing
|
35
|
+
License
|
36
|
+
-------
|
26
37
|
|
27
|
-
|
28
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
29
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
30
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
31
|
-
5. Create a new Pull Request
|
38
|
+
Copyright 2015 Brandon Fosdick <bfoz@bfoz.net> and released under the BSD license.
|
data/jsgf.gemspec
CHANGED
@@ -4,7 +4,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
|
5
5
|
Gem::Specification.new do |spec|
|
6
6
|
spec.name = "jsgf"
|
7
|
-
spec.version = '0.
|
7
|
+
spec.version = '0.2'
|
8
8
|
spec.authors = ["Brandon Fosdick"]
|
9
9
|
spec.email = ["bfoz@bfoz.net"]
|
10
10
|
spec.summary = %q{Java Speech Grammar Format}
|
data/lib/jsgf/alternation.rb
CHANGED
data/lib/jsgf/grammar.rb
CHANGED
@@ -2,13 +2,15 @@ module JSGF
|
|
2
2
|
class Grammar
|
3
3
|
attr_reader :character_encoding
|
4
4
|
attr_reader :locale
|
5
|
+
attr_reader :grammar_name
|
5
6
|
attr_reader :private_rules
|
6
7
|
attr_reader :public_rules
|
7
8
|
attr_reader :version
|
8
9
|
|
9
|
-
def initialize(character_encoding:nil, locale:nil, private_rules:{}, public_rules:{}, version:nil)
|
10
|
+
def initialize(name:nil, character_encoding:nil, locale:nil, private_rules:{}, public_rules:{}, version:nil)
|
10
11
|
@character_encoding = character_encoding
|
11
12
|
@locale = locale
|
13
|
+
@grammar_name = name
|
12
14
|
@private_rules = private_rules
|
13
15
|
@public_rules = public_rules
|
14
16
|
@version = version
|
@@ -19,5 +21,48 @@ module JSGF
|
|
19
21
|
def rules
|
20
22
|
@public_rules.merge(@private_rules)
|
21
23
|
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
private_rule_array = @private_rules.map do |(name, rule)|
|
27
|
+
atoms = rule.map {|a| unparse_atom(a) }.join(' ')
|
28
|
+
"<#{name}> = #{atoms};"
|
29
|
+
end
|
30
|
+
public_rule_array = @public_rules.map do |(name, rule)|
|
31
|
+
atoms = rule.map {|a| unparse_atom(a) }.join(' ')
|
32
|
+
"public <#{name}> = #{atoms};"
|
33
|
+
end
|
34
|
+
|
35
|
+
[header, grammar_header, *public_rule_array, *private_rule_array].join('\n')
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
# Generate the grammar name header line
|
40
|
+
def grammar_header
|
41
|
+
"grammar #{grammar_name};"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Generate the JSGF header line
|
45
|
+
def header
|
46
|
+
['#JSGF', version, character_encoding, locale].compact.join(' ') + ';'
|
47
|
+
end
|
48
|
+
|
49
|
+
def unparse_atom(atom, nested:false)
|
50
|
+
case atom
|
51
|
+
when Array
|
52
|
+
s = atom.map {|a| unparse_atom(a, nested:nested)}.join(' ')
|
53
|
+
nested ? ('(' + s + ')') : s
|
54
|
+
when Alternation
|
55
|
+
s = atom.elements.map {|a| unparse_atom(a, nested:true)}.join(' | ')
|
56
|
+
atom.optional ? ('[' + s + ']') : s
|
57
|
+
when Optional then '[' + atom.elements.map {|a| unparse_atom(a, nested:nested)}.join(' | ') + ']'
|
58
|
+
else
|
59
|
+
weight = (atom[:weight] != 1.0) ? "/#{atom[:weight]}/" : nil
|
60
|
+
if atom[:name]
|
61
|
+
[weight, '<' + atom[:name] + '>'].compact.join(' ')
|
62
|
+
else
|
63
|
+
[weight, atom[:atom], *atom[:tags]].compact.join(' ')
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
22
67
|
end
|
23
68
|
end
|
data/lib/jsgf/optional.rb
CHANGED
data/lib/jsgf/parser.rb
CHANGED
@@ -11,6 +11,7 @@ require_relative 'alternation'
|
|
11
11
|
require_relative 'grammar'
|
12
12
|
require_relative 'optional'
|
13
13
|
require_relative 'repetition'
|
14
|
+
require_relative 'tokenizer'
|
14
15
|
|
15
16
|
module JSGF
|
16
17
|
class Parser < Racc::Parser
|
@@ -22,6 +23,7 @@ attr_reader :handler
|
|
22
23
|
def initialize(tokenizer)
|
23
24
|
@private_rules = {}
|
24
25
|
@public_rules = {}
|
26
|
+
@rules = {}
|
25
27
|
tokenizer = JSGF::Tokenizer.new(tokenizer) if tokenizer.is_a?(String)
|
26
28
|
@tokenizer = tokenizer
|
27
29
|
super()
|
@@ -50,22 +52,32 @@ def define_atom(atom, weight=1.0, tags=[])
|
|
50
52
|
end
|
51
53
|
|
52
54
|
def define_rule(name, visibility=:private, *args)
|
53
|
-
r = {name:name, visibility:visibility, atoms:args}
|
54
|
-
|
55
|
-
@private_rules[name] = r
|
56
|
-
else
|
57
|
-
@public_rules[name] = r
|
58
|
-
end
|
55
|
+
r = {name: name, visibility:visibility, atoms:args.flatten}
|
56
|
+
@rules[name] = r
|
59
57
|
r
|
60
58
|
end
|
61
59
|
|
60
|
+
def rule_reference(name)
|
61
|
+
{name:name, weight:1.0, tags:[]}
|
62
|
+
end
|
63
|
+
|
62
64
|
def next_token
|
63
65
|
@tokenizer.next_token
|
64
|
-
end
|
66
|
+
end
|
65
67
|
|
66
68
|
def parse
|
67
69
|
do_parse
|
68
|
-
|
70
|
+
|
71
|
+
@rules.each do |(k,v)|
|
72
|
+
if v[:visibility] == :private
|
73
|
+
@private_rules[k] = v[:atoms]
|
74
|
+
else
|
75
|
+
@public_rules[k] = v[:atoms]
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
JSGF::Grammar.new( name:@grammar_name,
|
80
|
+
character_encoding:@charset,
|
69
81
|
locale:@locale,
|
70
82
|
private_rules:@private_rules,
|
71
83
|
public_rules:@public_rules,
|
@@ -74,62 +86,62 @@ end
|
|
74
86
|
##### State transition tables begin ###
|
75
87
|
|
76
88
|
racc_action_table = [
|
77
|
-
|
78
|
-
40, 37,
|
79
|
-
40,
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
89
|
+
-21, 9, 13, 28, -21, 27, -21, 11, -21, 52,
|
90
|
+
53, 40, 37, 17, 11, 16, 40, 37, 38, 11,
|
91
|
+
39, 40, 13, 38, 11, 39, 44, 11, 38, 40,
|
92
|
+
39, 49, 11, 30, 40, 37, 38, 11, 39, 40,
|
93
|
+
29, 38, 11, 39, 40, 37, 38, 11, 39, 9,
|
94
|
+
13, 38, 13, 39, 13, 11, 47, 11, 54, 11,
|
95
|
+
48, 46, 26, 45, 52, 53, 52, 53, 52, 53,
|
96
|
+
24, 23, 60, 11, 18, 54, 15, 48, 5, 63,
|
97
|
+
64, 4 ]
|
86
98
|
|
87
99
|
racc_action_check = [
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
100
|
+
34, 7, 7, 17, 34, 17, 34, 7, 34, 34,
|
101
|
+
34, 48, 48, 4, 48, 4, 38, 38, 48, 38,
|
102
|
+
48, 37, 20, 38, 37, 38, 26, 20, 37, 32,
|
103
|
+
37, 32, 32, 23, 24, 24, 32, 24, 32, 57,
|
104
|
+
22, 24, 57, 24, 39, 39, 57, 39, 57, 2,
|
105
|
+
2, 39, 13, 39, 6, 2, 31, 13, 36, 6,
|
106
|
+
31, 28, 15, 28, 50, 50, 55, 55, 62, 62,
|
107
|
+
12, 11, 46, 9, 5, 51, 3, 56, 1, 58,
|
108
|
+
59, 0 ]
|
97
109
|
|
98
110
|
racc_action_pointer = [
|
99
|
-
|
100
|
-
nil,
|
101
|
-
|
102
|
-
nil,
|
103
|
-
nil, nil, nil, nil,
|
104
|
-
|
105
|
-
nil, nil, nil ]
|
111
|
+
78, 78, 45, 74, 6, 74, 49, -3, nil, 63,
|
112
|
+
nil, 64, 58, 47, nil, 55, nil, -4, nil, nil,
|
113
|
+
17, nil, 31, 22, 27, nil, 17, nil, 54, nil,
|
114
|
+
nil, 47, 22, nil, -9, nil, 52, 14, 9, 37,
|
115
|
+
nil, nil, nil, nil, nil, nil, 63, nil, 4, nil,
|
116
|
+
46, 69, nil, nil, nil, 48, 64, 32, 64, 63,
|
117
|
+
nil, nil, 50, nil, nil ]
|
106
118
|
|
107
119
|
racc_action_default = [
|
108
|
-
-
|
109
|
-
-13, -
|
110
|
-
-3, -11, -
|
111
|
-
-15, -
|
112
|
-
-
|
113
|
-
-
|
114
|
-
-
|
120
|
+
-38, -38, -1, -38, -38, -38, -2, -38, -10, -38,
|
121
|
+
-13, -38, -38, -38, -4, -38, -5, -38, 65, -14,
|
122
|
+
-3, -11, -38, -38, -38, -18, -38, -6, -38, -12,
|
123
|
+
-15, -38, -38, -19, -23, -22, -25, -38, -38, -38,
|
124
|
+
-32, -33, -34, -35, -9, -7, -38, -16, -38, -17,
|
125
|
+
-23, -26, -36, -37, -24, -27, -28, -29, -38, -38,
|
126
|
+
-8, -20, -21, -30, -31 ]
|
115
127
|
|
116
128
|
racc_goto_table = [
|
117
|
-
50,
|
118
|
-
|
119
|
-
12,
|
129
|
+
50, 51, 12, 19, 14, 55, 12, 12, 3, 22,
|
130
|
+
25, 58, 59, 12, 6, 31, 62, 19, 8, 20,
|
131
|
+
12, 32, 61, 21, 7, 50, 51, 2, 1 ]
|
120
132
|
|
121
133
|
racc_goto_check = [
|
122
|
-
|
123
|
-
|
124
|
-
8,
|
134
|
+
13, 15, 8, 9, 6, 13, 8, 8, 5, 8,
|
135
|
+
9, 16, 16, 8, 3, 10, 13, 9, 7, 3,
|
136
|
+
8, 11, 12, 7, 4, 13, 15, 2, 1 ]
|
125
137
|
|
126
138
|
racc_goto_pointer = [
|
127
|
-
nil,
|
128
|
-
|
139
|
+
nil, 28, 27, 12, 22, 8, 1, 16, 0, -3,
|
140
|
+
-9, -3, -26, -32, nil, -31, -27, nil, nil ]
|
129
141
|
|
130
142
|
racc_goto_default = [
|
131
143
|
nil, nil, nil, nil, nil, nil, nil, nil, 41, 10,
|
132
|
-
|
144
|
+
56, 57, 33, 34, 35, 36, nil, 42, 43 ]
|
133
145
|
|
134
146
|
racc_reduce_table = [
|
135
147
|
0, 0, :racc_error,
|
@@ -149,28 +161,31 @@ racc_reduce_table = [
|
|
149
161
|
2, 23, :_reduce_none,
|
150
162
|
3, 28, :_reduce_15,
|
151
163
|
4, 29, :_reduce_16,
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
2, 31, :_reduce_21,
|
164
|
+
4, 29, :_reduce_17,
|
165
|
+
2, 29, :_reduce_18,
|
166
|
+
1, 30, :_reduce_19,
|
167
|
+
3, 30, :_reduce_20,
|
157
168
|
1, 32, :_reduce_none,
|
158
|
-
|
169
|
+
1, 32, :_reduce_none,
|
170
|
+
1, 35, :_reduce_none,
|
171
|
+
2, 35, :_reduce_24,
|
172
|
+
1, 31, :_reduce_none,
|
173
|
+
2, 31, :_reduce_26,
|
174
|
+
2, 34, :_reduce_27,
|
175
|
+
1, 36, :_reduce_none,
|
176
|
+
1, 36, :_reduce_none,
|
177
|
+
3, 37, :_reduce_30,
|
178
|
+
3, 38, :_reduce_31,
|
179
|
+
1, 33, :_reduce_32,
|
180
|
+
1, 33, :_reduce_33,
|
159
181
|
1, 33, :_reduce_none,
|
160
182
|
1, 33, :_reduce_none,
|
161
|
-
2,
|
162
|
-
|
163
|
-
3, 37, :_reduce_28,
|
164
|
-
1, 34, :_reduce_29,
|
165
|
-
1, 34, :_reduce_none,
|
166
|
-
1, 34, :_reduce_none,
|
167
|
-
1, 34, :_reduce_none,
|
168
|
-
2, 34, :_reduce_33,
|
169
|
-
2, 34, :_reduce_34 ]
|
183
|
+
2, 33, :_reduce_36,
|
184
|
+
2, 33, :_reduce_37 ]
|
170
185
|
|
171
|
-
racc_reduce_n =
|
186
|
+
racc_reduce_n = 38
|
172
187
|
|
173
|
-
racc_shift_n =
|
188
|
+
racc_shift_n = 65
|
174
189
|
|
175
190
|
racc_token_table = {
|
176
191
|
false => 0,
|
@@ -245,12 +260,13 @@ Racc_token_to_s_table = [
|
|
245
260
|
"import_statement",
|
246
261
|
"rule_name",
|
247
262
|
"rule",
|
248
|
-
"
|
249
|
-
"
|
250
|
-
"
|
251
|
-
"rule_item",
|
263
|
+
"alternation",
|
264
|
+
"atom_list",
|
265
|
+
"alternation_item",
|
252
266
|
"rule_atom",
|
253
267
|
"weighted_item",
|
268
|
+
"tagged_atom",
|
269
|
+
"group_list",
|
254
270
|
"rule_group",
|
255
271
|
"rule_optional" ]
|
256
272
|
|
@@ -306,78 +322,87 @@ def _reduce_15(val, _values, result)
|
|
306
322
|
end
|
307
323
|
|
308
324
|
def _reduce_16(val, _values, result)
|
309
|
-
define_rule(val[0], :private, *(val[2..-2]))
|
325
|
+
result = define_rule(val[0], :private, *(val[2..-2]))
|
310
326
|
result
|
311
327
|
end
|
312
328
|
|
313
329
|
def _reduce_17(val, _values, result)
|
314
|
-
define_rule(val[
|
330
|
+
result = define_rule(val[0], :private, *(val[2..-2]))
|
315
331
|
result
|
316
332
|
end
|
317
333
|
|
318
334
|
def _reduce_18(val, _values, result)
|
319
|
-
|
335
|
+
val[1][:visibility] = :public
|
320
336
|
result
|
321
337
|
end
|
322
338
|
|
323
339
|
def _reduce_19(val, _values, result)
|
324
|
-
result =
|
340
|
+
result = val.first
|
325
341
|
result
|
326
342
|
end
|
327
343
|
|
328
344
|
def _reduce_20(val, _values, result)
|
329
|
-
result = val
|
345
|
+
result = define_alternation(*val)
|
330
346
|
result
|
331
347
|
end
|
332
348
|
|
333
|
-
|
334
|
-
result = val
|
335
|
-
result
|
336
|
-
end
|
349
|
+
# reduce 21 omitted
|
337
350
|
|
338
351
|
# reduce 22 omitted
|
339
352
|
|
340
|
-
|
353
|
+
# reduce 23 omitted
|
354
|
+
|
355
|
+
def _reduce_24(val, _values, result)
|
341
356
|
val[0][:tags].push(val[1]); result = val[0]
|
342
357
|
result
|
343
358
|
end
|
344
359
|
|
345
|
-
# reduce 24 omitted
|
346
|
-
|
347
360
|
# reduce 25 omitted
|
348
361
|
|
349
362
|
def _reduce_26(val, _values, result)
|
350
|
-
|
363
|
+
result = val;
|
351
364
|
result
|
352
365
|
end
|
353
366
|
|
354
367
|
def _reduce_27(val, _values, result)
|
368
|
+
val[1][:weight] = val.first[1..-2].to_f; result = val[1]
|
369
|
+
result
|
370
|
+
end
|
371
|
+
|
372
|
+
# reduce 28 omitted
|
373
|
+
|
374
|
+
# reduce 29 omitted
|
375
|
+
|
376
|
+
def _reduce_30(val, _values, result)
|
355
377
|
result = val[1]
|
356
378
|
result
|
357
379
|
end
|
358
380
|
|
359
|
-
def
|
381
|
+
def _reduce_31(val, _values, result)
|
360
382
|
result = define_optional(val[1])
|
361
383
|
result
|
362
384
|
end
|
363
385
|
|
364
|
-
def
|
386
|
+
def _reduce_32(val, _values, result)
|
365
387
|
result = define_atom(val.first)
|
366
388
|
result
|
367
389
|
end
|
368
390
|
|
369
|
-
|
391
|
+
def _reduce_33(val, _values, result)
|
392
|
+
result = rule_reference(val[0])
|
393
|
+
result
|
394
|
+
end
|
370
395
|
|
371
|
-
# reduce
|
396
|
+
# reduce 34 omitted
|
372
397
|
|
373
|
-
# reduce
|
398
|
+
# reduce 35 omitted
|
374
399
|
|
375
|
-
def
|
400
|
+
def _reduce_36(val, _values, result)
|
376
401
|
result = JSGF::Repetition.new(val[0], 0)
|
377
402
|
result
|
378
403
|
end
|
379
404
|
|
380
|
-
def
|
405
|
+
def _reduce_37(val, _values, result)
|
381
406
|
result = JSGF::Repetition.new(val[0], 1)
|
382
407
|
result
|
383
408
|
end
|
data/lib/jsgf/tokenizer.rb
CHANGED
@@ -24,6 +24,12 @@ module JSGF
|
|
24
24
|
@scanner.skip(/\s+/) # Skip all leading whitespace
|
25
25
|
@scanner.skip(%r{//.*\n}) # Skip single-line comments
|
26
26
|
|
27
|
+
# Skip C-style comments
|
28
|
+
if @scanner.scan(%r{/\*})
|
29
|
+
# Look for the end of the block, and skip any trailing whitespace
|
30
|
+
@scanner.skip_until(%r{\*/\s*})
|
31
|
+
end
|
32
|
+
|
27
33
|
TOKENS.each do |(pattern, token)|
|
28
34
|
text = @scanner.scan(pattern)
|
29
35
|
return [token, text] if text
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'jsgf/parser'
|
3
|
+
|
4
|
+
describe JSGF::Grammar do
|
5
|
+
it 'must unparse a header' do
|
6
|
+
grammar = JSGF::Parser.new('#JSGF; grammar header_grammar;').parse
|
7
|
+
grammar.to_s.must_equal '#JSGF;\ngrammar header_grammar;'
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'must unparse a header with a version' do
|
11
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;').parse
|
12
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;'
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'must unparse a header with a version and a character encoding' do
|
16
|
+
grammar = JSGF::Parser.new('#JSGF V1.0 ENCODING; grammar header_grammar;').parse
|
17
|
+
grammar.to_s.must_equal '#JSGF V1.0 ENCODING;\ngrammar header_grammar;'
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'must unparse a simple rule' do
|
21
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one;').parse
|
22
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = one;'
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'must unparse a public rule' do
|
26
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;public <rule>=one;').parse
|
27
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\npublic <rule> = one;'
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'must unparse a multi-atom rule' do
|
31
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one two;').parse
|
32
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = one two;'
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'must unparse a multi-atom optional' do
|
36
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=[one two];').parse
|
37
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = [one two];'
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'must unparse an alternation' do
|
41
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one | two;').parse
|
42
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = one | two;'
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'must unparse an optional alternation' do
|
46
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=[one | two];').parse
|
47
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = [one | two];'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'must unparse an alternation with a nested group' do
|
51
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=(one two) | three;').parse
|
52
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = (one two) | three;'
|
53
|
+
end
|
54
|
+
|
55
|
+
describe 'when unparsing rule references' do
|
56
|
+
it 'must unparse a rule reference' do
|
57
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=(one <rule2>) | three; <rule2>=two;').parse
|
58
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = (one <rule2>) | three;\n<rule2> = two;'
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'must unparse a weighted rule reference' do
|
62
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>= /0.5/ one | /0.5/ <rule2>; <rule2>=two;').parse
|
63
|
+
grammar.to_s.must_equal '#JSGF V1.0;\ngrammar header_grammar;\n<rule> = /0.5/ one | /0.5/ <rule2>;\n<rule2> = two;'
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
data/test/jsgf/parser.rb
CHANGED
@@ -26,23 +26,21 @@ describe JSGF::Parser do
|
|
26
26
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one;').parse
|
27
27
|
grammar.rules.size.must_equal 1
|
28
28
|
grammar.rules.keys.must_equal ['rule']
|
29
|
-
grammar.rules['rule']
|
29
|
+
grammar.rules['rule'].size.must_equal 1
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'must parse a rule with multiple atoms' do
|
33
33
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one two;').parse
|
34
34
|
grammar.rules.size.must_equal 1
|
35
35
|
grammar.rules.keys.must_equal ['rule']
|
36
|
-
grammar.rules['rule']
|
37
|
-
grammar.rules['rule'][:atoms].first.size.must_equal 2
|
36
|
+
grammar.rules['rule'].size.must_equal 2
|
38
37
|
end
|
39
38
|
|
40
39
|
it 'must parse a rule with multiple grouped atoms' do
|
41
40
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=(one two);').parse
|
42
41
|
grammar.rules.size.must_equal 1
|
43
42
|
grammar.rules.keys.must_equal ['rule']
|
44
|
-
grammar.rules['rule']
|
45
|
-
grammar.rules['rule'][:atoms].first.size.must_equal 2
|
43
|
+
grammar.rules['rule'].size.must_equal 2
|
46
44
|
end
|
47
45
|
|
48
46
|
describe 'when parsing an alternation' do
|
@@ -50,60 +48,98 @@ describe JSGF::Parser do
|
|
50
48
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one | two;').parse
|
51
49
|
grammar.rules.size.must_equal 1
|
52
50
|
grammar.rules.keys.must_equal ['rule']
|
53
|
-
grammar.rules['rule']
|
51
|
+
grammar.rules['rule'].size.must_equal 1
|
54
52
|
|
55
|
-
alternation = grammar.rules['rule']
|
53
|
+
alternation = grammar.rules['rule'].first
|
56
54
|
alternation.must_be_kind_of JSGF::Alternation
|
57
55
|
alternation.size.must_equal 2
|
58
56
|
end
|
59
|
-
|
57
|
+
|
60
58
|
it 'must parse a rule with a bigger alternation' do
|
61
59
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one | two | three;').parse
|
62
60
|
grammar.rules.size.must_equal 1
|
63
61
|
grammar.rules.keys.must_equal ['rule']
|
64
|
-
grammar.rules['rule']
|
62
|
+
grammar.rules['rule'].size.must_equal 1
|
65
63
|
|
66
|
-
alternation = grammar.rules['rule']
|
64
|
+
alternation = grammar.rules['rule'].first
|
67
65
|
alternation.must_be_kind_of JSGF::Alternation
|
68
66
|
alternation.size.must_equal 3
|
69
|
-
alternation.elements[0]
|
70
|
-
alternation.elements[1]
|
71
|
-
alternation.elements[2]
|
67
|
+
alternation.elements[0].must_equal Hash[atom:'one', weight:1.0, tags:[]]
|
68
|
+
alternation.elements[1].must_equal Hash[atom:'two', weight:1.0, tags:[]]
|
69
|
+
alternation.elements[2].must_equal Hash[atom:'three', weight:1.0, tags:[]]
|
72
70
|
end
|
73
71
|
|
74
72
|
it 'must parse a weighted alternation' do
|
75
73
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>= /0.5/ one | /0.25/ two | /0.25/ three;').parse
|
76
74
|
grammar.rules.keys.must_equal ['rule']
|
77
|
-
grammar.rules['rule']
|
75
|
+
grammar.rules['rule'].size.must_equal 1
|
78
76
|
|
79
|
-
alternation = grammar.rules['rule']
|
77
|
+
alternation = grammar.rules['rule'].first
|
80
78
|
alternation.must_be_kind_of JSGF::Alternation
|
81
79
|
alternation.size.must_equal 3
|
82
80
|
alternation.weights.must_equal [0.5, 0.25, 0.25]
|
83
|
-
alternation.elements[0]
|
81
|
+
alternation.elements[0].must_equal Hash[atom:'one', weight:0.5, tags:[]]
|
84
82
|
end
|
85
83
|
|
86
84
|
it 'must parse a grouped alternation' do
|
87
85
|
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=(one | two | three);').parse
|
88
86
|
grammar.rules.size.must_equal 1
|
89
87
|
grammar.rules.keys.must_equal ['rule']
|
90
|
-
grammar.rules['rule']
|
91
|
-
grammar.rules['rule']
|
92
|
-
grammar.rules['rule']
|
88
|
+
grammar.rules['rule'].size.must_equal 1
|
89
|
+
grammar.rules['rule'].first.must_be_kind_of JSGF::Alternation
|
90
|
+
grammar.rules['rule'].first.size.must_equal 3
|
93
91
|
end
|
94
92
|
end
|
95
93
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
94
|
+
describe 'when parsing optionals' do
|
95
|
+
it 'must parse an optional group of a single atom' do
|
96
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=[one];').parse
|
97
|
+
grammar.rules.size.must_equal 1
|
98
|
+
grammar.rules.keys.must_equal ['rule']
|
99
|
+
grammar.rules['rule'].size.must_equal 1
|
100
|
+
end
|
101
|
+
|
102
|
+
it 'must parse an optional alternation' do
|
103
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=[one | two];').parse
|
104
|
+
grammar.rules.size.must_equal 1
|
105
|
+
grammar.rules.keys.must_equal ['rule']
|
106
|
+
grammar.rules['rule'].size.must_equal 1
|
107
|
+
|
108
|
+
rule = grammar.rules['rule']
|
109
|
+
rule.first.must_be_kind_of JSGF::Alternation
|
110
|
+
rule.first.optional.must_equal true
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'must parse a multi-atom optional alternation' do
|
114
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=one two [three | four];').parse
|
115
|
+
grammar.rules.size.must_equal 1
|
116
|
+
grammar.rules.keys.must_equal ['rule']
|
117
|
+
grammar.rules['rule'].size.must_equal 3
|
118
|
+
|
119
|
+
rule = grammar.rules['rule']
|
120
|
+
rule.size.must_equal 3
|
121
|
+
end
|
101
122
|
end
|
102
123
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
124
|
+
describe 'when parsing rule references' do
|
125
|
+
it 'must parse a rule reference' do
|
126
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>=<rule1>;<rule1>=one;').parse
|
127
|
+
grammar.rules.size.must_equal 2
|
128
|
+
grammar.rules.keys.must_equal ['rule', 'rule1']
|
129
|
+
grammar.rules['rule'].must_equal [{name:'rule1', weight:1.0, tags:[]}]
|
130
|
+
grammar.rules['rule1'].must_equal [{atom:'one', weight:1.0, tags:[]}]
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'must parse a weighted rule reference' do
|
134
|
+
grammar = JSGF::Parser.new('#JSGF V1.0; grammar header_grammar;<rule>= /0.5/ <rule1> | /0.5/ two; <rule1>=one;').parse
|
135
|
+
grammar.rules.size.must_equal 2
|
136
|
+
grammar.rules.keys.must_equal ['rule', 'rule1']
|
137
|
+
|
138
|
+
grammar.rules['rule'].size.must_equal 1
|
139
|
+
grammar.rules['rule'].first.must_be_kind_of JSGF::Alternation
|
140
|
+
grammar.rules['rule'].first.elements.must_equal [{name:'rule1', weight:0.5, tags:[]}, {atom:'two', weight:0.5, tags:[]}]
|
141
|
+
|
142
|
+
grammar.rules['rule1'].must_equal [{atom:'one', weight:1.0, tags:[]}]
|
143
|
+
end
|
108
144
|
end
|
109
145
|
end
|
data/test/jsgf/tokenizer.rb
CHANGED
@@ -33,4 +33,10 @@ describe JSGF::Tokenizer do
|
|
33
33
|
it 'must recognize a token' do
|
34
34
|
JSGF::Tokenizer.new(' some_token ').next_token.must_equal [:TOKEN, 'some_token']
|
35
35
|
end
|
36
|
+
|
37
|
+
describe 'when given comments' do
|
38
|
+
it 'must skip C-style comments' do
|
39
|
+
JSGF::Tokenizer.new(' /* a comment */ some_token ').next_token.must_equal [:TOKEN, 'some_token']
|
40
|
+
end
|
41
|
+
end
|
36
42
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsgf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.2'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon Fosdick
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-01-
|
11
|
+
date: 2015-01-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -46,6 +46,7 @@ extensions: []
|
|
46
46
|
extra_rdoc_files: []
|
47
47
|
files:
|
48
48
|
- .gitignore
|
49
|
+
- .travis.yml
|
49
50
|
- Gemfile
|
50
51
|
- README.md
|
51
52
|
- Rakefile
|
@@ -57,6 +58,7 @@ files:
|
|
57
58
|
- lib/jsgf/parser.rb
|
58
59
|
- lib/jsgf/repetition.rb
|
59
60
|
- lib/jsgf/tokenizer.rb
|
61
|
+
- test/jsgf/grammar.rb
|
60
62
|
- test/jsgf/parser.rb
|
61
63
|
- test/jsgf/tokenizer.rb
|
62
64
|
homepage: http://github.com/bfoz/jsgf-ruby
|
@@ -84,5 +86,6 @@ signing_key:
|
|
84
86
|
specification_version: 4
|
85
87
|
summary: Java Speech Grammar Format
|
86
88
|
test_files:
|
89
|
+
- test/jsgf/grammar.rb
|
87
90
|
- test/jsgf/parser.rb
|
88
91
|
- test/jsgf/tokenizer.rb
|