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,499 @@
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 ParsletParser < Parslet::Parser
23
+ class << self
24
+ def sequence(name, separator, element, min=0)
25
+ if min == 0
26
+ eval %[rule(:#{name.to_s.dump}) {
27
+ (#{element}.as(:sequence_x) >> (#{separator} >> #{element}.as(:sequence_xs)).repeat).maybe.as(:sequence)
28
+ }]
29
+ else
30
+ eval %[rule(:#{name.to_s.dump}) {
31
+ (#{element}.as(:sequence_x) >> (#{separator} >> #{element}.as(:sequence_xs)).repeat(#{min-1})).as(:sequence)
32
+ }]
33
+ end
34
+ end
35
+
36
+ def keyword(string, name="k_"+string)
37
+ rule(name.to_sym) {
38
+ space? >> str(string) >> boundary
39
+ }
40
+ end
41
+
42
+ def separator(char, name)
43
+ rule(name.to_sym) {
44
+ space? >> str(char)
45
+ }
46
+ end
47
+ end
48
+
49
+ root :expression
50
+
51
+ rule(:expression) {
52
+ space? >> document >> space?
53
+ }
54
+
55
+ rule(:document) {
56
+ (include_ | definition).repeat.as(:document)
57
+ }
58
+
59
+ rule(:include_) {
60
+ k_include >>
61
+ path.as(:include) >>
62
+ eol
63
+ }
64
+
65
+ rule(:definition) {
66
+ namespace |
67
+ message |
68
+ enum |
69
+ exception |
70
+ service |
71
+ application
72
+ #const |
73
+ #typedef |
74
+ #typespec |
75
+ }
76
+
77
+
78
+ rule(:namespace) {
79
+ k_namespace >> (
80
+ lang_name.as(:namespace_lang) >> namespace_name.as(:namespace_name) |
81
+ namespace_name.as(:namespace_name)
82
+ ) >> eol
83
+ }
84
+
85
+
86
+ rule(:message) {
87
+ k_message >>
88
+ class_name.as(:message_name) >>
89
+ lt_extend_class.maybe.as(:super_class) >>
90
+ k_lwing >>
91
+ field.repeat.as(:message_body) >>
92
+ k_rwing
93
+ }
94
+
95
+ rule(:exception) {
96
+ k_exception >>
97
+ class_name.as(:exception_name) >>
98
+ lt_extend_class.maybe.as(:super_class) >>
99
+ k_lwing >>
100
+ field.repeat.as(:exception_body) >>
101
+ k_rwing
102
+ }
103
+
104
+
105
+ rule(:field) {
106
+ field_element >> eol
107
+ }
108
+
109
+ rule(:field_element) {
110
+ field_id.as(:field_id) >>
111
+ field_modifier.maybe.as(:field_modifier) >>
112
+ field_type.as(:field_type) >>
113
+ field_name.as(:field_name) >>
114
+ eq_value.maybe.as(:field_value)
115
+ }
116
+
117
+ rule(:field_id) {
118
+ # terminal
119
+ space? >>
120
+ (str('0') | (match('[1-9]') >> match('[0-9]').repeat)).as(:val_int) >>
121
+ str(':') >> str(':').absent?
122
+ }
123
+
124
+ rule(:field_modifier) {
125
+ k_optional.as(:val_optional) |
126
+ k_required.as(:val_required)
127
+ }
128
+
129
+
130
+ rule(:enum) {
131
+ k_enum >>
132
+ class_name.as(:enum_name) >>
133
+ k_lwing >>
134
+ enum_field.repeat.as(:enum_body) >>
135
+ k_rwing
136
+ }
137
+
138
+ rule(:enum_field) {
139
+ enum_field_element >> eol
140
+ }
141
+
142
+ rule(:enum_field_element) {
143
+ field_id.as(:enum_field_id) >> field_name.as(:enum_field_name)
144
+ }
145
+
146
+
147
+ rule(:service) {
148
+ k_service >>
149
+ service_name.as(:service_name) >>
150
+ service_version.maybe.as(:service_version) >>
151
+ k_lwing >>
152
+ func.repeat.as(:service_funcs) >>
153
+ k_rwing
154
+ }
155
+
156
+ rule(:service_version) {
157
+ # terminal
158
+ space? >> str(':') >> space? >>
159
+ (str('0') | (match('[1-9]') >> match('[0-9]').repeat)).as(:val_int)
160
+ }
161
+
162
+ rule(:func) {
163
+ return_type.as(:return_type) >>
164
+ func_name.as(:func_name) >>
165
+ k_lparen >>
166
+ func_args.as(:func_args) >>
167
+ k_rparen >>
168
+ throws_classes.maybe.as(:func_throws) >>
169
+ eol
170
+ }
171
+
172
+ sequence :func_args_seq, :k_comma, :field_element
173
+
174
+ rule(:func_args) {
175
+ func_args_seq
176
+ }
177
+
178
+ sequence :throws_classes_seq, :k_comma, :generic_type, 1
179
+
180
+ rule(:throws_classes) {
181
+ k_throws >> throws_classes_seq
182
+ }
183
+
184
+
185
+ rule(:application) {
186
+ k_application >>
187
+ service_name.as(:application_name) >>
188
+ k_lwing >>
189
+ scope.repeat.as(:application_body) >>
190
+ k_rwing
191
+ }
192
+
193
+ rule(:scope) {
194
+ service_name.as(:scope_service) >>
195
+ service_version.as(:scope_service_version) >>
196
+ field_name.as(:scope_name) >>
197
+ k_default.maybe.as(:scope_default) >>
198
+ eol
199
+ }
200
+
201
+
202
+ rule(:eq_value) {
203
+ k_equal >> literal
204
+ }
205
+
206
+ rule(:lt_extend_class) {
207
+ k_lpoint >> generic_type
208
+ }
209
+
210
+
211
+ rule(:field_type) {
212
+ generic_type.as(:field_type) >> k_question.maybe.as(:field_type_maybe)
213
+ }
214
+
215
+ rule(:return_type) {
216
+ field_type
217
+ }
218
+
219
+ rule(:generic_type) {
220
+ class_name.as(:generic_type) >> type_param.maybe.as(:type_params)
221
+ }
222
+
223
+ sequence :type_param_seq, :k_comma, :generic_type, 1
224
+
225
+ rule(:type_param) {
226
+ k_lpoint >> type_param_seq >> k_rpoint
227
+ }
228
+
229
+ sequence :type_param_decl_seq, :k_comma, :class_name, 1
230
+
231
+ rule(:type_param_decl) {
232
+ k_lpoint >> type_param_decl_seq >> k_rpoint
233
+ }
234
+
235
+
236
+ rule(:literal) {
237
+ literal_nil | literal_bool | literal_int |
238
+ literal_enum |
239
+ #literal_float | literal_str |
240
+ #literal_list | literal_map |
241
+ literal_const
242
+ }
243
+
244
+ rule(:literal_nil) {
245
+ k_nil.as(:literal_nil)
246
+ }
247
+
248
+ rule(:literal_bool) {
249
+ k_true.as(:literal_true) | k_false.as(:literal_false)
250
+ }
251
+
252
+ rule(:literal_const) {
253
+ const_name.as(:literal_const)
254
+ }
255
+
256
+ rule(:literal_enum) {
257
+ class_name.as(:literal_enum_name) >> str('.') >> field_name.as(:literal_enum_field)
258
+ }
259
+
260
+ rule(:literal_int) {
261
+ space? >> (
262
+ (str('-') | str('+')).maybe >>
263
+ (str('0') | (match('[1-9]') >> match('[0-9]').repeat))
264
+ ).as(:literal_int) >>
265
+ boundary
266
+ }
267
+
268
+ rule(:literal_float) {
269
+ space? >> (
270
+ (str('0') | (match('[1-9]') >> match('[0-9]').repeat)) >> str('.') >> match('[0-9]').repeat(1)
271
+ ).as(:literal_float) >>
272
+ boundary
273
+ }
274
+
275
+ rule(:literal_str_dq) {
276
+ space? >> str('"') >> (
277
+ (str('\\') >> any | str('"').absent? >> any ).repeat
278
+ ).as(:literal_str_dq) >>
279
+ str('"')
280
+ }
281
+
282
+ rule(:literal_str_sq) {
283
+ space? >> str("'") >> (
284
+ (str('\\') >> any | str("'").absent? >> any ).repeat
285
+ ).as(:literal_str_sq) >>
286
+ str("'")
287
+ }
288
+
289
+ rule(:literal_str) {
290
+ (literal_str_dq | literal_str_sq).repeat(1).as(:literal_str_seq)
291
+ }
292
+
293
+ #sequence :literal_list_seq, :k_comma, :literal
294
+ #
295
+ #rule(:literal_list) {
296
+ # space? >> k_lbracket >>
297
+ # literal_list_seq.as(:literal_list) >>
298
+ # k_rbracket
299
+ #}
300
+
301
+ #sequence :literal_map_seq, :k_comma, :literal_map_pair
302
+ #
303
+ #rule(:literal_map) {
304
+ # space? >> k_lwing >>
305
+ # literal_map_seq.as(:literal_map) >>
306
+ # k_rwing
307
+ #}
308
+ #
309
+ #rule(:literal_map_pair) {
310
+ # literal.as(:literal_map_key) >> k_colon >> literal.as(:literal_map_value)
311
+ #}
312
+
313
+
314
+ rule(:path) {
315
+ # TODO path
316
+ space? >> match('[a-zA-Z0-9_\-\.\ ]').repeat(1).as(:path) >> boundary
317
+ }
318
+
319
+ rule(:lang_name) {
320
+ name
321
+ }
322
+
323
+ rule(:namespace_name) {
324
+ (name >> ((str('.') | str('::')) >> name).repeat).as(:sequence)
325
+ }
326
+
327
+ rule(:class_name) {
328
+ name
329
+ }
330
+
331
+ rule(:field_name) {
332
+ name
333
+ }
334
+
335
+ rule(:service_name) {
336
+ class_name
337
+ }
338
+
339
+ rule(:func_name) {
340
+ field_name
341
+ }
342
+
343
+ rule(:name) {
344
+ # terminal
345
+ space? >> (match('[a-zA-Z]') >> match('[a-zA-Z0-9_]').repeat).as(:name) >> boundary
346
+ }
347
+
348
+
349
+ rule(:inline_comment) {
350
+ str('/*') >> (
351
+ inline_comment | # accepts nested comments
352
+ (str('*') >> str('/').absent?) |
353
+ (str('*').absent? >> any)
354
+ ).repeat >> str('*/')
355
+ }
356
+
357
+ rule(:line_comment) {
358
+ (str('//') | str('#')) >>
359
+ (match('[\r\n]').absent? >> any).repeat >>
360
+ match('[\r\n]').repeat(1)
361
+ }
362
+
363
+ rule(:comment) {
364
+ inline_comment | line_comment
365
+ }
366
+
367
+
368
+ rule(:space) {
369
+ (match('[ \r\n\t]') | comment).repeat(1)
370
+ }
371
+
372
+ rule(:space?) {
373
+ space.maybe
374
+ }
375
+
376
+ rule(:eol) {
377
+ match('[ \t]').repeat >>
378
+ (match('[ \t;\r\n]') | line_comment).repeat(1)
379
+ }
380
+
381
+ rule(:boundary) {
382
+ match('[a-zA-Z0-9_]').absent?
383
+ }
384
+
385
+
386
+ keyword('include')
387
+ keyword('namespace')
388
+ keyword('message')
389
+ keyword('enum')
390
+ keyword('exception')
391
+ keyword('const')
392
+ keyword('typedef')
393
+ keyword('typespec')
394
+ keyword('service')
395
+ keyword('application')
396
+ keyword('optional')
397
+ keyword('required')
398
+ keyword('obsolete')
399
+ keyword('throws')
400
+ keyword('default')
401
+ keyword('nil')
402
+ keyword('true')
403
+ keyword('false')
404
+ keyword('void')
405
+
406
+ separator('=', :k_equal)
407
+ separator('{', :k_lwing)
408
+ separator('}', :k_rwing)
409
+ separator('(', :k_lparen)
410
+ separator(')', :k_rparen)
411
+ separator(':', :k_colon)
412
+ separator(',', :k_comma)
413
+ separator(';', :k_semi)
414
+ separator('<', :k_lpoint)
415
+ separator('>', :k_rpoint)
416
+ separator('[', :k_lbracket)
417
+ separator(']', :k_rbracket)
418
+ separator('-', :k_minus)
419
+ separator('+', :k_plus)
420
+ separator('!', :k_bang)
421
+ separator('?', :k_question)
422
+ separator('.', :k_dot)
423
+
424
+ LINE_HEAD_FORMAT = " % 4d: "
425
+ LINE_HEAD_SIZE = (LINE_HEAD_FORMAT % 0).size
426
+ AFTER_BUFFER = 200
427
+ AFTER_LINES = 3
428
+ BEFORE_BUFFER = 200
429
+ BEFORE_LINES = 4
430
+
431
+ def print_error(error, fname, out=STDERR)
432
+ error_tree = self.root.error_tree
433
+
434
+ last = error_tree
435
+ until last.children.empty?
436
+ last = last.children.last
437
+ end
438
+ last_cause = last.parslet.instance_eval('@last_cause') # FIXME
439
+ source = last_cause.source
440
+
441
+ row, col = source.line_and_column(last_cause.pos)
442
+
443
+ old_pos = source.pos
444
+ begin
445
+ source.pos = last_cause.pos - col + 1
446
+ line, *after = source.read(AFTER_BUFFER).to_s.split("\n")
447
+ after = after[0,AFTER_LINES]
448
+
449
+ source.pos = last_cause.pos - col - BEFORE_BUFFER
450
+ before = source.read(BEFORE_BUFFER).to_s.split("\n")
451
+ before = before[-BEFORE_LINES,BEFORE_LINES] || []
452
+ ensure
453
+ source.pos = old_pos
454
+ end
455
+
456
+ if m = /[ \t\r\n]*/.match(line)
457
+ heading = m[0]
458
+ else
459
+ heading = ""
460
+ end
461
+
462
+ out.puts "syntax error:"
463
+ (
464
+ error.to_s.split("\n") +
465
+ error_tree.to_s.split("\n")
466
+ ).each {|ln|
467
+ out.puts " "+ln
468
+ }
469
+
470
+ out.puts ""
471
+ out.puts "around line #{row} column #{heading.size}-#{col}:"
472
+ out.puts ""
473
+
474
+ before.each_with_index {|ln,i|
475
+ l = row - after.size - 1 + i
476
+ out.print LINE_HEAD_FORMAT % l
477
+ out.puts ln
478
+ }
479
+
480
+ out.print LINE_HEAD_FORMAT % row
481
+ out.puts line
482
+ out.print " "*LINE_HEAD_SIZE
483
+ out.puts heading + '^'*(col - heading.size)
484
+
485
+ after.each_with_index {|ln,i|
486
+ l = row + 1 + i
487
+ out.print LINE_HEAD_FORMAT % l
488
+ out.puts ln
489
+ }
490
+
491
+ out.puts ""
492
+
493
+ out
494
+ end
495
+ end
496
+
497
+
498
+ end
499
+ end