bitgirder-platform 0.1.7

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.
Files changed (51) hide show
  1. data/LICENSE.txt +176 -0
  2. data/bin/ensure-test-db +117 -0
  3. data/bin/install-mysql +375 -0
  4. data/bin/tomcat7 +569 -0
  5. data/lib/bitgirder/concurrent.rb +400 -0
  6. data/lib/bitgirder/core.rb +1235 -0
  7. data/lib/bitgirder/etl.rb +58 -0
  8. data/lib/bitgirder/event/file.rb +485 -0
  9. data/lib/bitgirder/event/logger/testing.rb +140 -0
  10. data/lib/bitgirder/event/logger.rb +137 -0
  11. data/lib/bitgirder/event/testing.rb +88 -0
  12. data/lib/bitgirder/http.rb +255 -0
  13. data/lib/bitgirder/io/testing.rb +33 -0
  14. data/lib/bitgirder/io.rb +959 -0
  15. data/lib/bitgirder/irb.rb +35 -0
  16. data/lib/bitgirder/mysql.rb +60 -0
  17. data/lib/bitgirder/ops/java.rb +117 -0
  18. data/lib/bitgirder/ops/ruby.rb +235 -0
  19. data/lib/bitgirder/testing.rb +152 -0
  20. data/lib/doc-gen0.rb +0 -0
  21. data/lib/doc-gen1.rb +0 -0
  22. data/lib/doc-gen10.rb +0 -0
  23. data/lib/doc-gen11.rb +0 -0
  24. data/lib/doc-gen12.rb +0 -0
  25. data/lib/doc-gen13.rb +0 -0
  26. data/lib/doc-gen14.rb +0 -0
  27. data/lib/doc-gen15.rb +0 -0
  28. data/lib/doc-gen16.rb +0 -0
  29. data/lib/doc-gen17.rb +14 -0
  30. data/lib/doc-gen18.rb +0 -0
  31. data/lib/doc-gen19.rb +0 -0
  32. data/lib/doc-gen2.rb +0 -0
  33. data/lib/doc-gen20.rb +182 -0
  34. data/lib/doc-gen21.rb +0 -0
  35. data/lib/doc-gen3.rb +0 -0
  36. data/lib/doc-gen4.rb +0 -0
  37. data/lib/doc-gen5.rb +0 -0
  38. data/lib/doc-gen6.rb +0 -0
  39. data/lib/doc-gen7.rb +0 -0
  40. data/lib/doc-gen8.rb +0 -0
  41. data/lib/doc-gen9.rb +0 -0
  42. data/lib/mingle/bincodec.rb +512 -0
  43. data/lib/mingle/codec.rb +54 -0
  44. data/lib/mingle/http.rb +156 -0
  45. data/lib/mingle/io/stream.rb +142 -0
  46. data/lib/mingle/io.rb +160 -0
  47. data/lib/mingle/json.rb +257 -0
  48. data/lib/mingle/service.rb +110 -0
  49. data/lib/mingle-em.rb +92 -0
  50. data/lib/mingle.rb +2917 -0
  51. metadata +100 -0
