msgpack-idl 0.1.0

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.
@@ -0,0 +1,60 @@
1
+ #
2
+ # MessagePack IDL Processor
3
+ #
4
+ # Copyright (C) 2011 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module IDL
20
+
21
+
22
+ class IDLError < StandardError
23
+ end
24
+
25
+ class IncludeError < IDLError
26
+ end
27
+
28
+ class SyntaxError < IDLError
29
+ end
30
+
31
+ class SemanticsError < IDLError
32
+ end
33
+
34
+ class NameError < SemanticsError
35
+ end
36
+
37
+ class InvlaidNameError < NameError
38
+ end
39
+
40
+ class NameNotFoundError < NameError
41
+ end
42
+
43
+ class InvalidNameError < NameError
44
+ end
45
+
46
+ class DuplicatedNameError < NameError
47
+ end
48
+
49
+ class TypeError < SemanticsError
50
+ end
51
+
52
+ class InheritanceError < IDLError
53
+ end
54
+
55
+ class GeneratorError < IDLError
56
+ end
57
+
58
+
59
+ end
60
+ end
@@ -0,0 +1,616 @@
1
+ #
2
+ # MessagePack IDL Processor
3
+ #
4
+ # Copyright (C) 2011 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module IDL
20
+
21
+
22
+ class Evaluator
23
+ include ProcessorModule
24
+
25
+ class Template
26
+ def initialize(generic_type, nullable=false)
27
+ @name = generic_type.name
28
+ @params = generic_type.type_params
29
+ @generic_type = generic_type
30
+ @nullable = nullable
31
+ end
32
+ attr_reader :generic_type, :nullable
33
+
34
+ def nullable?
35
+ @nullable
36
+ end
37
+
38
+ def match_all(name, array)
39
+ if @name != name
40
+ return nil
41
+ end
42
+ if array.size != @params.size
43
+ return nil
44
+ end
45
+ resolved_params = @params.zip(array).map {|a,b|
46
+ if b.class == IR::TypeParameterSymbol
47
+ return nil
48
+ end
49
+ if a.class != IR::TypeParameterSymbol && a != b
50
+ return nil
51
+ end
52
+ b
53
+ }
54
+ resolved_params
55
+ end
56
+ end
57
+
58
+ def initialize
59
+ @names = {} # name:String => AST::Element
60
+
61
+ @types = {} # name:String => AST::Type
62
+ @generic_types = [] # Template
63
+
64
+ @global_namespace = "" # Namespace
65
+ @lang_namespace = {} # lang:String => scope:Namespace
66
+
67
+ @services = [] # name:String => IR::Service
68
+
69
+ init_built_in
70
+
71
+ @ir_types = []
72
+ @ir_services = []
73
+ @ir_applications = []
74
+ end
75
+
76
+ def evaluate(ast)
77
+ ast.each {|e|
78
+ evaluate_one(e)
79
+ }
80
+ end
81
+
82
+ def evaluate_one(e)
83
+ case e
84
+ when AST::Namespace
85
+ add_namespace(e)
86
+
87
+ when AST::Exception
88
+ check_name(e.name, e)
89
+ if e.super_class
90
+ super_message = resolve_type(e.super_class)
91
+ if !super_message.is_a?(IR::Exception)
92
+ raise InvalidNameError, "`#{e.super_class}' is not a #{IR::Exception} but a #{super_message.class}"
93
+ end
94
+ end
95
+ new_fields = resolve_fields(e.fields, super_message)
96
+ add_exception(e.name, super_message, new_fields)
97
+
98
+ when AST::Message
99
+ check_name(e.name, e)
100
+ if e.super_class
101
+ super_message = resolve_type(e.super_class)
102
+ if !super_message.is_a?(IR::Message)
103
+ raise InvalidNameError, "`#{e.super_class}' is not a #{IR::Message} but a #{super_message.class}"
104
+ end
105
+ end
106
+ new_fields = resolve_fields(e.fields, super_message)
107
+ add_message(e.name, super_message, new_fields)
108
+
109
+ when AST::Enum
110
+ check_name(e.name, e)
111
+ fields = resolve_enum_fields(e.fields)
112
+ add_enum(e.name, fields)
113
+
114
+ when AST::Service
115
+ v = e.version || 0
116
+ s = check_service_version(e.name, v)
117
+ funcs = resolve_funcs(e.funcs)
118
+ add_service_version(s, e.name, v, funcs)
119
+
120
+ when AST::Application
121
+ check_name(e.name, e)
122
+ scopes = resolve_scopes(e.scopes)
123
+ add_application(e.name, scopes)
124
+
125
+ else
126
+ raise SemanticsError, "Unknown toplevel AST element `#{e.class}': #{e.inspect}"
127
+ end
128
+ end
129
+
130
+ def evaluate_inheritance
131
+ @services.each {|s|
132
+ super_versions = []
133
+ s.versions = s.versions.sort_by {|sv| sv.version }
134
+ s.versions.each do |sv|
135
+
136
+ sv.functions.each {|f|
137
+ f.super_version = nil
138
+ f.super_func = nil
139
+ super_versions.reverse_each do |ssv|
140
+ if sf = ssv.functions.find {|sf| sf.name == f.name }
141
+ if f.args == sf.args && f.return_type == sf.return_type
142
+ f.super_version = ssv.version
143
+ f.super_func = sf
144
+ end
145
+ break
146
+ end
147
+ end
148
+ }
149
+
150
+ super_versions << sv
151
+ end
152
+ }
153
+ @ir_services = @services
154
+ self
155
+ end
156
+
157
+ def evaluate_spec(lang)
158
+ lang = lang.to_s
159
+ ns = spec_namespace(lang)
160
+ types = spec_types(lang)
161
+ services = spec_services(lang)
162
+ applications = spec_applications(lang)
163
+ IR::Spec.new(ns, types, services, applications)
164
+ end
165
+
166
+ private
167
+ def spec_namespace(lang)
168
+ if ns = @lang_namespace[lang]
169
+ return ns
170
+ else
171
+ @global_namespace
172
+ end
173
+ end
174
+
175
+ def spec_types(lang)
176
+ @ir_types
177
+ end
178
+
179
+ def spec_services(lang)
180
+ @ir_services
181
+ end
182
+
183
+ def spec_applications(lang)
184
+ @ir_applications
185
+ end
186
+
187
+ def check_name(name, e)
188
+ if ee = @names[name]
189
+ raise DuplicatedNameError, "duplicated name `#{name}': #{e.inspect}"
190
+ end
191
+ @names[name] = e
192
+ end
193
+
194
+
195
+ def resolve_simple_type(e)
196
+ type = @types[e.name]
197
+ unless type
198
+ raise NameNotFoundError, "type not found: #{e.name}"
199
+ end
200
+ if e.nullable? && !type.is_a?(IR::NullableType)
201
+ IR::NullableType.new(type)
202
+ else
203
+ type
204
+ end
205
+ end
206
+
207
+ def resolve_generic_type(e)
208
+ query = e.type_params.map {|v|
209
+ resolve_type(v)
210
+ }
211
+ resolved_types = nil
212
+ template = nil
213
+ @generic_types.find {|tmpl|
214
+ if resolved_types = tmpl.match_all(e.name, query)
215
+ template = tmpl
216
+ true
217
+ end
218
+ }
219
+ unless resolved_types
220
+ raise NameNotFoundError, "generic type not matched: #{e.name}"
221
+ end
222
+ type = IR::ParameterizedType.new(resolved_types, template.generic_type)
223
+ if template.nullable || e.nullable?
224
+ IR::NullableType.new(type)
225
+ else
226
+ type
227
+ end
228
+ end
229
+
230
+ def resolve_type(e)
231
+ if e.is_a?(AST::GenericType)
232
+ resolve_generic_type(e)
233
+ else
234
+ resolve_simple_type(e)
235
+ end
236
+ end
237
+
238
+ def resolve_fields(fields, super_message)
239
+ used_ids = []
240
+ used_names = {}
241
+ super_used_names = {}
242
+ super_used_ids = []
243
+
244
+ if super_message
245
+ super_message.all_fields.each {|f|
246
+ super_used_ids[f.id] = true
247
+ super_used_names[f.name] = true
248
+ }
249
+ end
250
+
251
+ new_fields = fields.map {|e|
252
+ if e.id == 0
253
+ raise InvalidNameError, "field id 0 is invalid"
254
+ end
255
+ if e.id < 0
256
+ raise InvalidNameError, "field id < 0 is invalid"
257
+ end
258
+ if n = used_ids[e.id]
259
+ raise DuplicatedNameError, "duplicated field id #{e.id}: #{n}, #{e.name}"
260
+ end
261
+ if used_names[e.name]
262
+ raise DuplicatedNameError, "duplicated field name: #{e.name}"
263
+ end
264
+ if super_used_ids[e.id]
265
+ raise InheritanceError, "field id is duplicated with super class: #{e.is}"
266
+ end
267
+ if super_used_names[e.name]
268
+ raise InheritanceError, "field name is duplicated with super class: #{e.name}"
269
+ end
270
+
271
+ used_ids[e.id] = e.name
272
+ used_names[e.name] = e.name
273
+
274
+ type = resolve_type(e.type)
275
+ if e.modifier == AST::FIELD_OPTIONAL
276
+ option = IR::FIELD_OPTIONAL
277
+ else
278
+ option = IR::FIELD_REQUIRED
279
+ end
280
+
281
+ if e.is_a?(AST::ValueAssignedField)
282
+ v = resolve_initial_value(type, e.value)
283
+ else
284
+ v = resolve_implicit_value(type)
285
+ end
286
+
287
+ IR::Field.new(e.id, type, e.name, option, v)
288
+ }.sort_by {|f|
289
+ f.id
290
+ }
291
+
292
+ return new_fields
293
+ end
294
+
295
+ BUILT_IN_LITERAL = {
296
+ 'BYTE_MAX' => AST::IntLiteral.new((2**7)-1),
297
+ 'SHORT_MAX' => AST::IntLiteral.new((2**15)-1),
298
+ 'INT_MAX' => AST::IntLiteral.new((2**31)-1),
299
+ 'LONG_MAX' => AST::IntLiteral.new((2**63)-1),
300
+ 'UBYTE_MAX' => AST::IntLiteral.new((2**8)-1),
301
+ 'USHORT_MAX' => AST::IntLiteral.new((2**16)-1),
302
+ 'UINT_MAX' => AST::IntLiteral.new((2**32)-1),
303
+ 'ULONG_MAX' => AST::IntLiteral.new((2**64)-1),
304
+ 'BYTE_MIN' => AST::IntLiteral.new(-(2**7)),
305
+ 'SHORT_MIN' => AST::IntLiteral.new(-(2**15)),
306
+ 'INT_MIN' => AST::IntLiteral.new(-(2**31)),
307
+ 'LONG_MIN' => AST::IntLiteral.new(-(2**63)),
308
+ }
309
+
310
+ def resolve_initial_value(type, e)
311
+ if e.is_a?(AST::ConstLiteral)
312
+ e = BUILT_IN_LITERAL[e.name] || e
313
+ end
314
+ v = case e
315
+ when AST::NilLiteral
316
+ IR::NilValue.nil
317
+
318
+ when AST::TrueLiteral
319
+ IR::BoolValue.true
320
+
321
+ when AST::FalseLiteral
322
+ IR::BoolValue.false
323
+
324
+ when AST::IntLiteral
325
+ IR::IntValue.new(e.value)
326
+
327
+ when AST::EnumLiteral
328
+ enum = resolve_type(e.name)
329
+ if !enum.is_a?(IR::Enum)
330
+ raise NameNotFoundError, "not a enum type: #{e.name}"
331
+ end
332
+ f = enum.fields.find {|f|
333
+ f.name == e.field
334
+ }
335
+ if !f
336
+ raise NameNotFoundError, "no such field in enum `#{e.name}': #{e.field}"
337
+ end
338
+ IR::EnumValue.new(enum, f)
339
+
340
+ when AST::ConstLiteral
341
+ raise NameNotFoundError, "unknown constant: #{name}"
342
+
343
+ else
344
+ raise SemanticsError, "Unknown literal type: #{e.class}"
345
+ end
346
+
347
+ check_assignable(type, v)
348
+ v
349
+ end
350
+
351
+ def check_assignable(type, v)
352
+ if type.nullable_type? && v != IR::NilValue.nil
353
+ raise TypeError, "not-nullable value for nullable type is not allowed"
354
+ end
355
+
356
+ case v
357
+ when IR::NilValue
358
+ unless type.nullable_type?
359
+ raise TypeError, "nullable is expected: #{type}"
360
+ end
361
+
362
+ when IR::IntValue
363
+ unless IR::Primitive::INT_TYPES.include?(type)
364
+ raise TypeError, "integer type is expected: #{type}"
365
+ end
366
+ # TODO overflow
367
+
368
+ when IR::BoolValue
369
+ if type != IR::Primitive::bool
370
+ raise TypeError, "bool type is expected: #{type}"
371
+ end
372
+
373
+ end
374
+ end
375
+
376
+ def resolve_implicit_value(t)
377
+ if t.nullable_type?
378
+ return IR::NilValue.nil
379
+ end
380
+
381
+ if IR::Primitive::INT_TYPES.include?(t)
382
+ IR::IntValue.new(0)
383
+
384
+ elsif t == IR::Primitive.bool
385
+ IR::BoolValue.false
386
+
387
+ elsif t.is_a?(IR::Enum)
388
+ if t.fields.empty?
389
+ raise TypeError, "empty enum: #{t.name}"
390
+ end
391
+ IR::EnumValue.new(t, t.fields.first)
392
+
393
+ else
394
+ IR::EmptyValue.new
395
+ end
396
+ end
397
+
398
+ def resolve_enum_fields(fields)
399
+ used_ids = []
400
+ used_names = {}
401
+
402
+ fields = fields.map {|e|
403
+ if e.id < 0
404
+ raise InvalidNameError, "enum id < 0 is invalid"
405
+ end
406
+ if n = used_ids[e.id]
407
+ raise DuplicatedNameError, "duplicated enum id #{e.id}: #{n}, #{e.name}"
408
+ end
409
+ if used_names[e.name]
410
+ raise DuplicatedNameError, "duplicated field name: #{e.name}"
411
+ end
412
+
413
+ used_ids[e.id] = e.name
414
+ used_names[e.name] = e.name
415
+
416
+ IR::EnumField.new(e.id, e.name)
417
+ }.sort_by {|f|
418
+ f.id
419
+ }
420
+
421
+ return fields
422
+ end
423
+
424
+ def check_service_version(name, version)
425
+ s = @services.find {|s|
426
+ s.name == name
427
+ }
428
+ if s
429
+ s.versions.each {|sv|
430
+ if sv.version == version
431
+ raise DuplicatedNameError, "duplicated version #{version}"
432
+ end
433
+ }
434
+ else
435
+ check_name(name, nil)
436
+ end
437
+ s
438
+ end
439
+
440
+ def resolve_funcs(funcs)
441
+ used_names = {}
442
+
443
+ funcs = funcs.map {|e|
444
+ if used_names[e.name]
445
+ raise DuplicatedNameError, "duplicated function name: #{e.name}"
446
+ end
447
+
448
+ used_names[e.name] = true
449
+
450
+ args = resolve_args(e.args)
451
+ if e.return_type.name == "void"
452
+ return_type = IR::Primitive.void
453
+ else
454
+ return_type = resolve_type(e.return_type)
455
+ end
456
+
457
+ IR::Function.new(e.name, return_type, args, nil, nil)
458
+ }.sort_by {|f|
459
+ f.name
460
+ }
461
+
462
+ return funcs
463
+ end
464
+
465
+ def resolve_args(args)
466
+ used_ids = []
467
+ used_names = {}
468
+
469
+ args = args.map {|e|
470
+ if e.id == 0
471
+ raise InvalidNameError, "argument id 0 is invalid"
472
+ end
473
+ if e.id < 0
474
+ raise InvalidNameError, "argument id < 0 is invalid"
475
+ end
476
+ if n = used_ids[e.id]
477
+ raise DuplicatedNameError, "duplicated argument id #{e.id}: #{n}, #{e.name}"
478
+ end
479
+ if used_names[e.name]
480
+ raise DuplicatedNameError, "duplicated argument name: #{e.name}"
481
+ end
482
+
483
+ used_ids[e.id] = e.name
484
+ used_names[e.name] = e.name
485
+
486
+ type = resolve_type(e.type)
487
+ if e.modifier == AST::FIELD_OPTIONAL
488
+ option = IR::FIELD_OPTIONAL
489
+ else
490
+ option = IR::FIELD_REQUIRED
491
+ end
492
+
493
+ if e.is_a?(AST::ValueAssignedField)
494
+ v = resolve_initial_value(type, e.value)
495
+ else
496
+ v = resolve_implicit_value(type)
497
+ end
498
+
499
+ IR::Argument.new(e.id, type, e.name, option, v)
500
+ }.sort_by {|a|
501
+ a.id
502
+ }
503
+
504
+ return args
505
+ end
506
+
507
+ def resolve_scopes(scopes)
508
+ ds = scopes.find_all {|e|
509
+ e.default?
510
+ }
511
+ if ds.size > 1
512
+ raise DuplicatedNameError, "multiple default scope: #{ds.map {|e| e.name}.join(', ')}"
513
+ end
514
+
515
+ if ds.empty?
516
+ default_scope = scopes.first.name
517
+ else
518
+ default_scope = ds.first.name
519
+ end
520
+
521
+ used_names = {}
522
+
523
+ scopes = scopes.map {|e|
524
+ if used_names[e.name]
525
+ raise DuplicatedNameError, "duplicated scope name: #{e.name}"
526
+ end
527
+
528
+ s = @services.find {|s|
529
+ s.name == e.service
530
+ }
531
+ unless s
532
+ raise NameNotFoundError, "no such service: #{e.name}"
533
+ end
534
+
535
+ sv = s.versions.find {|sv|
536
+ sv.version == e.version
537
+ }
538
+ unless sv
539
+ raise NameNotFoundError, "no such service version: #{e.service}:#{s.version}"
540
+ end
541
+
542
+ used_names[e.name] = true
543
+
544
+ default = default_scope == e.name
545
+
546
+ IR::Scope.new(e.name, s, e.version, default)
547
+ }
548
+
549
+ return scopes
550
+ end
551
+
552
+
553
+ def add_namespace(e)
554
+ if e.lang
555
+ @lang_namespace[e.lang] = IR::Namespace.new(e.scopes)
556
+ else
557
+ @global_namespace = IR::Namespace.new(e.scopes)
558
+ end
559
+ end
560
+
561
+ def add_message(name, super_message, fields)
562
+ m = IR::Message.new(name, super_message, fields)
563
+ @types[name] = m
564
+ @ir_types << m
565
+ m
566
+ end
567
+
568
+ def add_exception(name, super_message, fields)
569
+ e = IR::Exception.new(name, super_message, fields)
570
+ @types[name] = e
571
+ @ir_types << e
572
+ e
573
+ end
574
+
575
+ def add_enum(name, fields)
576
+ e = IR::Enum.new(name, fields)
577
+ @types[name] = e
578
+ @ir_types << e
579
+ e
580
+ end
581
+
582
+ def add_service_version(s, name, version, funcs)
583
+ sv = IR::ServiceVersion.new(version, funcs)
584
+ if s
585
+ s.versions << sv
586
+ else
587
+ s = IR::Service.new(name, [sv])
588
+ @services << s
589
+ end
590
+ sv
591
+ end
592
+
593
+ def add_application(name, scopes)
594
+ app = IR::Application.new(name, scopes)
595
+ @ir_applications << app
596
+ app
597
+ end
598
+
599
+
600
+ def init_built_in
601
+ %w[byte short int long ubyte ushort uint ulong float double bool raw string].each {|name|
602
+ check_name(name, nil)
603
+ @types[name] = IR::Primitive.send(name)
604
+ }
605
+ check_name('list', nil)
606
+ @generic_types << Template.new(IR::Primitive.list)
607
+ check_name('map', nil)
608
+ @generic_types << Template.new(IR::Primitive.map)
609
+ #check_name('nullable', nil)
610
+ #@generic_types << Template.new(IR::Primitive.nullable)
611
+ end
612
+ end
613
+
614
+
615
+ end
616
+ end
@@ -0,0 +1,58 @@
1
+ #
2
+ # MessagePack IDL Processor
3
+ #
4
+ # Copyright (C) 2011 FURUHASHI Sadayuki
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ module MessagePack
19
+ module IDL
20
+
21
+
22
+ class GeneratorModule
23
+ include ProcessorModule
24
+
25
+ def self.generate(ir, out)
26
+ new(ir, out).generate!
27
+ end
28
+ end
29
+
30
+
31
+ class Generator
32
+ include ProcessorModule
33
+
34
+ GENERATORS = {}
35
+
36
+ def self.register(lang, impl)
37
+ GENERATORS[lang.to_s] = impl
38
+ end
39
+
40
+ def initialize
41
+ end
42
+
43
+ def self.available?(lang)
44
+ GENERATORS.has_key?(lang)
45
+ end
46
+
47
+ def generate(lang, ir, outdir)
48
+ gen = GENERATORS[lang]
49
+ unless gen
50
+ raise IDLError, "generator not found: #{lang}"
51
+ end
52
+ gen.generate(ir, outdir)
53
+ end
54
+ end
55
+
56
+
57
+ end
58
+ end