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.
- data/LICENSE.txt +176 -0
- data/bin/ensure-test-db +117 -0
- data/bin/install-mysql +375 -0
- data/bin/tomcat7 +569 -0
- data/lib/bitgirder/concurrent.rb +400 -0
- data/lib/bitgirder/core.rb +1235 -0
- data/lib/bitgirder/etl.rb +58 -0
- data/lib/bitgirder/event/file.rb +485 -0
- data/lib/bitgirder/event/logger/testing.rb +140 -0
- data/lib/bitgirder/event/logger.rb +137 -0
- data/lib/bitgirder/event/testing.rb +88 -0
- data/lib/bitgirder/http.rb +255 -0
- data/lib/bitgirder/io/testing.rb +33 -0
- data/lib/bitgirder/io.rb +959 -0
- data/lib/bitgirder/irb.rb +35 -0
- data/lib/bitgirder/mysql.rb +60 -0
- data/lib/bitgirder/ops/java.rb +117 -0
- data/lib/bitgirder/ops/ruby.rb +235 -0
- data/lib/bitgirder/testing.rb +152 -0
- data/lib/doc-gen0.rb +0 -0
- data/lib/doc-gen1.rb +0 -0
- data/lib/doc-gen10.rb +0 -0
- data/lib/doc-gen11.rb +0 -0
- data/lib/doc-gen12.rb +0 -0
- data/lib/doc-gen13.rb +0 -0
- data/lib/doc-gen14.rb +0 -0
- data/lib/doc-gen15.rb +0 -0
- data/lib/doc-gen16.rb +0 -0
- data/lib/doc-gen17.rb +14 -0
- data/lib/doc-gen18.rb +0 -0
- data/lib/doc-gen19.rb +0 -0
- data/lib/doc-gen2.rb +0 -0
- data/lib/doc-gen20.rb +182 -0
- data/lib/doc-gen21.rb +0 -0
- data/lib/doc-gen3.rb +0 -0
- data/lib/doc-gen4.rb +0 -0
- data/lib/doc-gen5.rb +0 -0
- data/lib/doc-gen6.rb +0 -0
- data/lib/doc-gen7.rb +0 -0
- data/lib/doc-gen8.rb +0 -0
- data/lib/doc-gen9.rb +0 -0
- data/lib/mingle/bincodec.rb +512 -0
- data/lib/mingle/codec.rb +54 -0
- data/lib/mingle/http.rb +156 -0
- data/lib/mingle/io/stream.rb +142 -0
- data/lib/mingle/io.rb +160 -0
- data/lib/mingle/json.rb +257 -0
- data/lib/mingle/service.rb +110 -0
- data/lib/mingle-em.rb +92 -0
- data/lib/mingle.rb +2917 -0
- 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
|