data/lib/mingle.rb ADDED
@@ -0,0 +1,2917 @@
1
+ require 'bitgirder/core'
2
+ include BitGirder::Core
3
+
4
+ require 'bitgirder/io'
5
+
6
+ require 'bigdecimal'
7
+ require 'forwardable'
8
+
9
+ module Mingle
10
+
11
+ # For processing \uXXXX escapes in string tokens
12
+ USE_ICONV = ! "".respond_to?( :encode )
13
+ require 'iconv' if USE_ICONV
14
+
15
+ class MingleValue < BitGirderClass
16
+ end
17
+
18
+ class MingleNull < MingleValue
19
+
20
+ private_class_method :new
21
+
22
+ INSTANCE = self.send( :new )
23
+ end
24
+
25
+ # Note: it's important that this class be defined before
26
+ # things like MingleNamespace, MingleIdentifier, etc, which register parse
27
+ # handlers for values of type MingleString.
28
+ class MingleString < MingleValue
29
+
30
+ bg_attr :str
31
+
32
+ extend Forwardable
33
+
34
+ def_delegators :@str, :[], :=~, :to_sym, :split
35
+
36
+ include Comparable
37
+
38
+ def initialize( str )
39
+ @str = not_nil( str, "str" ).to_s.dup
40
+ end
41
+
42
+ public
43
+ def <=>( other )
44
+
45
+ if other.class == self.class
46
+ @str <=> other.str
47
+ else
48
+ raise TypeError, "Not a #{self.class}: #{other.class}"
49
+ end
50
+ end
51
+
52
+ public
53
+ def to_s
54
+ @str.to_s
55
+ end
56
+
57
+ public
58
+ def inspect
59
+ to_s.inspect
60
+ end
61
+
62
+ public
63
+ def ==( other )
64
+
65
+ return true if other.equal?( self )
66
+ return false unless other.is_a?( MingleString )
67
+
68
+ other_str = other.instance_variable_get( :@str )
69
+ @str == other_str
70
+ end
71
+
72
+ public
73
+ def eql?( other )
74
+ self == other
75
+ end
76
+
77
+ public
78
+ def hash
79
+ @str.hash
80
+ end
81
+
82
+ public
83
+ def to_i
84
+ @str.to_i
85
+ end
86
+ end
87
+
88
+ class MingleBoolean < MingleValue
89
+
90
+ private_class_method :new
91
+
92
+ extend Forwardable
93
+
94
+ def initialize( b )
95
+ @b = b
96
+ end
97
+
98
+ public
99
+ def to_s
100
+ @b.to_s
101
+ end
102
+
103
+ public
104
+ def inspect
105
+ to_s.inspect
106
+ end
107
+
108
+ public
109
+ def as_boolean
110
+ @b
111
+ end
112
+
113
+ alias to_b as_boolean
114
+ alias to_bool as_boolean
115
+ alias to_boolean as_boolean
116
+
117
+ public
118
+ def ==( other )
119
+ other.is_a?( MingleBoolean ) && @b == other.as_boolean
120
+ end
121
+
122
+ def_delegator :@b, :hash
123
+ alias eql? ==
124
+
125
+ TRUE = new( true )
126
+ FALSE = new( false )
127
+
128
+ def self.for_boolean( b )
129
+ b ? TRUE : FALSE
130
+ end
131
+ end
132
+
133
+ class MingleNumber < MingleValue
134
+
135
+ include Comparable
136
+ extend Forwardable
137
+
138
+ attr_reader :num
139
+
140
+ def initialize( num, convert_meth = nil )
141
+
142
+ not_nil( num, :num )
143
+ @num = convert_meth ? num.send( convert_meth ) : num
144
+ end
145
+
146
+ public
147
+ def to_s
148
+ @num.to_s
149
+ end
150
+
151
+ public
152
+ def inspect
153
+ to_s.inspect
154
+ end
155
+
156
+ public
157
+ def ==( other )
158
+ other.class == self.class && other.num == @num
159
+ end
160
+
161
+ def_delegator :@num, :hash
162
+ alias eql? ==
163
+
164
+ public
165
+ def <=>( other )
166
+
167
+ if other.is_a?( MingleNumber )
168
+ @num <=> other.num
169
+ else
170
+ raise TypeError, other.class.to_s
171
+ end
172
+ end
173
+
174
+ public
175
+ def to_i
176
+ @num.to_i
177
+ end
178
+
179
+ public
180
+ def to_f
181
+ @num.to_f
182
+ end
183
+ end
184
+
185
+ class MingleIntegerImpl < MingleNumber
186
+
187
+ def self.can_hold?( num )
188
+ num >= self::MIN_NUM && num <= self::MAX_NUM
189
+ end
190
+
191
+ def initialize( num )
192
+ super( num, :to_i )
193
+ end
194
+ end
195
+
196
+ class MingleFloatingPointImpl < MingleNumber
197
+
198
+ def initialize( num, fmt )
199
+ super( [ num.to_f ].pack( fmt ).unpack( fmt )[ 0 ] )
200
+ end
201
+ end
202
+
203
+ class MingleFloat64 < MingleFloatingPointImpl
204
+ def initialize( num )
205
+ super( num, 'd' )
206
+ end
207
+ end
208
+
209
+ class MingleFloat32 < MingleFloatingPointImpl
210
+
211
+ def initialize( num )
212
+ super( num, 'f' )
213
+ end
214
+ end
215
+
216
+ class MingleInt32 < MingleIntegerImpl
217
+
218
+ MAX_NUM = ( 2 ** 31 ) - 1
219
+ MIN_NUM = -( 2 ** 31 )
220
+ end
221
+
222
+ class MingleInt64 < MingleIntegerImpl
223
+
224
+ MAX_NUM = ( 2 ** 63 ) - 1
225
+ MIN_NUM = -( 2 ** 63 )
226
+ end
227
+
228
+ class MingleUint32 < MingleIntegerImpl
229
+
230
+ MAX_NUM = ( 2 ** 32 ) - 1
231
+ MIN_NUM = 0
232
+ end
233
+
234
+ class MingleUint64 < MingleIntegerImpl
235
+
236
+ MAX_NUM = ( 2 ** 64 ) - 1
237
+ MIN_NUM = 0
238
+ end
239
+
240
+ class MingleBuffer < MingleValue
241
+
242
+ extend Forwardable
243
+
244
+ attr_reader :buf
245
+
246
+ class EncodingError < StandardError; end
247
+
248
+ private
249
+ def process_buffer_encoding( buf, encode_mode )
250
+
251
+ enc_bin = Encoding::BINARY
252
+
253
+ if ( enc = buf.encoding ) != enc_bin
254
+
255
+ case encode_mode
256
+
257
+ when :copy then buf = buf.encode( enc_bin )
258
+ when :in_place then buf = buf.encode!( enc_bin )
259
+
260
+ when :none
261
+ raise EncodingError,
262
+ "Encoding should be binary (got : #{enc})"
263
+
264
+ else raise "Invalid encode mode: #{encode_mode}"
265
+ end
266
+ end
267
+
268
+ buf
269
+ end
270
+
271
+ def initialize( buf, encode_mode = :none )
272
+
273
+ not_nil( buf, "buf" )
274
+
275
+ @buf = RubyVersions.when_19x( buf ) do
276
+ process_buffer_encoding( buf, encode_mode )
277
+ end
278
+ end
279
+
280
+ public
281
+ def ==( other )
282
+ other.is_a?( MingleBuffer ) && other.buf == @buf
283
+ end
284
+
285
+ def_delegator :@buf, :hash
286
+ alias eql? ==
287
+ end
288
+
289
+ class MingleTimestamp < MingleValue
290
+
291
+ extend BitGirder::Core::BitGirderMethods
292
+ include Comparable
293
+
294
+ extend Forwardable
295
+
296
+ require 'time'
297
+
298
+ attr_reader :time
299
+
300
+ # Uses iso8601 serialize --> parse to make a copy of the supplied time
301
+ # unless make_copy is false, in which case time is used directly by this
302
+ # instance
303
+ def initialize( time, make_copy = true )
304
+
305
+ not_nil( time, "time" )
306
+ @time = ( make_copy ? Time.iso8601( time.iso8601( 9 ) ) : time ).utc
307
+ end
308
+
309
+ def self.now
310
+ new( Time.now, false )
311
+ end
312
+
313
+ class Rfc3339FormatError < StandardError; end
314
+
315
+ def self.rfc3339( str )
316
+
317
+ begin
318
+ new( Time.iso8601( not_nil( str, :str ).to_s ), false )
319
+ rescue ArgumentError => ae
320
+
321
+ if ae.message =~ /^invalid date: /
322
+ raise Rfc3339FormatError.new( ae.message )
323
+ else
324
+ raise ae
325
+ end
326
+ end
327
+ end
328
+
329
+ def self.from_seconds( secs )
330
+
331
+ not_nil( secs, :secs )
332
+ new( Time.at( secs ), false )
333
+ end
334
+
335
+ # Impl :note => simply calling Time.at( ms / 1000.0 ) doesn't work as we might
336
+ # want, since it ends up passing a Float to Time.at() which apparently
337
+ # performs more calculations or otherwise leads to a time which is close to
338
+ # but not precisely the result of the division. To illustrate:
339
+ #
340
+ # irb(main):013:0> Time.at( 1299534304123 / 1000.0 ).iso8601( 9 )
341
+ # => "2011-03-07T13:45:04.122999907-08:00"
342
+ #
343
+ # while the algorithm we use, which uses integral values only, gives the 123
344
+ # fractional value as expected:
345
+ #
346
+ # irb(main):014:0> Time.at( 1299534304123 / 1000, ( 1299534304123 % 1000 ) *
347
+ # 1000 ).iso8601( 9 )
348
+ # => "2011-03-07T13:45:04.123000000-08:00"
349
+ #
350
+ def self.from_millis( ms )
351
+
352
+ not_nil( ms, :ms )
353
+
354
+ secs = ms / 1000
355
+ usec = ( ms % 1000 ) * 1000
356
+
357
+ new( Time.at( secs, usec ), false )
358
+ end
359
+
360
+ public
361
+ def rfc3339
362
+ @time.iso8601( 9 )
363
+ end
364
+
365
+ alias to_s rfc3339
366
+
367
+ public
368
+ def to_i
369
+ @time.to_i
370
+ end
371
+
372
+ public
373
+ def to_f
374
+ @time.to_f
375
+ end
376
+
377
+ public
378
+ def ==( other )
379
+ other.is_a?( MingleTimestamp ) && other.rfc3339 == rfc3339
380
+ end
381
+
382
+ def_delegator :@time, :hash
383
+ alias eql? ==
384
+
385
+ public
386
+ def <=>( other )
387
+
388
+ if other.is_a?( MingleTimestamp )
389
+ @time <=> other.time
390
+ else
391
+ raise TypeError, other.class.to_s
392
+ end
393
+ end
394
+ end
395
+
396
+ class MingleList < MingleValue
397
+
398
+ extend Forwardable
399
+ include Enumerable
400
+
401
+ def_delegators :@arr, :each, :[], :join, :empty?, :size
402
+
403
+ def initialize( obj )
404
+ @arr = obj.map { |elt| MingleModels.as_mingle_value( elt ) }.freeze
405
+ end
406
+
407
+ public
408
+ def to_s
409
+ @arr.to_s
410
+ end
411
+
412
+ public
413
+ def to_a
414
+ Array.new( @arr )
415
+ end
416
+
417
+ public
418
+ def ==( other )
419
+ other.is_a?( MingleList ) &&
420
+ other.instance_variable_get( :@arr ) == @arr
421
+ end
422
+
423
+ public
424
+ def +( coll )
425
+
426
+ not_nil( coll, :coll )
427
+
428
+ case coll
429
+
430
+ when MingleList
431
+ MingleList.new( @arr + coll.instance_variable_get( :@arr ) )
432
+
433
+ when Array then self + MingleList.new( coll )
434
+
435
+ else
436
+ raise "Operation '+' not supported for objects of " \
437
+ "type #{coll.class}"
438
+ end
439
+ end
440
+ end
441
+
442
+ class ParseLocation < BitGirderClass
443
+
444
+ bg_attr :source, :default => "<>"
445
+ bg_attr :line, :validation => :nonnegative, :default => 1
446
+ bg_attr :col, :validation => :nonnegative
447
+
448
+ public
449
+ def to_s
450
+ "[#@source, line #@line, col #@col]"
451
+ end
452
+ end
453
+
454
+ class MingleParseError < BitGirderError
455
+
456
+ bg_attr :err
457
+ bg_attr :loc
458
+
459
+ public
460
+ def to_s
461
+ "#@loc: #@err"
462
+ end
463
+ end
464
+
465
+ class RestrictionTypeError < StandardError; end
466
+
467
+ PARSED_TYPES = [ MingleString, String, Symbol ]
468
+
469
+ ID_STYLE_LC_CAMEL_CAPPED = :lc_camel_capped
470
+ ID_STYLE_LC_UNDERSCORE = :lc_underscore
471
+ ID_STYLE_LC_HYPHENATED = :lc_hyphenated
472
+
473
+ ID_STYLES = [
474
+ ID_STYLE_LC_CAMEL_CAPPED,
475
+ ID_STYLE_LC_UNDERSCORE,
476
+ ID_STYLE_LC_HYPHENATED
477
+ ]
478
+
479
+ class SpecialToken < BitGirderClass
480
+
481
+ bg_attr :val
482
+
483
+ COLON = new( :val => ":" )
484
+ ASPERAND = new( :val => "@" )
485
+ PERIOD = new( :val => "." )
486
+ FORWARD_SLASH = new( :val => "/" )
487
+ PLUS = new( :val => "+" )
488
+ MINUS = new( :val => "-" )
489
+ ASTERISK = new( :val => "*" )
490
+ QUESTION_MARK = new( :val => "?" )
491
+ TILDE = new( :val => "~" )
492
+ OPEN_BRACKET = new( :val => "[" )
493
+ CLOSE_BRACKET = new( :val => "]" )
494
+ OPEN_PAREN = new( :val => "(" )
495
+ CLOSE_PAREN = new( :val => ")" )
496
+ COMMA = new( :val => "," )
497
+
498
+ TOK_CHARS = ":@./+-*?~[](),"
499
+
500
+ public
501
+ def hash
502
+ @val.hash
503
+ end
504
+
505
+ public
506
+ def to_s
507
+ @val.to_s
508
+ end
509
+ end
510
+
511
+ class WhitespaceToken < BitGirderClass
512
+
513
+ bg_attr :ws
514
+
515
+ public
516
+ def to_s
517
+ @ws.to_s.inspect
518
+ end
519
+ end
520
+
521
+ module Chars
522
+
523
+ module_function
524
+
525
+ SIMPLE_ESCAPE_VALS = "\n\r\t\f\b"
526
+ SIMPLE_ESCAPE_STRS = '\n\r\t\f\b'
527
+
528
+ def ctl_char?( ch )
529
+ ( 0x00 ... 0x20 ).include?( ch.ord )
530
+ end
531
+
532
+ def get_simple_escape( ch )
533
+
534
+ if i = SIMPLE_ESCAPE_VALS.index( ch.chr )
535
+ SIMPLE_ESCAPE_STRS[ 2 * i, 2 ]
536
+ else
537
+ nil
538
+ end
539
+ end
540
+
541
+ def external_form_of( val )
542
+
543
+ res = RubyVersions.when_19x( '"' ) { |s| s.encode!( "binary" ) }
544
+
545
+ val.each_byte do |b|
546
+
547
+ case
548
+ when Chars.ctl_char?( b )
549
+ if s = Chars.get_simple_escape( b )
550
+ res << s
551
+ else
552
+ res << sprintf( "\\u%04X", b )
553
+ end
554
+ when b == ?".ord || b == ?\\.ord then res << "\\" << b
555
+ else res << b
556
+ end
557
+ end
558
+
559
+ RubyVersions.when_19x( res << '"' ) { |s| s.force_encoding( "utf-8" ) }
560
+ end
561
+ end
562
+
563
+ class StringToken < BitGirderClass
564
+
565
+ bg_attr :val
566
+
567
+ public
568
+ def hash
569
+ @val.hash
570
+ end
571
+
572
+ public
573
+ def external_form
574
+ Chars.external_form_of( @val )
575
+ end
576
+
577
+ alias to_s external_form
578
+ end
579
+
580
+ class NumericToken < BitGirderClass
581
+
582
+ bg_attr :int
583
+ bg_attr :frac, :default => ""
584
+ bg_attr :exp, :default => ""
585
+ bg_attr :exp_char, :default => ""
586
+
587
+ public
588
+ def hash
589
+ [ @int, @frac, @exp, @exp_char ].hash
590
+ end
591
+
592
+ public
593
+ def external_form
594
+
595
+ res = @int.dup
596
+ ( res << "." << @frac ) unless @frac.empty?
597
+ ( res << @exp_char << @exp ) unless @exp_char.empty?
598
+
599
+ res
600
+ end
601
+
602
+ alias to_s external_form
603
+
604
+ public
605
+ def integer?
606
+ @exp_char.empty? && @frac.empty?
607
+ end
608
+ end
609
+
610
+ class MingleLexer < BitGirderClass
611
+
612
+ bg_attr :io
613
+
614
+ map_instance_of( String ) do |s|
615
+ s = s.dup if s.frozen?
616
+ self.new( :io => StringIO.new( s ) )
617
+ end
618
+
619
+ LC_ALPHA = ( ?a .. ?z )
620
+ IDENT_SEPS = [ ?-, ?_ ]
621
+ UC_ALPHA = ( ?A .. ?Z )
622
+ DIGIT = ( ?0 .. ?9 )
623
+ UC_HEX = ( ?A .. ?F )
624
+ LC_HEX = ( ?a .. ?f )
625
+ LEAD_SURROGATE = ( 0xD800 ... 0xDC00 )
626
+ TRAIL_SURROGATE = ( 0xDC00 ... 0xE000 )
627
+
628
+ private
629
+ def impl_initialize
630
+ @line, @col = 1, 0
631
+ end
632
+
633
+ public
634
+ def eof?
635
+ @io.eof?
636
+ end
637
+
638
+ public
639
+ def create_loc( col_adj = 0 )
640
+ ParseLocation.new( :col => @col + col_adj, :line => @line )
641
+ end
642
+
643
+ private
644
+ def impl_fail_parse( msg, loc )
645
+ raise MingleParseError.new( :err => msg, :loc => loc )
646
+ end
647
+
648
+ private
649
+ def fail_parse( msg )
650
+ impl_fail_parse( msg, create_loc )
651
+ end
652
+
653
+ private
654
+ def fail_parsef( *argv )
655
+ fail_parse( sprintf( *argv ) )
656
+ end
657
+
658
+ private
659
+ def fail_unexpected_end( msg = "Unexpected end of input" )
660
+
661
+ @col += 1 if eof?
662
+ fail_parse( msg )
663
+ end
664
+
665
+ # For compatibility and ease of asserting error messages, we make sure this
666
+ # converts \t --> "\t", \n --> "\n", etc, and otherwise converts 0x01 -->
667
+ # "\x01" (even though ruby 1.9x would yield "\u0001")
668
+ private
669
+ def inspect_char( ch )
670
+ case
671
+ when ch == ?\n then '"\n"'
672
+ when ch == ?\t then '"\t"'
673
+ when ch == ?\f then '"\f"'
674
+ when ch == ?\r then '"\r"'
675
+ when ch == ?\b then '"\b"'
676
+ when Chars.ctl_char?( ch ) then sprintf( '"\x%02X"', ch.ord )
677
+ else ch.chr.inspect
678
+ end
679
+ end
680
+
681
+ private
682
+ def err_ch( ch, ch_desc = nil )
683
+
684
+ if ch
685
+ ch_desc ||= inspect_char( ch )
686
+ sprintf( "#{ch_desc} (0x%02X)", ch.ord )
687
+ else
688
+ "END"
689
+ end
690
+ end
691
+
692
+ private
693
+ def get_char( fail_on_eof = false )
694
+
695
+ if ch = @io.getc
696
+
697
+ if ch == ?\n
698
+ @unread_col, @col = @col, 0
699
+ @line += 1
700
+ else
701
+ @col += 1
702
+ end
703
+
704
+ ch
705
+ else
706
+ fail_parse( "Unexpected end of input" ) if fail_on_eof
707
+ end
708
+ end
709
+
710
+ # Okay to call with nil (okay to unget EOF)
711
+ private
712
+ def unget_char( ch )
713
+
714
+ if ch
715
+
716
+ @io.ungetc( ch )
717
+
718
+ if ch == ?\n
719
+ @line, @col = @line - 1, @unread_col
720
+ else
721
+ @col -= 1
722
+ end
723
+ end
724
+ end
725
+
726
+ private
727
+ def peek_char
728
+ get_char.tap { |ch| unget_char( ch ) }
729
+ end
730
+
731
+ private
732
+ def poll_chars( *expct )
733
+
734
+ if expct.include?( ch = get_char )
735
+ ch
736
+ else
737
+ unget_char( ch )
738
+ nil
739
+ end
740
+ end
741
+
742
+ private
743
+ def ident_start?( ch )
744
+ LC_ALPHA.include?( ch )
745
+ end
746
+
747
+ private
748
+ def ident_part_char?( ch )
749
+ [ LC_ALPHA, DIGIT ].find { |rng| rng.include?( ch ) }
750
+ end
751
+
752
+ private
753
+ def ident_part_sep?( ch )
754
+ [ IDENT_SEPS, UC_ALPHA ].find { |rng| rng.include?( ch ) }
755
+ end
756
+
757
+ private
758
+ def sep_char_for( styl )
759
+ case styl
760
+ when ID_STYLE_LC_HYPHENATED then ?-
761
+ when ID_STYLE_LC_UNDERSCORE then ?_
762
+ else nil
763
+ end
764
+ end
765
+
766
+ private
767
+ def can_trail?( styl )
768
+ styl == ID_STYLE_LC_UNDERSCORE || styl == ID_STYLE_LC_HYPHENATED
769
+ end
770
+
771
+ private
772
+ def read_ident_part_start( styl, expct )
773
+
774
+ ch, res = get_char, nil
775
+
776
+ if styl == ID_STYLE_LC_CAMEL_CAPPED
777
+ res = ch.chr.downcase if UC_ALPHA.include?( ch )
778
+ else
779
+ res = ch if ident_start?( ch )
780
+ end
781
+
782
+ unless res
783
+ if expct
784
+ fail_parse "Illegal start of identifier part: #{err_ch( ch )}"
785
+ else
786
+ unget_char( ch )
787
+ end
788
+ end
789
+
790
+ res
791
+ end
792
+
793
+ private
794
+ def read_ident_sep( ch, styl )
795
+
796
+ if styl
797
+ if ch == sep_char_for( styl )
798
+ if eof? && can_trail?( styl )
799
+ fail_unexpected_end( "Empty identifier part" )
800
+ end
801
+ else
802
+ unget_char( ch )
803
+ end
804
+ else
805
+ case ch
806
+ when ?- then styl = ID_STYLE_LC_HYPHENATED
807
+ when ?_ then styl = ID_STYLE_LC_UNDERSCORE
808
+ else
809
+ styl = ID_STYLE_LC_CAMEL_CAPPED
810
+ unget_char( ch )
811
+ end
812
+ end
813
+
814
+ styl
815
+ end
816
+
817
+ private
818
+ def read_ident_part_tail( part, styl )
819
+
820
+ part_done = false
821
+
822
+ begin
823
+
824
+ ch = get_char
825
+ case
826
+ when ident_part_char?( ch ) then part << ch
827
+ when ident_part_sep?( ch )
828
+ styl, part_done = read_ident_sep( ch, styl ), true
829
+ else
830
+ part_done, id_done = true, true
831
+ unget_char( ch )
832
+ end
833
+
834
+ end until part_done
835
+
836
+ [ styl, id_done ]
837
+ end
838
+
839
+ private
840
+ def read_ident_part( styl, expct )
841
+
842
+ part, id_done = "", false
843
+
844
+ if ch = read_ident_part_start( styl, expct )
845
+
846
+ part << ch
847
+ styl, id_done = read_ident_part_tail( part, styl )
848
+ end
849
+
850
+ [ part, styl, part.empty? || id_done ]
851
+ end
852
+
853
+ private
854
+ def read_ident( styl = nil )
855
+
856
+ parts = []
857
+
858
+ begin
859
+ unless eof?
860
+ expct = parts.empty? || can_trail?( styl )
861
+ part, styl, id_done = read_ident_part( styl, expct )
862
+ parts << part unless part.empty?
863
+ end
864
+
865
+ end until id_done || eof?
866
+
867
+ fail_unexpected_end( "Empty identifier" ) if parts.empty?
868
+ MingleIdentifier.send( :new, :parts => parts )
869
+ end
870
+
871
+ private
872
+ def decl_nm_start?( ch )
873
+ UC_ALPHA.include?( ch )
874
+ end
875
+
876
+ private
877
+ def decl_nm_char?( ch )
878
+ [ UC_ALPHA, LC_ALPHA, DIGIT ].find { |rng| rng.include?( ch ) }
879
+ end
880
+
881
+ private
882
+ def read_decl_type_name
883
+
884
+ fail_unexpected_end( "Empty type name" ) if eof?
885
+
886
+ if decl_nm_start?( ch = get_char )
887
+ res = ch.chr
888
+ else
889
+ fail_parse( "Illegal type name start: #{err_ch( ch )}" )
890
+ end
891
+
892
+ begin
893
+ if decl_nm_char?( ch = get_char )
894
+ res << ch
895
+ else
896
+ unget_char( ch )
897
+ ch = nil
898
+ end
899
+ end while ch
900
+
901
+ DeclaredTypeName.send( :new, :name => res )
902
+ end
903
+
904
+ private
905
+ def special_char?( ch )
906
+ ch && SpecialToken::TOK_CHARS.index( ch )
907
+ end
908
+
909
+ private
910
+ def read_special
911
+ SpecialToken.new( :val => get_char.chr )
912
+ end
913
+
914
+ private
915
+ def whitespace?( ch )
916
+ ch && " \n\r\t".index( ch )
917
+ end
918
+
919
+ private
920
+ def read_whitespace
921
+
922
+ ws = ""
923
+
924
+ begin
925
+ if whitespace?( ch = get_char )
926
+ ws << ch
927
+ else
928
+ unget_char( ch )
929
+ ch = nil
930
+ end
931
+ end while ch
932
+
933
+ WhitespaceToken.new( :ws => ws )
934
+ end
935
+
936
+ private
937
+ def hex_char?( ch )
938
+ [ DIGIT, UC_HEX, LC_HEX ].find { |rng| rng.include?( ch ) }
939
+ end
940
+
941
+ private
942
+ def new_bin_str
943
+ RubyVersions.when_19x( "" ) { |s| s.encode!( "binary" ) }
944
+ end
945
+
946
+ private
947
+ def read_utf16_bytes
948
+
949
+ Array.new( 2 ) do
950
+
951
+ s = ""
952
+
953
+ 2.times do
954
+ if hex_char?( ch = get_char )
955
+ s << ch
956
+ else
957
+ fail_parse( "Invalid hex char in escape: #{err_ch( ch )}" )
958
+ end
959
+ end
960
+
961
+ s.to_i( 16 )
962
+ end
963
+ end
964
+
965
+ private
966
+ def surrogate?( hi, lo, rng )
967
+ rng.include?( ( hi << 8 ) + lo )
968
+ end
969
+
970
+ private
971
+ def escape_utf16( bin )
972
+
973
+ res = ""
974
+
975
+ unless bin.size % 2 == 0
976
+ raise "Bin string size #{bin.size} not a multiple of 4 bytes"
977
+ end
978
+
979
+ ( bin.size / 2 ).times do |i|
980
+ res << sprintf( "\\u%04X", bin[ 2 * i, 2 ].unpack( "n" )[ 0 ] )
981
+ end
982
+
983
+ res
984
+ end
985
+
986
+ private
987
+ def read_trail_surrogate( bin )
988
+
989
+ tmpl = "Expected trailing surrogate, found: %s"
990
+
991
+ unless ( ch = get_char( true ) ) == ?\\
992
+ impl_fail_parse( sprintf( tmpl, err_ch( ch ) ), create_loc )
993
+ end
994
+
995
+ unless ( ch = get_char( true ) ) == ?u
996
+ impl_fail_parse( sprintf( tmpl, "\\#{ch.chr}" ), create_loc( -1 ) )
997
+ end
998
+
999
+ hi, lo = read_utf16_bytes
1000
+ bin << hi << lo
1001
+
1002
+ unless surrogate?( hi, lo, TRAIL_SURROGATE )
1003
+ msg = "Invalid surrogate pair #{escape_utf16( bin )}"
1004
+ impl_fail_parse( msg, create_loc( -11 ) )
1005
+ end
1006
+ end
1007
+
1008
+ private
1009
+ def read_utf16_escape( dest )
1010
+
1011
+ bin = new_bin_str
1012
+
1013
+ hi, lo = read_utf16_bytes
1014
+ bin << hi << lo
1015
+
1016
+ if surrogate?( hi, lo, LEAD_SURROGATE )
1017
+ read_trail_surrogate( bin )
1018
+ elsif surrogate?( hi, lo, TRAIL_SURROGATE )
1019
+ msg = "Trailing surrogate with no lead: #{escape_utf16( bin )}"
1020
+ impl_fail_parse( msg, create_loc( -5 ) )
1021
+ end
1022
+
1023
+ if USE_ICONV
1024
+ dest << Iconv.conv( "utf-8", "utf-16be", bin )
1025
+ else
1026
+ dest << bin.encode!( "utf-8", "utf-16be" )
1027
+ end
1028
+ end
1029
+
1030
+ private
1031
+ def read_escaped_char( dest )
1032
+
1033
+ case ch = get_char
1034
+ when ?n then dest << "\n"
1035
+ when ?t then dest << "\t"
1036
+ when ?f then dest << "\f"
1037
+ when ?r then dest << "\r"
1038
+ when ?b then dest << "\b"
1039
+ when ?\\ then dest << "\\"
1040
+ when ?" then dest << "\""
1041
+ when ?u then read_utf16_escape( dest )
1042
+ else fail_parse( "Unrecognized escape: #{err_ch( ch, "\\#{ch.chr}" )}" )
1043
+ end
1044
+ end
1045
+
1046
+ private
1047
+ def append_string_tok( dest, ch )
1048
+
1049
+ if Chars.ctl_char?( ch )
1050
+
1051
+ unget_char( ch ) # To reset line num in case we read \n
1052
+ msg = "Invalid control character in string literal: #{err_ch( ch )}"
1053
+ impl_fail_parse( msg, create_loc( 1 ) )
1054
+ else
1055
+ dest << ch
1056
+ end
1057
+ end
1058
+
1059
+ private
1060
+ def read_string
1061
+
1062
+ unless ( ch = get_char ) == ?"
1063
+ fail_parse( "Expected string start, saw #{err_ch( ch )}" )
1064
+ end
1065
+
1066
+ res = RubyVersions.when_19x( "" ) { |s| s.encode!( "utf-8" ) }
1067
+
1068
+ begin
1069
+ case ch = get_char
1070
+ when nil then fail_parse( "Unterminated string literal" )
1071
+ when ?\\ then read_escaped_char( res )
1072
+ when ?" then nil
1073
+ else append_string_tok( res, ch )
1074
+ end
1075
+ end until ch == ?"
1076
+
1077
+ StringToken.new( :val => res )
1078
+ end
1079
+
1080
+ private
1081
+ def starts_num?( ch )
1082
+ DIGIT.include?( ch )
1083
+ end
1084
+
1085
+ private
1086
+ def read_dig_str( err_desc, *ends )
1087
+
1088
+ res = ""
1089
+
1090
+ begin
1091
+ if DIGIT.include?( ch = get_char )
1092
+ res << ch
1093
+ else
1094
+ if [ nil, ?e, ?E ].include?( ch ) || special_char?( ch )
1095
+ unget_char( ch )
1096
+ ch = nil
1097
+ else
1098
+ fail_parse(
1099
+ "Unexpected char in #{err_desc}: #{err_ch( ch )}" )
1100
+ end
1101
+ end
1102
+ end while ch
1103
+
1104
+ fail_parse( "Number has empty or invalid #{err_desc}" ) if res.empty?
1105
+
1106
+ res
1107
+ end
1108
+
1109
+ private
1110
+ def read_num_exp( opts )
1111
+
1112
+ if [ ?e, ?E ].include?( ch = get_char )
1113
+
1114
+ opts[ :exp_char ] = ch.chr
1115
+
1116
+ opts[ :exp ] =
1117
+ ( poll_chars( ?-, ?+ ) == ?- ? "-" : "" ) +
1118
+ read_dig_str( "exponent" )
1119
+ else
1120
+ if ch == nil || whitespace?( ch ) ||
1121
+ ( ch != ?. && special_char?( ch ) )
1122
+ unget_char( ch )
1123
+ else
1124
+ fail_parse(
1125
+ "Expected exponent start or num end, found: " +
1126
+ err_ch( ch )
1127
+ )
1128
+ end
1129
+ end
1130
+ end
1131
+
1132
+ private
1133
+ def read_number
1134
+
1135
+ opts = {}
1136
+
1137
+ opts[ :int ] = read_dig_str( "integer part" )
1138
+ opts[ :frac ] = read_dig_str( "fractional part" ) if poll_chars( ?. )
1139
+ read_num_exp( opts )
1140
+
1141
+ NumericToken.new( opts )
1142
+ end
1143
+
1144
+ # Note about the case statement: the typ based checks need to fire before
1145
+ # char ones so that if, for example, typ is DeclaredTypeName and the input
1146
+ # is 'a', we will fail as a bad type name rather than returning the
1147
+ # identifier 'a'
1148
+ public
1149
+ def read_token( typ = nil )
1150
+
1151
+ # Don't peek -- do get/unget so we get a true loc
1152
+ ch = get_char
1153
+ loc = create_loc
1154
+ unget_char( ch )
1155
+
1156
+ case
1157
+ when typ == StringToken then res = read_string
1158
+ when typ == NumericToken then res = read_number
1159
+ when typ == MingleIdentifier then res = read_ident
1160
+ when typ == DeclaredTypeName then res = read_decl_type_name
1161
+ when ident_start?( ch ) then res = read_ident
1162
+ when decl_nm_start?( ch ) then res = read_decl_type_name
1163
+ when special_char?( ch ) then res = read_special
1164
+ when whitespace?( ch ) then res = read_whitespace
1165
+ when ch == ?" then res = read_string
1166
+ when starts_num?( ch ) then res = read_number
1167
+ else fail_parsef( "Unrecognized token: #{err_ch( get_char )}" )
1168
+ end
1169
+
1170
+ [ res, loc ]
1171
+ end
1172
+
1173
+ public
1174
+ def expect_token( typ = nil )
1175
+ case
1176
+ when typ == nil then read_token || fail_unexpected_end
1177
+ when typ == StringToken || typ == NumericToken ||
1178
+ typ == MingleIdentifier || typ == DeclaredTypeName
1179
+ read_token( typ )
1180
+ else raise "Unhandled token expect type: #{typ}"
1181
+ end
1182
+ end
1183
+ end
1184
+
1185
+ class MingleParser < BitGirderClass
1186
+
1187
+ bg_attr :lexer
1188
+
1189
+ QUANTS = [
1190
+ SpecialToken::QUESTION_MARK,
1191
+ SpecialToken::PLUS,
1192
+ SpecialToken::ASTERISK
1193
+ ]
1194
+
1195
+ RANGE_OPEN = [ SpecialToken::OPEN_PAREN, SpecialToken::OPEN_BRACKET ]
1196
+ RANGE_CLOSE = [ SpecialToken::CLOSE_PAREN, SpecialToken::CLOSE_BRACKET ]
1197
+
1198
+ private
1199
+ def loc
1200
+ @saved ? @saved[ 1 ] : @lexer.create_loc
1201
+ end
1202
+
1203
+ private
1204
+ def next_loc
1205
+ @saved ? @saved[ 1 ] : @lexer.create_loc( 1 )
1206
+ end
1207
+
1208
+ private
1209
+ def eof?
1210
+ @saved == nil && @lexer.eof?
1211
+ end
1212
+
1213
+ private
1214
+ def read_tok( typ = nil )
1215
+
1216
+ pair, @saved = @saved, nil
1217
+ pair || ( @lexer.eof? ? [ nil, nil ] : @lexer.read_token( typ ) )
1218
+ end
1219
+
1220
+ private
1221
+ def unread_tok( tok, loc )
1222
+
1223
+ pair = [ tok, loc ]
1224
+ raise "Attempt to unread #{pair} while @saved is #@saved" if @saved
1225
+ @saved = tok ? pair : nil
1226
+ end
1227
+
1228
+ private
1229
+ def peek_tok( typ = nil )
1230
+ read_tok.tap { |pair| unread_tok( *pair ) }
1231
+ end
1232
+
1233
+ private
1234
+ def fail_parse( msg, err_loc = loc )
1235
+ raise MingleParseError.new( :err => msg, :loc => err_loc )
1236
+ end
1237
+
1238
+ private
1239
+ def fail_unexpected_token( desc )
1240
+
1241
+ tok, err_loc = read_tok
1242
+
1243
+ unless tok
1244
+ tok, err_loc = "END", @lexer.create_loc( 1 )
1245
+ end
1246
+
1247
+ fail_parse( "Expected #{desc} but found: #{tok}", err_loc )
1248
+ end
1249
+
1250
+ private
1251
+ def skip_ws
1252
+ begin
1253
+ tok, loc = read_tok
1254
+ unless tok.is_a?( WhitespaceToken )
1255
+ unread_tok( tok, loc )
1256
+ tok = nil
1257
+ end
1258
+ end while tok
1259
+ end
1260
+
1261
+ public
1262
+ def check_trailing
1263
+
1264
+ res = yield if block_given?
1265
+
1266
+ unless eof?
1267
+
1268
+ tok, _ = read_tok
1269
+ fail_parse( "Unexpected token: #{tok}" )
1270
+ end
1271
+
1272
+ res
1273
+ end
1274
+
1275
+ private
1276
+ def poll_special_loc( *specs )
1277
+
1278
+ tok, loc = read_tok
1279
+
1280
+ unless specs.include?( tok )
1281
+ unread_tok( tok, loc )
1282
+ tok, loc = nil, nil
1283
+ end
1284
+
1285
+ [ tok, loc ]
1286
+ end
1287
+
1288
+ private
1289
+ def expect_special_loc( desc, *spec )
1290
+
1291
+ res = poll_special_loc( *spec )
1292
+
1293
+ if tok = res[ 0 ]
1294
+ res
1295
+ else
1296
+ fail_unexpected_token( desc )
1297
+ end
1298
+ end
1299
+
1300
+ %w{ poll expect }.each do |nm|
1301
+ define_method( :"#{nm}_special" ) do |*argv|
1302
+ self.send( :"#{nm}_special_loc", *argv )[ 0 ]
1303
+ end
1304
+ end
1305
+
1306
+ # Does not allow for unread of its result
1307
+ private
1308
+ def expect_typed_loc( typ )
1309
+
1310
+ if @saved
1311
+ if ( id = @saved[ 0 ] ).is_a?( typ )
1312
+ @saved.tap { @saved = nil }
1313
+ else
1314
+ fail_parse( "Expected identifier" )
1315
+ end
1316
+ else
1317
+ @lexer.expect_token( typ )
1318
+ end
1319
+ end
1320
+
1321
+ private
1322
+ def expect_typed( typ )
1323
+ expect_typed_loc( typ )[ 0 ]
1324
+ end
1325
+
1326
+ public
1327
+ def expect_number
1328
+
1329
+ tok, _ = peek_tok
1330
+
1331
+ if neg = ( tok == SpecialToken::MINUS )
1332
+ read_tok
1333
+ end
1334
+
1335
+ ParsedNumber.new(
1336
+ :negative => neg,
1337
+ :num => expect_typed( NumericToken )
1338
+ )
1339
+ end
1340
+
1341
+ public
1342
+ def expect_identifier
1343
+ expect_typed( MingleIdentifier )
1344
+ end
1345
+
1346
+ public
1347
+ def expect_namespace
1348
+
1349
+ parts = [ expect_identifier ]
1350
+
1351
+ begin
1352
+ if colon = poll_special( SpecialToken::COLON )
1353
+ parts << expect_identifier
1354
+ end
1355
+ end while colon
1356
+
1357
+ poll_special( SpecialToken::ASPERAND ) or
1358
+ fail_unexpected_token( "':' or '@'" )
1359
+
1360
+ ver = expect_identifier
1361
+
1362
+ MingleNamespace.send( :new, :parts => parts, :version => ver )
1363
+ end
1364
+
1365
+ public
1366
+ def expect_declared_type_name
1367
+ expect_typed( DeclaredTypeName )
1368
+ end
1369
+
1370
+ public
1371
+ def expect_qname
1372
+
1373
+ ns = expect_namespace
1374
+ expect_special( "type path", SpecialToken::FORWARD_SLASH )
1375
+ nm = expect_declared_type_name
1376
+
1377
+ QualifiedTypeName.send( :new, :namespace => ns, :name => nm )
1378
+ end
1379
+
1380
+ public
1381
+ def expect_identified_name
1382
+
1383
+ ns = expect_namespace
1384
+
1385
+ names = []
1386
+
1387
+ begin
1388
+ if tok = poll_special( SpecialToken::FORWARD_SLASH )
1389
+ names << expect_identifier
1390
+ end
1391
+ end while tok
1392
+
1393
+ fail_parse( "Missing name", next_loc ) if names.empty?
1394
+
1395
+ MingleIdentifiedName.send( :new, :namespace => ns, :names => names )
1396
+ end
1397
+
1398
+ private
1399
+ def expect_type_name
1400
+
1401
+ tok, _ = peek_tok
1402
+
1403
+ case tok
1404
+ when MingleIdentifier then expect_qname
1405
+ when DeclaredTypeName then expect_declared_type_name
1406
+ else fail_unexpected_token( "identifier or declared type name" )
1407
+ end
1408
+ end
1409
+
1410
+ private
1411
+ def resolve_type_name( nm )
1412
+
1413
+ if res = QNAME_RESOLV_MAP[ nm ]
1414
+ res
1415
+ else
1416
+ nm
1417
+ end
1418
+ end
1419
+
1420
+ private
1421
+ def fail_restriction_type( found, desc )
1422
+ raise RestrictionTypeError.new(
1423
+ "Invalid target type for #{desc} restriction: #{found}" )
1424
+ end
1425
+
1426
+ private
1427
+ def expect_pattern_restriction( nm )
1428
+
1429
+ str, loc = expect_typed_loc( StringToken )
1430
+
1431
+ if nm == QNAME_STRING
1432
+ begin
1433
+ RegexRestriction.new( :ext_pattern => str.val )
1434
+ rescue RegexpError => e
1435
+ raise RestrictionTypeError, "Invalid regex: #{e.message}"
1436
+ end
1437
+ else
1438
+ fail_restriction_type( nm, "regex" )
1439
+ end
1440
+ end
1441
+
1442
+ # Expects one of the tokens in toks, and returns the pair [ true, loc ] or [
1443
+ # false, loc ] based on whether the expected pair had the token matching
1444
+ # close_test
1445
+ private
1446
+ def read_range_bound( err_desc, toks, close_test )
1447
+
1448
+ pair = expect_special_loc( err_desc, *toks )
1449
+
1450
+ [ pair[ 0 ] == close_test, pair[ 1 ] ]
1451
+ end
1452
+
1453
+ private
1454
+ def check_allow_cast( val, typ, bound )
1455
+
1456
+ err_desc = nil
1457
+
1458
+ case val
1459
+ when StringToken
1460
+ err_desc = "string" if NUM_TYPES.include?( typ )
1461
+ when ParsedNumber
1462
+ if NUM_TYPES.include?( typ )
1463
+ if INT_TYPES.include?( typ ) && ( ! val.integer? )
1464
+ err_desc = "decimal"
1465
+ end
1466
+ else
1467
+ err_desc = "number"
1468
+ end
1469
+ end
1470
+
1471
+ if err_desc
1472
+ raise RestrictionTypeError.new(
1473
+ "Got #{err_desc} as #{bound} value for range" )
1474
+ end
1475
+ end
1476
+
1477
+ private
1478
+ def cast_range_value( val, nm, bound )
1479
+
1480
+ return nil if val.nil?
1481
+
1482
+ typ = AtomicTypeReference.send( :new, :name => nm )
1483
+
1484
+ unless COMPARABLE_TYPES.include?( typ )
1485
+ fail_restriction_type( typ, "range" )
1486
+ end
1487
+
1488
+ check_allow_cast( val, typ, bound )
1489
+
1490
+ # s is a StringToken or a ParsedNumber
1491
+ s = val.is_a?( StringToken ) ? val.val : val.external_form
1492
+
1493
+ Mingle.cast_value( MingleString.new( s ), typ )
1494
+ end
1495
+
1496
+ private
1497
+ def read_range_value( nm )
1498
+
1499
+ tok, _ = peek_tok
1500
+
1501
+ val = case
1502
+ when tok == SpecialToken::COMMA || RANGE_CLOSE.include?( tok ) then nil
1503
+ when tok == SpecialToken::MINUS || tok.is_a?( NumericToken )
1504
+ expect_number
1505
+ when tok.is_a?( StringToken ) then expect_typed( StringToken )
1506
+ else fail_unexpected_token( "range value" )
1507
+ end
1508
+ end
1509
+
1510
+ private
1511
+ def check_range_restriction_syntax( opts )
1512
+
1513
+ min_closed, min_sx, max_sx, max_closed =
1514
+ opts.values_at( :min_closed, :min_syntax, :max_syntax, :max_closed )
1515
+
1516
+ err_desc, loc =
1517
+ case
1518
+ when min_sx.nil? && max_sx.nil? && ( min_closed || max_closed )
1519
+ [ " ", opts[ :open_loc ] ]
1520
+ when min_sx.nil? && min_closed then [ " low ", opts[ :open_loc ] ]
1521
+ when max_sx.nil? && max_closed then [ " high ", opts[ :close_loc ] ]
1522
+ end
1523
+
1524
+ fail_parse( "Infinite#{err_desc}range must be open", loc ) if loc
1525
+ end
1526
+
1527
+ private
1528
+ def read_range_restriction_syntax( nm )
1529
+
1530
+ res = {}
1531
+
1532
+ res[ :min_closed ], res[ :open_loc ] =
1533
+ read_range_bound(
1534
+ "range open", RANGE_OPEN, SpecialToken::OPEN_BRACKET )
1535
+
1536
+ res[ :min_syntax ] = read_range_value( nm )
1537
+ skip_ws
1538
+ expect_special( ",", SpecialToken::COMMA )
1539
+ res[ :max_syntax ] = read_range_value( nm )
1540
+ skip_ws
1541
+
1542
+ res[ :max_closed ], res[ :close_loc ] =
1543
+ read_range_bound(
1544
+ "range close", RANGE_CLOSE, SpecialToken::CLOSE_BRACKET )
1545
+
1546
+ res
1547
+ end
1548
+
1549
+ private
1550
+ def adjacent_ints?( min, max )
1551
+
1552
+ case min
1553
+ when MingleInt32, MingleInt64, MingleUint32, MingleUint64
1554
+ min.num.succ == max.num
1555
+ else false
1556
+ end
1557
+ end
1558
+
1559
+ private
1560
+ def check_satisfiable_range( opts )
1561
+
1562
+ min_closed, min, max, max_closed =
1563
+ opts.values_at( :min_closed, :min, :max, :max_closed )
1564
+
1565
+ # If min,max are nil this is an infinite range and therefore
1566
+ # satisifiable (bounds will have been checked to be open elsewhere)
1567
+ return if min.nil? && max.nil?
1568
+
1569
+ cmp, failed = min <=> max, false
1570
+
1571
+ case
1572
+ when cmp == 0 then failed = ! ( min_closed && max_closed )
1573
+ when cmp > 0 then failed = true
1574
+ else
1575
+ unless min_closed || max_closed
1576
+ failed = adjacent_ints?( min, max )
1577
+ end
1578
+ end
1579
+
1580
+ raise RestrictionTypeError, "Unsatisfiable range" if failed
1581
+ end
1582
+
1583
+ private
1584
+ def expect_range_restriction( nm )
1585
+
1586
+ opts = read_range_restriction_syntax( nm )
1587
+ check_range_restriction_syntax( opts )
1588
+
1589
+ opts[ :min ] = cast_range_value( opts[ :min_syntax ], nm, "min" )
1590
+ opts[ :max ] = cast_range_value( opts[ :max_syntax ], nm, "max" )
1591
+
1592
+ check_satisfiable_range( opts )
1593
+
1594
+ RangeRestriction.new( opts )
1595
+ end
1596
+
1597
+ private
1598
+ def expect_type_restriction( nm )
1599
+
1600
+ tok, _ = peek_tok
1601
+
1602
+ case
1603
+ when tok.is_a?( StringToken ) then expect_pattern_restriction( nm )
1604
+ when RANGE_OPEN.include?( tok ) then expect_range_restriction( nm )
1605
+ else fail_unexpected_token( "type restriction" )
1606
+ end
1607
+ end
1608
+
1609
+ private
1610
+ def expect_atomic_type_reference
1611
+
1612
+ nm = resolve_type_name( expect_type_name )
1613
+
1614
+ skip_ws
1615
+ restr = nil
1616
+
1617
+ if poll_special( SpecialToken::TILDE )
1618
+ skip_ws
1619
+ restr = expect_type_restriction( nm )
1620
+ end
1621
+
1622
+ AtomicTypeReference.send( :new, :name => nm, :restriction => restr )
1623
+ end
1624
+
1625
+ private
1626
+ def poll_quants
1627
+
1628
+ res = []
1629
+
1630
+ begin
1631
+ if tok = poll_special( *QUANTS )
1632
+ res << tok
1633
+ end
1634
+ end while tok
1635
+
1636
+ res
1637
+ end
1638
+
1639
+ public
1640
+ def expect_type_reference
1641
+
1642
+ at = expect_atomic_type_reference
1643
+
1644
+ poll_quants.inject( at ) do |typ, quant|
1645
+ case quant
1646
+ when SpecialToken::ASTERISK
1647
+ ListTypeReference.send(
1648
+ :new, :element_type => typ, :allows_empty => true )
1649
+ when SpecialToken::PLUS
1650
+ ListTypeReference.send(
1651
+ :new, :element_type => typ, :allows_empty => false )
1652
+ when SpecialToken::QUESTION_MARK
1653
+ NullableTypeReference.send( :new, :type => typ )
1654
+ end
1655
+ end
1656
+ end
1657
+
1658
+ def self.for_string( s )
1659
+ self.new( :lexer => MingleLexer.as_instance( s ) )
1660
+ end
1661
+
1662
+ def self.consume_string( s )
1663
+
1664
+ p = self.for_string( s )
1665
+ yield( p ).tap { p.check_trailing }
1666
+ end
1667
+ end
1668
+
1669
+ # Including classes must define impl_parse() as a class method; this module will
1670
+ # add class methods parse()/get() which can take any of PARSED_TYPES and return
1671
+ # an instance according to impl_parse. Also installs BitGirderClass instance
1672
+ # handlers for PARSED_TYPES
1673
+ module StringParser
1674
+
1675
+ def self.included( cls )
1676
+
1677
+ cls.class_eval do
1678
+
1679
+ map_instance_of( *PARSED_TYPES ) { |s| self.impl_parse( s.to_s ) }
1680
+
1681
+ def self.get( val )
1682
+ self.as_instance( val )
1683
+ end
1684
+
1685
+ def self.parse( val )
1686
+ self.as_instance( val )
1687
+ end
1688
+ end
1689
+ end
1690
+ end
1691
+
1692
+ class ParsedNumber < BitGirderClass
1693
+
1694
+ include StringParser
1695
+ extend Forwardable
1696
+
1697
+ bg_attr :negative, :default => false
1698
+ bg_attr :num
1699
+
1700
+ def_delegators :@num, :integer?
1701
+
1702
+ public
1703
+ def hash
1704
+ [ @negative, @num ].hash
1705
+ end
1706
+
1707
+ public
1708
+ def external_form
1709
+ ( @negative ? "-" : "" ) << @num.external_form
1710
+ end
1711
+
1712
+ def self.impl_parse( s )
1713
+ MingleParser.consume_string( s ) { |p| p.expect_number }
1714
+ end
1715
+ end
1716
+
1717
+ class MingleIdentifier < BitGirderClass
1718
+
1719
+ include StringParser
1720
+
1721
+ bg_attr :parts
1722
+
1723
+ private_class_method :new
1724
+
1725
+ private
1726
+ def impl_initialize
1727
+
1728
+ @parts.each_with_index do |part, idx|
1729
+ raise "Empty id part at index #{idx}" if part.size == 0
1730
+ end
1731
+ end
1732
+
1733
+ def self.impl_parse( s )
1734
+ MingleParser.consume_string( s ) { |p| p.expect_identifier }
1735
+ end
1736
+
1737
+ public
1738
+ def format( fmt )
1739
+
1740
+ not_nil( fmt, :fmt )
1741
+
1742
+ case fmt
1743
+
1744
+ when ID_STYLE_LC_HYPHENATED then @parts.join( "-" )
1745
+
1746
+ when ID_STYLE_LC_UNDERSCORE then @parts.join( "_" )
1747
+
1748
+ when ID_STYLE_LC_CAMEL_CAPPED
1749
+ @parts[ 0 ] +
1750
+ @parts[ 1 .. -1 ].map do
1751
+ |t| t[ 0, 1 ].upcase + t[ 1 .. -1 ]
1752
+ end.join
1753
+
1754
+ else raise "Invalid format: #{fmt}"
1755
+ end
1756
+ end
1757
+
1758
+ public
1759
+ def external_form
1760
+ format( :lc_hyphenated )
1761
+ end
1762
+
1763
+ alias to_s external_form
1764
+
1765
+ public
1766
+ def to_sym
1767
+ format( :lc_underscore ).to_sym
1768
+ end
1769
+
1770
+ public
1771
+ def hash
1772
+ @parts.hash
1773
+ end
1774
+
1775
+ def self.as_format_name( id )
1776
+
1777
+ sym = self.get( id ).to_sym
1778
+
1779
+ if ID_STYLES.include?( sym )
1780
+ sym
1781
+ else
1782
+ raise "Unknown or invalid identifier format: #{id} (#{id.class})"
1783
+ end
1784
+ end
1785
+ end
1786
+
1787
+ class MingleNamespace < BitGirderClass
1788
+
1789
+ include StringParser
1790
+
1791
+ bg_attr :parts
1792
+ bg_attr :version
1793
+
1794
+ private_class_method :new
1795
+
1796
+ def self.create( opts )
1797
+ self.send( :new, opts )
1798
+ end
1799
+
1800
+ def self.impl_parse( s )
1801
+ MingleParser.consume_string( s ) { |p| p.expect_namespace }
1802
+ end
1803
+
1804
+ public
1805
+ def format( id_styl )
1806
+ parts = @parts.map { |p| p.format( id_styl ) }
1807
+ ver = @version.format( id_styl )
1808
+ "#{parts.join( ":" )}@#{ver}"
1809
+ end
1810
+
1811
+ public
1812
+ def external_form
1813
+ format( ID_STYLE_LC_CAMEL_CAPPED )
1814
+ end
1815
+
1816
+ alias to_s external_form
1817
+
1818
+ public
1819
+ def inspect
1820
+ to_s.inspect
1821
+ end
1822
+
1823
+ public
1824
+ def ==( other )
1825
+ other.is_a?( MingleNamespace ) &&
1826
+ other.parts == @parts && other.version == @version
1827
+ end
1828
+
1829
+ public
1830
+ def hash
1831
+ @parts.hash | @version.hash
1832
+ end
1833
+
1834
+ public
1835
+ def eql?( other )
1836
+ self == other
1837
+ end
1838
+ end
1839
+
1840
+ class DeclaredTypeName < BitGirderClass
1841
+
1842
+ include StringParser
1843
+
1844
+ bg_attr :name
1845
+
1846
+ private_class_method :new
1847
+
1848
+ def external_form
1849
+ @name.to_s
1850
+ end
1851
+
1852
+ alias to_s external_form
1853
+
1854
+ def hash
1855
+ @name.hash
1856
+ end
1857
+
1858
+ def self.impl_parse( s )
1859
+ MingleParser.consume_string( s ) { |p| p.expect_declared_type_name }
1860
+ end
1861
+ end
1862
+
1863
+ class QualifiedTypeName < BitGirderClass
1864
+
1865
+ include StringParser
1866
+
1867
+ bg_attr :namespace, :processor => MingleNamespace
1868
+ bg_attr :name, :processor => DeclaredTypeName
1869
+
1870
+ def self.impl_parse( s )
1871
+ MingleParser.consume_string( s ) { |p| p.expect_qname }
1872
+ end
1873
+
1874
+ public
1875
+ def hash
1876
+ [ @namespace, @name ].hash
1877
+ end
1878
+
1879
+ public
1880
+ def external_form
1881
+ "#{@namespace.external_form}/#{@name.external_form}"
1882
+ end
1883
+
1884
+ alias to_s external_form
1885
+ end
1886
+
1887
+ class MingleTypeReference < BitGirderClass
1888
+
1889
+ include StringParser
1890
+
1891
+ private_class_method :new
1892
+
1893
+ def self.impl_parse( s )
1894
+ MingleParser.consume_string( s ) { |p| p.expect_type_reference }
1895
+ end
1896
+
1897
+ bg_abstract :external_form
1898
+
1899
+ public
1900
+ def to_s
1901
+ external_form
1902
+ end
1903
+ end
1904
+
1905
+ class RegexRestriction < BitGirderClass
1906
+
1907
+ bg_attr :ext_pattern # Raw text of original input pattern
1908
+
1909
+ attr_reader :regexp
1910
+
1911
+ install_hash
1912
+
1913
+ private
1914
+ def impl_initialize
1915
+ @regexp = Regexp.new( @ext_pattern )
1916
+ end
1917
+
1918
+ public
1919
+ def external_form
1920
+ StringToken.new( :val => @ext_pattern ).external_form
1921
+ end
1922
+ end
1923
+
1924
+ class RangeRestriction < BitGirderClass
1925
+
1926
+ bg_attr :min_closed, :processor => :boolean
1927
+ bg_attr :min, :required => false
1928
+ bg_attr :max, :required => false
1929
+ bg_attr :max_closed, :processor => :boolean
1930
+
1931
+ install_hash
1932
+
1933
+ public
1934
+ def external_form
1935
+
1936
+ res = @min_closed ? "[" : "("
1937
+ ( res << Mingle.quote_value( @min ) ) if @min
1938
+ res << ","
1939
+ ( res << Mingle.quote_value( @max ) ) if @max
1940
+ res << ( @max_closed ? "]" : ")" )
1941
+
1942
+ res
1943
+ end
1944
+ end
1945
+
1946
+ class AtomicTypeReference < MingleTypeReference
1947
+
1948
+ bg_attr :name # A DeclaredTypeName or QualifiedTypeName
1949
+
1950
+ bg_attr :restriction, :required => false
1951
+
1952
+ public
1953
+ def hash
1954
+ [ @name, @restriction ].hash
1955
+ end
1956
+
1957
+ public
1958
+ def external_form
1959
+
1960
+ res = @name.external_form.dup
1961
+ ( res << "~" << @restriction.external_form ) if @restriction
1962
+
1963
+ res
1964
+ end
1965
+ end
1966
+
1967
+ QNAME_RESOLV_MAP = {}
1968
+
1969
+ %w{
1970
+ Value
1971
+ Boolean
1972
+ Buffer
1973
+ String
1974
+ Int32
1975
+ Int64
1976
+ Uint32
1977
+ Uint64
1978
+ Float32
1979
+ Float64
1980
+ Timestamp
1981
+ Enum
1982
+ SymbolMap
1983
+ Struct
1984
+ Null
1985
+
1986
+ }.each do |nm|
1987
+
1988
+ uc = nm.upcase
1989
+
1990
+ nm = DeclaredTypeName.send( :new, :name => nm )
1991
+
1992
+ qn = const_set( :"QNAME_#{uc}",
1993
+ QualifiedTypeName.send( :new,
1994
+ :namespace => MingleNamespace.send( :new,
1995
+ :parts => [
1996
+ MingleIdentifier.send( :new, :parts => %w{ mingle } ),
1997
+ MingleIdentifier.send( :new, :parts => %w{ core } )
1998
+ ],
1999
+ :version => MingleIdentifier.send( :new, :parts => %w{ v1 } )
2000
+ ),
2001
+ :name => nm
2002
+ )
2003
+ )
2004
+
2005
+ QNAME_RESOLV_MAP[ nm ] = qn
2006
+
2007
+ const_set( :"TYPE_#{uc}", AtomicTypeReference.send( :new, :name => qn ) )
2008
+ end
2009
+
2010
+ NUM_TYPES =
2011
+ %w{ INT32 INT64 UINT32 UINT64 FLOAT32 FLOAT64 }.map do |s|
2012
+ const_get( :"TYPE_#{s}" )
2013
+ end
2014
+
2015
+ INT_TYPES = [ TYPE_INT32, TYPE_INT64, TYPE_UINT32, TYPE_UINT64 ]
2016
+
2017
+ COMPARABLE_TYPES = NUM_TYPES + [ TYPE_STRING, TYPE_TIMESTAMP ]
2018
+
2019
+ class ListTypeReference < MingleTypeReference
2020
+
2021
+ bg_attr :element_type
2022
+ bg_attr :allows_empty, :processor => :boolean
2023
+
2024
+ public
2025
+ def hash
2026
+ [ @element_type, @allows_empty ].hash
2027
+ end
2028
+
2029
+ public
2030
+ def external_form
2031
+ "#{@element_type.external_form}#{@allows_empty ? "*" : "+"}"
2032
+ end
2033
+ end
2034
+
2035
+ class NullableTypeReference < MingleTypeReference
2036
+
2037
+ bg_attr :type
2038
+
2039
+ public
2040
+ def hash
2041
+ @type.hash
2042
+ end
2043
+
2044
+ public
2045
+ def external_form
2046
+ "#{@type.external_form}?"
2047
+ end
2048
+ end
2049
+
2050
+ class MingleIdentifiedName < BitGirderClass
2051
+
2052
+ include StringParser
2053
+
2054
+ bg_attr :namespace, :processor => MingleNamespace
2055
+
2056
+ bg_attr :names,
2057
+ :list_validation => :not_empty,
2058
+ :processor => lambda { |arr|
2059
+ arr.map { |nm| MingleIdentifier.as_instance( nm ) }
2060
+ }
2061
+
2062
+ def self.impl_parse( s )
2063
+ MingleParser.consume_string( s ) { |p| p.expect_identified_name }
2064
+ end
2065
+
2066
+ public
2067
+ def hash
2068
+ [ @namespace, @names ].hash
2069
+ end
2070
+
2071
+ public
2072
+ def external_form
2073
+
2074
+ @names.inject( @namespace.format( ID_STYLE_LC_HYPHENATED ) ) do |s, nm|
2075
+ s << "/" << nm.format( ID_STYLE_LC_HYPHENATED )
2076
+ end
2077
+ end
2078
+ end
2079
+
2080
+ class MingleTypedValue < MingleValue
2081
+
2082
+ bg_attr :type, :processor => MingleTypeReference
2083
+ end
2084
+
2085
+ class MingleEnum < MingleTypedValue
2086
+
2087
+ bg_attr :value, :processor => MingleIdentifier
2088
+
2089
+ public
2090
+ def to_s
2091
+ "#{@type.external_form}.#{@value.external_form}"
2092
+ end
2093
+
2094
+ public
2095
+ def ==( other )
2096
+ other.is_a?( MingleEnum ) &&
2097
+ other.type == @type &&
2098
+ other.value == @value
2099
+ end
2100
+ end
2101
+
2102
+ class MingleSymbolMap < MingleValue
2103
+
2104
+ include Enumerable
2105
+
2106
+ extend Forwardable
2107
+ def_delegators :@map,
2108
+ :size, :empty?, :each, :each_pair, :to_s, :to_hash, :keys
2109
+
2110
+ class NoSuchKeyError < StandardError; end
2111
+
2112
+ extend BitGirder::Core::BitGirderMethods
2113
+
2114
+ private_class_method :new
2115
+
2116
+ def self.create( map = {} )
2117
+
2118
+ res = {}
2119
+
2120
+ not_nil( map, "map" ).each_pair do |k, v|
2121
+
2122
+ mv = MingleModels.as_mingle_value( v )
2123
+ res[ MingleIdentifier::get( k ) ] = mv unless mv.is_a?( MingleNull )
2124
+ end
2125
+
2126
+ new( res )
2127
+ end
2128
+
2129
+ map_instance_of( Hash ) { |h| self.create( h ) }
2130
+
2131
+ def initialize( map )
2132
+ @map = map.freeze
2133
+ end
2134
+
2135
+ def get_map
2136
+ {}.merge( @map )
2137
+ end
2138
+
2139
+ public
2140
+ def fields
2141
+ self
2142
+ end
2143
+
2144
+ public
2145
+ def []( key )
2146
+
2147
+ case not_nil( key, :key )
2148
+
2149
+ when MingleIdentifier then @map[ key ]
2150
+
2151
+ when String then self[ key.to_sym ]
2152
+
2153
+ when Symbol
2154
+ if res = ( @vals_by_sym ||= {} )[ key ]
2155
+ res
2156
+ else
2157
+ res = self[ MingleIdentifier.get( key ) ]
2158
+ @vals_by_sym[ key ] = res if res
2159
+
2160
+ res
2161
+ end
2162
+
2163
+ else raise TypeError, "Unexpected key type: #{key.class}"
2164
+ end
2165
+ end
2166
+
2167
+ alias get []
2168
+
2169
+ public
2170
+ def expect( key )
2171
+
2172
+ if ( res = self[ key ] ) == nil
2173
+ raise NoSuchKeyError, "Map has no value for key: #{key}"
2174
+ else
2175
+ res
2176
+ end
2177
+ end
2178
+
2179
+ public
2180
+ def values_at( *arg )
2181
+ not_nil( arg, :arg ).map { |k| get( k ) }
2182
+ end
2183
+
2184
+ public
2185
+ def ==( other )
2186
+
2187
+ other.is_a?( MingleSymbolMap ) &&
2188
+ other.instance_variable_get( :@map ) == @map
2189
+ end
2190
+
2191
+ # Util function for method_missing
2192
+ private
2193
+ def expect_one_arg( args )
2194
+
2195
+ case sz = args.size
2196
+ when 0 then nil
2197
+ when 1 then args[ 0 ]
2198
+ else raise ArgumentError, "Wrong number of arguments (#{sz} for 1)"
2199
+ end
2200
+ end
2201
+
2202
+ private
2203
+ def method_missing( meth, *args )
2204
+
2205
+ case meth.to_s
2206
+
2207
+ when /^(expect|get)_(mingle_[a-z][a-z\d]*(?:_[a-z][a-z\d]*)*)$/
2208
+
2209
+ case val = send( $1.to_sym, expect_one_arg( args ) )
2210
+ when nil then nil
2211
+ else MingleModels.as_mingle_instance( val, $2.to_sym )
2212
+ end
2213
+
2214
+ when /^(expect|get)_string$/
2215
+ s = send( :"#{$1}_mingle_string", *args ) and s.to_s
2216
+
2217
+ when /^(expect|get)_int$/
2218
+ s = send( :"#{$1}_mingle_int64", *args ) and s.to_i
2219
+
2220
+ when /^(expect|get)_timestamp$/
2221
+ s = send( :"#{$1}_mingle_timestamp", *args )
2222
+
2223
+ when /^(expect|get)_boolean$/
2224
+ s = send( :"#{$1}_mingle_boolean", *args ) and s.to_bool
2225
+
2226
+ else super
2227
+ end
2228
+ end
2229
+
2230
+ EMPTY = new( {} )
2231
+ end
2232
+
2233
+ class MingleStruct < MingleValue
2234
+
2235
+ bg_attr :type, :processor => MingleTypeReference
2236
+
2237
+ bg_attr :fields,
2238
+ :default => MingleSymbolMap::EMPTY,
2239
+ :processor => MingleSymbolMap
2240
+
2241
+ public
2242
+ def to_s
2243
+ "#@type:#{fields}"
2244
+ end
2245
+
2246
+ public
2247
+ def []( fld )
2248
+ @fields[ fld ]
2249
+ end
2250
+ end
2251
+
2252
+ class GenericRaisedMingleError < StandardError
2253
+
2254
+ include BitGirder::Core::BitGirderMethods
2255
+ extend Forwardable
2256
+
2257
+ def_delegators :@me, :type, :fields, :[]
2258
+
2259
+ def initialize( me, trace = nil )
2260
+
2261
+ @me = not_nil( me, :me )
2262
+
2263
+ super( "#{@me.type}: #{@me[ :message ]}" )
2264
+ set_backtrace( trace ) if trace
2265
+ end
2266
+ end
2267
+
2268
+ module MingleModels
2269
+
2270
+ require 'base64'
2271
+
2272
+ extend BitGirder::Core::BitGirderMethods
2273
+
2274
+ NUM_TYPES = {
2275
+ :mingle_int64 => MingleInt64,
2276
+ :mingle_int32 => MingleInt32,
2277
+ :mingle_uint32 => MingleUint32,
2278
+ :mingle_uint64 => MingleUint64,
2279
+ :mingle_float64 => MingleFloat64,
2280
+ :mingle_float32 => MingleFloat32,
2281
+ }
2282
+
2283
+ module_function
2284
+
2285
+ def create_coerce_error( val, targ_type )
2286
+ TypeError.new "Can't coerce value of type #{val.class} to #{targ_type}"
2287
+ end
2288
+
2289
+ def as_mingle_string( val )
2290
+
2291
+ case val
2292
+
2293
+ when MingleString then val
2294
+
2295
+ when MingleNumber, MingleBoolean, MingleTimestamp
2296
+ MingleString.new( val.to_s )
2297
+
2298
+ else raise create_coerce_error( val, MingleString )
2299
+ end
2300
+ end
2301
+
2302
+ def impl_string_to_num( str, typ )
2303
+
2304
+ if [ MingleInt64, MingleInt32, MingleUint32, MingleUint64 ].
2305
+ include?( typ )
2306
+ str.to_i
2307
+ elsif [ MingleFloat64, MingleFloat32 ].include?( typ )
2308
+ str.to_f
2309
+ else
2310
+ raise "Unhandled number target type: #{typ}"
2311
+ end
2312
+ end
2313
+
2314
+ def as_mingle_number( val, num_typ )
2315
+
2316
+ case val
2317
+
2318
+ when num_typ then val
2319
+
2320
+ when MingleString
2321
+ num_typ.new( impl_string_to_num( val.to_s, num_typ ) )
2322
+
2323
+ when MingleNumber then num_typ.new( val.num )
2324
+
2325
+ else raise create_coerce_error( val, num_typ )
2326
+ end
2327
+ end
2328
+
2329
+ def as_mingle_boolean( val )
2330
+
2331
+ case val
2332
+
2333
+ when MingleBoolean then val
2334
+
2335
+ when MingleString
2336
+ case val.to_s.strip.downcase
2337
+ when "true" then MingleBoolean::TRUE
2338
+ when "false" then MingleBoolean::FALSE
2339
+ end
2340
+
2341
+ else raise create_coerce_error( val, MingleBoolean )
2342
+ end
2343
+ end
2344
+
2345
+ def as_mingle_buffer( val )
2346
+
2347
+ not_nil( val, "val" )
2348
+
2349
+ case val
2350
+
2351
+ when MingleBuffer then val
2352
+
2353
+ when MingleString
2354
+ MingleBuffer.new( BitGirder::Io.strict_decode64( val.to_s ) )
2355
+
2356
+ else raise create_coerce_error( val, MingleBuffer )
2357
+ end
2358
+ end
2359
+
2360
+ def as_mingle_timestamp( val )
2361
+
2362
+ not_nil( val, "val" )
2363
+
2364
+ case val
2365
+
2366
+ when MingleTimestamp then val
2367
+ when MingleString then MingleTimestamp.rfc3339( val )
2368
+ when Time then MingleTimestamp.new( val )
2369
+
2370
+ else raise create_coerce_error( val, MingleTimestamp )
2371
+ end
2372
+ end
2373
+
2374
+ def impl_as_typed_value( val, typ )
2375
+ if val.is_a?( typ )
2376
+ val
2377
+ else
2378
+ sym = get_coerce_type_symbol( typ )
2379
+ raise create_coerce_error( val, typ )
2380
+ end
2381
+ end
2382
+
2383
+ def as_mingle_struct( val )
2384
+ impl_as_typed_value( val, MingleStruct )
2385
+ end
2386
+
2387
+ def as_mingle_list( val )
2388
+ impl_as_typed_value( val, MingleList )
2389
+ end
2390
+
2391
+ def as_mingle_symbol_map( val )
2392
+ impl_as_typed_value( val, MingleSymbolMap )
2393
+ end
2394
+
2395
+ def as_mingle_integer( num )
2396
+
2397
+ case
2398
+ when MingleInt32.can_hold?( num ) then MingleInt32.new( num )
2399
+ when MingleInt64.can_hold?( num ) then MingleInt64.new( num )
2400
+ when MingleUint64.can_hold?( num ) then MingleUint64.new( num )
2401
+ else raise "Number is out of range for mingle integer types: #{num}"
2402
+ end
2403
+ end
2404
+
2405
+ def as_mingle_value( val )
2406
+
2407
+ case val
2408
+ when MingleValue then val
2409
+ when String then MingleString.new( val )
2410
+ when Symbol then MingleString.new( val.to_s )
2411
+ when TrueClass then MingleBoolean::TRUE
2412
+ when FalseClass then MingleBoolean::FALSE
2413
+ when Integer then as_mingle_integer( val )
2414
+ when Float, BigDecimal, Rational then MingleFloat64.new( val )
2415
+ when Array then MingleList.new( val )
2416
+ when Hash then MingleSymbolMap.create( val )
2417
+ when Time then as_mingle_timestamp( val )
2418
+ when nil then MingleNull::INSTANCE
2419
+ else raise "Can't create mingle value for instance of #{val.class}"
2420
+ end
2421
+ end
2422
+
2423
+ # No assertions or other type checking at this :level => if it's a sym we
2424
+ # assume it is of the form mingle_foo_bar where foo_bar is a coercable type;
2425
+ # if a class we assume it is of the form MingleFooBar that we can convert to
2426
+ # a symbol of the former form.
2427
+ def get_coerce_type_symbol( typ )
2428
+
2429
+ case typ
2430
+
2431
+ when Symbol then typ
2432
+
2433
+ when Class
2434
+
2435
+ base_name = typ.to_s.split( /::/ )[ -1 ] # Get last name part
2436
+ str =
2437
+ base_name.gsub( /(^[A-Z])|([A-Z])/ ) do |m|
2438
+ ( $2 ? "_" : "" ) + m.downcase
2439
+ end
2440
+
2441
+ str.to_sym
2442
+
2443
+ else raise "Unexpected coerce type indicator: #{typ}"
2444
+ end
2445
+ end
2446
+
2447
+ def as_mingle_instance( val, typ )
2448
+
2449
+ type_sym = get_coerce_type_symbol( not_nil( typ, "typ" ) )
2450
+
2451
+ if num_typ = NUM_TYPES[ type_sym ]
2452
+ as_mingle_number( val, num_typ )
2453
+ else
2454
+ send( :"as_#{type_sym}", val )
2455
+ end
2456
+ end
2457
+
2458
+ def as_ruby_error( me, trace = nil )
2459
+ GenericRaisedMingleError.new( not_nil( me, :me ), trace )
2460
+ end
2461
+
2462
+ def raise_as_ruby_error( me )
2463
+ raise as_ruby_error( me )
2464
+ end
2465
+ end
2466
+
2467
+ class TypeCastError < BitGirderError
2468
+
2469
+ bg_attr :actual
2470
+ bg_attr :expected
2471
+ bg_attr :path
2472
+
2473
+ public
2474
+ def to_s
2475
+
2476
+ res = @path ? "#{@path.format}: " : ""
2477
+ res << "Can't cast #@actual to #@expected"
2478
+ end
2479
+ end
2480
+
2481
+ module CastImpl
2482
+
2483
+ module_function
2484
+
2485
+ def fail_cast( val, typ, path )
2486
+
2487
+ raise TypeCastError.new(
2488
+ :actual => Mingle.type_of( val ),
2489
+ :expected => typ,
2490
+ :path => path
2491
+ )
2492
+ end
2493
+
2494
+ def cast_num( val, typ, path )
2495
+
2496
+ cls, meth =
2497
+ case typ
2498
+ when TYPE_INT32 then [ MingleInt32, :to_i ]
2499
+ when TYPE_INT64 then [ MingleInt64, :to_i ]
2500
+ when TYPE_UINT32 then [ MingleUint32, :to_i ]
2501
+ when TYPE_UINT64 then [ MingleUint64, :to_i ]
2502
+ when TYPE_FLOAT32 then [ MingleFloat32, :to_f ]
2503
+ when TYPE_FLOAT64 then [ MingleFloat64, :to_f ]
2504
+ else raise "Bad num type: #{typ}"
2505
+ end
2506
+
2507
+ case val
2508
+ when cls then val
2509
+ when MingleString then cls.new( val.to_s.send( meth ) )
2510
+ when MingleNumber then cls.new( val.num.send( meth ) )
2511
+ else fail_cast( val, typ, path )
2512
+ end
2513
+ end
2514
+
2515
+ def cast_timestamp( val, typ, path )
2516
+
2517
+ case val
2518
+ when MingleTimestamp then val
2519
+ when MingleString then MingleTimestamp.rfc3339( val )
2520
+ else fail_cast( val, typ, path )
2521
+ end
2522
+ end
2523
+
2524
+ def cast_string( val, typ, path )
2525
+
2526
+ case val
2527
+ when MingleString then val
2528
+ when MingleTimestamp then val.rfc3339
2529
+ when MingleNumber, MingleBoolean then MingleString.new( val.to_s )
2530
+ else fail_cast( val, typ, path )
2531
+ end
2532
+ end
2533
+
2534
+ def cast_atomic_value( val, typ, path )
2535
+
2536
+ case typ
2537
+ when TYPE_INT32, TYPE_INT64, TYPE_UINT32, TYPE_UINT64,
2538
+ TYPE_FLOAT32, TYPE_FLOAT64
2539
+ cast_num( val, typ, path )
2540
+ when TYPE_TIMESTAMP then cast_timestamp( val, typ, path )
2541
+ when TYPE_STRING then cast_string( val, typ, path )
2542
+ else raise "Can't cast to #{typ}"
2543
+ end
2544
+ end
2545
+
2546
+ def cast_value( val, typ, path )
2547
+
2548
+ case typ
2549
+ when AtomicTypeReference then cast_atomic_value( val, typ, path )
2550
+ else raise "Unimplemented"
2551
+ end
2552
+ end
2553
+ end
2554
+
2555
+ def self.cast_value( val, typ, path = nil )
2556
+ CastImpl.cast_value( val, typ, path )
2557
+ end
2558
+
2559
+ def self.quote_value( val )
2560
+ case val
2561
+ when MingleString then Chars.external_form_of( val.to_s )
2562
+ when MingleInt32, MingleInt64, MingleUint32, MingleUint64,
2563
+ MingleFloat32, MingleFloat64
2564
+ val.to_s
2565
+ when MingleTimestamp then Chars.external_form_of( val.rfc3339 )
2566
+ else raise "Can't quote: #{val} (#{val.class})"
2567
+ end
2568
+ end
2569
+
2570
+ module IoConstants
2571
+
2572
+ TYPE_CODE_NIL = 0x00
2573
+ TYPE_CODE_ID = 0x01
2574
+ TYPE_CODE_NS = 0x02
2575
+ TYPE_CODE_DECL_NM = 0x03
2576
+ TYPE_CODE_QN = 0x04
2577
+ TYPE_CODE_ATOM_TYP = 0x05
2578
+ TYPE_CODE_LIST_TYP = 0x06
2579
+ TYPE_CODE_NULLABLE_TYP = 0x07
2580
+ TYPE_CODE_REGEX_RESTRICT = 0x08
2581
+ TYPE_CODE_RANGE_RESTRICT = 0x09
2582
+ TYPE_CODE_BOOL = 0x0a
2583
+ TYPE_CODE_STRING = 0x0b
2584
+ TYPE_CODE_INT32 = 0x0c
2585
+ TYPE_CODE_INT64 = 0x0d
2586
+ TYPE_CODE_FLOAT32 = 0x0e
2587
+ TYPE_CODE_FLOAT64 = 0x0f
2588
+ TYPE_CODE_TIME_RFC3339 = 0x10
2589
+ TYPE_CODE_BUFFER = 0x11
2590
+ TYPE_CODE_ENUM = 0x12
2591
+ TYPE_CODE_SYM_MAP = 0x13
2592
+ TYPE_CODE_MAP_PAIR = 0x14
2593
+ TYPE_CODE_STRUCT = 0x15
2594
+ TYPE_CODE_LIST = 0x17
2595
+ TYPE_CODE_END = 0x18
2596
+ end
2597
+
2598
+ class BinIoError < StandardError; end
2599
+
2600
+ class BinIoBase < BitGirderClass
2601
+
2602
+ include IoConstants
2603
+
2604
+ private
2605
+ def error( msg )
2606
+ BinIoError.new( msg )
2607
+ end
2608
+
2609
+ private
2610
+ def errorf( msg, *argv )
2611
+ error( sprintf( msg, *argv ) )
2612
+ end
2613
+ end
2614
+
2615
+ class BinReader < BinIoBase
2616
+
2617
+ private_class_method :new
2618
+
2619
+ bg_attr :rd # A BitGirder::Io::BinaryReader
2620
+
2621
+ private
2622
+ def peek_type_code
2623
+ @rd.peek_int8
2624
+ end
2625
+
2626
+ private
2627
+ def read_type_code
2628
+ @rd.read_int8
2629
+ end
2630
+
2631
+ private
2632
+ def expect_type_code( tc )
2633
+
2634
+ if ( act = read_type_code ) == tc
2635
+ tc
2636
+ else
2637
+ raise errorf( "Expected type code 0x%02x but got 0x%02x", tc, act )
2638
+ end
2639
+ end
2640
+
2641
+ private
2642
+ def buf32_as_utf8
2643
+
2644
+ RubyVersions.when_19x( @rd.read_buffer32 ) do |buf|
2645
+ buf.force_encoding( "utf-8" )
2646
+ end
2647
+ end
2648
+
2649
+ public
2650
+ def read_identifier
2651
+
2652
+ expect_type_code( TYPE_CODE_ID )
2653
+
2654
+ parts = Array.new( @rd.read_uint8 ) { buf32_as_utf8 }
2655
+ MingleIdentifier.send( :new, :parts => parts )
2656
+ end
2657
+
2658
+ private
2659
+ def read_identifiers
2660
+ Array.new( @rd.read_uint8 ) { read_identifier }
2661
+ end
2662
+
2663
+ private
2664
+ def read_namespace
2665
+
2666
+ expect_type_code( TYPE_CODE_NS )
2667
+
2668
+ MingleNamespace.send( :new,
2669
+ :parts => read_identifiers,
2670
+ :version => read_identifier
2671
+ )
2672
+ end
2673
+
2674
+ private
2675
+ def read_declared_type_name
2676
+
2677
+ expect_type_code( TYPE_CODE_DECL_NM )
2678
+
2679
+ DeclaredTypeName.send( :new, :name => buf32_as_utf8 )
2680
+ end
2681
+
2682
+ private
2683
+ def read_qualified_type_name
2684
+
2685
+ expect_type_code( TYPE_CODE_QN )
2686
+
2687
+ QualifiedTypeName.new(
2688
+ :namespace => read_namespace,
2689
+ :name => read_declared_type_name
2690
+ )
2691
+ end
2692
+
2693
+ private
2694
+ def read_type_name
2695
+
2696
+ case tc = peek_type_code
2697
+ when TYPE_CODE_DECL_NM then read_declared_type_name
2698
+ when TYPE_CODE_QN then read_qualified_type_name
2699
+ else raise errorf( "Unrecognized type name code: 0x%02x", tc )
2700
+ end
2701
+ end
2702
+
2703
+ private
2704
+ def read_restriction
2705
+
2706
+ if ( tc = read_type_code ) == TYPE_CODE_NIL
2707
+ nil
2708
+ else
2709
+ raise error( "Non-nil restrictions not yet implemented" )
2710
+ end
2711
+ end
2712
+
2713
+ private
2714
+ def read_atomic_type_reference
2715
+
2716
+ expect_type_code( TYPE_CODE_ATOM_TYP )
2717
+
2718
+ AtomicTypeReference.send( :new,
2719
+ :name => read_type_name,
2720
+ :restriction => read_restriction
2721
+ )
2722
+ end
2723
+
2724
+ public
2725
+ def read_type_reference
2726
+
2727
+ case tc = peek_type_code
2728
+ when TYPE_CODE_ATOM_TYP then read_atomic_type_reference
2729
+ when TYPE_CODE_LIST_TYP then read_list_type_reference
2730
+ when TYPE_CODE_NULLABLE_TYP then read_nullable_type_reference
2731
+ else raise errorf( "Unrecognized type reference code: 0x%02x", tc )
2732
+ end
2733
+ end
2734
+
2735
+ def self.as_bin_reader( io_rd )
2736
+ self.send( :new, :rd => io_rd )
2737
+ end
2738
+ end
2739
+
2740
+ class BinWriter < BinIoBase
2741
+
2742
+ bg_attr :wr
2743
+
2744
+ private_class_method :new
2745
+
2746
+ private
2747
+ def write_type_code( tc )
2748
+ @wr.write_uint8( tc )
2749
+ end
2750
+
2751
+ private
2752
+ def write_nil
2753
+ write_type_code( TYPE_CODE_NIL )
2754
+ end
2755
+
2756
+ private
2757
+ def write_qualified_type_name( qn )
2758
+
2759
+ write_type_code( TYPE_CODE_QN )
2760
+ write_namespace( qn.namespace )
2761
+ write_declared_type_name( qn.name )
2762
+ end
2763
+
2764
+ public
2765
+ def write_identifier( id )
2766
+
2767
+ write_type_code( TYPE_CODE_ID )
2768
+
2769
+ @wr.write_uint8( id.parts.size )
2770
+ id.parts.each { |part| @wr.write_buffer32( part ) }
2771
+ end
2772
+
2773
+ private
2774
+ def write_identifiers( ids )
2775
+
2776
+ @wr.write_uint8( ids.size )
2777
+ ids.each { |id| write_identifier( id ) }
2778
+ end
2779
+
2780
+ private
2781
+ def write_namespace( ns )
2782
+
2783
+ write_type_code( TYPE_CODE_NS )
2784
+ write_identifiers( ns.parts )
2785
+ write_identifier( ns.version )
2786
+ end
2787
+
2788
+ private
2789
+ def write_declared_type_name( nm )
2790
+
2791
+ write_type_code( TYPE_CODE_DECL_NM )
2792
+ @wr.write_buffer32( nm.name )
2793
+ end
2794
+
2795
+ private
2796
+ def write_type_name( nm )
2797
+
2798
+ case nm
2799
+ when DeclaredTypeName then write_declared_type_name( nm )
2800
+ when QualifiedTypeName then write_qualified_type_name( nm )
2801
+ else raise error( "Unhandled type name: #{nm.class}" )
2802
+ end
2803
+ end
2804
+
2805
+ private
2806
+ def write_atomic_type_reference( typ )
2807
+
2808
+ write_type_code( TYPE_CODE_ATOM_TYP )
2809
+ write_type_name( typ.name )
2810
+
2811
+ case typ.restriction
2812
+ when nil then write_nil
2813
+ else raise error( "Unhandled restriction: #{typ}" )
2814
+ end
2815
+ end
2816
+
2817
+ public
2818
+ def write_type_reference( typ )
2819
+
2820
+ case typ
2821
+ when AtomicTypeReference then write_atomic_type_reference( typ )
2822
+ when ListTypeReference then write_list_type_reference( typ )
2823
+ when NullableTypeReference then write_nullable_type_reference( typ )
2824
+ else raise error( "Unhandled type reference: #{typ.class}" )
2825
+ end
2826
+ end
2827
+
2828
+ def self.as_bin_writer( io_wr )
2829
+ self.send( :new, :wr => io_wr )
2830
+ end
2831
+ end
2832
+
2833
+ class MingleServiceRequest < BitGirder::Core::BitGirderClass
2834
+
2835
+ bg_attr :namespace, :processor => MingleNamespace
2836
+
2837
+ bg_attr :service, :processor => MingleIdentifier
2838
+
2839
+ bg_attr :operation, :processor => MingleIdentifier
2840
+
2841
+ bg_attr :authentication,
2842
+ :required => false,
2843
+ :processor => lambda { |v| MingleModels.as_mingle_value( v ) }
2844
+
2845
+ bg_attr :parameters,
2846
+ :default => MingleSymbolMap::EMPTY,
2847
+ :processor => MingleSymbolMap
2848
+ end
2849
+
2850
+ class MingleServiceResponse < BitGirder::Core::BitGirderClass
2851
+
2852
+ def initialize( res, ex )
2853
+
2854
+ @res = res
2855
+ @ex = ex
2856
+ end
2857
+
2858
+ public
2859
+ def ok?
2860
+ ! @ex
2861
+ end
2862
+
2863
+ alias is_ok ok?
2864
+
2865
+ public
2866
+ def get
2867
+
2868
+ if ok?
2869
+ @res
2870
+ else
2871
+ MingleModels.raise_as_ruby_error( @ex )
2872
+ end
2873
+ end
2874
+
2875
+ public
2876
+ def get_result
2877
+
2878
+ if ok?
2879
+ @res
2880
+ else
2881
+ raise "get_res called on non-ok response"
2882
+ end
2883
+ end
2884
+
2885
+ alias result get_result
2886
+
2887
+ public
2888
+ def get_error
2889
+
2890
+ if ok?
2891
+ raise "get_error called on ok response"
2892
+ else
2893
+ @ex
2894
+ end
2895
+ end
2896
+
2897
+ alias error get_error
2898
+
2899
+ public
2900
+ def to_s
2901
+ super.inspect
2902
+ end
2903
+
2904
+ def self.create_success( res )
2905
+
2906
+ res = MingleModels.as_mingle_value( res );
2907
+ res = nil if res.is_a?( MingleNull )
2908
+
2909
+ MingleServiceResponse.new( res, nil )
2910
+ end
2911
+
2912
+ def self.create_failure( ex )
2913
+ MingleServiceResponse.new( nil, ex )
2914
+ end
2915
+ end
2916
+
2917
+ end