cddl 0.6.2 → 0.6.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e5369f34b05a1ece8d8f11f3b4a04d704928850e
4
- data.tar.gz: a35dff8b713d0a6baca7bca0554fdfad498fd490
3
+ metadata.gz: 7ed6608fc505b18aec7d8e30bac4b1faca1265da
4
+ data.tar.gz: 46a78ea14fc09cc01a56ca63320e2f8a9de175d3
5
5
  SHA512:
6
- metadata.gz: 8d21bb24a81af9f70f698e97f38e96fa3ae37bc904841f3f29abf246b013a450816a28612729e0b82c0505a376603330156c7666e943e39ad296422c581cc818
7
- data.tar.gz: 086513c70f53d7b21e7e8447f36002aa05cab7e66d1f744711600967bd0fbfad3741d318c00e4696cbbaa8b5e82ff16b440e5dd1b79129fc717c2674b5ff81f0
6
+ metadata.gz: c941909e3cf4064ae0fbcb3f94e8bb54a10da19c294f1b6a7d5152cb0dd653a7ac6652f11bddc3d2a0e30a8679e823585b235acdf3479e660a66ba33b793e069
7
+ data.tar.gz: 2dd6ad6d49ab40dc1ccba874ee722aa3e490075886f8af51255ad33b5656c0b5c009f326727689f36f0ebd2cc7a30944e69209c6340fead7277a8294dc2878ba
data/bin/cddl CHANGED
@@ -1,5 +1,6 @@
1
1
  #!/usr/bin/env ruby
2
2
  # -*- coding: utf-8 -*-
3
+ # require_relative '../lib/cddl'
3
4
  require 'cddl'
4
5
  require 'cbor-diagnostic'
5
6
  require 'json'
@@ -28,17 +29,44 @@ def parser
28
29
  @parser ||= CDDL::Parser.new(read_arg(ARGV[0]))
29
30
  end
30
31
 
32
+ def my_pp(v)
33
+ if $annotate
34
+ CBOR::PP.pp v
35
+ else
36
+ pp v
37
+ end
38
+ end
39
+
40
+ def my_diag(v)
41
+ if $annotate
42
+ CBOR::PP.pp v
43
+ else
44
+ puts v.cbor_diagnostic
45
+ end
46
+ end
47
+
31
48
  begin
49
+ case ARGV[1]
50
+ when /\A.p/
51
+ $annotate = true
52
+ require_relative '../lib/cbor-pp'
53
+ end
32
54
  case ARGV[1]
33
55
  when /\Ar/ # secret
34
56
  $advanced = true
35
- pp parser.rules
57
+ my_pp parser.rules
36
58
  when /\Ag/
37
59
  n = 1
38
60
  n = ARGV[2].to_i if ARGV[2]
39
61
  n.times do
40
62
  g = parser.generate
41
- puts g.cbor_diagnostic
63
+ if $annotate
64
+ g = g.cbor_clone if ENV["EXPERIMENTAL_ANNOTATE"]
65
+ ann = parser.validate(g)
66
+ # my_pp ann
67
+ g.cbor_add_annotations_from(ann) rescue nil
68
+ end
69
+ my_diag(g)
42
70
  end
43
71
  when /\Aj/
44
72
  n = 1
@@ -50,7 +78,11 @@ begin
50
78
  when /\Av/
51
79
  instance = read_arg(ARGV[2])
52
80
  instance = CBOR.decode(instance.b) rescue JSON.load(instance)
53
- p parser.validate(instance)
81
+ instance = instance.cbor_clone if $annotate && ENV["EXPERIMENTAL_ANNOTATE"]
82
+ ann = parser.validate(instance)
83
+ # my_pp ann
84
+ instance.cbor_add_annotations_from(ann) rescue nil
85
+ my_diag(instance) if $annotate
54
86
  else
55
87
  usage
56
88
  end
data/cddl.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  spec = Gem::Specification.new do |s|
2
2
  s.name = 'cddl'
3
- s.version = '0.6.2'
3
+ s.version = '0.6.3'
4
4
  s.summary = "CDDL generator and validator."
5
5
  s.description = %{A parser, generator, and validator for CDDL}
