rpg_lib 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d34b6d848dfd8d8f76606d2ff2da3e4db758349f
4
- data.tar.gz: 92897b0065a31f7c747b0806a9be0ec7a0d8b99d
3
+ metadata.gz: 136dbff71bbb97184c6835b956e5cc79a3578142
4
+ data.tar.gz: 356ce85a68d6f9a03d87335452dd6293bd8453d3
5
5
  SHA512:
6
- metadata.gz: 5cc706792314e57fc3a7612194b215a4f8e9b6c02aef932c8150e26b0d836589830c28d2292ab9335877058df7da9ad7a49fd8d68576d805fa45577e6e058d14
7
- data.tar.gz: 035d42799027fdadcafdb903d7c4ab8a7355cb05bb0d0ec49e54ca62e3271bd68bbc319aad6598f080c8a4331ec653484fd093cf9350e12dddd14445b698537b
6
+ metadata.gz: 7ed15287c7b7c90cdd89cf6f50e98591be19ac72ab74fc4cec1d999e775e6258daa2b59178da775c7ace7b89a5c30382ab823900d9fe27c65925c26ee7184df1
7
+ data.tar.gz: '08bd9248297bd14ed7226d391df5cc46a8712ac3d2ad6806c615f3a43f2e8c82b0d1977c30363a960d5a227c0f8e3c87cc066451f6165eab930ffe229703b155'
data/.gitignore CHANGED
@@ -1 +1,3 @@
1
1
  /coverage
2
+ /pkg
3
+ *.swp
data/.rubocop.yml CHANGED
@@ -1,3 +1,7 @@
1
+ AllCops:
2
+ Exclude:
3
+ - 'lib/rpg_lib/parser/dice_expression_parser.rb'
4
+
1
5
  Metrics/LineLength:
2
6
  Enabled: false
3
7
  Metrics/ModuleLength:
data/Gemfile CHANGED
@@ -1,3 +1,20 @@
1
+ # Copyright 2017 Jamie Hale
2
+ #
3
+ # This file is part of the RpgLib gem.
4
+ #
5
+ # RpgLib is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # RpgLib is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with RpgLib. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  source 'https://rubygems.org'
2
19
 
3
20
  gemspec
data/Gemfile.lock CHANGED
@@ -2,6 +2,7 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  rpg_lib (1.0.0)
5
+ treetop (~> 1.6)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
@@ -12,6 +13,7 @@ GEM
12
13
  json (2.0.3)
13
14
  parser (2.4.0.0)
14
15
  ast (~> 2.2)
16
+ polyglot (0.3.5)
15
17
  powerpack (0.1.1)
16
18
  rainbow (2.2.1)
17
19
  rake (12.0.0)
@@ -40,6 +42,8 @@ GEM
40
42
  json (>= 1.8, < 3)
41
43
  simplecov-html (~> 0.10.0)
42
44
  simplecov-html (0.10.0)
45
+ treetop (1.6.8)
46
+ polyglot (~> 0.3)
43
47
  unicode-display_width (1.1.3)
44
48
 
45
49
  PLATFORMS
data/Rakefile CHANGED
@@ -26,3 +26,7 @@ task default: :spec
26
26
  task :rubocop do
27
27
  sh 'bundle exec rubocop'
28
28
  end
