cddlc 0.1.1 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
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