msgpack-idl 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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