6
6
  s.add_dependency('cbor-diag')
data/data/prelude.cddl CHANGED
@@ -11,7 +11,7 @@ bytes = bstr
11
11
  tstr = #3
12
12
  text = tstr
13
13
 
14
- tdate = #6.0(tstr)
14
+ tdate = #6.0(tstr .regexp "\\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[1-2]\\d|3[0-1])[Tt]([0-1]\\d|2[0-3]):([0-5]\\d):([0-5]\\d)(\\.\\d+)?([Zz]|[+\\-](?:[0-1]\\d|2[0-3]):[0-5]\\d)")
15
15
  time = #6.1(number)
16
16
  number = int / float
17
17
  biguint = #6.2(bstr)
@@ -0,0 +1,13 @@
1
+ require_relative "cbor-pp"
2
+
3
+ a = [1, {foo: "bar", busel: "basel", baz: "bass", ant: "cat", bat: "dog", eel: "fox"},
4
+ 2, 3, 4, [3]*55, "foo".b, 0.00006103515625, 0.0000099, 1e-7, nil]
5
+ a[1].cbor_annotation_add "fasel"
6
+ CBOR::PP.pp a
7
+
8
+ a = [1, "baz", 3]
9
+ a.cbor_annotation_add "foo"
10
+ a[1].cbor_annotation_add "bar"
11
+ CBOR::PP.pp(a)
12
+
13
+ p 1.cbor_annotation_format
data/lib/cbor-pp.rb ADDED
@@ -0,0 +1,180 @@
1
+ require 'prettyprint'
2
+ require 'cbor-diagnostic'
3
+ require 'delegate'
4
+
5
+ class CBOR::PP < PrettyPrint
6
+ # Outputs +obj+ to +out+ in pretty printed format of
7
+ # +width+ columns in width.
8
+ #
9
+ # If +out+ is omitted, <code>$></code> is assumed.
10
+ # If +width+ is omitted, 79 is assumed.
11
+ #
12
+ # CBOR::PP.pp returns +out+.
13
+ def self.pp(obj, out=$>, width=79)
14
+ q = new(out, width)
15
+ q.pp obj
16
+ q.flush
17
+ #$pp = q
18
+ out << "\n"
19
+ end
20
+
21
+ module PPMethods
22
+ # Adds +obj+ to the pretty printing buffer
23
+ # using Object#cbor_pp.
24
+ def pp(obj)
25
+ group {obj.cbor_pp self}
26
+ end
27
+
28
+ # XXX: a nested group that is broken should not have things added at the end
29
+ def comma_breakable
30
+ text ','
31
+ fill_breakable
32
+ end
33
+
34
+ def seplist(list, sep=nil, iter_method=:each) # :yield: element
35
+ sep ||= lambda { comma_breakable }
36
+ first = true
37
+ list.__send__(iter_method) {|*v|
38
+ if first
39
+ first = false
40
+ else
41
+ sep.call
42
+ end
43
+ yield(*v)
44
+ }
45
+ end
46
+
47
+ # A pretty print for a Hash
48
+ def pp_hash(obj, anno)
49
+ s = "#{anno}{"
50
+ group(1, s, '}') {
51
+ seplist(obj, nil, :each_pair) {|k, v|
52
+ group {
53
+ pp k
54
+ text ':'
55
+ group(1) {
56
+ breakable ' '
57
+ pp v
58
+ }
59
+ }
60
+ }
61
+ }
62
+ end
63
+ end
64
+
65
+ include PPMethods
66
+
67
+ module ObjectMixin # :nodoc:
68
+ def cbor_pp(q)
69
+ if @cbor_annotation
70
+ q.text cbor_annotation_format
71
+ end
72
+ q.text cbor_diagnostic
73
+ end
74
+ def cbor_annotation_add(v)
75
+ unless frozen?
76
+ @cbor_annotation ||= []
77
+ @cbor_annotation << v unless @cbor_annotation.include? v
78
+ end
79
+ end
80
+ def cbor_annotation_replace(v)
81
+ @cbor_annotation = [v]
82
+ end
83
+ def cbor_annotations
84
+ @cbor_annotation
85
+ end
86
+ def cbor_annotation_format
87
+ if @cbor_annotation
88
+ "/" << @cbor_annotation.join(", ") << "/ "
89
+ end
90
+ end
91
+ def cbor_add_annotations_from(ann_list)
92
+ _data, anno = ann_list.find{|data, _anno| equal?(data)}
93
+ f = anno.cbor_annotations
94
+ f.each {|a| cbor_annotation_add(a)} if f
95
+ end
96
+ def cbor_clone
97
+ if frozen?
98
+ CBOR::PP::Cloak.new(self)
99
+ else
100
+ self
101
+ end
102
+ end
103
+ def eql?(other)
104
+ if other.respond_to? :__getobj__
105
+ eql? other.__getobj__
106
+ else
107
+ super
108
+ end
109
+ end
110
+ end
111
+
112
+ def self.add_annotations(tree, ann_list)
113
+ tree.cbor_add_annotations_from(ann_list)
114
+ end
115
+
116
+ class Cloak < ::SimpleDelegator
117
+ def class
118
+ @delegate_sd_obj.class
119
+ end
120
+ include CBOR::PP::ObjectMixin
121
+ end
122
+ end
123
+
124
+ class Class
125
+ def ===(other)
126
+ if other.respond_to? :__getobj__
127
+ other.__getobj__.kind_of? self
128
+ else
129
+ other.kind_of? self
130
+ end
131
+ end
132
+ end
133
+
134
+ class Array # :nodoc:
135
+ def cbor_pp(q) # :nodoc:
136
+ s = "#{cbor_annotation_format}["
137
+ q.group(1, s, ']') {
138
+ q.seplist(self) {|v|
139
+ q.pp v
140
+ }
141
+ }
142
+ end
143
+ def cbor_add_annotations_from(ann_list)
144
+ super
145
+ each {|m| m.cbor_add_annotations_from(ann_list)}
146
+ end
147
+ def cbor_clone
148
+ map(&:cbor_clone)
149
+ end
150
+ end
151
+
152
+ class Hash # :nodoc:
153
+ def cbor_pp(q) # :nodoc:
154
+ q.pp_hash self, cbor_annotation_format
155
+ end
156
+ def cbor_add_annotations_from(ann_list)
157
+ super
158
+ each {|k, v|
159
+ # k.cbor_add_annotations_from(ann_list)
160
+ v.cbor_add_annotations_from(ann_list)
161
+ }
162
+ end
163
+ def cbor_clone
164
+ to_a.cbor_clone.to_h
165
+ end
166
+ end
167
+
168
+ class Numeric
169
+ def eql?(other)
170
+ if other.respond_to? :__getobj__
171
+ eql? other.__getobj__
172
+ else
173
+ super
174
+ end
175
+ end
176
+ end
177
+
178
+ class Object < BasicObject # :nodoc:
179
+ include CBOR::PP::ObjectMixin
180
+ end
data/lib/cddl.rb CHANGED
@@ -377,10 +377,10 @@ module CDDL
377
377
 
