rubyang 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,44 @@
1
+ # coding: utf-8
2
+
3
+ require 'json'
4
+ require 'rexml/document'
5
+
6
+ def json_to_xml( json_str )
7
+ hash = JSON.parse( json_str )
8
+ if hash.keys.size > 1
9
+ raise 'root key size must be 1'
10
+ end
11
+ #doc_xml = REXML::Document.new( "<#{hash.keys.first} />" )
12
+ doc_xml = REXML::Document.new
13
+ json_to_xml_recursive( hash.keys.first, hash.values.first, doc_xml )
14
+ return doc_xml.to_s
15
+ end
16
+
17
+ def json_to_xml_recursive( _key, _value, _doc_xml )
18
+ doc_xml = _doc_xml.add_element( _key )
19
+ case _value
20
+ when Hash
21
+ _value.each{ |key, value|
22
+ case value
23
+ when Hash
24
+ json_to_xml_recursive( key, value, doc_xml )
25
+ when Array
26
+ value.each{ |hash|
27
+ json_to_xml_recursive( key, hash, doc_xml )
28
+ }
29
+ else
30
+ doc_xml.add_element( key ).add_text value
31
+ end
32
+ }
33
+ else
34
+ raise "case value when other than Hash is not implemented"
35
+ end
36
+ end
37
+
38
+
39
+ if __FILE__ == $0
40
+ json_str = '{"config": {"a": [{"b1": {"c1": "c1"}}, {"b2": {"c2": "c2"}}]}}'
41
+ puts json_to_xml( json_str )
42
+ json_str = '{"config":{"leaf1":"0"}}'
43
+ puts json_to_xml( json_str )
44
+ end
@@ -0,0 +1,1060 @@
1
+ # coding: utf-8
2
+
3
+ require 'json'
4
+ require 'base64'
5
+
6
+ require_relative '../model'
7
+ require_relative '../xpath'
8
+
9
+ module Rubyang
10
+ class Database
11
+ class SchemaTree
12
+ class Type
13
+ attr_reader :arg
14
+ end
15
+ class IntegerType < Type
16
+ def initialize arg
17
+ @arg = arg
18
+ range = case arg
19
+ when 'int8' then '-128..127'
20
+ when 'int16' then '-32768..32767'
21
+ when 'int32' then '-2147483648..2147483647'
22
+ when 'int64' then '-9223372036854775808..9223372036854775807'
23
+ when 'uint8' then '0..255'
24
+ when 'uint16' then '0..65535'
25
+ when 'uint32' then '0..4294967295'
26
+ when 'uint64' then '0..18446744073709551615'
27
+ end
28
+ @range = Range.new range
29
+ end
30
+ def update_range arg
31
+ @range.update arg
32
+ end
33
+ def valid? value
34
+ result = true
35
+ result &&= @range.valid? value
36
+ result
37
+ end
38
+ end
39
+ class StringType < Type
40
+ attr_reader :length, :pattern
41
+ def initialize
42
+ @arg = 'string'
43
+ @length = Length.new
44
+ @pattern = Pattern.new
45
+ end
46
+ def update_length arg
47
+ @length.update arg
48
+ end
49
+ def update_pattern arg
50
+ @pattern.update arg
51
+ end
52
+ def valid? value
53
+ result = true
54
+ result &&= @length.valid? value
55
+ result &&= @pattern.valid? value
56
+ result
57
+ end
58
+ end
59
+ class BooleanType < Type
60
+ def initialize
61
+ @arg = 'boolean'
62
+ end
63
+ def valid? value
64
+ if 'true' == value
65
+ true
66
+ elsif 'false' == value
67
+ true
68
+ else
69
+ false
70
+ end
71
+ end
72
+ end
73
+ class EnumerationType < Type
74
+ def initialize
75
+ @arg = 'enumeration'
76
+ @enum = Enum.new
77
+ end
78
+ def update_enum arg
79
+ @enum.update arg
80
+ end
81
+ def valid? value
82
+ result = true
83
+ result &&= @enum.valid? value
84
+ result
85
+ end
86
+ end
87
+ class BitsType < Type
88
+ def initialize
89
+ @arg = 'bits'
90
+ @bit = Bit.new
91
+ end
92
+ def update_bit arg
93
+ @bit.update arg
94
+ end
95
+ def valid? value
96
+ result = true
97
+ result &&= @bit.valid? value
98
+ result
99
+ end
100
+ end
101
+ class BinaryType < Type
102
+ def initialize
103
+ @arg = 'binary'
104
+ @length = Length.new
105
+ end
106
+ def update_length arg
107
+ @length.update arg
108
+ end
109
+ def valid? value
110
+ result = true
111
+ result &&= @length.valid? Base64.strict_decode64( value )
112
+ result
113
+ end
114
+ end
115
+ class LeafrefType < Type
116
+ def initialize interior_schema_node, path_arg
117
+ @arg = 'leafref'
118
+ @path_arg = path_arg
119
+ @path = Path.new interior_schema_node, path_arg
120
+ end
121
+ def path
122
+ @path_arg
123
+ @path.path
124
+ end
125
+ def valid? data_tree, value
126
+ result = true
127
+ result &&= @path.valid? data_tree, true
128
+ result
129
+ end
130
+ end
131
+
132
+ class Path
133
+ attr_reader :path
134
+
135
+ def initialize interior_schema_node, arg
136
+ @path = Rubyang::Xpath::Parser.parse arg
137
+ if !(@path[0].axis.name == Rubyang::Xpath::Axis::PARENT && @path[0].node_test.node_test == Rubyang::Xpath::NodeTest::NodeType::NODE)
138
+ raise "unsupported path: #{@path}"
139
+ end
140
+ target = interior_schema_node.evaluate_xpath( @path[1..-1] )
141
+ if target.size == 0
142
+ raise ArgumentError, "#{arg} is not valid"
143
+ end
144
+ @target = target
145
+ end
146
+ def valid? data_tree, value
147
+ true
148
+ end
149
+ end
150
+ class Range
151
+ def initialize arg
152
+ @range = [[-Float::INFINITY, Float::INFINITY]]
153
+ self.update arg
154
+ end
155
+ def valid? value
156
+ if @range.find{ |min2, max2| (min2..max2).include?( value.to_i ) }
157
+ true
158
+ else
159
+ false
160
+ end
161
+ end
162
+ def update arg
163
+ new_range = Array.new
164
+ arg.gsub( ' ', '' ).split( '|' ).each{ |range_part|
165
+ case range_part
166
+ when /[^\.]+\.\.[^\.]+/
167
+ min, max = range_part.split('..')
168
+ else
169
+ min = max = range_part
170
+ end
171
+ case min
172
+ when /^min$/
173
+ min = @range.map{ |r| r[0] }.min
174
+ else
175
+ min = min.to_i
176
+ end
177
+ case max
178
+ when /^max$/
179
+ max = @range.map{ |r| r[1] }.max
180
+ else
181
+ max = max.to_i
182
+ end
183
+ unless @range.find{ |min2, max2| (min2..max2).include?( min ) && (min2..max2).include?( max ) }
184
+ raise ArgumentError, "#{range_part} is not valid"
185
+ end
186
+ new_range.push [min, max]
187
+ }
188
+ @range = new_range
189
+ end
190
+ def to_s
191
+ @range.map{ |l| "#{l[0]}..#{l[1]}" }.join( "|" )
192
+ end
193
+ end
194
+ class Length
195
+ def initialize
196
+ @length = [[0, 18446744073709551615]]
197
+ end
198
+ def valid? value
199
+ if @length.find{ |min2, max2| (min2..max2).include?( value.size ) }
200
+ true
201
+ else
202
+ false
203
+ end
204
+ end
205
+ def update arg
206
+ new_length = Array.new
207
+ arg.gsub( ' ', '' ).split( '|' ).each{ |length_part|
208
+ case length_part
209
+ when /[^\.]+\.\.[^\.]+/
210
+ min, max = length_part.split('..')
211
+ else
212
+ min = max = length_part
213
+ end
214
+ case min
215
+ when /^min$/
216
+ min = @length.map{ |r| r[0] }.min
217
+ else
218
+ min = min.to_i
219
+ end
220
+ case max
221
+ when /^max$/
222
+ max = @length.map{ |r| r[1] }.max
223
+ else
224
+ max = max.to_i
225
+ end
226
+ unless @length.find{ |min2, max2| (min2..max2).include?( min ) && (min2..max2).include?( max ) }
227
+ raise ArgumentError, "#{length_part} is not valid"
228
+ end
229
+ new_length.push [min, max]
230
+ }
231
+ @length = new_length
232
+ end
233
+ def to_s
234
+ @length.map{ |l| "#{l[0]}..#{l[1]}" }.join( "|" )
235
+ end
236
+ end
237
+ class Pattern
238
+ def initialize
239
+ @pattern = Regexp.new( '.*' )
240
+ end
241
+ def valid? value
242
+ if @pattern =~ value
243
+ true
244
+ else
245
+ false
246
+ end
247
+ end
248
+ def update arg
249
+ @pattern = Regexp.new( arg )
250
+ end
251
+ def to_s
252
+ @pattern.inspect
253
+ end
254
+ end
255
+ class Enum
256
+ def initialize
257
+ @enum = []
258
+ end
259
+ def valid? value
260
+ if @enum.find{ |e| e == value }
261
+ true
262
+ else
263
+ false
264
+ end
265
+ end
266
+ def update arg
267
+ if @enum.find{ |e| e == arg }
268
+ raise ArgumentError, "#{arg} is not valid"
269
+ end
270
+ @enum.push arg
271
+ end
272
+ end
273
+ class Bit
274
+ def initialize
275
+ @bit = []
276
+ end
277
+ def valid? value
278
+ values = value.split( ' ' )
279
+ if values.inject( true ){ |result, v| result && @bit.find{ |b| b == v } }
280
+ true
281
+ else
282
+ false
283
+ end
284
+ end
285
+ def update arg
286
+ if @bit.find{ |b| b == arg }
287
+ raise ArgumentError, "#{arg} is not valid"
288
+ end
289
+ @bit.push arg
290
+ end
291
+ end
292
+
293
+ class SchemaNode
294
+ attr_accessor :yangs, :arg, :yang, :parent, :module
295
+ def initialize yangs, arg, yang, parent, _module
296
+ @yangs = yangs
297
+ @arg = arg
298
+ @yang = yang
299
+ @parent = parent
300
+ @module = _module
301
+ end
302
+ def model
303
+ @yang
304
+ end
305
+ def namespace
306
+ @module.substmt( 'namespace' )[0].arg
307
+ end
308
+ def prefix
309
+ @module.substmt( 'prefix' )[0].arg
310
+ end
311
+ def root
312
+ if @parent == nil
313
+ self
314
+ else
315
+ @parent.root
316
+ end
317
+ end
318
+ def to_json
319
+ h = Hash.new
320
+ self.to_json_recursive( h )
321
+ h.to_json
322
+ end
323
+ def evaluate_xpath location_steps, current=self
324
+ location_step = location_steps.first
325
+ candidates_by_axis = self.evaluate_xpath_axis( location_step, current )
326
+ candidates_by_node_test = candidates_by_axis.inject([]){ |cs, c| cs + c.evaluate_xpath_node_test( location_step, current ) }
327
+ candidates_by_predicates = candidates_by_node_test.inject([]){ |cs, c| cs + c.evaluate_xpath_predicates( location_step, current ) }
328
+ if location_steps[1..-1].size == 0
329
+ candidates_by_predicates
330
+ else
331
+ candidates_by_predicates.inject([]){ |cs, c| c.evaluate_xpath( location_steps[1..-1], current ) }
332
+ end
333
+ end
334
+ def evaluate_xpath_axis location_step, current
335
+ case location_step.axis.name
336
+ when Rubyang::Xpath::Axis::PARENT
337
+ [@parent]
338
+ when Rubyang::Xpath::Axis::CHILD
339
+ @children
340
+ else
341
+ raise "location_step.axis.name: #{location_step.axis.name} NOT implemented"
342
+ end
343
+ end
344
+ def evaluate_xpath_node_test location_step, current
345
+ case location_step.node_test.node_test_type
346
+ when Rubyang::Xpath::NodeTest::NodeTestType::NAME_TEST
347
+ if self.model.arg == location_step.node_test.node_test
348
+ [self]
349
+ else
350
+ []
351
+ end
352
+ when Rubyang::Xpath::NodeTest::NodeTestType::NODE_TYPE
353
+ case location_step.node_test.node_test
354
+ when Rubyang::Xpath::NodeTest::NodeType::COMMENT
355
+ raise "node-type: comment is not implemented"
356
+ when Rubyang::Xpath::NodeTest::NodeType::TEXT
357
+ raise "node-type: text is not implemented"
358
+ when Rubyang::Xpath::NodeTest::NodeType::NODE
359
+ [self]
360
+ else
361
+ raise "node-type not match to comment or text or node"
362
+ end
363
+ when Rubyang::Xpath::NodeTest::NodeTestType::PROCESSING_INSTRUCTION
364
+ raise "processing-instruction is not implemented"
365
+ else
366
+ raise ""
367
+ end
368
+ end
369
+ def evaluate_xpath_predicates location_step, current
370
+ case location_step.predicates.size
371
+ when 0
372
+ [self]
373
+ else
374
+ location_step.predicates.inject([]){ |cs, predicate|
375
+ self.evaluate_xpath_predicate_expr predicate.expr, current
376
+ }
377
+ end
378
+ end
379
+ def evaluate_xpath_predicate_expr expr, current
380
+ case expr
381
+ when Rubyang::Xpath::Predicate::OrExpr
382
+ if Rubyang::Xpath::Parser::DEBUG
383
+ puts
384
+ puts "in OrExpr"
385
+ puts "op1: #{expr.op1}"
386
+ puts "op2: #{expr.op2}"
387
+ puts
388
+ end
389
+ op1 = expr.op1
390
+ op2 = expr.op2
391
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
392
+ if op2 == nil
393
+ op1_result
394
+ else
395
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
396
+ op1_result | op2_result
397
+ end
398
+ when Rubyang::Xpath::Predicate::AndExpr
399
+ if Rubyang::Xpath::Parser::DEBUG
400
+ puts
401
+ puts "in AndExpr"
402
+ puts "op1: #{expr.op1}"
403
+ puts "op2: #{expr.op2}"
404
+ puts
405
+ end
406
+ op1 = expr.op1
407
+ op2 = expr.op2
408
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
409
+ if op2 == nil
410
+ op1_result
411
+ else
412
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
413
+ op1_result & op2_result
414
+ end
415
+ when Rubyang::Xpath::Predicate::EqualityExpr
416
+ if Rubyang::Xpath::Parser::DEBUG
417
+ puts
418
+ puts "in EqualityExpr"
419
+ puts "op1: #{expr.op1}"
420
+ puts "op2: #{expr.op2}"
421
+ puts "operator: #{expr.operator}"
422
+ puts
423
+ end
424
+ op1 = expr.op1
425
+ op2 = expr.op2
426
+ operator = expr.operator
427
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
428
+ if op2 == nil
429
+ op1_result
430
+ else
431
+ case operator
432
+ when /^\=$/
433
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
434
+ if op1_result.size > 0 and op2_result.size >0
435
+ [self]
436
+ else
437
+ []
438
+ end
439
+ #op1_result.select{ |a| op2_result.map{ |b| b.value }.include? a }
440
+ when /^\!\=$/
441
+ raise "Equality Expr: '!=' not implemented"
442
+ else
443
+ raise "Equality Expr: other than '=' and '!=' not implemented"
444
+ end
445
+ end
446
+ when Rubyang::Xpath::Predicate::RelationalExpr
447
+ if Rubyang::Xpath::Parser::DEBUG
448
+ puts
449
+ puts "in RelationalExpr"
450
+ puts "op1: #{expr.op1}"
451
+ puts "op2: #{expr.op2}"
452
+ puts "operator: #{expr.operator}"
453
+ puts
454
+ end
455
+ op1 = expr.op1
456
+ op2 = expr.op2
457
+ operator = expr.operator
458
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
459
+ if op2 == nil
460
+ op1_result
461
+ else
462
+ case operator
463
+ when /^\>$/
464
+ raise "Relational Expr: '>' not implemented"
465
+ when /^\<$/
466
+ raise "Relational Expr: '<' not implemented"
467
+ when /^\>\=$/
468
+ raise "Relational Expr: '>=' not implemented"
469
+ when /^\<\=$/
470
+ raise "Relational Expr: '<=' not implemented"
471
+ else
472
+ raise "Relational Expr: other than '>', '<', '>=' and '<=' not implemented"
473
+ end
474
+ end
475
+ when Rubyang::Xpath::Predicate::AdditiveExpr
476
+ if Rubyang::Xpath::Parser::DEBUG
477
+ puts
478
+ puts "in AdditiveExpr"
479
+ puts "op1: #{expr.op1}"
480
+ puts "op2: #{expr.op2}"
481
+ puts "operator: #{expr.operator}"
482
+ puts
483
+ end
484
+ op1 = expr.op1
485
+ op2 = expr.op2
486
+ operator = expr.operator
487
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
488
+ if op2 == nil
489
+ op1_result
490
+ else
491
+ case operator
492
+ when /^\+$/
493
+ raise "Additive Expr: '+' not implemented"
494
+ when /^\-$/
495
+ raise "Additive Expr: '-' not implemented"
496
+ else
497
+ raise "Additive Expr: other than '+' and '-' not implemented"
498
+ end
499
+ end
500
+ when Rubyang::Xpath::Predicate::MultiplicativeExpr
501
+ if Rubyang::Xpath::Parser::DEBUG
502
+ puts
503
+ puts "in MultiplicativeExpr"
504
+ puts "op1: #{expr.op1}"
505
+ puts "op2: #{expr.op2}"
506
+ puts "operator: #{expr.operator}"
507
+ puts
508
+ end
509
+ op1 = expr.op1
510
+ op2 = expr.op2
511
+ operator = expr.operator
512
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
513
+ if op2 == nil
514
+ op1_result
515
+ else
516
+ case operator
517
+ when /^\*$/
518
+ raise "Multiplicative Expr: '*' not implemented"
519
+ when /^\/$/
520
+ raise "Multiplicative Expr: '/' not implemented"
521
+ else
522
+ raise "Multiplicative Expr: other than '*' and '/' not implemented"
523
+ end
524
+ end
525
+ when Rubyang::Xpath::Predicate::UnaryExpr
526
+ if Rubyang::Xpath::Parser::DEBUG
527
+ puts
528
+ puts "in UnaryExpr"
529
+ puts "op1: #{expr.op1}"
530
+ puts "operator: #{expr.operator}"
531
+ puts
532
+ end
533
+ op1 = expr.op1
534
+ operator = expr.operator
535
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
536
+ case operator
537
+ when nil
538
+ op1_result
539
+ when /^\-$/
540
+ raise "Unary Expr: '-' not implemented"
541
+ else
542
+ raise "Unary Expr: other than '-' not implemented"
543
+ end
544
+ when Rubyang::Xpath::Predicate::UnionExpr
545
+ if Rubyang::Xpath::Parser::DEBUG
546
+ puts
547
+ puts "in UnionExpr"
548
+ puts "op1: #{expr.op1}"
549
+ puts "op2: #{expr.op2}"
550
+ puts "operator: #{expr.operator}"
551
+ puts
552
+ end
553
+ op1 = expr.op1
554
+ op2 = expr.op2
555
+ operator = expr.operator
556
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
557
+ if op2 == nil
558
+ op1_result
559
+ else
560
+ case operator
561
+ when /^\|$/
562
+ raise "Union Expr: '|' not implemented"
563
+ else
564
+ raise "Union Expr: other than '|' not implemented"
565
+ end
566
+ end
567
+ when Rubyang::Xpath::Predicate::PathExpr
568
+ if Rubyang::Xpath::Parser::DEBUG
569
+ puts
570
+ puts "in PathExpr"
571
+ puts "op1: #{expr.op1}"
572
+ puts "op2: #{expr.op2}"
573
+ puts "operator: #{expr.operator}"
574
+ puts
575
+ end
576
+ op1 = expr.op1
577
+ op2 = expr.op2
578
+ operator = expr.operator
579
+ case op1
580
+ when Rubyang::Xpath::LocationSteps
581
+ op1_result = self.evaluate_xpath( op1, current )
582
+ when Rubyang::Xpath::Predicate::FilterExpr
583
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
584
+ if op2 == nil
585
+ op1_result
586
+ else
587
+ case operator
588
+ when /^\/$/
589
+ case op2
590
+ when Rubyang::Xpath::LocationSteps
591
+ if !(op2[0].axis.name == Rubyang::Xpath::Axis::PARENT &&
592
+ op2[0].node_test.node_test == Rubyang::Xpath::NodeTest::NodeType::NODE)
593
+ raise "unsupported path: #{op2}"
594
+ end
595
+ current.evaluate_xpath (op1_result + op2[1..-1]), current
596
+ else
597
+ raise "Path Expr: op1 is not LocationSteps"
598
+ end
599
+ when /^\/\/$/
600
+ raise "Path Expr: '//' not implemented"
601
+ else
602
+ raise "Path Expr: other than '/' and '//' not implemented"
603
+ end
604
+ end
605
+ else
606
+ raise ""
607
+ end
608
+ when Rubyang::Xpath::Predicate::FilterExpr
609
+ if Rubyang::Xpath::Parser::DEBUG
610
+ puts
611
+ puts "in FilterExpr"
612
+ puts "op1: #{expr.op1}"
613
+ puts "op2: #{expr.op2}"
614
+ puts
615
+ end
616
+ op1 = expr.op1
617
+ op2 = expr.op2
618
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
619
+ if op2 == nil
620
+ op1_result
621
+ else
622
+ op2_result = self.evaluate_xpath_predicate_expr( op2.expr, current )
623
+ raise "Filter Expr: Filter Predicate not implemented"
624
+ end
625
+ when Rubyang::Xpath::Predicate::PrimaryExpr
626
+ if Rubyang::Xpath::Parser::DEBUG
627
+ puts
628
+ puts "in PrimaryExpr"
629
+ puts "op1: #{expr.op1}"
630
+ puts
631
+ end
632
+ op1 = expr.op1
633
+ case op1
634
+ when Rubyang::Xpath::Predicate::Expr
635
+ raise "Primary Expr: '( Expr )' not implemented"
636
+ when Rubyang::Xpath::Predicate::FunctionCall
637
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
638
+ when /^\$.*$/
639
+ raise "Primary Expr: 'Variable Reference' not implemented"
640
+ else
641
+ raise "Primary Expr: 'Literal' and 'Number' not implemented"
642
+ end
643
+ when Rubyang::Xpath::Predicate::FunctionCall
644
+ if Rubyang::Xpath::Parser::DEBUG
645
+ puts
646
+ puts "in FunctionCall"
647
+ puts "name: #{expr.name}"
648
+ puts "args: #{expr.args}"
649
+ puts
650
+ end
651
+ name = expr.name
652
+ case name
653
+ when Rubyang::Xpath::Predicate::FunctionCall::CURRENT
654
+ Rubyang::Xpath::LocationSteps.new
655
+ else
656
+ raise "FunctionCall: #{name} not implemented"
657
+ end
658
+ else
659
+ raise "Unrecognized predicate: #{predicate}"
660
+ end
661
+ end
662
+ end
663
+
664
+ class InteriorSchemaNode < SchemaNode
665
+ attr_accessor :yangs, :arg, :yang, :parent, :children
666
+
667
+ def initialize yangs, arg, yang, parent, _module
668
+ super yangs, arg, yang, parent, _module
669
+ @children = []
670
+ end
671
+
672
+ def resolve_type type_stmt, yangs, current_module, typedef_list
673
+ case type_stmt.arg
674
+ when 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'
675
+ type = IntegerType.new type_stmt.arg
676
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
677
+ case s
678
+ when Rubyang::Model::Range
679
+ type.update_range s.arg
680
+ else
681
+ raise ArgumentError, "#{s} is not valid"
682
+ end
683
+ }
684
+ when 'string'
685
+ type = StringType.new
686
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
687
+ case s
688
+ when Rubyang::Model::Length
689
+ type.update_length s.arg
690
+ when Rubyang::Model::Pattern
691
+ type.update_pattern s.arg
692
+ else
693
+ raise ArgumentError, "#{s} is not valid"
694
+ end
695
+ }
696
+ when 'boolean'
697
+ type = BooleanType.new
698
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
699
+ raise ArgumentError, "#{s} is not valid"
700
+ }
701
+ when 'enumeration'
702
+ type = EnumerationType.new
703
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
704
+ case s
705
+ when Rubyang::Model::Enum
706
+ type.update_enum s.arg
707
+ else
708
+ raise ArgumentError, "#{s} is not valid"
709
+ end
710
+ }
711
+ when 'bits'
712
+ type = BitsType.new
713
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
714
+ case s
715
+ when Rubyang::Model::Bit
716
+ type.update_bit s.arg
717
+ else
718
+ raise ArgumentError, "#{s} is not valid"
719
+ end
720
+ }
721
+ when 'binary'
722
+ type = BinaryType.new
723
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
724
+ case s
725
+ when Rubyang::Model::Length
726
+ type.update_length s.arg
727
+ else
728
+ raise ArgumentError, "#{s} is not valid"
729
+ end
730
+ }
731
+ when 'leafref'
732
+ type = LeafrefType.new self, type_stmt.substmt( 'path' )[0].arg
733
+ else
734
+ case type_stmt.arg
735
+ when /^[^:]+$/
736
+ arg = type_stmt.arg
737
+ if typedef_list.find{ |s| s.arg == arg }
738
+ typedef_stmt = typedef_list.find{ |s| s.arg == arg }
739
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, current_module, typedef_list
740
+ else
741
+ include_submodule = current_module.substmt( 'include' ).map{ |s|
742
+ yangs.find{ |y| y.arg == s.arg }
743
+ }.find{ |s|
744
+ s.substmt( 'typedef' ).find{ |t| t.arg == arg }
745
+ }
746
+ typedef_stmt = include_submodule.substmt( 'typedef' ).find{ |s| s.arg == arg }
747
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, include_submodule, include_submodule.substmt( 'typedef' )
748
+ end
749
+ when /^[^:]+:[^:]+$/
750
+ prefix, arg = type_stmt.arg.split(':')
751
+ case current_module
752
+ when Rubyang::Model::Module
753
+ case prefix
754
+ when current_module.substmt( 'prefix' )[0].arg
755
+ typedef_stmt = typedef_list.find{ |s| s.arg == arg }
756
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, current_module, typedef_list
757
+ else
758
+ import_module = yangs.find{ |y|
759
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
760
+ }
761
+ typedef_stmt = import_module.substmt( 'typedef' ).find{ |s| s.arg == arg }
762
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, import_module, import_module.substmt( 'typedef' )
763
+ end
764
+ when Rubyang::Model::Submodule
765
+ case prefix
766
+ when current_module.substmt( 'belongs-to' )[0].substmt( 'prefix' )[0].arg
767
+ typedef_stmt = typedef_list.find{ |s| s.arg == arg }
768
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, current_module, typedef_list
769
+ else
770
+ import_module = yangs.find{ |y|
771
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
772
+ }
773
+ typedef_stmt = import_module.substmt( 'typedef' ).find{ |s| s.arg == arg }
774
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, import_module, import_module.substmt( 'typedef' )
775
+ end
776
+ else
777
+ raise
778
+ end
779
+ end
780
+ end
781
+ type
782
+ end
783
+
784
+ def load_yang yang, yangs=@yangs, parent_module=yang, current_module=yang, grouping_list=[], typedef_list=[]
785
+ case yang
786
+ when Rubyang::Model::Module
787
+ yangs.push yang
788
+ module_arg = yang.arg
789
+ namespace_arg = yang.substmt( 'namespace' )[0].arg
790
+ prefix_arg = yang.substmt( 'prefix' )[0].arg
791
+ grouping_list += yang.substmt( 'grouping' )
792
+ typedef_list += yang.substmt( 'typedef' )
793
+ yang.substmt( 'include' ).each{ |i|
794
+ i.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
795
+ self.load_yang s, yangs, parent_module, i, i.substmt( 'grouping' ), i.substmt( 'typedef' )
796
+ }
797
+ }
798
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
799
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
800
+ }
801
+ when Rubyang::Model::Submodule
802
+ yangs.push yang
803
+ when Rubyang::Model::Container
804
+ container_arg = yang.arg
805
+ grouping_list += yang.substmt( 'grouping' )
806
+ typedef_list += yang.substmt( 'typedef' )
807
+ self.children.push Container.new( yangs, container_arg, yang, self, parent_module )
808
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
809
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
810
+ }
811
+ when Rubyang::Model::Leaf
812
+ leaf_arg = yang.arg
813
+ type = self.resolve_type yang.substmt( 'type' )[0], yangs, current_module, typedef_list
814
+ self.children.push Leaf.new( yangs, leaf_arg, yang, self, parent_module, type )
815
+ when Rubyang::Model::LeafList
816
+ leaf_arg = yang.arg
817
+ type = self.resolve_type yang.substmt( 'type' )[0], yangs, current_module, typedef_list
818
+ self.children.push LeafList.new( yangs, leaf_arg, yang, self, parent_module, type )
819
+ when Rubyang::Model::List
820
+ list_arg = yang.arg
821
+ grouping_list += yang.substmt( 'grouping' )
822
+ typedef_list += yang.substmt( 'typedef' )
823
+ self.children.push List.new( yangs, list_arg, yang, self, parent_module )
824
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
825
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
826
+ }
827
+ when Rubyang::Model::Choice
828
+ choice_arg = yang.arg
829
+ grouping_list += yang.substmt( 'grouping' )
830
+ typedef_list += yang.substmt( 'typedef' )
831
+ self.children.push Choice.new( yangs, choice_arg, yang, self, parent_module )
832
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
833
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
834
+ }
835
+ when Rubyang::Model::Case
836
+ case_arg = yang.arg
837
+ grouping_list += yang.substmt( 'grouping' )
838
+ typedef_list += yang.substmt( 'typedef' )
839
+ self.children.push Case.new( yangs, case_arg, yang, self, parent_module )
840
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
841
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
842
+ }
843
+ when Rubyang::Model::Augment
844
+ target_node = self.resolve_node( yang.arg )
845
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
846
+ target_node.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
847
+ }
848
+ when Rubyang::Model::Uses
849
+ self.resolve_uses( yang, yangs, parent_module, current_module, grouping_list, typedef_list )
850
+ end
851
+ end
852
+
853
+ def resolve_uses uses_stmt, yangs, parent_module, current_module, grouping_list, typedef_list
854
+ case uses_stmt.arg
855
+ when /^[^:]+$/
856
+ arg = uses_stmt.arg
857
+ if grouping_list.find{ |s| s.arg == arg }
858
+ grouping_stmt = grouping_list.find{ |s| s.arg == arg }
859
+ grouping_list += grouping_stmt.substmt( 'grouping' )
860
+ typedef_list += grouping_stmt.substmt( 'typedef' )
861
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
862
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
863
+ }
864
+ else
865
+ include_submodule = current_module.substmt( 'include' ).map{ |s|
866
+ yangs.find{ |y| y.arg == s.arg }
867
+ }.find{ |s|
868
+ s.substmt( 'grouping' ).find{ |t| t.arg == arg }
869
+ }
870
+ grouping_stmt = include_submodule.substmt( 'grouping' ).find{ |s| s.arg == arg }
871
+ grouping_list = include_submodule.substmt( 'grouping' ) + grouping_stmt.substmt( 'grouping' )
872
+ typedef_list = include_submodule.substmt( 'typedef' ) + grouping_stmt.substmt( 'typedef' )
873
+ grouping_stmt.substmt( Rubyang::Model::DataDefStmtList ).each{ |s|
874
+ self.load_yang s, yangs, parent_module, include_submodule, grouping_list, typedef_list
875
+ }
876
+ end
877
+ when /^[^:]+:[^:]+$/
878
+ prefix, arg = uses_stmt.arg.split(':')
879
+ case current_module
880
+ when Rubyang::Model::Module
881
+ case prefix
882
+ when current_module.substmt( 'prefix' )[0].arg
883
+ grouping_stmt = grouping_list.find{ |s| s.arg == arg }
884
+ grouping_list += grouping_stmt.substmt( 'grouping' )
885
+ typedef_list += grouping_stmt.substmt( 'typedef' )
886
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
887
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
888
+ }
889
+ else
890
+ import_module = yangs.find{ |y|
891
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
892
+ }
893
+ grouping_stmt = import_module.substmt( 'grouping' ).find{ |s| s.arg == arg }
894
+ grouping_list = import_module.substmt( 'grouping' ) + grouping_stmt.substmt( 'grouping' )
895
+ typedef_list = import_module.substmt( 'typedef' ) + grouping_stmt.substmt( 'typedef' )
896
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
897
+ self.load_yang s, yangs, parent_module, import_module, grouping_list, typedef_list
898
+ }
899
+ end
900
+ when Rubyang::Model::Submodule
901
+ case prefix
902
+ when current_module.substmt( 'belongs-to' )[0].substmt( 'prefix' )[0].arg
903
+ grouping_stmt = grouping_list.find{ |s| s.arg == arg }
904
+ grouping_list += grouping_stmt.substmt( 'grouping' )
905
+ typedef_list += grouping_stmt.substmt( 'typedef' )
906
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
907
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
908
+ }
909
+ else
910
+ import_module = yangs.find{ |y|
911
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
912
+ }
913
+ grouping_stmt = import_module.substmt( 'grouping' ).find{ |s| s.arg == arg }
914
+ grouping_list = import_module.substmt( 'grouping' ) + grouping_stmt.substmt( 'grouping' )
915
+ typedef_list = import_module.substmt( 'typedef' ) + grouping_stmt.substmt( 'typedef' )
916
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
917
+ self.load_yang s, yangs, parent_module, import_module, grouping_list, typedef_list
918
+ }
919
+ end
920
+ else
921
+ raise
922
+ end
923
+ end
924
+ end
925
+ def resolve_node path
926
+ path_splitted = path.split( '/' )
927
+ next_node = case path_splitted.first
928
+ when '', '.'
929
+ self
930
+ when '..'
931
+ self
932
+ else
933
+ @children.find{ |c| c.model.arg == path_splitted.first }
934
+ end
935
+ if path_splitted.size == 1
936
+ next_node
937
+ else
938
+ next_node.resolve_node( path_splitted[1..-1].join( '/' ) )
939
+ end
940
+ end
941
+ end
942
+
943
+ class LeafSchemaNode < SchemaNode
944
+ attr_reader :yangs, :arg, :yang, :parent, :module, :type
945
+ def initialize yangs, arg, yang, parent, _module, type
946
+ super yangs, arg, yang, parent, _module
947
+ @type = type
948
+ end
949
+ def type
950
+ @type
951
+ end
952
+ end
953
+
954
+ class Root < InteriorSchemaNode
955
+ def initialize yangs, arg=nil, yang=nil, parent=nil, _module=nil
956
+ super
957
+ end
958
+ def namespace
959
+ 'http://rubyang/config/0.1'
960
+ end
961
+ def prefix
962
+ ''
963
+ end
964
+ def to_json_recursive h
965
+ @children.each{ |c|
966
+ c.to_json_recursive h
967
+ }
968
+ h
969
+ end
970
+ end
971
+
972
+ class Container < InteriorSchemaNode
973
+ def to_json_recursive h
974
+ h['type'] = 'container'
975
+ h['arg'] = @arg
976
+ h['children'] = Hash.new
977
+ @children.each{ |c|
978
+ c.to_json_recursive h['children']
979
+ }
980
+ h
981
+ end
982
+ end
983
+
984
+ class Leaf < LeafSchemaNode
985
+ def to_json_recursive h
986
+ h['type'] = 'leaf'
987
+ h['arg'] = @arg
988
+ case @type
989
+ when Rubyang::Database::SchemaTree::StringType
990
+ h['datatype'] = 'string'
991
+ h['parameters'] = Hash.new
992
+ h['parameters']['length'] = @type.length.to_s
993
+ h['parameters']['pattern'] = @type.pattern.to_s
994
+ else
995
+ raise
996
+ end
997
+ h
998
+ end
999
+ end
1000
+
1001
+ class List < InteriorSchemaNode
1002
+ def keys
1003
+ @yang.substmt( 'key' )[0].arg.split( /[ \t]+/ )
1004
+ end
1005
+ end
1006
+
1007
+ class LeafList < LeafSchemaNode
1008
+ end
1009
+
1010
+ class Choice < InteriorSchemaNode
1011
+ end
1012
+
1013
+ class Case < InteriorSchemaNode
1014
+ end
1015
+
1016
+ class Rpc < SchemaNode
1017
+ end
1018
+ class Input < SchemaNode
1019
+ end
1020
+ class Output < SchemaNode
1021
+ end
1022
+ class Notification < SchemaNode
1023
+ end
1024
+ class Anyxml < SchemaNode
1025
+ end
1026
+
1027
+ def initialize yangs
1028
+ @yangs = yangs
1029
+ @root = Root.new @yangs
1030
+ end
1031
+ def root
1032
+ @root
1033
+ end
1034
+ def load model
1035
+ @root.load_yang( model )
1036
+ end
1037
+ end
1038
+ end
1039
+ end
1040
+
1041
+ if __FILE__ == $0
1042
+ require_relative '../../rubyang'
1043
+ yang_str =<<-EOB
1044
+ module module1 {
1045
+ namespace "http://module1.rspec/";
1046
+ prefix module1;
1047
+ container container1 {
1048
+ leaf leaf1 {
1049
+ type string {
1050
+ length 0..10;
1051
+ pattern '[0-9]+';
1052
+ }
1053
+ }
1054
+ }
1055
+ }
1056
+ EOB
1057
+ db = Rubyang::Database.new
1058
+ db.load_model Rubyang::Model::Parser.parse( yang_str )
1059
+ puts db.configure.schema.to_json
1060
+ end