junoser 0.7.2 → 0.7.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/CHANGELOG.md +8 -0
- data/Gemfile +10 -0
- data/Gemfile.lock +36 -6
- data/Rakefile +6 -3
- data/bin/console +4 -3
- data/exe/junoser +6 -5
- data/exe/junoser-squash +9 -6
- data/junoser.gemspec +15 -17
- data/lib/junoser/cli.rb +2 -2
- data/lib/junoser/development.rb +2 -0
- data/lib/junoser/display/config_store.rb +12 -12
- data/lib/junoser/display/enumerable.rb +6 -4
- data/lib/junoser/display/set.rb +15 -17
- data/lib/junoser/display/structure.rb +7 -7
- data/lib/junoser/display.rb +2 -0
- data/lib/junoser/input.rb +11 -10
- data/lib/junoser/js_ruler.rb +74 -66
- data/lib/junoser/parser.rb +156 -0
- data/lib/junoser/rule_tree/node.rb +3 -1
- data/lib/junoser/rule_tree/parser.rb +11 -8
- data/lib/junoser/rule_tree.rb +2 -0
- data/lib/junoser/ruler.rb +190 -170
- data/lib/junoser/squash.rb +16 -14
- data/lib/junoser/transformer.rb +9 -8
- data/lib/junoser/version.rb +3 -1
- data/lib/junoser/xsd/base.rb +15 -14
- data/lib/junoser/xsd/choice.rb +10 -9
- data/lib/junoser/xsd/complex_type.rb +13 -11
- data/lib/junoser/xsd/element.rb +34 -36
- data/lib/junoser/xsd/enumeration.rb +9 -8
- data/lib/junoser/xsd/parsable.rb +2 -0
- data/lib/junoser/xsd/restriction.rb +15 -13
- data/lib/junoser/xsd/sequence.rb +11 -8
- data/lib/junoser/xsd/simple_content.rb +6 -4
- data/lib/junoser/xsd/simple_type.rb +7 -5
- data/lib/junoser/xsd/union.rb +6 -4
- data/lib/junoser.rb +2 -0
- data/lib/underscorable.rb +10 -5
- metadata +5 -65
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/test-linux.yaml +0 -30
- data/.gitignore +0 -11
- data/.pre-commit-config.yaml +0 -7
- data/commitlint.config.js +0 -6
data/lib/junoser/ruler.rb
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# rubocop:disable Style/PerlBackrefs -- to simplify
|
4
|
+
|
1
5
|
module Junoser
|
2
6
|
class Ruler
|
3
7
|
OFFSET = ' '
|
@@ -7,20 +11,20 @@ module Junoser
|
|
7
11
|
end
|
8
12
|
|
9
13
|
def to_rule
|
10
|
-
rule_header << rule << rule_footer
|
14
|
+
+rule_header << rule << rule_footer
|
11
15
|
end
|
12
16
|
|
13
17
|
def rule
|
14
18
|
str = @rule.read
|
15
19
|
str = remove_comments(str)
|
16
20
|
str = process_reserved_element(str)
|
17
|
-
str.split(
|
21
|
+
str.split("\n").map { |l| fmt(process_line(l)) }.join("\n")
|
18
22
|
end
|
19
23
|
|
20
24
|
private
|
21
25
|
|
22
26
|
def remove_comments(str)
|
23
|
-
str.gsub(%r
|
27
|
+
str.gsub(%r{\s*/\*.*\*/}, '')
|
24
28
|
end
|
25
29
|
|
26
30
|
def process_line(str)
|
@@ -29,21 +33,31 @@ module Junoser
|
|
29
33
|
str.gsub!(/("[^"]+")/) { "str(#{$1})" } # "foo" -> str("foo")
|
30
34
|
|
31
35
|
str.gsub!(/^(\s*)arg(\.as\(:\S+\))? \($/) { "#{$1}b(arg#{$2}," } # arg ( -> b(arg,
|
32
|
-
|
33
|
-
str.gsub!(/^(\s*)(str\(\S+\)) (
|
34
|
-
|
36
|
+
# str("foo") bar -> a(str("foo"), bar)
|
37
|
+
str.gsub!(/^(\s*)(str\(\S+\)) ([^ \t\n\r\f(|,]+)(\.as\(:\S+\))?(,?)$/) do
|
38
|
+
"#{$1}a(#{$2}, #{$3})#{$4}#{$5}"
|
39
|
+
end
|
40
|
+
# str("foo") (a | b) -> a(str("foo"), a | b)
|
41
|
+
str.gsub!(/^(\s*)(str\(\S+\)) (enum)?\((.*)\)(,?)$/) do
|
42
|
+
"#{$1}a(#{$2}, #{$3}#{$4})#{$5}"
|
43
|
+
end
|
35
44
|
str.gsub!(/^(\s*)(str\(\S+\)) \($/) { "#{$1}b(#{$2}," } # str("foo") ( -> b(str("foo"),
|
36
45
|
str.gsub!(/^(\s*)(enum)?(\(.*\))(\.as\(:\S\))? \($/) { "#{$1}b(#{$2}#{$3}#{$4}," } # (a | b) ( -> b((a | b),
|
37
|
-
|
38
|
-
str.gsub!(/^(\s*)(str\(\S+\)) (
|
39
|
-
|
46
|
+
# str("foo") bar ( -> b(a(str("foo"), bar),
|
47
|
+
str.gsub!(/^(\s*)(str\(\S+\)) ([^ \t\n\r\f(|,]+) \($/) do
|
48
|
+
"#{$1}b(a(#{$2}, #{$3}),"
|
49
|
+
end
|
50
|
+
# str("foo") (a | b) ( -> a(str("foo"), a | b,
|
51
|
+
str.gsub!(/^(\s*)(str\(\S+\)) (enum)?\((.*)\) \($/) do
|
52
|
+
"#{$1}a(#{$2}, #{$3}#{$4},"
|
53
|
+
end
|
40
54
|
str
|
41
55
|
end
|
42
56
|
|
43
57
|
def process_reserved_element(str)
|
44
|
-
str.gsub!
|
58
|
+
str.gsub!(/"\$\S+"/, 'arg')
|
45
59
|
|
46
|
-
str.gsub!
|
60
|
+
str.gsub!(/"groups" \(\s*s\(\s*any\s*\)\s*\)/, <<-REPLACE.strip)
|
47
61
|
b(a("groups", arg),
|
48
62
|
c(
|
49
63
|
configuration,
|
@@ -65,7 +79,7 @@ module Junoser
|
|
65
79
|
)
|
66
80
|
)
|
67
81
|
)
|
68
|
-
|
82
|
+
REPLACE
|
69
83
|
|
70
84
|
str.gsub! '"equal-literal"', '"="'
|
71
85
|
str.gsub! '"plus-literal"', '"+"'
|
@@ -81,55 +95,55 @@ module Junoser
|
|
81
95
|
str.gsub! '"tcp-flags" arg', '"tcp-flags" (quote | arg)'
|
82
96
|
|
83
97
|
str.gsub!(/^(\s*)"as-path" arg \(\s*c\(\s*arg/) do
|
84
|
-
|
85
|
-
|
86
|
-
|
98
|
+
fmt(['"as-path" arg (',
|
99
|
+
' c(',
|
100
|
+
' quote | arg'], $1)
|
87
101
|
end
|
88
102
|
|
89
103
|
str.gsub!(/^rule\(:regular_expression\) do\s.*?\s*end/) do
|
90
|
-
<<~
|
104
|
+
<<~REPLACE
|
91
105
|
rule(:regular_expression) do
|
92
106
|
(quote | arg).as(:arg)
|
93
107
|
end
|
94
|
-
|
108
|
+
REPLACE
|
95
109
|
end
|
96
110
|
|
97
111
|
str.gsub!(/^rule\(:login_user_object\) do\s*arg\.as\(:arg\) \(\s*c\(\s*"full-name" arg,/) do
|
98
|
-
<<~
|
112
|
+
<<~REPLACE
|
99
113
|
rule(:login_user_object) do
|
100
114
|
arg.as(:arg) (
|
101
115
|
sc(
|
102
116
|
"full-name" (quote | arg),
|
103
|
-
|
117
|
+
REPLACE
|
104
118
|
end
|
105
119
|
|
106
120
|
str.gsub!(/^(\s*)"location" arg,\s*"contact" arg,/) do
|
107
|
-
|
108
|
-
|
121
|
+
fmt(['"location" (quote | arg),',
|
122
|
+
'"contact" (quote | arg),'], $1)
|
109
123
|
end
|
110
124
|
|
111
125
|
str.gsub!(/^(\s*)"as-path" \(\s*c\(\s*"path" arg/) do
|
112
|
-
|
113
|
-
|
114
|
-
|
126
|
+
fmt(['"as-path" (',
|
127
|
+
' c(',
|
128
|
+
' "path" (quote | arg)'], $1)
|
115
129
|
end
|
116
130
|
|
117
131
|
str.gsub!(/^(\s*)prefix_list_items,\s*"apply-path" arg/) do
|
118
|
-
|
119
|
-
|
132
|
+
fmt(['"apply-path" (quote | arg),',
|
133
|
+
'prefix_list_items'], $1)
|
120
134
|
end
|
121
135
|
|
122
136
|
str.gsub!(/^(\s*)"drop-profile-map" \(\s*s\(\s*"loss-priority" \(\s*(.*\s*\),)\s*"protocol" \(\s*(.*\s*\),)\s*c\(\s*"drop-profile" (.*)/) do
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
137
|
+
fmt([
|
138
|
+
'"drop-profile-map" (',
|
139
|
+
' s(',
|
140
|
+
' s("loss-priority",',
|
141
|
+
" #{$2}",
|
142
|
+
' s("protocol",',
|
143
|
+
" #{$3}",
|
144
|
+
' s("drop-profile",',
|
145
|
+
" #{$4}"
|
146
|
+
], $1)
|
133
147
|
end
|
134
148
|
|
135
149
|
#
|
@@ -145,15 +159,15 @@ module Junoser
|
|
145
159
|
str.gsub!(/^(rule\(:server_group_type\) do\s*)c\(\s*c\(\s*arg\s*\)\s*\)/) { "#{$1}s(arg, arg)" }
|
146
160
|
|
147
161
|
str.gsub!(/^(rule\(:rib_group_inet_type\) do)\s*c\(\s*arg/) do
|
148
|
-
|
149
|
-
|
150
|
-
|
162
|
+
fmt([$1,
|
163
|
+
' ca(',
|
164
|
+
' a(arg, arg)'], '')
|
151
165
|
end
|
152
166
|
|
153
167
|
# Fix overkill
|
154
168
|
str.gsub!(/^(\s*)"priority" \(\s*ca\(\s*arg\s*\)/) do
|
155
|
-
|
156
|
-
|
169
|
+
fmt(['"priority" (',
|
170
|
+
' a(arg, arg)', $1])
|
157
171
|
end
|
158
172
|
|
159
173
|
#
|
@@ -166,37 +180,37 @@ module Junoser
|
|
166
180
|
#
|
167
181
|
# "inet",
|
168
182
|
# "inet6"
|
169
|
-
str.gsub!(/"cspf"(.*\s*.*)"cspf-link"/) { %
|
170
|
-
str.gsub!(/"http"(.*\s*.*)"https"/) { %
|
171
|
-
str.gsub!(/"inet"(.*\s*.*)"inet6"/) { %
|
172
|
-
str.gsub!(/"icmp"(.*\s*.*)"icmp6"/) { %
|
173
|
-
str.gsub!(/"icmp"(.*\s*.*)"icmpv6"/) { %
|
174
|
-
str.gsub!(/"snmp"(.*\s*.*)"snmptrap"/) { %
|
175
|
-
str.gsub!(/"ospf"(.*\s*.*)"ospf3"/) { %
|
176
|
-
str.gsub!(/"deny"(.*\s*.*)"deny-password"/) { %
|
177
|
-
str.gsub!(/"no-redirects"(.*\s*.*)"no-redirects-ipv6"/) { %
|
178
|
-
str.gsub!(/"chassis"([^()]*)"chassis-ha-reswatch"/m) { %
|
183
|
+
str.gsub!(/"cspf"(.*\s*.*)"cspf-link"/) { %("cspf-link"#{$1}"cspf") }
|
184
|
+
str.gsub!(/"http"(.*\s*.*)"https"/) { %("https"#{$1}"http") }
|
185
|
+
str.gsub!(/"inet"(.*\s*.*)"inet6"/) { %("inet6"#{$1}"inet") }
|
186
|
+
str.gsub!(/"icmp"(.*\s*.*)"icmp6"/) { %("icmp6"#{$1}"icmp") }
|
187
|
+
str.gsub!(/"icmp"(.*\s*.*)"icmpv6"/) { %("icmpv6"#{$1}"icmp") }
|
188
|
+
str.gsub!(/"snmp"(.*\s*.*)"snmptrap"/) { %("snmptrap"#{$1}"snmp") }
|
189
|
+
str.gsub!(/"ospf"(.*\s*.*)"ospf3"/) { %("ospf3"#{$1}"ospf") }
|
190
|
+
str.gsub!(/"deny"(.*\s*.*)"deny-password"/) { %("deny-password"#{$1}"deny") }
|
191
|
+
str.gsub!(/"no-redirects"(.*\s*.*)"no-redirects-ipv6"/) { %("no-redirects-ipv6"#{$1}"no-redirects") }
|
192
|
+
str.gsub!(/"chassis"([^()]*)"chassis-ha-reswatch"/m) { %("chassis-ha-reswatch"#{$1}"chassis") }
|
179
193
|
str.gsub! '"tls1" | "tls11" | "tls12"', '"tls11" | "tls12" | "tls1"'
|
180
194
|
str.gsub!(/("group1" \| "group2" \| "group5") \| ([^)]+)/) { "#{$2} | #{$1}" }
|
181
195
|
|
182
196
|
%w[ccc ethernet-over-atm tcc vpls bridge].each do |encap|
|
183
|
-
str.gsub!(/"ethernet"(.*)"ethernet-#{encap}"/) { %
|
197
|
+
str.gsub!(/"ethernet"(.*)"ethernet-#{encap}"/) { %("ethernet-#{encap}"#{$1}"ethernet") }
|
184
198
|
end
|
185
199
|
|
186
200
|
str.gsub!(/^(\s*)"path" arg \(\s*c\(\s*sc\(\s*"abstract",\s*c\(\s*"loose",\s*"loose-link",\s*"strict"\s*\)\s*\)\.as\(:oneline\)/) do
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
201
|
+
fmt(['"path" arg (',
|
202
|
+
' c(',
|
203
|
+
' b(',
|
204
|
+
' ipaddr,',
|
205
|
+
' c(',
|
206
|
+
' "abstract",',
|
207
|
+
' c(',
|
208
|
+
' "loose-link",',
|
209
|
+
' "loose",',
|
210
|
+
' "strict"',
|
211
|
+
' )',
|
212
|
+
' ).as(:oneline)',
|
213
|
+
' )', $1])
|
200
214
|
end
|
201
215
|
|
202
216
|
#
|
@@ -207,7 +221,7 @@ module Junoser
|
|
207
221
|
str.gsub!(/\((.*) \| "vlan-id"\)/) { "(#{$1} | arg)" }
|
208
222
|
|
209
223
|
%w[filename].each do |key|
|
210
|
-
str.gsub! %
|
224
|
+
str.gsub! %("#{key}" arg), 'arg'
|
211
225
|
end
|
212
226
|
|
213
227
|
# "filename" fix above leaves "arg". Move to the end
|
@@ -226,14 +240,16 @@ module Junoser
|
|
226
240
|
# Fix .xsd: "arg" is missing
|
227
241
|
#
|
228
242
|
str.gsub!(/"route-filter" (\(\s*control_route_filter_type\s*\))/) { %["route-filter" arg #{$1}.as(:oneline)] }
|
229
|
-
str.gsub!(/"source-address-filter" (\(\s*control_source_address_filter_type\s*\))/)
|
243
|
+
str.gsub!(/"source-address-filter" (\(\s*control_source_address_filter_type\s*\))/) do
|
244
|
+
%["source-adress-filter" arg #{$1}.as(:oneline)]
|
245
|
+
end
|
230
246
|
%w[file].each do |key|
|
231
247
|
str.gsub!(/^(\s*"#{key}" \(\s*)c\(\s*arg,/) { "#{$1}sca(" }
|
232
248
|
end
|
233
249
|
|
234
250
|
# Fix .xsd: Unnecessary "arg" is added
|
235
251
|
%w[exact longer orlonger].each do |key|
|
236
|
-
str.gsub!(/^(\s*"#{key}") arg/) {
|
252
|
+
str.gsub!(/^(\s*"#{key}") arg/) { $1.to_s }
|
237
253
|
end
|
238
254
|
|
239
255
|
# Fix .xsd: "ieee-802.3ad" is invalid
|
@@ -247,7 +263,7 @@ module Junoser
|
|
247
263
|
|
248
264
|
# Fix .xsd: "from-zone" arg is also required
|
249
265
|
str.gsub!(/^ "policy" \(\s*s\(\s*arg,\s*"to-zone-name" arg,\s*(.*?)\s*\)\s*^ \),/m) do
|
250
|
-
|
266
|
+
fmt(['b(', ' s("from-zone", arg, "to-zone", arg),', " #{$1}", '),'], ' ')
|
251
267
|
end
|
252
268
|
|
253
269
|
# Fix .xsd: "members" accepts [ foo bar ]
|
@@ -282,18 +298,20 @@ module Junoser
|
|
282
298
|
|
283
299
|
# Fix .xsd: support "set protocols iccp peer xxx liveness-detection single-hop"
|
284
300
|
str.gsub!(/(^rule\(:peer_group\) do.*?\n(\s*)"detection-time" \(\s*c\(\s*"threshold" arg\s*\)\s*\))/m) do
|
285
|
-
"#{$1},\n#{
|
301
|
+
"#{$1},\n#{fmt('"single-hop"', $2)}"
|
286
302
|
end
|
287
303
|
|
288
304
|
# Fix .xsd: support "set interfaces xxx ether-options speed"
|
289
305
|
str.gsub! '"ethernet-1', '"1'
|
290
306
|
|
291
307
|
# Fix .xsd: support "set policy-options policy-statement xxx from policy [expression]"
|
292
|
-
str.gsub!(/^rule\(:policy_algebra\) do(\s*)arg\.as\(:arg\)\send/)
|
308
|
+
str.gsub!(/^rule\(:policy_algebra\) do(\s*)arg\.as\(:arg\)\send/) do
|
309
|
+
"rule(:policy_algebra) do#{$1}any.as(:arg)\nend"
|
310
|
+
end
|
293
311
|
|
294
312
|
# Fix .xsd: support "set interfaces xxx enable"
|
295
313
|
str.gsub!(/^(rule\(:interfaces_type\) do\s*[^\n]*\s*c\()(\s*)/m) do
|
296
|
-
%
|
314
|
+
%(#{$1}#{$2}"enable",#{$2})
|
297
315
|
end
|
298
316
|
|
299
317
|
# Fix .xsd: arg should be regular_expression
|
@@ -302,7 +320,7 @@ module Junoser
|
|
302
320
|
str
|
303
321
|
end
|
304
322
|
|
305
|
-
def
|
323
|
+
def fmt(str, offset = OFFSET)
|
306
324
|
case str
|
307
325
|
when String
|
308
326
|
str.empty? ? '' : offset + str
|
@@ -314,107 +332,109 @@ module Junoser
|
|
314
332
|
end
|
315
333
|
|
316
334
|
def rule_header
|
317
|
-
|
318
|
-
require 'parslet'
|
319
|
-
|
320
|
-
module Junoser
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
406
|
-
|
407
|
-
|
408
|
-
|
409
|
-
|
335
|
+
<<~HEADER
|
336
|
+
require 'parslet'
|
337
|
+
|
338
|
+
module Junoser
|
339
|
+
class Parser < Parslet::Parser
|
340
|
+
def parse_lines(config)
|
341
|
+
lines = config.split("\\n").map(&:strip)
|
342
|
+
lines_without_deactivate = lines.reject {|l| l =~ /^deactivate/ }
|
343
|
+
|
344
|
+
lines.inject(true) do |passed, line|
|
345
|
+
passed & parse_line(line, lines_without_deactivate)
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def parse_line(line, lines_without_deactivate)
|
350
|
+
if line =~ /^deactivate/
|
351
|
+
if lines_without_deactivate.grep(/^\#{line.sub(/^deactivate/, 'set')}/).empty?
|
352
|
+
$stderr.puts %(Corresponding "set" statement is not found: \#{line})
|
353
|
+
return false
|
354
|
+
else
|
355
|
+
return true
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
begin
|
360
|
+
# .xsd doesn't include "apply-groups"
|
361
|
+
if line =~ /(.*)\\s+apply-groups(-except)?\\s+(\\S+|\\[.*\\])$/
|
362
|
+
return $1 == 'set' ? true : parse($1)
|
363
|
+
end
|
364
|
+
|
365
|
+
parse line
|
366
|
+
true
|
367
|
+
rescue Parslet::ParseFailed
|
368
|
+
$stderr.puts "Invalid syntax: \#{line}"
|
369
|
+
false
|
370
|
+
end
|
371
|
+
end
|
372
|
+
|
373
|
+
# block with children maybe
|
374
|
+
def b(object, *children)
|
375
|
+
children.inject(object) {|rule, child| rule.as(:label) >> (space >> child.as(:child) | eos) }
|
376
|
+
end
|
377
|
+
|
378
|
+
# with an argument, and children maybe
|
379
|
+
def a(object, arg, *children)
|
380
|
+
b(object.as(:statement) >> space >> arg.as(:argument), *children)
|
381
|
+
end
|
382
|
+
|
383
|
+
# choice
|
384
|
+
def c(*objects)
|
385
|
+
objects.inject {|rule, object| rule | object }
|
386
|
+
end
|
387
|
+
|
388
|
+
def ca(*objects)
|
389
|
+
objects.inject {|rule, object| rule | object } | arg
|
390
|
+
end
|
391
|
+
|
392
|
+
# sequence
|
393
|
+
def s(*objects)
|
394
|
+
# TODO: eval "minOccurs" attribute of choice element
|
395
|
+
objects.inject {|rule, object| rule >> (space >> object).maybe }
|
396
|
+
end
|
397
|
+
|
398
|
+
# sequential choice
|
399
|
+
def sc(*objects)
|
400
|
+
(c(*objects) >> space.maybe).repeat(0)
|
401
|
+
end
|
402
|
+
|
403
|
+
def sca(*objects)
|
404
|
+
(c(*objects, arg) >> space.maybe).repeat(0)
|
405
|
+
end
|
406
|
+
|
407
|
+
def enum(object)
|
408
|
+
(object.as(:enum))
|
409
|
+
end
|
410
|
+
|
411
|
+
rule(:arg) { match('\\S').repeat(1) }
|
412
|
+
rule(:space) { match('\\s').repeat(1) }
|
413
|
+
rule(:any) { match('.').repeat(1) }
|
414
|
+
rule(:eos) { match('$') }
|
415
|
+
rule(:dotted) { match('[^. \\t\\n\\r\\f]').repeat(1) >> str('.') >> match('[^. \\t\\n\\r\\f]').repeat(1) }
|
416
|
+
rule(:quote) { str('"') >> match('[^"]').repeat(1) >> str('"') }
|
417
|
+
rule(:address) { match('[0-9a-fA-F:.]').repeat(1) }
|
418
|
+
rule(:prefix ) { address >> (str('/') >> match('[0-9]').repeat(1)).maybe }
|
419
|
+
|
420
|
+
root(:set)
|
421
|
+
rule(:set) { str('set') >> space >> configuration.as(:config) >> comment.maybe }
|
422
|
+
|
423
|
+
rule(:comment) { space.maybe >> (hash_comment | slash_asterisk) }
|
424
|
+
rule(:hash_comment) { str('#') >> any.maybe }
|
425
|
+
rule(:slash_asterisk) { str('/*') >> match('(?!\\*\\/).').repeat(0) >> str('*/') }
|
426
|
+
|
427
|
+
HEADER
|
410
428
|
end
|
411
429
|
|
412
430
|
def rule_footer
|
413
|
-
|
431
|
+
<<~FOOTER
|
414
432
|
|
415
|
-
|
416
|
-
end
|
417
|
-
|
433
|
+
end
|
434
|
+
end
|
435
|
+
FOOTER
|
418
436
|
end
|
419
437
|
end
|
420
438
|
end
|
439
|
+
|
440
|
+
# rubocop:enable Style/PerlBackrefs
|
data/lib/junoser/squash.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'junoser'
|
2
4
|
require 'parslet'
|
3
5
|
|
@@ -22,9 +24,9 @@ module Junoser
|
|
22
24
|
when /^activate /
|
23
25
|
delete_lines l.gsub(/^activate /, 'deactivate ')
|
24
26
|
when /^insert (.*) before (.*)/
|
25
|
-
insert_before "set #{
|
27
|
+
insert_before "set #{::Regexp.last_match(1)}", ::Regexp.last_match(2)
|
26
28
|
when /^insert (.*) after (.*)/
|
27
|
-
insert_after "set #{
|
29
|
+
insert_after "set #{::Regexp.last_match(1)}", ::Regexp.last_match(2)
|
28
30
|
end
|
29
31
|
end
|
30
32
|
|
@@ -36,11 +38,11 @@ module Junoser
|
|
36
38
|
|
37
39
|
def remove_command_context(lines)
|
38
40
|
lines.each_with_index do |l, i|
|
39
|
-
lines[i
|
40
|
-
if l2[-1] ==
|
41
|
-
lines.delete(l2) if l.include?(l2)
|
42
|
-
|
43
|
-
lines.delete(l2)
|
41
|
+
lines[i..].each do |l2|
|
42
|
+
if l2[-1] == ' ' # l2 is a command context
|
43
|
+
lines.delete(l2) if l.include?(l2) && (l != l2)
|
44
|
+
elsif l.include?("#{l2} ") # l2 has argument
|
45
|
+
lines.delete(l2)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -48,24 +50,24 @@ module Junoser
|
|
48
50
|
|
49
51
|
def delete_lines(pattern)
|
50
52
|
@lines.each do |l|
|
51
|
-
l.sub!(/#{pattern}/) {
|
53
|
+
l.sub!(/#{pattern}/) { ::Regexp.last_match(1) }
|
52
54
|
end
|
53
55
|
end
|
54
56
|
|
55
57
|
def split_last_token(line)
|
56
58
|
tokens = join_arg(@transformer.apply(@parser.parse(line))).split("\n")
|
57
|
-
tokens.map!
|
58
|
-
t.gsub!(/arg\((.*)\)/) {
|
59
|
+
tokens.map! do |t|
|
60
|
+
t.gsub!(/arg\((.*)\)/) { ::Regexp.last_match(1).to_s } # Strip arg
|
59
61
|
Regexp.escape(t.strip)
|
60
|
-
|
62
|
+
end
|
61
63
|
|
62
64
|
[tokens[0..-2].join(' '), tokens.last]
|
63
65
|
end
|
64
66
|
|
65
67
|
# Ported from lib/junoser/display/config_store.rb
|
66
68
|
def join_arg(str)
|
67
|
-
str.gsub!(/\narg\((.*)\)$/) { "
|
68
|
-
str.gsub!(/arg\((.*)\)/) {
|
69
|
+
str.gsub!(/\narg\((.*)\)$/) { " #{::Regexp.last_match(1)}" }
|
70
|
+
str.gsub!(/arg\((.*)\)/) { ::Regexp.last_match(1).to_s }
|
69
71
|
str
|
70
72
|
end
|
71
73
|
|
@@ -76,7 +78,7 @@ module Junoser
|
|
76
78
|
|
77
79
|
def insert_before(statement_to_insert, key_statement)
|
78
80
|
key_tokens = key_statement.strip.split
|
79
|
-
key_statement = (statement_to_insert.strip.split[0..-(key_tokens.size+1)] + key_tokens).join(' ')
|
81
|
+
key_statement = (statement_to_insert.strip.split[0..-(key_tokens.size + 1)] + key_tokens).join(' ')
|
80
82
|
|
81
83
|
lines_to_insert = @lines.select { |l| l.include?(statement_to_insert) }
|
82
84
|
@lines.reject! { |l| l.include?(statement_to_insert) }
|
data/lib/junoser/transformer.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'parslet'
|
2
4
|
|
3
5
|
module Junoser
|
@@ -24,7 +26,7 @@ module Junoser
|
|
24
26
|
|
25
27
|
rule(label: simple(:label), child: sequence(:children)) do
|
26
28
|
Junoser::Transformer.remove_slash_asterisk children
|
27
|
-
%
|
29
|
+
%(#{label}\n#{children.join("\n")})
|
28
30
|
end
|
29
31
|
|
30
32
|
rule(statement: simple(:statement), argument: simple(:argument)) do
|
@@ -33,7 +35,7 @@ module Junoser
|
|
33
35
|
|
34
36
|
rule(statement: simple(:statement), argument: sequence(:arguments)) do
|
35
37
|
Junoser::Transformer.remove_slash_asterisk arguments
|
36
|
-
%
|
38
|
+
%(#{statement}\n#{arguments.join("\n")})
|
37
39
|
end
|
38
40
|
|
39
41
|
rule(oneline: simple(:str)) do
|
@@ -52,15 +54,14 @@ module Junoser
|
|
52
54
|
strs.join(' ')
|
53
55
|
end
|
54
56
|
|
55
|
-
|
56
57
|
def self.remove_slash_asterisk(array)
|
57
58
|
open = array.index("arg(/*)\n")
|
58
|
-
close = array.index(
|
59
|
+
close = array.index('arg(*/)')
|
60
|
+
|
61
|
+
return unless open && close
|
59
62
|
|
60
|
-
|
61
|
-
|
62
|
-
array.delete_at i
|
63
|
-
end
|
63
|
+
(open..close).reverse_each do |i|
|
64
|
+
array.delete_at i
|
64
65
|
end
|
65
66
|
end
|
66
67
|
end
|
data/lib/junoser/version.rb
CHANGED