29
+
30
+ task :treetop do
31
+ sh 'tt --force --output lib/rpg_lib/parser/dice_expression_parser.rb grammar/dice_expression.treetop'
32
+ end
@@ -0,0 +1,95 @@
1
+ module RpgLib
2
+ module Parser
3
+ # :nocov:
4
+ grammar DiceExpression
5
+ rule additive
6
+ head:multitive
7
+ tail:(
8
+ space operator:additive_op
9
+ space operand:multitive)* <BinaryOperation>
10
+ end
11
+
12
+ rule additive_op
13
+ '+' {
14
+ def apply(a, b)
15
+ a + b
16
+ end
17
+ }
18
+ /
19
+ '-' {
20
+ def apply(a, b)
21
+ a - b
22
+ end
23
+ }
24
+ end
25
+
26
+ rule multitive
27
+ head:primary
28
+ tail:(
29
+ space operator:multitive_op
30
+ space operand:primary)* <BinaryOperation>
31
+ end
32
+
33
+ rule multitive_op
34
+ '*' {
35
+ def apply(a, b)
36
+ a * b
37
+ end
38
+ }
39
+ /
40
+ '/' {
41
+ def apply(a, b)
42
+ a / b
43
+ end
44
+ }
45
+ end
46
+
47
+ rule primary
48
+ dice
49
+ /
50
+ number
51
+ /
52
+ '(' space additive space ')' {
53
+ def eval(roller)
54
+ additive.eval(roller)
55
+ end
56
+ }
57
+ end
58
+
59
+ rule number
60
+ ('-'? [1-9] [0-9]* / '0' ) {
61
+ def eval(_roller)
62
+ text_value.to_i
63
+ end
64
+ }
65
+ end
66
+
67
+ rule positive_integer
68
+ ([1-9] [0-9]*) {
69
+ def eval(_roller)
70
+ text_value.to_i
71
+ end
72
+ }
73
+ end
74
+
75
+ rule dice
76
+ count:positive_integer? 'd' sides:positive_integer {
77
+ def eval(roller)
78
+ die_count = count.empty? ? 1 : count.eval(nil)
79
+ die_sides = sides.eval(nil)
80
+ rolls = []
81
+ die_count.times do
82
+ rolls << roller.roll(die_sides)
83
+ end
84
+ rolls.inject(&:+)
85
+ end
86
+ }
87
+ end
88
+
89
+ rule space
90
+ ' '*
91
+ end
92
+ end
93
+ # :nocov:
94
+ end
95
+ end
data/lib/rpg_lib.rb CHANGED
@@ -17,6 +17,12 @@
17
17
 
18
18
  require 'rpg_lib/version'
19
19
  require 'rpg_lib/roll_set'
20
- require 'rpg_lib/roll_descriptor'
20
+ require 'rpg_lib/die_roller'
21
21
  require 'rpg_lib/dice_roller'
22
22
  require 'rpg_lib/string'
23
+ require 'rpg_lib/api'
24
+
25
+ require 'treetop'
26
+ require 'rpg_lib/parser/dice_expression_nodes.rb'
27
+ require 'rpg_lib/parser/dice_expression_parser.rb'
28
+ require 'rpg_lib/parser/dice_parser.rb'
data/lib/rpg_lib/api.rb CHANGED
@@ -1,11 +1,35 @@
1
+ # Copyright 2017 Jamie Hale
2
+ #
3
+ # This file is part of the RpgLib gem.
4
+ #
5
+ # RpgLib is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # RpgLib is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with RpgLib. If not, see <http://www.gnu.org/licenses/>.
17
+
1
18
  module RpgLib
19
+ ##
20
+ # Api
21
+ #
2
22
  module Api
3
23
  def roll(dice)
4
24
  DiceRoller.instance.roll(dice)
5
25
  end
6
26
 
7
27
  def roll_and_ignore(dice, *args)
8
- DiceRoller.instance.roll_and_ignore(dice, *args)
28
+ DiceRoller.instance.roll_and_ignore(dice, RollSet.new(*args))
29
+ end
30
+
31
+ def choose(options)
32
+ options[DiceRoller.instance.roll_die(options.size) - 1]
9
33
  end
10
34
  end
11
35
  end
@@ -24,59 +24,27 @@ module RpgLib
24
24
  class DiceRoller
25
25
  include Singleton
26
26
 
27
- DICE_REGEXP = /(\d*)d(\d+)((dl)(\d*)|(dh)(\d*))?/
27
+ attr_reader :parser
28
+ attr_accessor :roller
28
29
 
29
- def random_value_in_range(range)
30
- rand(range)
30
+ def initialize
31
+ @roller = DieRoller.new
32
+ @parser = Parser::DiceParser.new
31
33
  end
32
34
 
33
- def roll_dice(roll_descriptor)
34
- rolled_values = roll_all_dice_from_descriptor(roll_descriptor)
35
- drop_lowest(rolled_values, roll_descriptor)
36
- drop_highest(rolled_values, roll_descriptor)
37
- total(rolled_values)
35
+ def roll_die(n)
36
+ @roller.roll(n)
38
37
  end
