cddlc 0.1.1 → 0.1.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.
data/lib/cddlc.rb CHANGED
@@ -1,8 +1,18 @@
1
1
  require_relative "parser/cddl-util.rb"
2
+ require_relative "processor/cddl-visitor.rb"
3
+ require_relative 'processor/cddl-undefined.rb'
2
4
 
3
5
  class CDDL
4
6
  @@parser = CDDLGRAMMARParser.new
5
7
 
8
+ DATA_DIR = Pathname.new(__FILE__) + "../../data/"
9
+ # empty string is for CDDL::DATA_DIR
10
+ CDDL_INCLUDE_PATH = ENV["CDDL_INCLUDE_PATH"] || ".:"
11
+
12
+ def self.cddl_include_path
13
+ CDDL_INCLUDE_PATH.split(":", -1).map {_1 == "" ? CDDL::DATA_DIR : Pathname.new(_1)}
14
+ end
15
+
6
16
  def self.reason(parser, s)
7
17
  reason = [parser.failure_reason]
8
18
  parser.failure_reason =~ /^(Expected .+) after/m
@@ -14,21 +24,133 @@ class CDDL
14
24
  reason.join("\n")
15
25
  end
16
26
 
27
+ # (keeps only renamed rules)
28
+ def rename(rename_map)
29
+ rules.replace(
30
+ Hash[rename_map.map do |o, n|
31
+ [n, visit(rules[o]) do |prod|
32
+ case prod
33
+ in ["name", *] | ["gen", *]
34
+ prod[1] = rename_map[prod[1]] || prod[1]
35
+ else
36
+ end
37
+ false
38
+ end]
39
+ end])
40
+ end
41
+
42
+ SAFE_FN = /\A[-._a-zA-Z0-9]+\z/
43
+
17
44
  def self.from_cddl(s)
18
45
  ast = @@parser.parse s
19
46
  if !ast
20
47
  fail self.reason(@@parser, s)
21
48
  end
