cddl 0.8.8 → 0.9.3
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.
- checksums.yaml +4 -4
- data/bin/cddl +35 -15
- data/cddl.gemspec +4 -2
- data/data/cddl.abnf +2 -1
- data/lib/cbor-pp-play.rb +1 -0
- data/lib/cddl.rb +234 -39
- data/test/test-cddl.rb +51 -0
- data/test-data/7807.cddl +14 -0
- data/test-data/abignum.cddl +1 -0
- data/test-data/abnf1.cddl +3 -0
- data/test-data/abnf2.cddl +37 -0
- data/test-data/abnf3.cddl +32 -0
- data/test-data/bat.cddl +16 -0
- data/test-data/bpv7.cddl +136 -0
- data/test-data/bpv7a.cddl +181 -0
- data/test-data/bpv7b.cddl +167 -0
- data/test-data/cat-re.cddl +2 -0
- data/test-data/complex-occ.cddl +11 -0
- data/test-data/coral.cddl +10 -0
- data/test-data/coral1.cddl +5 -0
- data/test-data/coral2.cddl +7 -0
- data/test-data/coral3.cddl +7 -0
- data/test-data/det1.cddl +12 -0
- data/test-data/feat1.cddl +4 -0
- data/test-data/feature-controller.cddl +6 -0
- data/test-data/feature-detail.cddl +5 -0
- data/test-data/foo.cddl +1 -0
- data/test-data/homenet-de.cddl +12 -0
- data/test-data/homenet-fe.cddl +12 -0
- data/test-data/jim-cut-2.cddl +11 -0
- data/test-data/jim-cut.cddl +12 -0
- data/test-data/jsoniodef.cddl +719 -0
- data/test-data/lint1.cddl +9 -0
- data/test-data/mdl-ble.cddl +9 -0
- data/test-data/mdl-deve.cddl +54 -0
- data/test-data/mdl-dp.cddl +11 -0
- data/test-data/mdl-mso.cddl +20 -0
- data/test-data/mdl-request.cddl +26 -0
- data/test-data/mdl-response.cddl +66 -0
- data/test-data/mdl.cddl +11 -0
- data/test-data/mon-val.cddl +1 -0
- data/test-data/multipart-ct.cddl +2 -0
- data/test-data/named-group.cddl +7 -0
- data/test-data/non-empty.cddl +5 -0
- data/test-data/oid.cddl +8 -0
- data/test-data/oidbat.cddl +8 -0
- data/test-data/plus.cddl +3 -0
- data/test-data/sasl.cddl +24 -0
- data/test-data/sequence.cddl +1 -0
- data/test-data/sipos.cddl +8 -0
- data/test-data/star-edited.cddl +98 -0
- data/test-data/star.cddl +95 -0
- data/test-data/test-gen.cddl +3 -0
- data/test-data/time.cddl +11 -0
- data/test-data/yangid.cddl +1 -0
- data/test-data/yaron1.cddl +95 -0
- metadata +70 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 53440c040b2f038a19f13930772e0c274d40c2074818c333883f571048b094f1
|
|
4
|
+
data.tar.gz: 606acb287909e0abbf9fe6c038bd1a29649a966a4feab28fa3ffaa20090e3531
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 7ede3ed88ccb5dba90731fa47da28ed2bd68a05b207fdd4c10cbf495c3fea7da31a65b25aa9d24000276ba1a7518d3d11d6c5a156239e7901b105646bfec6b1f
|
|
7
|
+
data.tar.gz: 5003a424b4e7edaca09bff529acc1349006dcfba8d3b645b1e3b084aacaf3a0b146f0e371a77427dfbedeb978ff12a10896cc87e1ef44854f6bae94f0b614031
|
data/bin/cddl
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env ruby
|
|
1
|
+
#!/usr/bin/env RUBY_THREAD_VM_STACK_SIZE=5000000 ruby
|
|
2
2
|
# -*- coding: utf-8 -*-
|
|
3
3
|
# require_relative '../lib/cddl'
|
|
4
4
|
require 'cddl'
|
|
@@ -14,22 +14,24 @@ def usage
|
|
|
14
14
|
warn "Usage:"
|
|
15
15
|
warn "#$0 spec.cddl generate [n]"
|
|
16
16
|
warn "#$0 spec.cddl json-generate [n]"
|
|
17
|
-
warn "#$0 spec.cddl validate instance.cbor"
|
|
18
|
-
warn "#$0 spec.cddl validate instance.json"
|
|
17
|
+
warn "#$0 spec.cddl validate instance.cbor..."
|
|
18
|
+
warn "#$0 spec.cddl validate instance.json..."
|
|
19
19
|
exit EX_USAGE
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def read_arg(arg)
|
|
22
|
+
def read_arg(arg, remember_fn = true)
|
|
23
23
|
if arg == "-"
|
|
24
|
+
$fn = "(stdin)" if remember_fn
|
|
24
25
|
STDIN.read
|
|
25
26
|
else
|
|
26
27
|
usage unless arg
|
|
28
|
+
$fn = arg if remember_fn
|
|
27
29
|
File.read(arg, mode: "rb")
|
|
28
30
|
end
|
|
29
31
|
end
|
|
30
32
|
|
|
31
33
|
def parser
|
|
32
|
-
@parser ||= CDDL::Parser.new(read_arg(ARGV[0]))
|
|
34
|
+
@parser ||= CDDL::Parser.new(read_arg(ARGV[0], false))
|
|
33
35
|
end
|
|
34
36
|
|
|
35
37
|
def my_pp(v)
|
|
@@ -48,13 +50,19 @@ def my_diag(v)
|
|
|
48
50
|
end
|
|
49
51
|
end
|
|
50
52
|
|
|
53
|
+
retcode = 0
|
|
54
|
+
|
|
51
55
|
begin
|
|
52
56
|
case ARGV[1]
|
|
53
|
-
when /\A
|
|
57
|
+
when /\A..*p/
|
|
54
58
|
$annotate = true
|
|
55
59
|
require_relative '../lib/cbor-pp'
|
|
56
60
|
end
|
|
57
61
|
case ARGV[1]
|
|
62
|
+
when /\A..*s/
|
|
63
|
+
$sequence = true
|
|
64
|
+
end
|
|
65
|
+
case ARGV[1]
|
|
58
66
|
when /\Ar/ # secret
|
|
59
67
|
$advanced = true
|
|
60
68
|
my_pp parser.rules
|
|
@@ -81,15 +89,25 @@ begin
|
|
|
81
89
|
g = parser.generate
|
|
82
90
|
puts JSON.pretty_generate(g)
|
|
83
91
|
end
|
|
84
|
-
when /\Av
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
92
|
+
when /\Av(v)?/
|
|
93
|
+
verbose = $1
|
|
94
|
+
ARGV[2..-1].each do |fn|
|
|
95
|
+
instance = read_arg(fn)
|
|
96
|
+
instance = if $sequence
|
|
97
|
+
CBOR.decode("\x9f".b << instance.b << "\xff".b)
|
|
98
|
+
else
|
|
99
|
+
CBOR.decode(instance.b) rescue JSON.load(instance)
|
|
100
|
+
end
|
|
101
|
+
instance = instance.cbor_clone if $annotate && ENV["EXPERIMENTAL_ANNOTATE"]
|
|
102
|
+
warn "#{fn}:" if verbose
|
|
103
|
+
ann = parser.validate(instance)
|
|
104
|
+
# my_pp ann
|
|
105
|
+
instance.cbor_add_annotations_from(ann) rescue nil
|
|
106
|
+
my_diag(instance) if $annotate
|
|
107
|
+
unless ann
|
|
108
|
+
retcode = 1
|
|
109
|
+
end
|
|
110
|
+
end
|
|
93
111
|
else
|
|
94
112
|
usage
|
|
95
113
|
end
|
|
@@ -97,3 +115,5 @@ rescue CDDL::ParseError => e
|
|
|
97
115
|
warn e.message
|
|
98
116
|
exit EX_DATAERR
|
|
99
117
|
end
|
|
118
|
+
|
|
119
|
+
exit retcode
|
data/cddl.gemspec
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
spec = Gem::Specification.new do |s|
|
|
2
2
|
s.name = 'cddl'
|
|
3
|
-
s.version = '0.
|
|
3
|
+
s.version = '0.9.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')
|
|
7
7
|
s.add_dependency('abnc')
|
|
8
|
-
s.add_dependency('
|
|
8
|
+
s.add_dependency('json_pure')
|
|
9
|
+
s.add_dependency('abnftt')
|
|
9
10
|
s.add_dependency('regexp-examples') # , '1.1.0')
|
|
10
11
|
s.add_dependency('colorize')
|
|
11
12
|
s.files = `git ls-files`.split("\n").grep(/^[a-z]/)
|
|
@@ -19,3 +20,4 @@ spec = Gem::Specification.new do |s|
|
|
|
19
20
|
s.homepage = "http://github.com/cabo/cddl"
|
|
20
21
|
s.license = 'MIT'
|
|
21
22
|
end
|
|
23
|
+
|
data/data/cddl.abnf
CHANGED
|
@@ -16,6 +16,7 @@ type1 = type2 [S (rangeop / annotator) S type2]
|
|
|
16
16
|
/ "#" "6" ["." uint] "(" S type S ")" ; note no space!
|
|
17
17
|
/ "#" DIGIT ["." uint] ; major/ai
|
|
18
18
|
/ "#" ; any
|
|
19
|
+
/ "~" S typename [genericarg]
|
|
19
20
|
/ "{" S group S "}"
|
|
20
21
|
/ "[" S group S "]"
|
|
21
22
|
/ "&" S "(" S group S ")"
|
|
@@ -70,7 +71,7 @@ SCHAR = %x20-21 / %x23-7E / SESC
|
|
|
70
71
|
SESC = "\" %x20-7E
|
|
71
72
|
|
|
72
73
|
bytes = [bsqual] %x27 *BCHAR %x27
|
|
73
|
-
BCHAR = %x20-26 / %x28-7E / SESC / CRLF
|
|
74
|
+
BCHAR = %x20-26 / %x28-5B / %x5D-7E / SESC / CRLF
|
|
74
75
|
bsqual = %x68 ; "h"
|
|
75
76
|
/ %x62.36.34 ; "b64"
|
|
76
77
|
|
data/lib/cbor-pp-play.rb
CHANGED
|
@@ -2,6 +2,7 @@ require_relative "cbor-pp"
|
|
|
2
2
|
|
|
3
3
|
a = [1, {foo: "bar", busel: "basel", baz: "bass", ant: "cat", bat: "dog", eel: "fox"},
|
|
4
4
|
2, 3, 4, [3]*55, "foo".b, 0.00006103515625, 0.0000099, 1e-7, nil]
|
|
5
|
+
a[0].cbor_annotation_add "flurp"
|
|
5
6
|
a[1].cbor_annotation_add "fasel"
|
|
6
7
|
CBOR::PP.pp a
|
|
7
8
|
|
data/lib/cddl.rb
CHANGED
|
@@ -3,6 +3,7 @@ require 'pp'
|
|
|
3
3
|
require 'pathname'
|
|
4
4
|
require 'cbor-pure' unless defined?(CBOR::Tagged)
|
|
5
5
|
require 'regexp-examples'
|
|
6
|
+
require 'abnftt'
|
|
6
7
|
require 'colorize'
|
|
7
8
|
require 'base64'
|
|
8
9
|
|
|
@@ -55,6 +56,8 @@ module CDDL
|
|
|
55
56
|
@ast = @abnf.ast?
|
|
56
57
|
# our little argument stack for rule processing
|
|
57
58
|
@insides = []
|
|
59
|
+
# collect error information
|
|
60
|
+
@last_message = ""
|
|
58
61
|
end
|
|
59
62
|
|
|
60
63
|
def apr # for debugging
|
|
@@ -243,10 +246,26 @@ module CDDL
|
|
|
243
246
|
[rule[0], *rule[1]]
|
|
244
247
|
end
|
|
245
248
|
|
|
249
|
+
def remove_indentation(s)
|
|
250
|
+
l = s.lines
|
|
251
|
+
indent = l.grep(/\S/).map {|l| l[/^\s*/].size}.min
|
|
252
|
+
l.map {|l| l.sub(/^ {0,#{indent}}/, "")}.join
|
|
253
|
+
end
|
|
254
|
+
|
|
246
255
|
# Memoize a bit here
|
|
247
256
|
|
|
248
257
|
REGEXP_FOR_STRING = Hash.new {|h, k|
|
|
249
|
-
h[k] = Regexp.new("\\A
|
|
258
|
+
h[k] = Regexp.new("\\A(?:#{k})\\z")
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
ABNF_PARSER_FOR_STRING = Hash.new {|h, k|
|
|
262
|
+
grammar = "cddl-t0p--1eve1-f0r--abnf = " << k # XXX
|
|
263
|
+
h[k] = ABNF.from_abnf(grammar)
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
ABNF_ENCODING_FOR_CONOP = {
|
|
267
|
+
abnf: Encoding::UTF_8,
|
|
268
|
+
abnfb: Encoding::BINARY
|
|
250
269
|
}
|
|
251
270
|
|
|
252
271
|
def generate
|
|
@@ -329,8 +348,12 @@ module CDDL
|
|
|
329
348
|
unless kr
|
|
330
349
|
case vr[0]
|
|
331
350
|
when :grpent
|
|
332
|
-
fail "grpent in map #{vr.inspect}" unless vr.size == 2
|
|
333
|
-
g = Array.new(st) {
|
|
351
|
+
# fail "grpent in map #{vr.inspect}" unless vr.size == 2
|
|
352
|
+
g = Array.new(st) {
|
|
353
|
+
vr[1..-1].map{ |vrx|
|
|
354
|
+
generate1(vrx, true)
|
|
355
|
+
}.flatten(1)
|
|
356
|
+
}.flatten(1)
|
|
334
357
|
# warn "GGG #{g.inspect}"
|
|
335
358
|
return g
|
|
336
359
|
when :grpchoice
|
|
@@ -389,7 +412,7 @@ module CDDL
|
|
|
389
412
|
when :anno
|
|
390
413
|
target = where[2]
|
|
391
414
|
control = where[3]
|
|
392
|
-
case where[1]
|
|
415
|
+
case conop = where[1]
|
|
393
416
|
when :size
|
|
394
417
|
should_be_int = generate1(control)
|
|
395
418
|
unless (Array === target && target[0] == :prim && [0, 2, 3].include?(target[1])) && Integer === should_be_int && should_be_int >= 0
|
|
@@ -435,6 +458,35 @@ module CDDL
|
|
|
435
458
|
$default_warned = true
|
|
436
459
|
end
|
|
437
460
|
generate1(target, inmap)
|
|
461
|
+
when :feature
|
|
462
|
+
generate1(target, inmap)
|
|
463
|
+
when :cat, :det
|
|
464
|
+
lhs = generate1(target, inmap)
|
|
465
|
+
rhs = generate1(control)
|
|
466
|
+
if conop == :det
|
|
467
|
+
lhs = remove_indentation(lhs)
|
|
468
|
+
rhs = remove_indentation(rhs)
|
|
469
|
+
end
|
|
470
|
+
begin
|
|
471
|
+
lhs + rhs
|
|
472
|
+
rescue Exception => e
|
|
473
|
+
fail "Can't #{lhs.inspect} .cat #{rhs.inspect}: #{e.message}"
|
|
474
|
+
end
|
|
475
|
+
when :plus
|
|
476
|
+
lhs = generate1(target, inmap)
|
|
477
|
+
rhs = generate1(control)
|
|
478
|
+
begin
|
|
479
|
+
case lhs
|
|
480
|
+
when Integer
|
|
481
|
+
lhs + Integer(rhs)
|
|
482
|
+
when Numeric
|
|
483
|
+
lhs + rhs
|
|
484
|
+
else
|
|
485
|
+
fail "#{lhs.inspect}: Not a number"
|
|
486
|
+
end
|
|
487
|
+
rescue Exception => e
|
|
488
|
+
fail "Can't #{lhs.inspect} .plus #{rhs.inspect}: #{e.message}"
|
|
489
|
+
end
|
|
438
490
|
when :eq
|
|
439
491
|
content = generate1(control)
|
|
440
492
|
if validate1(content, where)
|
|
@@ -448,7 +500,7 @@ module CDDL
|
|
|
448
500
|
content = Integer(content)
|
|
449
501
|
case target[1]
|
|
450
502
|
when 0
|
|
451
|
-
case
|
|
503
|
+
case conop
|
|
452
504
|
when :lt
|
|
453
505
|
rand(0...content)
|
|
454
506
|
when :le
|
|
@@ -475,12 +527,26 @@ module CDDL
|
|
|
475
527
|
fail "Don't know yet how to generate #{where}"
|
|
476
528
|
end
|
|
477
529
|
REGEXP_FOR_STRING[regexp].random_example(max_repeater_variance: 5)
|
|
530
|
+
when :abnf, :abnfb
|
|
531
|
+
grammar = generate1(control)
|
|
532
|
+
bytes = true if target == [:prim, 2]
|
|
533
|
+
bytes = false if target == [:prim, 3]
|
|
534
|
+
unless !bytes.nil? && String === grammar
|
|
535
|
+
fail "Don't know yet how to generate #{where}"
|
|
536
|
+
end
|
|
537
|
+
grammar << "\n" unless grammar =~ /\n\z/
|
|
538
|
+
out = ABNF_PARSER_FOR_STRING[grammar].generate
|
|
539
|
+
if conop == :abnfb
|
|
540
|
+
out = out.codepoints.pack("C*")
|
|
541
|
+
end
|
|
542
|
+
enc = bytes ? Encoding::BINARY : Encoding::UTF_8
|
|
543
|
+
out.force_encoding(enc)
|
|
478
544
|
when :cbor, :cborseq
|
|
479
545
|
unless target == [:prim, 2]
|
|
480
546
|
fail "Don't know yet how to generate #{where}"
|
|
481
547
|
end
|
|
482
548
|
content = CBOR::encode(generate1(control))
|
|
483
|
-
if
|
|
549
|
+
if conop == :cborseq
|
|
484
550
|
# remove the first head
|
|
485
551
|
n = case content.getbyte(0) - (4 << 5)
|
|
486
552
|
when 0..23; 1
|
|
@@ -498,7 +564,7 @@ module CDDL
|
|
|
498
564
|
content = generate1(target)
|
|
499
565
|
if validate1(content, control)
|
|
500
566
|
return content
|
|
501
|
-
elsif
|
|
567
|
+
elsif conop == :within
|
|
502
568
|
warn "*** #{content.inspect} meets #{target.inspect} but not #{control.inspect}"
|
|
503
569
|
end
|
|
504
570
|
end
|
|
@@ -523,7 +589,7 @@ module CDDL
|
|
|
523
589
|
end
|
|
524
590
|
end
|
|
525
591
|
|
|
526
|
-
VALUE_TYPE = {text: String, int: Integer, float: Float}
|
|
592
|
+
VALUE_TYPE = {text: String, bytes: String, int: Integer, float: Float}
|
|
527
593
|
SIMPLE_VALUE = {
|
|
528
594
|
[:prim, 7, 20] => [true, false, :bool],
|
|
529
595
|
[:prim, 7, 21] => [true, true, :bool],
|
|
@@ -536,9 +602,38 @@ module CDDL
|
|
|
536
602
|
[true, t[1], vt]
|
|
537
603
|
elsif v = SIMPLE_VALUE[t]
|
|
538
604
|
v
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
605
|
+
elsif t[0] == :anno
|
|
606
|
+
_, conop, target, control = t
|
|
607
|
+
# warn ["EXV0", conop, target, control].inspect
|
|
608
|
+
if conop == :cat || conop == :plus || conop == :det
|
|
609
|
+
ok1, v1, vt1 = extract_value(target)
|
|
610
|
+
ok2, v2, vt2 = extract_value(control)
|
|
611
|
+
# warn ["EXV", ok1, v1, vt1, ok2, v2, vt2].inspect
|
|
612
|
+
if ok1 && ok2
|
|
613
|
+
if vt1 == Integer
|
|
614
|
+
[true, v1 + Integer(v2), Integer] if vt2 == Integer || vt2 == Float
|
|
615
|
+
elsif vt1 == Float
|
|
616
|
+
[true, v1 + v2, vt1] if vt2 == Integer || vt2 == Float
|
|
617
|
+
else
|
|
618
|
+
if conop == :det
|
|
619
|
+
v1 = remove_indentation(v1)
|
|
620
|
+
v2 = remove_indentation(v2)
|
|
621
|
+
end
|
|
622
|
+
[true, v1 + v2, vt1] if vt1 == vt2
|
|
623
|
+
end
|
|
624
|
+
end rescue nil
|
|
625
|
+
end
|
|
626
|
+
end || [false]
|
|
627
|
+
end
|
|
628
|
+
|
|
629
|
+
def extract_array(t)
|
|
630
|
+
return [false] unless t[0] == :array
|
|
631
|
+
[true, *t[1..-1].map { |el|
|
|
632
|
+
return [false] unless el[0..3] == [:member, 1, 1, nil]
|
|
633
|
+
ok, v, vt = extract_value(el[4])
|
|
634
|
+
return [false] unless ok
|
|
635
|
+
[v, vt]
|
|
636
|
+
}]
|
|
542
637
|
end
|
|
543
638
|
|
|
544
639
|
def validate_diag
|
|
@@ -547,11 +642,20 @@ module CDDL
|
|
|
547
642
|
|
|
548
643
|
def validate(d, warn=true)
|
|
549
644
|
@recursion = 0
|
|
645
|
+
$features = Hash.new {|h, k| h[k] = {}}
|
|
550
646
|
result = validate1a(d, rules)
|
|
551
|
-
|
|
552
|
-
if
|
|
647
|
+
if warn
|
|
648
|
+
if result
|
|
649
|
+
if $features != {}
|
|
650
|
+
ok = ENV["CDDL_FEATURE_OK"] and ok = ok.split(/,\s*/) or ok = []
|
|
651
|
+
# warn([:OK, ok, $features].inspect)
|
|
652
|
+
features = $features.reject {|k, v| ok.include? k.to_s }
|
|
653
|
+
warn "** Features potentially used (#$fn): #{features.map {|k, v| "#{k}: #{v.keys}"}.join(", ")}" if features != {}
|
|
654
|
+
end
|
|
655
|
+
else
|
|
553
656
|
warn "CDDL validation failure (#{result.inspect} for #{d.inspect}):"
|
|
554
657
|
PP::pp(validate_diag, STDERR)
|
|
658
|
+
puts(validate_diag.cbor_diagnostic)
|
|
555
659
|
end
|
|
556
660
|
end
|
|
557
661
|
result
|
|
@@ -559,7 +663,7 @@ module CDDL
|
|
|
559
663
|
|
|
560
664
|
def validate_result(check)
|
|
561
665
|
check || (
|
|
562
|
-
@last_message
|
|
666
|
+
@last_message << yield
|
|
563
667
|
false
|
|
564
668
|
)
|
|
565
669
|
end
|
|
@@ -592,7 +696,9 @@ module CDDL
|
|
|
592
696
|
ann.concat(ann2)
|
|
593
697
|
end
|
|
594
698
|
if occ < s
|
|
595
|
-
|
|
699
|
+
# warn "*** lme #{@last_message.encoding} #{@last_message}"
|
|
700
|
+
# warn "*** #{"\noccur #{occ} < #{s}, not reached at #{i} in array #{d} for #{where}".encoding}"
|
|
701
|
+
@last_message << "\noccur #{occ} < #{s}, not reached at #{i} in array #{d} for #{where}"
|
|
596
702
|
return [false, ann]
|
|
597
703
|
end
|
|
598
704
|
end
|
|
@@ -681,13 +787,17 @@ module CDDL
|
|
|
681
787
|
puts "COMPLEX: #{k.inspect} #{simple.inspect} #{simpleval.inspect}" if ENV["CDDL_TRACE"]
|
|
682
788
|
keys = d_check.keys
|
|
683
789
|
ta, keys = keys.partition{ |key| validate1(key, k)}
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
790
|
+
count = 0
|
|
791
|
+
catch :enough do
|
|
792
|
+
ta.all? { |val|
|
|
793
|
+
if (ann2 = validate1a(d[val], v)) && # XXX check cut or not!
|
|
794
|
+
d_check.delete(val) {:not_found} != :not_found
|
|
795
|
+
anno.concat(ann2)
|
|
796
|
+
throw :enough, true if (count += 1) == e
|
|
797
|
+
true
|
|
798
|
+
end
|
|
799
|
+
}
|
|
800
|
+
end and validate_result(count >= s) { "not enough #{ta.inspect} for #{r.inspect}" }
|
|
691
801
|
end
|
|
692
802
|
end
|
|
693
803
|
else
|
|
@@ -741,16 +851,31 @@ module CDDL
|
|
|
741
851
|
idx, ann = validate_forward(d, 0, where)
|
|
742
852
|
ann if validate_result(idx == d.size) { "#{validate_diag.inspect} -- cannot complete (#{idx}, #{d.size}) array #{d} for #{where}" }
|
|
743
853
|
end
|
|
744
|
-
when :
|
|
854
|
+
when :int, :float
|
|
745
855
|
_, v = extract_value(where)
|
|
746
856
|
[] if d == v
|
|
857
|
+
when :text, :bytes
|
|
858
|
+
_, v = extract_value(where)
|
|
859
|
+
[] if d == v && ((d.encoding == Encoding::BINARY) == (v.encoding == Encoding::BINARY))
|
|
747
860
|
when :range
|
|
748
861
|
[] if where[2] === d && where[1].include?(d)
|
|
749
862
|
when :anno
|
|
750
|
-
target = where
|
|
751
|
-
if
|
|
752
|
-
|
|
753
|
-
|
|
863
|
+
_, conop, target, control = where
|
|
864
|
+
if conop == :cat || conop == :plus || conop == :det
|
|
865
|
+
ok1, v1, vt1 = extract_value(target)
|
|
866
|
+
ok2, v2, vt2 = extract_value(control)
|
|
867
|
+
# warn ["ANNO0", ok1, v1, vt1, ok2, v2, vt2, d].inspect
|
|
868
|
+
if ok1 && ok2
|
|
869
|
+
v2 = Integer(v2) if vt1 == Integer
|
|
870
|
+
if conop == :det
|
|
871
|
+
v1 = remove_indentation(v1)
|
|
872
|
+
v2 = remove_indentation(v2)
|
|
873
|
+
end
|
|
874
|
+
# warn ["ANNO", ok1, v1, vt1, ok2, v2, vt2, d].inspect
|
|
875
|
+
[] if d == v1 + v2 # XXX Focus ArgumentError
|
|
876
|
+
end
|
|
877
|
+
elsif ann = validate1a(d, target)
|
|
878
|
+
case conop
|
|
754
879
|
when :size
|
|
755
880
|
case d
|
|
756
881
|
when Integer
|
|
@@ -789,8 +914,26 @@ module CDDL
|
|
|
789
914
|
$default_warned = true
|
|
790
915
|
end
|
|
791
916
|
ann
|
|
917
|
+
when :feature
|
|
918
|
+
ok, v, vt = extract_value(control)
|
|
919
|
+
if ok
|
|
920
|
+
nm = v
|
|
921
|
+
det = d
|
|
922
|
+
warn "*** feature controller should be a string: #{control.inspect}" unless String == vt
|
|
923
|
+
else
|
|
924
|
+
ok, *v = extract_array(control)
|
|
925
|
+
if ok && v.size == 2
|
|
926
|
+
nm = v[0][0]
|
|
927
|
+
det = v[1][0]
|
|
928
|
+
warn "*** first element of feature controller should be a string: #{control.inspect}" unless String === nm
|
|
929
|
+
else
|
|
930
|
+
warn "*** feature controller not implemented: #{control.inspect}"
|
|
931
|
+
end
|
|
932
|
+
end
|
|
933
|
+
$features[nm][det] = true
|
|
934
|
+
ann
|
|
792
935
|
when :lt, :le, :gt, :ge, :eq, :ne
|
|
793
|
-
op = OPERATORS[
|
|
936
|
+
op = OPERATORS[conop]
|
|
794
937
|
ok, v, _vt = extract_value(control)
|
|
795
938
|
if ok
|
|
796
939
|
ann if d.send(op, v) rescue nil # XXX Focus ArgumentError
|
|
@@ -806,6 +949,24 @@ module CDDL
|
|
|
806
949
|
end
|
|
807
950
|
end
|
|
808
951
|
)
|
|
952
|
+
when :abnf, :abnfb
|
|
953
|
+
ann if (
|
|
954
|
+
if String === d
|
|
955
|
+
ok, v, vt = extract_value(control)
|
|
956
|
+
if ok && vt == String
|
|
957
|
+
begin
|
|
958
|
+
ABNF_PARSER_FOR_STRING[v].validate(
|
|
959
|
+
d.dup.force_encoding(ABNF_ENCODING_FOR_CONOP[conop]).codepoints.pack("U*")
|
|
960
|
+
)
|
|
961
|
+
true
|
|
962
|
+
rescue => e
|
|
963
|
+
# warn "*** #{e}" # XXX
|
|
964
|
+
@last_message = e.to_s.force_encoding(Encoding::UTF_8)
|
|
965
|
+
nil
|
|
966
|
+
end
|
|
967
|
+
end
|
|
968
|
+
end
|
|
969
|
+
)
|
|
809
970
|
when :cbor
|
|
810
971
|
ann if validate1((CBOR::decode(d) rescue :BAD_CBOR), control)
|
|
811
972
|
when :cborseq
|
|
@@ -837,6 +998,14 @@ module CDDL
|
|
|
837
998
|
when 3
|
|
838
999
|
String === d && d.encoding != Encoding::BINARY # cheat
|
|
839
1000
|
when 6
|
|
1001
|
+
if Integer === d
|
|
1002
|
+
t = 2 # assuming only 2/3 match an Integer
|
|
1003
|
+
if d < 0
|
|
1004
|
+
d = ~d
|
|
1005
|
+
t = 3
|
|
1006
|
+
end
|
|
1007
|
+
d = CBOR::Tagged.new(t, d == 0 ? "".b : d.digits(256).reverse!.pack("C*"))
|
|
1008
|
+
end
|
|
840
1009
|
CBOR::Tagged === d && d.tag == where[2] && validate1a(d.data, where[3])
|
|
841
1010
|
when 7
|
|
842
1011
|
t, v = extract_value(where)
|
|
@@ -950,20 +1119,21 @@ module CDDL
|
|
|
950
1119
|
# warn n
|
|
951
1120
|
s = n.to_s
|
|
952
1121
|
if s[-1] == "'"
|
|
953
|
-
parts = s.split("'",
|
|
954
|
-
if parts[
|
|
955
|
-
warn "***
|
|
1122
|
+
bsqual, *parts = s.split("'", -1)
|
|
1123
|
+
if parts[-1] != ""
|
|
1124
|
+
warn "*** Problem decoding byte string #{s.inspect}"
|
|
956
1125
|
end
|
|
1126
|
+
bsval = parts[0...-1].join("'").gsub(/\\(.)/){$1}
|
|
957
1127
|
[:bytes,
|
|
958
|
-
case
|
|
1128
|
+
case bsqual
|
|
959
1129
|
when ""
|
|
960
|
-
|
|
1130
|
+
bsval.b
|
|
961
1131
|
when "h"
|
|
962
|
-
|
|
1132
|
+
bsval.gsub(/\s/, "").chars.each_slice(2).map{ |x| Integer(x.join, 16).chr("BINARY") }.join.b
|
|
963
1133
|
when "b64"
|
|
964
|
-
Base64.urlsafe_decode64(
|
|
1134
|
+
Base64.urlsafe_decode64(bsval)
|
|
965
1135
|
else
|
|
966
|
-
warn "*** Can't handle byte string type #{
|
|
1136
|
+
warn "*** Can't handle byte string type #{bsqual.inspect} yet"
|
|
967
1137
|
end
|
|
968
1138
|
]
|
|
969
1139
|
else
|
|
@@ -1073,9 +1243,13 @@ module CDDL
|
|
|
1073
1243
|
def g_process(name, g, genericargs)
|
|
1074
1244
|
r, ids = g
|
|
1075
1245
|
args = genericargs.children(:type1).map {|x| type1(x, true)}
|
|
1246
|
+
# warn "** args #{args.inspect}"
|
|
1076
1247
|
fail "number of args #{name} #{ids.size} #{args.size}" if ids.size != args.size
|
|
1077
1248
|
bindings = Hash[ids.zip(args)]
|
|
1078
|
-
|
|
1249
|
+
# warn "** bindings: #{bindings.inspect}"
|
|
1250
|
+
genname = "#{name}<#{args.inspect}>" # XXX this works up to a RECURSE...
|
|
1251
|
+
# warn "** genname #{genname}"
|
|
1252
|
+
r_process(genname, r, bindings)
|
|
1079
1253
|
end
|
|
1080
1254
|
|
|
1081
1255
|
def type_recall(name, canbegroup, genericargs)
|
|
@@ -1142,7 +1316,7 @@ module CDDL
|
|
|
1142
1316
|
end
|
|
1143
1317
|
when :recurse_grpent # XXX we don't have the entry yet
|
|
1144
1318
|
when :member
|
|
1145
|
-
fail "map entry without member key given: #{member}" unless member[3] || member[4][0] == :grpent || member[4][0] == :grpchoice
|
|
1319
|
+
fail "map entry #{member.inspect} without member key given: #{member}" unless member[3] || member[4][0] == :grpent || member[4][0] == :grpchoice
|
|
1146
1320
|
else
|
|
1147
1321
|
fail ["type1 member", member].inspect unless member[0] == :member
|
|
1148
1322
|
end
|
|
@@ -1152,7 +1326,8 @@ module CDDL
|
|
|
1152
1326
|
BRACE = {"{" => :map, "[" => :array}
|
|
1153
1327
|
RANGE_EXCLUDE_END = {".." => false, "..." => true}
|
|
1154
1328
|
SUPPORTED_ANNOTATIONS = [:bits, :size, :regexp, :cbor, :cborseq, :within, :and,
|
|
1155
|
-
:default, :lt, :le, :gt, :ge, :eq, :ne
|
|
1329
|
+
:default, :lt, :le, :gt, :ge, :eq, :ne,
|
|
1330
|
+
:feature, :abnf, :abnfb, :det, :cat, :plus]
|
|
1156
1331
|
|
|
1157
1332
|
def type1(n, canbegroup = false)
|
|
1158
1333
|
# puts "NVALUE #{n.value.inspect}"
|
|
@@ -1214,6 +1389,26 @@ module CDDL
|
|
|
1214
1389
|
v
|
|
1215
1390
|
}
|
|
1216
1391
|
]
|
|
1392
|
+
when /\A~/
|
|
1393
|
+
if tn = n.typename
|
|
1394
|
+
s = type_recall(tn.to_s, false, n.genericarg).flatten(1)
|
|
1395
|
+
else
|
|
1396
|
+
fail "No typename in unwrap #{n}"
|
|
1397
|
+
end
|
|
1398
|
+
if s[0] != :type1
|
|
1399
|
+
fail [:UNWRAPs0, s].inspect
|
|
1400
|
+
end
|
|
1401
|
+
case s[1]
|
|
1402
|
+
when :map, :array
|
|
1403
|
+
[:grpent, s[2..-1]]
|
|
1404
|
+
when :prim
|
|
1405
|
+
if s[2] != 6
|
|
1406
|
+
fail [:UNWRAPs2, s].inspect
|
|
1407
|
+
end
|
|
1408
|
+
s[4] # check :type1?
|
|
1409
|
+
else
|
|
1410
|
+
fail [:UNWRAPs1, s].inspect
|
|
1411
|
+
end
|
|
1217
1412
|
else
|
|
1218
1413
|
"unimplemented #{n}"
|
|
1219
1414
|
end
|
data/test/test-cddl.rb
CHANGED
|
@@ -171,6 +171,57 @@ HERE
|
|
|
171
171
|
assert parser.validate_for_test(true)
|
|
172
172
|
end
|
|
173
173
|
|
|
174
|
+
def test_validate_bignum
|
|
175
|
+
parser = CDDL::Parser.new <<HERE
|
|
176
|
+
test = bigint
|
|
177
|
+
HERE
|
|
178
|
+
assert parser.validate_for_test(2**4711)
|
|
179
|
+
assert parser.validate_for_test(-2**815)
|
|
180
|
+
assert parser.validate_for_test(1)
|
|
181
|
+
assert parser.validate_for_test(0)
|
|
182
|
+
assert parser.validate_for_test(-11)
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_aaaaaaaa_invalidate_bignum
|
|
186
|
+
parser = CDDL::Parser.new <<HERE
|
|
187
|
+
test = bignint
|
|
188
|
+
HERE
|
|
189
|
+
refute parser.validate_for_test(2**4711, false)
|
|
190
|
+
assert parser.validate_for_test(-2**815)
|
|
191
|
+
refute parser.validate_for_test(1, false)
|
|
192
|
+
refute parser.validate_for_test(0, false)
|
|
193
|
+
assert parser.validate_for_test(-11)
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
def test_aaaaaaaa_validate_bignum0b
|
|
198
|
+
parser = CDDL::Parser.new <<HERE
|
|
199
|
+
test = #6.2("")
|
|
200
|
+
HERE
|
|
201
|
+
refute parser.validate_for_test(1, false)
|
|
202
|
+
refute parser.validate_for_test(0, false)
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def test_aaaaaaaa_validate_bignum0
|
|
207
|
+
parser = CDDL::Parser.new <<HERE
|
|
208
|
+
test = #6.2(h'')
|
|
209
|
+
HERE
|
|
210
|
+
assert parser.validate_for_test(0)
|
|
211
|
+
refute parser.validate_for_test(1, false)
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
def test_aaaaaaaa_validate_bignum1
|
|
216
|
+
parser = CDDL::Parser.new <<HERE
|
|
217
|
+
test = #6.2(h'01')
|
|
218
|
+
HERE
|
|
219
|
+
assert parser.validate_for_test(1)
|
|
220
|
+
refute parser.validate_for_test(0, false)
|
|
221
|
+
refute parser.validate_for_test(2, false)
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
|
|
174
225
|
def test_validate_a
|
|
175
226
|
parser = CDDL::Parser.new <<HERE
|
|
176
227
|
test = [* one: 1]
|
data/test-data/7807.cddl
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
coap-problem-details = {
|
|
2
|
+
type => uint,
|
|
3
|
+
? title => text,
|
|
4
|
+
? response-code => bstr .size 1,
|
|
5
|
+
? detail => text,
|
|
6
|
+
? instance => uri,
|
|
7
|
+
* $$coap-problem-details-extension,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
type = 0
|
|
11
|
+
title = 1
|
|
12
|
+
response-code = 2
|
|
13
|
+
detail = 3
|
|
14
|
+
instance = 4
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
abignum = unsigned
|