378
378
  def validate(d, warn=true)
379
379
  @recursion = 0
380
- result = validate1(d)
380
+ result = validate1a(d, rules)
381
381
  unless result
382
382
  if warn
383
- warn "CDDL validation failure:"
383
+ warn "CDDL validation failure (#{result.inspect} for #{d.inspect}):"
384
384
  PP::pp(validate_diag, STDERR)
385
385
  end
386
386
  end
@@ -395,60 +395,72 @@ module CDDL
395
395
  end
396
396
 
397
397
  def validate_forward(d, start, where)
398
+ # warn ["valforw", d, start, where].inspect
398
399
  i = 0
400
+ ann = []
399
401
  where[1..-1].each { |r|
400
402
  t, s, e, _k, v = r # XXX
401
403
  if t == :recurse_grpent
402
404
  rule = lookup_recurse_grpent(s)
403
- n = validate_linear(d, start+i, rule)
404
- return false unless n
405
+ n, ann2 = validate_linear(d, start+i, rule)
406
+ return [false, ann] unless n
405
407
  i += n
408
+ ann.concat(ann2)
406
409
  elsif t == :grpchoice
407
- return false unless r[1..-1].any? {|cand|
408
- if n = validate_forward(d, start+i, [:foo, *cand])
410
+ return [false, ann] unless r[1..-1].any? {|cand|
411
+ n, ann2 = validate_forward(d, start+i, [:foo, *cand])
412
+ if n
409
413
  i += n
414
+ ann.concat(ann2)
410
415
  end}
411
416
  else
412
417
  fail r.inspect unless t == :member
413
418
  occ = 0
414
- while ((occ < e) && i != d.size && (n = validate_linear(d, start+i, v)))
419
+ while ((occ < e) && i != d.size && ((n, ann2 = validate_linear(d, start+i, v)); n))
415
420
  i += n
416
421
  occ += 1
422
+ ann.concat(ann2)
417
423
  end
418
424
  if occ < s
419
425
  @last_message = "occur not reached in array #{d} for #{where}"
420
- return false
426
+ return [false, ann]
421
427
  end
422
428
  end
423
429
  }
424
- i
430
+ # warn ["valforw>", i].inspect
431
+ [i, ann]
425
432
  end
426
433
 
427
434
  # returns number of matches or false for breakage
428
435
  def validate_linear(d, start, where)
436
+ # warn ["vallin", d, start, where].inspect
429
437
  fail unless Array === d
430
438
  case where[0]
431
439
  when :grpent
432
440
  # must be inside an array with nested occurrences
433
441
  validate_forward(d, start, where)
434
442
  else
435
- validate1(d[start], where) ? 1 : false
443
+ (ann = validate1a(d[start], where)) ? [1, ann] : [false, ann]
436
444
  end
437
445
  end
438
446
 
439
447
  def map_check(d, d_check, members)
440
- members.all? { |r|
448
+ anno = []
449
+ anno if members.all? { |r|
441
450
  # puts "SUBRULE: #{r.inspect}"
442
- t, s, _e, k, v = r
451
+ t, s, e, k, v = r
443
452
  case t
444
453
  when :recurse_grpent
445
454
  rule = lookup_recurse_grpent(s)
446
- map_check(d, d_check, rule[1..-1])
455
+ if ann2 = map_check(d, d_check, rule[1..-1])
456
+ anno.concat(ann2)
457
+ end
447
458
  when :grpchoice
448
459
  r[1..-1].any? {|cand|
449
460
  cand_d_check = d_check.dup
450
- if map_check(d, cand_d_check, cand)
461
+ if ann2 = map_check(d, cand_d_check, cand)
451
462
  d_check.replace(cand_d_check)
463
+ anno.concat(ann2)
452
464
  end
453
465
  }
454
466
  when :member
@@ -462,8 +474,20 @@ module CDDL
462
474
  fail "member name not known for group entry #{r} in map"
463
475
  end
464
476
  d_check1 = d_check.dup
465
- # XXX this is ignoring occur = [s, _e] FIXME!
466
- return map_check(d, d_check1, entries) && d_check.replace(d_check1)
477
+ occ = 0
478
+ ann2 = []
479
+ while occ < e && (ann3 = map_check(d, d_check1, entries))
480
+ occ += 1
481
+ ann2.concat(ann3)
482
+ end
483
+ if occ >= s
484
+ d_check.replace(d_check1)
485
+ anno.concat(ann2)
486
+ return anno
487
+ else
488
+ # leave some diagnostic breadcrumbs?
489
+ return false
490
+ end
467
491
  end
468
492
  # this is mostly quadratic; let's do the linear thing if possible
469
493
  simple, simpleval = extract_value(k)
@@ -474,7 +498,10 @@ module CDDL
474
498
  if actual == :not_found
475
499
  s == 0 # minimum occurrence must be 0 then
476
500
  else
477
- validate1(actual, v) && d_check.delete(simpleval)
501
+ if (ann2 = validate1a(actual, v)) &&
502
+ d_check.delete(simpleval) {:not_found} != :not_found
503
+ anno.concat(ann2)
504
+ end
478
505
  end
479
506
  else
480
507
  # puts "COMPLEX: #{k.inspect} #{simple.inspect} #{simpleval.inspect}"
@@ -482,7 +509,10 @@ module CDDL
482
509
  ta, keys = keys.partition{ |key| validate1(key, k)}
483
510
  # XXX check ta.size against s/e
484
511
  ta.all? { |val|
485
- validate1(d[val], v) && d_check.delete(val)
512
+ if (ann2 = validate1a(d[val], v)) &&
513
+ d_check.delete(val) {:not_found} != :not_found
514
+ anno.concat(ann2)
515
+ end
486
516
  }
487
517
  end
488
518
  else
@@ -491,42 +521,60 @@ module CDDL
491
521
  }
492
522
  end
493
523
 
494
- def validate1(d, where=rules)
524
+ def validate1a(d, where)
525
+ if ann = validate1(d, where)
526
+ here = [d, where]
527
+ if Array === ann
528
+ [here, *ann]
529
+ else
530
+ [here]
531
+ end
532
+ end
533
+ end
534
+
535
+ def validate1(d, where)
495
536
  # puts "DATA: #{d.inspect}"
496
537
  # puts "RULE: #{where.inspect}"
538
+ # warn ["val1", d, where].inspect
497
539
  @last_data = d
498
540
  @last_rule = where
541
+ ann = nil
499
542
  case where[0]
500
543
  when :type1
501
- where[1..-1].any? {|r| validate1(d, r)}
544
+ if where[1..-1].any? {|r| ann = validate1a(d, r)}
545
+ ann
546
+ end
502
547
  when :map
503
548
  if Hash === d
504
549
  d_check = d.dup
505
- map_check(d, d_check, where[1..-1]) && d_check == {}
550
+ if (ann = map_check(d, d_check, where[1..-1])) && d_check == {}
551
+ ann
552
+ end
506
553
  end
507
554
  when :array
555
+ # warn ["valarr", d, where].inspect
508
556
  if Array === d
509
557
  # validate1 against the record
510
- idx = validate_forward(d, 0, where)
511
- validate_result(idx == d.size) { "cannot complete array #{d} for #{where}" }
558
+ idx, ann = validate_forward(d, 0, where)
559
+ ann if validate_result(idx == d.size) { "cannot complete array #{d} for #{where}" }
512
560
  end
513
561
  when :string, :int, :float
514
562
  _, v = extract_value(where)
515
- d == v
563
+ [] if d == v
516
564
  when :range
517
- where[2] === d && where[1].include?(d)
565
+ [] if where[2] === d && where[1].include?(d)
518
566
  when :anno
519
567
  target = where[2]
520
- if validate1(d, target)
568
+ if ann = validate1a(d, target)
521
569
  control = where[3]
522
570
  case where[1]
523
571
  when :size
524
- validate1(d.bytesize, control)
572
+ ann if validate1(d.bytesize, control)
525
573
  when :bits
526
574
  if String === d
527
575
  d.each_byte.with_index.all? { |b, i|
528
576
  bit = i << 3
529
- 8.times.all? { |nb|
577
+ ann if 8.times.all? { |nb|
530
578
  b[nb] == 0 || validate1(bit+nb, control)
531
579
  }
532
580
  }
@@ -540,10 +588,11 @@ module CDDL
540
588
  end
541
589
  d >>= 1; i += 1
542
590
  end
543
- ok
591
+ ann if ok
544
592
  end
545
593
  end
546
594
  when :regexp
595
+ ann if (
547
596
  if String === d
548
597
  ok, v, vt = extract_value(control)
549
598
  if ok && vt == String
@@ -552,6 +601,7 @@ module CDDL
552
601
  d.match(re)
553
602
  end
554
603
  end
604
+ )
555
605
  else
556
606
  fail "Don't know yet how to validate against #{where}"
557
607
  end
@@ -570,7 +620,7 @@ module CDDL
570
620
  when 3
571
621
  String === d && d.encoding != Encoding::BINARY # cheat
572
622
  when 6
573
- CBOR::Tagged === d && d.tag == where[2] && validate1(d.data, where[3])
623
+ CBOR::Tagged === d && d.tag == where[2] && validate1a(d.data, where[3])
574
624
  when 7
575
625
  t, v = extract_value(where)
576
626
  if t
@@ -594,13 +644,15 @@ module CDDL
594
644
  rule = @stage1[name]
595
645
  if @recursion < MAX_RECURSE
596
646
  @recursion += 1
597
- r = validate1(d, rule)
647
+ r = validate1a(d, rule)
598
648
  @recursion -= 1
599
649
  r
600
650
  else
601
651
  fail "Deep recursion into #{name}: #{rule}, not yet implemented"
602
652
  end
603
653
  else
654
+ @last_message = "Don't know how to validate #{where}"
655
+ false
604
656
  # fail where
605
657
  end
606
658
  end
@@ -671,6 +723,7 @@ module CDDL
671
723
  fail t
672
724
  end}]
673
725
  @bindings.pop
726
+ r.cbor_annotation_add(n) rescue nil # AAA
674
727
  r
675
728
  end
676
729
  end
@@ -729,7 +782,10 @@ module CDDL
729
782
  else
730
783
  t = if nbw = nt.bareword
731
784
  t1 = nbw.type1 # || n.bareword.s.type.type1 # workaround
732
- type1(t1, true)
785
+ rest = type_collect(nt, true)
786
+ s = [:type1, type1(t1, true), *rest]
787
+ # warn "T2: #{s.size} #{s}" -- maybe this should have a parenthesis warning?
788
+ s.size == 2 ? s[1] : s # decapsulate single-element choice
733
789
  else
734
790
  type(nt, true) # type can actually be a group here!
735
791
  end
@@ -767,6 +823,9 @@ module CDDL
767
823
  if occ[0] == 0 && t == [:grpchoice]
768
824
  [] # we won't be able to generate any of those
769
825
  else
826
+ if t[0] == :grpchoice # FIXME: need to package grpchoice into grpent in a member
827
+ t = [:grpent, t]
828
+ end
770
829
  [[:member, *occ, nil, t]]
771
830
  end
772
831
  end
@@ -790,7 +849,7 @@ module CDDL
790
849
  elsif !genericargs && (t = rule_lookup(name, canbegroup))
791
850
  t
792
851
  else
793
- fail "Unknown type #{name} #{genericargs.inspect} #{@bindings} #{@abnf.ast?}"
852
+ fail "Unknown type #{name} #{genericargs.inspect} #{@bindings}" #{@abnf.ast?}"
794
853
  end
795
854
  end
796
855
 
@@ -801,7 +860,7 @@ module CDDL
801
860
  g[1..-1]
802
861
  elsif !genericargs && (g = rule_lookup(name, true))
803
862
  fail "#{name} not a group" unless g[0] == :grpent
804
- g[1..-1]
863
+ g[1..-1] # AAA
805
864
  else
806
865
  fail "Unknown group #{name}"
807
866
  end
@@ -829,6 +888,8 @@ module CDDL
829
888
 
830
889
  end
831
890
  end # XXX should flatten the thing, too
891
+ t = t.dup
892
+ t.cbor_annotation_replace(v.to_s) rescue nil # AAA
832
893
  t
833
894
  else
834
895
  fail [n, n.children].inspect
@@ -911,6 +972,7 @@ module CDDL
911
972
  [:type1, *s.map {|mem|
912
973
  t, _s, _e, _k, v = mem
913
974
  fail "enum #{t.inspect}" unless t == :member
975
+ v.cbor_annotation_add(generate1(_k)) rescue nil # AAA (XXX: what if more than one?)
914
976
  v
915
977
  }
916
978
  ]
@@ -920,9 +982,13 @@ module CDDL
920
982
  end
921
983
  end
922
984
 
985
+ def type_collect(n, canbegroup)
986
+ n.children(:type1).map {|ch| type1(ch, canbegroup)}
987
+ end
988
+
923
989
  def type(n, canbegroup = false)
924
990
  # pp ["nch", n.children]
925
- s = n.children(:type1).map {|ch| type1(ch, canbegroup)}
991
+ s = type_collect(n, canbegroup)
926
992
  if s.size == 1
927
993
  s.first
928
994
  else