22
- CDDL.new(ast)
49
+ if $options.cddl2
50
+ directives = s.lines.grep(/^;# /).map(&:chomp).map{|l| l.sub(/^;#\s+/, '').split(/\s+/)}
51
+ # puts directives.to_yaml
52
+ end
53
+ ret = CDDL.new(ast, directives)
54
+
55
+ if $options.cddl2
56
+ ret.directives.each do |di|
57
+ preferred_tag = nil
58
+ case di
59
+ in ["include" => dir, docref]
60
+ in ["include" => dir, docref, "as", preferred_tag]
61
+ in ["import" => dir, docref]
62
+ in ["import" => dir, docref, "as", preferred_tag]
63
+ else
64
+ warn "** Can't parse include directive #{di.inspect}"
65
+ next
66
+ end
67
+ unless docref =~ SAFE_FN
68
+ warn "** skipping unsafe filename #{docref}"
69
+ next
70
+ end
71
+ puts "PREFERRED_TAG #{preferred_tag}" if $options.verbose
72
+ puts "DOCREF #{docref}" if $options.verbose
73
+ fn = docref.downcase << ".cddl"
74
+
75
+ io = nil
76
+ CDDL::cddl_include_path.each do |path|
77
+ begin
78
+ io = (path + fn).open
79
+ break
80
+ rescue Errno::ENOENT
81
+ next
82
+ end
83
+ end
84
+ unless io
85
+ warn "** include file #{fn} not found in #{CDDL::cddl_include_path.map(&:to_s)}"
86
+ next
87
+ end
88
+
89
+ include_file = io.read
90
+ included_cddl = CDDL.from_cddl(include_file)
91
+ if preferred_tag
92
+ included_cddl = included_cddl.deep_clone # needed?
93
+ renamed_names = included_cddl.rules.keys
94
+ name_rename = Hash[
95
+ renamed_names.map { |o|
96
+ n = "#{preferred_tag}.#{o}"
97
+ warn "** Warning: renamed name #{n} already in #{fn}" if included_cddl.rules[n]
98
+ [o, n]}]
99
+ included_cddl.rename(name_rename)
100
+ end
101
+
102
+ case dir
103
+ in "import"
104
+ warn "** IMPORTING #{fn}" if $options.verbose
105
+ undef_rule = nil
106
+ loop do
107
+ undef_rule = ret.cddl_undefined # XXX square...
108
+ # p undef_rule
109
+ got_more = false
110
+ undef_rule.each do |name|
111
+ if rule = included_cddl.rules[name]
112
+ ret.rules[name] = rule
113
+ warn "IMPORTED #{name} from #{fn}" if $options.verbose
114
+ got_more = true
115
+ end
116
+ end
117
+ break unless got_more
118
+ end
119
+ if preferred_tag
120
+ undef_rule.each do |name|
121
+ warn "** Warning: undefined reference #{name} without namespace prefix is defined in namespaced imported module #{fn}" if name_rename[name]
122
+ end
123
+ end
124
+ in "include"
125
+ warn "** INCLUDING #{fn}" if $options.verbose
126
+ included_cddl.rules.each do |k, v|
127
+ if old = ret.rules[k]
128
+ if old != v
129
+ warn "** included rule #{k} = #{v} would overwrite #{old}"
130
+ end
131
+ else
132
+ ret.rules[k] = v
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ ret
23
139
  end
24
140
 
25
- attr_accessor :ast, :tree
26
- def initialize(ast_)
141
+ attr_accessor :ast, :tree, :directives
142
+ def initialize(ast_, directives_ = [])
27
143
  @ast = ast_
28
144
  @tree = ast.ast
29
145
  @rules = nil # only fill in if needed
146
+ @directives = directives_
147
+ end
148
+
149
+ def deep_clone
150
+ Marshal.load(Marshal.dump(self))
30
151
  end
31
152
 
153
+
32
154
  RULE_OP_TO_CHOICE = {"/=" => "tcho", "//=" => "gcho"}
33
155
 
34
156
  def rules
@@ -45,7 +167,19 @@ class CDDL
45
167
  fail unless name.size == 2
46
168
  name = name[1]
47
169
  when "gen"
48
- name = name[1..-1]
170
+ parmnames = name[2..-1]
171
+ name = name[1] # XXX update val with parm/arg
172
+ val = ["parm", parmnames,
173
+ visit(val) do |p|
174
+ case p
175
+ in ["name", nm]
176
+ if ix = parmnames.index(nm)
177
+ [true, ["arg", ix]]
178
+ end
179
+ else
180
+ false
181
+ end
182
+ end]
49
183
  else
50
184
  fail name
51
185
  end
@@ -66,8 +200,6 @@ class CDDL
66
200
  @rules
67
201
  end
68
202
 
69
- DATA_DIR = Pathname.new(__FILE__) + "../../data/"
70
-
71
203
  def prelude
72
204
  if @prelude.nil?
73
205
  @prelude = CDDL.from_cddl(File.read(DATA_DIR + "prelude.cddl"))
@@ -1,4 +1,4 @@
1
-
1
+ require 'treetop'
2
2
  require_relative './cddlgrammar'
3
3
 
4
4
  class Treetop::Runtime::SyntaxNode
@@ -2,14 +2,13 @@ require_relative "../cddlc.rb"
2
2
  require_relative "./cddl-visitor.rb"
3
3
 
4
4
  class CDDL
5
- def substitute(prod, parms, args, &block)
6
- subs = Hash[parms.zip(args)]
5
+ def substitute(prod, parms, subs, &block)
7
6
  visit(prod) do |p, &block1|
8
7
  case p
9
- in ["gen", name, *gen_args]
8
+ in ["gen", name, *gen_args] # XXX
10
9
  [true, gen_apply(name, gen_args, &block1)]
11
- in ["name", name]
12
- if replacement = subs[name]
10
+ in ["arg", num]
11
+ if replacement = subs[num]
13
12
  [true, visit(expand_prod(replacement), &block)]
14
13
  end
15
14
  else
@@ -35,15 +34,19 @@ class CDDL
35
34
  def expand_generics
36
35
  @gen = {}
37
36
  rules.each do |name, prod|
38
- if Array === name
39
- @gen[name[0]] = [name[1..-1], prod]
37
+ case prod
38
+ in ["parm", parmnames, type]
39
+ if prod[0] == "parm"
40
+ @gen[name] = [parmnames, type]
41
+ end
42
+ else
40
43
  end
41
44
  end
42
45
  p @gen if $options.verbose
43
46
  @gen.each do |k, v|
44
- namep = v[0]
45
- fail unless rules[[k, *namep]] == v[1]
46
- rules.delete([k, *namep])
47
+ parmnames = v[0]
48
+ fail unless rules[k] == ["parm", parmnames, v[1]]
49
+ rules.delete(k)
47
50
  end
48
51
  @new_rules = {}
49
52
  rules.each do |name, prod|
@@ -3,27 +3,36 @@ require_relative "./cddl-visitor.rb"
3
3
  require_relative "./cddl-expander.rb"
4
4
 
5
5
  class CDDL
6
- def cddl_undefined
7
- # currently only works on expanded...
8
- cddl2 = self
9
- cddl2.expand_generics
10
- used = {}
11
- gen_used = {}
12
- def_gen = {}
13
- cddl2.rules.each do |k, v|
14
- def_gen[k[0]] = true if Array === k
15
- cddl2.visit(v) do |p, &block|
16
- case p
6
+ def cddl_extract_names(prod, &name_used)
7
+ visit(prod) do |p|
8
+ case p
17
9
  in ["gen", name, *_gen_args]
18
- gen_used[name] = true
10
+ name_used.call(name)
11
+ false
19
12
  in ["name", name]
20
- used[name] = true
13
+ name_used.call(name)
14
+ false
21
15
  else
22
16
  false
23
- end
24
17
  end
25
18
  end
26
- [used.keys.reject {|name| cddl2.rules[name] || prelude.rules[name]},
27
- gen_used.keys.reject {|name| def_gen[name] }]
19
+ end
20
+
21
+ def cddl_add_used_by(prod, used)
22
+ cddl_extract_names(prod) do |name|
23
+ used[name] = true
24
+ end
25
+ end
26
+
27
+ def cddl_undefined
28
+ # currently only works on expanded...
29
+ cddl2 = self.deep_clone # needs deep-clone
30
+ cddl2.expand_generics
31
+ used = {}
32
+ cddl2.rules.each do |k, v|
33
+ fail unless String === k
34
+ cddl2.cddl_add_used_by(v, used)
35
+ end
36
+ used.keys.reject {|name| cddl2.rules[name] || prelude.rules[name]}
28
37
  end
29
38
  end
@@ -11,6 +11,8 @@ class CDDL
11
11
  end
12
12
 
13
13
  case prod
14
+ in ["parm", parmnames, prod]
15
+ ["parm", parmnames, visit(prod, &block)]
14
16
  in ["gen", name, *types]
15
17
  ["gen", name, *visit_all(types, &block)]
16
18
  in ["op", op, *prods]
@@ -2,11 +2,10 @@ require_relative "../cddlc.rb"
2
2
 
3
3
  class CDDL
4
4
 
5
- def write_lhs(k)
6
- case k
7
- in [id, *parms]
8
- "#{id}<#{parms.join(", ")}>"
9
- in String
5
+ def write_lhs(k, parmnames)
6
+ if parmnames
7
+ "#{k}<#{parmnames.join(", ")}>"
8
+ else
10
9
  k
11
10
  end
12
11
  end
@@ -26,35 +25,41 @@ class CDDL
26
25
  end
27
26
  end
28
27
 
29
- def write_rhs(v, targetprec = 0, indent = 0)
28
+ def write_rhs(v, targetprec = 0, indent = 0, pn = [])
29
+ # pn = parmnames
30
30
  # warn "** #{v.inspect}"
31
31
  indent_p = " " * indent
32
32
  indent += 1
33
33
  indent_s = " " * indent
34
34
  prec, ret =
35
35
  case v
36
+ in ["parm", parmnames, type]
37
+ [4, write_rhs(type, 2, indent, parmnames)]
38
+ in ["arg", Integer => num]
39
+ [4, pn[num] || "id$#{num}"]
36
40
  in ["name", id]
37
41
  [4, id]
38
42
  in ["gen", id, *parms] # oops -- namep vs. namea; ouch
39
- [4, "#{id}<#{parms.map{write_rhs(_1, 2, indent)}.join(", ")}>"]
43
+ [4, "#{id}<#{parms.map{write_rhs(_1, 2, indent, pn)}.join(", ")}>"]
40
44
  in ["tcho", *types]
41
- [2, types.map{write_rhs(_1, 3, indent)}.join(" / ")]
45
+ [2, types.map{write_rhs(_1, 3, indent, pn)}.join(" / ")]
42
46
  in ["gcho", *groups]
43
- [0, groups.map{write_rhs(_1, 2, indent)}.join(" // ")]
47
+ [0, groups.map{write_rhs(_1, 2, indent, pn)}.join(" // ")]
44
48
  in ["op", op, l, r]
45
- [3, "#{write_rhs(l, 3, indent)} #{op} #{write_rhs(r, 3, indent)}"]
49
+ [3, "#{write_rhs(l, 4, indent, pn)} #{op} #{write_rhs(r, 4, indent, pn)}"]
50
+ # 3->4: work around cddl tool limitation
46
51
  in ["map", group]
47
- [4, "{#{write_rhs(group, 0, indent)}}"]
52
+ [3, "{#{write_rhs(group, 0, indent, pn)}}"] # 4->3: work around cddl tool limitation
48
53
  in ["ary", group]
49
- [4, "[#{write_rhs(group, 0, indent)}]"]
54
+ [3, "[#{write_rhs(group, 0, indent, pn)}]"] # 4->3: work around cddl tool limitation
50
55
  in ["unwrap", namep]
51
- [4, "~#{write_rhs(namep, 4, indent)}"]
56
+ [4, "~#{write_rhs(namep, 4, indent, pn)}"]
52
57
  in ["enum", ["name", _name] => namep]
53
- [4, "&#{write_rhs(namep, 4, indent)}"]
58
+ [4, "&#{write_rhs(namep, 4, indent, pn)}"]
54
59
  in ["enum", ["gen", _name, *types] => namep]
55
- [4, "&#{write_rhs(namep, 4, indent)})"]
60
+ [4, "&#{write_rhs(namep, 4, indent, pn)})"]
56
61
  in ["enum", group]
57
- [4, "&(#{write_rhs(group, 0, indent)})"]
62
+ [4, "&(#{write_rhs(group, 0, indent, pn)})"]
58
63
  in ["prim"]
59
64
  [4, "#"]
60
65
  in ["prim", maj]
@@ -62,16 +67,16 @@ class CDDL
62
67
  in ["prim", maj, min]
63
68
  [4, "##{maj}.#{min}"]
64
69
  in ["prim", 6, Integer => tag, type]
65
- [4, "#6.#{tag}(#{write_rhs(type, 0, indent)})"]
70
+ [4, "#6.#{tag}(#{write_rhs(type, 0, indent, pn)})"]
66
71
  in ["prim", 6, nil, type]
67
- [4, "#6(#{write_rhs(type, 0, indent)})"]
72
+ [4, "#6(#{write_rhs(type, 0, indent, pn)})"]
68
73
  # prim: extension for #6.<i>(t)
69
74
  in ["seq", *groups]
70
75
  case groups.size
71
76
  when 0; [4, ""]
72
- # when 1; "#{write_rhs(g[0], targetprec, indent)}"
77
+ # when 1; "#{write_rhs(g[0], targetprec, indent, pn)}"
73
78
  else
74
- [1, "\n#{indent_p}#{groups.map{write_rhs(_1, 1, indent)}.join(",\n#{indent_p}")},\n"]
79
+ [1, "\n#{indent_p}#{groups.map{write_rhs(_1, 1, indent, pn)}.join(",\n#{indent_p}")},\n"]
75
80
  end
76
81
  in ["rep", s, e, group]
77
82
  occur = case [s, e]
@@ -82,13 +87,16 @@ class CDDL
82
87
  else
83
88
  "#{s}*#{e || ""}"
84
89
  end
85
- [1, "#{occur}#{write_rhs(group, 2, indent)}"]
90
+ [1, "#{occur}#{write_rhs(group, 2, indent, pn)}"]
86
91
  in ["mem", nil, t2]
87
- [2, write_rhs(t2, 2, indent)]
92
+ [2, write_rhs(t2, 2, indent, pn)]
88
93
  in ["mem", t1, t2]
89
- [2, "#{write_rhs(t1, 2, indent)} => #{write_rhs(t2, 2, indent)}"]
94
+ [2, "#{write_rhs(t1, 3, indent, pn)} => #{write_rhs(t2, 2, indent, pn)}"]
95
+ # 2->3: work around cddl tool limitation
96
+ in ["bytes", t]
97
+ [4, t] # XXX not very clean
90
98
  in ["text", t]
91
- [4, "\"#{t}\""] # XXX escape
99
+ [4, "\"#{t}\""] # XXX escape
92
100
  in ["number", t]
93
101
  [4, t.to_s]
94
102
  end
@@ -97,7 +105,12 @@ class CDDL
97
105
 
98
106
  def to_s
99
107
  rules.map {|k, v|
100
- "#{write_lhs(k)} = #{write_rhs(v, 2)}" # 2: parenthesize groups
108
+ parmnames = false
109
+ case v
110
+ in ["parm", parmnames, _type]
111
+ else
112
+ end
113
+ "#{write_lhs(k, parmnames)} = #{write_rhs(v, 2)}" # 2: parenthesize groups
101
114
  }.join("\n")
102
115
  end
103
116
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cddlc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Carsten Bormann
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-25 00:00:00.000000000 Z
11
+ date: 2023-02-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -76,7 +76,26 @@ files:
76
76
  - bin/cddlc
77
77
  - cddlc.gemspec
78
78
  - data/prelude.cddl
79
+ - data/rfc8727.cddl
80
+ - data/rfc8927.cddl
81
+ - data/rfc8990.cddl
79
82
  - data/rfc9052.cddl
83
+ - data/rfc9053.cddl
84
+ - data/rfc9054.cddl
85
+ - data/rfc9090.cddl
86
+ - data/rfc9115.cddl
87
+ - data/rfc9164.cddl
88
+ - data/rfc9165.cddl
89
+ - data/rfc9171.cddl
90
+ - data/rfc9173.cddl
91
+ - data/rfc9177.cddl
92
+ - data/rfc9202.cddl
93
+ - data/rfc9203.cddl
94
+ - data/rfc9237.cddl
95
+ - data/rfc9277.cddl
96
+ - data/rfc9290.cddl
97
+ - data/rfc9321.cddl
98
+ - data/rfc9338.cddl
80
99
  - lib/cddlc.rb
81
100
  - lib/parser/cddl-util.rb
82
101
  - lib/parser/cddlgrammar.rb