39
38
 
40
39
  def roll(dice)
41
- local_dice = dice.dup
42
- loop do
43
- m = local_dice.downcase.match(DICE_REGEXP)
44
- break if m.nil?
45
- rolled_value = roll_dice(RollDescriptor.new(m))
46
- local_dice[m.begin(0)...m.end(0)] = rolled_value.to_s
47
- end
48
- eval(local_dice)
40
+ @parser.parse(dice).eval(@roller)
49
41
  end
50
42
 
51
43
  def roll_and_ignore(dice, ignored_values)
52
- rolled_value = nil
53
44
  loop do
54
45
  rolled_value = roll(dice)
55
- break unless ignored_values.include?(rolled_value)
56
- end
57
- rolled_value
58
- end
59
-
60
- private
61
-
62
- def roll_all_dice_from_descriptor(roll_descriptor)
63
- rolled_values = []
64
- 1.upto roll_descriptor.count do
65
- rolled_values << random_value_in_range(1..roll_descriptor.die)
46
+ return rolled_value unless ignored_values.include?(rolled_value)
66
47
  end
67
- rolled_values.sort
68
- end
69
-
70
- def drop_lowest(rolled_values, roll_descriptor)
71
- rolled_values.slice!(0, roll_descriptor.drop_lowest)
72
- end
73
-
74
- def drop_highest(rolled_values, roll_descriptor)
75
- rolled_values.slice!(rolled_values.size - roll_descriptor.drop_highest, roll_descriptor.drop_highest)
76
- end
77
-
78
- def total(rolled_values)
79
- rolled_values.inject(:+)
80
48
  end
81
49
  end
82
50
  end
@@ -0,0 +1,14 @@
1
+ module RpgLib
2
+ ##
3
+ # DieRoller
4
+ #
5
+ class DieRoller
6
+ def initialize(generator = nil)
7
+ @generator = generator || Random.new
8
+ end
9
+
10
+ def roll(sides)
11
+ @generator.rand(1..sides)
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,16 @@
1
+ module RpgLib
2
+ module Parser
3
+ module DiceExpression
4
+ ##
5
+ # BinaryOperation
6
+ #
7
+ class BinaryOperation < Treetop::Runtime::SyntaxNode
8
+ def eval(roller)
9
+ tail.elements.inject(head.eval(roller)) do |value, element|
10
+ element.operator.apply(value, element.operand.eval(roller))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,677 @@
1
+ # Autogenerated from a Treetop grammar. Edits may be lost.
2
+
3
+
4
+ module RpgLib
5
+ module Parser
6
+ # :nocov:
7
+ module DiceExpression
8
+ include Treetop::Runtime
9
+
10
+ def root
11
+ @root ||= :additive
12
+ end
13
+
14
+ module Additive0
15
+ def space1
16
+ elements[0]
17
+ end
18
+
19
+ def operator
20
+ elements[1]
21
+ end
22
+
23
+ def space2
24
+ elements[2]
25
+ end
26
+
27
+ def operand
28
+ elements[3]
29
+ end
30
+ end
31
+
32
+ module Additive1
33
+ def head
34
+ elements[0]
35
+ end
36
+
37
+ def tail
38
+ elements[1]
39
+ end
40
+ end
41
+
42
+ def _nt_additive
43
+ start_index = index
44
+ if node_cache[:additive].has_key?(index)
45
+ cached = node_cache[:additive][index]
46
+ if cached
47
+ node_cache[:additive][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
48
+ @index = cached.interval.end
49
+ end
50
+ return cached
51
+ end
52
+
53
+ i0, s0 = index, []
54
+ r1 = _nt_multitive
55
+ s0 << r1
56
+ if r1
57
+ s2, i2 = [], index
58
+ loop do
59
+ i3, s3 = index, []
60
+ r4 = _nt_space
61
+ s3 << r4
62
+ if r4
63
+ r5 = _nt_additive_op
64
+ s3 << r5
65
+ if r5
66
+ r6 = _nt_space
67
+ s3 << r6
68
+ if r6
69
+ r7 = _nt_multitive
70
+ s3 << r7
71
+ end
72
+ end
73
+ end
74
+ if s3.last
75
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
76
+ r3.extend(Additive0)
77
+ else
78
+ @index = i3
79
+ r3 = nil
80
+ end
81
+ if r3
82
+ s2 << r3
83
+ else
84
+ break
85
+ end
86
+ end
87
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
88
+ s0 << r2
89
+ end
90
+ if s0.last
91
+ r0 = instantiate_node(BinaryOperation,input, i0...index, s0)
92
+ r0.extend(Additive1)
93
+ else
94
+ @index = i0
95
+ r0 = nil
96
+ end
97
+
98
+ node_cache[:additive][start_index] = r0
99
+
100
+ r0
101
+ end
102
+
103
+ module AdditiveOp0
104
+ def apply(a, b)
105
+ a + b
106
+ end
107
+ end
108
+
109
+ module AdditiveOp1
110
+ def apply(a, b)
111
+ a - b
112
+ end
113
+ end
114
+
115
+ def _nt_additive_op
116
+ start_index = index
117
+ if node_cache[:additive_op].has_key?(index)
118
+ cached = node_cache[:additive_op][index]
119
+ if cached
120
+ node_cache[:additive_op][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
121
+ @index = cached.interval.end
122
+ end
123
+ return cached
124
+ end
125
+
126
+ i0 = index
127
+ if (match_len = has_terminal?('+', false, index))
128
+ r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
129
+ r1.extend(AdditiveOp0)
130
+ @index += match_len
131
+ else
132
+ terminal_parse_failure('\'+\'')
133
+ r1 = nil
134
+ end
135
+ if r1
136
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
137
+ r0 = r1
138
+ else
139
+ if (match_len = has_terminal?('-', false, index))
140
+ r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
141
+ r2.extend(AdditiveOp1)
142
+ @index += match_len
143
+ else
144
+ terminal_parse_failure('\'-\'')
145
+ r2 = nil
146
+ end
147
+ if r2
148
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
149
+ r0 = r2
150
+ else
151
+ @index = i0
152
+ r0 = nil
153
+ end
154
+ end
155
+
156
+ node_cache[:additive_op][start_index] = r0
157
+
158
+ r0
159
+ end
160
+
161
+ module Multitive0
162
+ def space1
163
+ elements[0]
164
+ end
165
+
166
+ def operator
167
+ elements[1]
168
+ end
169
+
170
+ def space2
171
+ elements[2]
172
+ end
173
+
174
+ def operand
175
+ elements[3]
176
+ end
177
+ end
178
+
179
+ module Multitive1
180
+ def head
181
+ elements[0]
182
+ end
183
+
184
+ def tail
185
+ elements[1]
186
+ end
187
+ end
188
+
189
+ def _nt_multitive
190
+ start_index = index
191
+ if node_cache[:multitive].has_key?(index)
192
+ cached = node_cache[:multitive][index]
193
+ if cached
194
+ node_cache[:multitive][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
195
+ @index = cached.interval.end
196
+ end
197
+ return cached
198
+ end
199
+
200
+ i0, s0 = index, []
201
+ r1 = _nt_primary
202
+ s0 << r1
203
+ if r1
204
+ s2, i2 = [], index
205
+ loop do
206
+ i3, s3 = index, []
207
+ r4 = _nt_space
208
+ s3 << r4
209
+ if r4
210
+ r5 = _nt_multitive_op
211
+ s3 << r5
212
+ if r5
213
+ r6 = _nt_space
214
+ s3 << r6
215
+ if r6
216
+ r7 = _nt_primary
217
+ s3 << r7
218
+ end
219
+ end
220
+ end
221
+ if s3.last
222
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
223
+ r3.extend(Multitive0)
224
+ else
225
+ @index = i3
226
+ r3 = nil
227
+ end
228
+ if r3
229
+ s2 << r3
230
+ else
231
+ break
232
+ end
233
+ end
234
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
235
+ s0 << r2
236
+ end
237
+ if s0.last
238
+ r0 = instantiate_node(BinaryOperation,input, i0...index, s0)
239
+ r0.extend(Multitive1)
240
+ else
241
+ @index = i0
242
+ r0 = nil
243
+ end
244
+
245
+ node_cache[:multitive][start_index] = r0
246
+
247
+ r0
248
+ end
249
+
250
+ module MultitiveOp0
251
+ def apply(a, b)
252
+ a * b
253
+ end
254
+ end
255
+
256
+ module MultitiveOp1
257
+ def apply(a, b)
258
+ a / b
259
+ end
260
+ end
261
+
262
+ def _nt_multitive_op
263
+ start_index = index
264
+ if node_cache[:multitive_op].has_key?(index)
265
+ cached = node_cache[:multitive_op][index]
266
+ if cached
267
+ node_cache[:multitive_op][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
268
+ @index = cached.interval.end
269
+ end
270
+ return cached
271
+ end
272
+
273
+ i0 = index
274
+ if (match_len = has_terminal?('*', false, index))
275
+ r1 = instantiate_node(SyntaxNode,input, index...(index + match_len))
276
+ r1.extend(MultitiveOp0)
277
+ @index += match_len
278
+ else
279
+ terminal_parse_failure('\'*\'')
280
+ r1 = nil
281
+ end
282
+ if r1
283
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
284
+ r0 = r1
285
+ else
286
+ if (match_len = has_terminal?('/', false, index))
287
+ r2 = instantiate_node(SyntaxNode,input, index...(index + match_len))
288
+ r2.extend(MultitiveOp1)
289
+ @index += match_len
290
+ else
291
+ terminal_parse_failure('\'/\'')
292
+ r2 = nil
293
+ end
294
+ if r2
295
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
296
+ r0 = r2
297
+ else
298
+ @index = i0
299
+ r0 = nil
300
+ end
301
+ end
302
+
303
+ node_cache[:multitive_op][start_index] = r0
304
+
305
+ r0
306
+ end
307
+
308
+ module Primary0
309
+ def space1
310
+ elements[1]
311
+ end
312
+
313
+ def additive
314
+ elements[2]
315
+ end
316
+
317
+ def space2
318
+ elements[3]
319
+ end
320
+
321
+ end
322
+
323
+ module Primary1
324
+ def eval(roller)
325
+ additive.eval(roller)
326
+ end
327
+ end
328
+
329
+ def _nt_primary
330
+ start_index = index
331
+ if node_cache[:primary].has_key?(index)
332
+ cached = node_cache[:primary][index]
333
+ if cached
334
+ node_cache[:primary][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
335
+ @index = cached.interval.end
336
+ end
337
+ return cached
338
+ end
339
+
340
+ i0 = index
341
+ r1 = _nt_dice
342
+ if r1
343
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
344
+ r0 = r1
345
+ else
346
+ r2 = _nt_number
347
+ if r2
348
+ r2 = SyntaxNode.new(input, (index-1)...index) if r2 == true
349
+ r0 = r2
350
+ else
351
+ i3, s3 = index, []
352
+ if (match_len = has_terminal?('(', false, index))
353
+ r4 = true
354
+ @index += match_len
355
+ else
356
+ terminal_parse_failure('\'(\'')
357
+ r4 = nil
358
+ end
359
+ s3 << r4
360
+ if r4
361
+ r5 = _nt_space
362
+ s3 << r5
363
+ if r5
364
+ r6 = _nt_additive
365
+ s3 << r6
366
+ if r6
367
+ r7 = _nt_space
368
+ s3 << r7
369
+ if r7
370
+ if (match_len = has_terminal?(')', false, index))
371
+ r8 = true
372
+ @index += match_len
373
+ else
374
+ terminal_parse_failure('\')\'')
375
+ r8 = nil
376
+ end
377
+ s3 << r8
378
+ end
379
+ end
380
+ end
381
+ end
382
+ if s3.last
383
+ r3 = instantiate_node(SyntaxNode,input, i3...index, s3)
384
+ r3.extend(Primary0)
385
+ r3.extend(Primary1)
386
+ else
387
+ @index = i3
388
+ r3 = nil
389
+ end
390
+ if r3
391
+ r3 = SyntaxNode.new(input, (index-1)...index) if r3 == true
392
+ r0 = r3
393
+ else
394
+ @index = i0
395
+ r0 = nil
396
+ end
397
+ end
398
+ end
399
+
400
+ node_cache[:primary][start_index] = r0
401
+
402
+ r0
403
+ end
404
+
405
+ module Number0
406
+ end
407
+
408
+ module Number1
409
+ def eval(_roller)
410
+ text_value.to_i
411
+ end
412
+ end
413
+
414
+ def _nt_number
415
+ start_index = index
416
+ if node_cache[:number].has_key?(index)
417
+ cached = node_cache[:number][index]
418
+ if cached
419
+ node_cache[:number][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
420
+ @index = cached.interval.end
421
+ end
422
+ return cached
423
+ end
424
+
425
+ i0 = index
426
+ i1, s1 = index, []
427
+ if (match_len = has_terminal?('-', false, index))
428
+ r3 = true
429
+ @index += match_len
430
+ else
431
+ terminal_parse_failure('\'-\'')
432
+ r3 = nil
433
+ end
434
+ if r3
435
+ r2 = r3
436
+ else
437
+ r2 = instantiate_node(SyntaxNode,input, index...index)
438
+ end
439
+ s1 << r2
440
+ if r2
441
+ if has_terminal?(@regexps[gr = '\A[1-9]'] ||= Regexp.new(gr), :regexp, index)
442
+ r4 = true
443
+ @index += 1
444
+ else
445
+ terminal_parse_failure('[1-9]')
446
+ r4 = nil
447
+ end
448
+ s1 << r4
449
+ if r4
450
+ s5, i5 = [], index
451
+ loop do
452
+ if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index)
453
+ r6 = true
454
+ @index += 1
455
+ else
456
+ terminal_parse_failure('[0-9]')
457
+ r6 = nil
458
+ end
459
+ if r6
460
+ s5 << r6
461
+ else
462
+ break
463
+ end
464
+ end
465
+ r5 = instantiate_node(SyntaxNode,input, i5...index, s5)
466
+ s1 << r5
467
+ end
468
+ end
469
+ if s1.last
470
+ r1 = instantiate_node(SyntaxNode,input, i1...index, s1)
471
+ r1.extend(Number0)
472
+ else
473
+ @index = i1
474
+ r1 = nil
475
+ end
476
+ if r1
477
+ r1 = SyntaxNode.new(input, (index-1)...index) if r1 == true
478
+ r0 = r1
479
+ r0.extend(Number1)
480
+ r0.extend(Number1)
481
+ else
482
+ if (match_len = has_terminal?('0', false, index))
483
+ r7 = true
484
+ @index += match_len
485
+ else
486
+ terminal_parse_failure('\'0\'')
487
+ r7 = nil
488
+ end
489
+ if r7
490
+ r7 = SyntaxNode.new(input, (index-1)...index) if r7 == true
491
+ r0 = r7
492
+ r0.extend(Number1)
493
+ r0.extend(Number1)
494
+ else
495
+ @index = i0
496
+ r0 = nil
497
+ end
498
+ end
499
+
500
+ node_cache[:number][start_index] = r0
501
+
502
+ r0
503
+ end
504
+
505
+ module PositiveInteger0
506
+ end
507
+
508
+ module PositiveInteger1
509
+ def eval(_roller)
510
+ text_value.to_i
511
+ end
512
+ end
513
+
514
+ def _nt_positive_integer
515
+ start_index = index
516
+ if node_cache[:positive_integer].has_key?(index)
517
+ cached = node_cache[:positive_integer][index]
518
+ if cached
519
+ node_cache[:positive_integer][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
520
+ @index = cached.interval.end
521
+ end
522
+ return cached
523
+ end
524
+
525
+ i0, s0 = index, []
526
+ if has_terminal?(@regexps[gr = '\A[1-9]'] ||= Regexp.new(gr), :regexp, index)
527
+ r1 = true
528
+ @index += 1
529
+ else
530
+ terminal_parse_failure('[1-9]')
531
+ r1 = nil
532
+ end
533
+ s0 << r1
534
+ if r1
535
+ s2, i2 = [], index
536
+ loop do
537
+ if has_terminal?(@regexps[gr = '\A[0-9]'] ||= Regexp.new(gr), :regexp, index)
538
+ r3 = true
539
+ @index += 1
540
+ else
541
+ terminal_parse_failure('[0-9]')
542
+ r3 = nil
543
+ end
544
+ if r3
545
+ s2 << r3
546
+ else
547
+ break
548
+ end
549
+ end
550
+ r2 = instantiate_node(SyntaxNode,input, i2...index, s2)
551
+ s0 << r2
552
+ end
553
+ if s0.last
554
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
555
+ r0.extend(PositiveInteger0)
556
+ r0.extend(PositiveInteger1)
557
+ else
558
+ @index = i0
559
+ r0 = nil
560
+ end
561
+
562
+ node_cache[:positive_integer][start_index] = r0
563
+
564
+ r0
565
+ end
566
+
567
+ module Dice0
568
+ def count
569
+ elements[0]
570
+ end
571
+
572
+ def sides
573
+ elements[2]
574
+ end
575
+ end
576
+
577
+ module Dice1
578
+ def eval(roller)
579
+ die_count = count.empty? ? 1 : count.eval(nil)
580
+ die_sides = sides.eval(nil)
581
+ rolls = []
582
+ die_count.times do
583
+ rolls << roller.roll(die_sides)
584
+ end
585
+ rolls.inject(&:+)
586
+ end
587
+ end
588
+
589
+ def _nt_dice
590
+ start_index = index
591
+ if node_cache[:dice].has_key?(index)
592
+ cached = node_cache[:dice][index]
593
+ if cached
594
+ node_cache[:dice][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
595
+ @index = cached.interval.end
596
+ end
597
+ return cached
598
+ end
599
+
600
+ i0, s0 = index, []
601
+ r2 = _nt_positive_integer
602
+ if r2
603
+ r1 = r2
604
+ else
605
+ r1 = instantiate_node(SyntaxNode,input, index...index)
606
+ end
607
+ s0 << r1
608
+ if r1
609
+ if (match_len = has_terminal?('d', false, index))
610
+ r3 = true
611
+ @index += match_len
612
+ else
613
+ terminal_parse_failure('\'d\'')
614
+ r3 = nil
615
+ end
616
+ s0 << r3
617
+ if r3
618
+ r4 = _nt_positive_integer
619
+ s0 << r4
620
+ end
621
+ end
622
+ if s0.last
623
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
624
+ r0.extend(Dice0)
625
+ r0.extend(Dice1)
626
+ else
627
+ @index = i0
628
+ r0 = nil
629
+ end
630
+
631
+ node_cache[:dice][start_index] = r0
632
+
633
+ r0
634
+ end
635
+
636
+ def _nt_space
637
+ start_index = index
638
+ if node_cache[:space].has_key?(index)
639
+ cached = node_cache[:space][index]
640
+ if cached
641
+ node_cache[:space][index] = cached = SyntaxNode.new(input, index...(index + 1)) if cached == true
642
+ @index = cached.interval.end
643
+ end
644
+ return cached
645
+ end
646
+
647
+ s0, i0 = [], index
648
+ loop do
649
+ if (match_len = has_terminal?(' ', false, index))
650
+ r1 = true
651
+ @index += match_len
652
+ else
653
+ terminal_parse_failure('\' \'')
654
+ r1 = nil
655
+ end
656
+ if r1
657
+ s0 << r1
658
+ else
659
+ break
660
+ end
661
+ end
662
+ r0 = instantiate_node(SyntaxNode,input, i0...index, s0)
663
+
664
+ node_cache[:space][start_index] = r0
665
+
666
+ r0
667
+ end
668
+
669
+ end
670
+
671
+ class DiceExpressionParser < Treetop::Runtime::CompiledParser
672
+ include DiceExpression
673
+ end
674
+
675
+ # :nocov:
676
+ end
677
+ end