ebnf 1.1.3 → 1.2.0
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/VERSION +1 -1
- data/bin/ebnf +3 -3
- data/lib/ebnf.rb +2 -2
- data/lib/ebnf/ll1.rb +7 -3
- data/lib/ebnf/ll1/lexer.rb +17 -10
- data/lib/ebnf/ll1/parser.rb +19 -12
- data/lib/ebnf/ll1/scanner.rb +3 -3
- data/lib/ebnf/rule.rb +1 -0
- metadata +18 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aae4c0b2a8f6d03654bc5436b36c90e577669c41ea4df25d881be3aef86e5ace
|
4
|
+
data.tar.gz: 7f1b7fe448ae87f3755e6da4fc0faf47dbb3d3b573a3e4a8be9b3066f0fac6fa
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d0f441731842af8ac38f98352b96a47cf6810bfe81ce620f8ef57af87ce6d65c679d88903c35dbce99617b24bdea8fbb70a23d4873d941ae151275a11561627
|
7
|
+
data.tar.gz: f19f527e041a8f1c48da918497660466c5df71a02077e2183472b157a8611cbf87903fe2b6858e889c119211a7fedb279ad4889d811bec5d6132dd9287d74314
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.2.0
|
data/bin/ebnf
CHANGED
@@ -75,19 +75,19 @@ end
|
|
75
75
|
|
76
76
|
input = File.open(ARGV[0]) if ARGV[0]
|
77
77
|
|
78
|
-
ebnf = EBNF.parse(input || STDIN, options)
|
78
|
+
ebnf = EBNF.parse(input || STDIN, **options)
|
79
79
|
ebnf.make_bnf if options[:bnf] || options[:ll1]
|
80
80
|
if options[:ll1]
|
81
81
|
ebnf.first_follow(*options[:ll1])
|
82
82
|
ebnf.build_tables
|
83
|
-
|
83
|
+
end
|
84
84
|
|
85
85
|
res = case options[:output_format]
|
86
86
|
when :ebnf then ebnf.to_s
|
87
87
|
when :html then ebnf.to_html
|
88
88
|
when :sxp then ebnf.to_sxp
|
89
89
|
when :ttl then ebnf.to_ttl(options[:prefix], options[:namespace])
|
90
|
-
when :rb then ebnf.to_ruby(out,
|
90
|
+
when :rb then ebnf.to_ruby(out, grammarFile: ARGV[0], **options)
|
91
91
|
else ebnf.ast.inspect
|
92
92
|
end
|
93
93
|
|
data/lib/ebnf.rb
CHANGED
@@ -17,7 +17,7 @@ module EBNF
|
|
17
17
|
# @param [Hash{Symbol => Object}] options
|
18
18
|
# @return [EBNF::Base]
|
19
19
|
# @raise [Exception] on invalid input
|
20
|
-
def self.parse(input, options
|
21
|
-
query = ::EBNF::Base.new(input, options)
|
20
|
+
def self.parse(input, **options)
|
21
|
+
query = ::EBNF::Base.new(input, **options)
|
22
22
|
end
|
23
23
|
end
|
data/lib/ebnf/ll1.rb
CHANGED
@@ -168,6 +168,10 @@ module EBNF
|
|
168
168
|
progress("first_follow") {"(#{ittr}) firsts #{firsts}, follows #{follows}"}
|
169
169
|
ittr += 1
|
170
170
|
end while (firsts + follows) > 0
|
171
|
+
|
172
|
+
debug("Fi.2-post: non-terminals without first") do
|
173
|
+
ast.reject(&:terminal?).reject(&:first).map(&:sym)
|
174
|
+
end if ast.reject(&:terminal?).any? {|r| r.first.nil?}
|
171
175
|
end
|
172
176
|
end
|
173
177
|
|
@@ -287,16 +291,16 @@ module EBNF
|
|
287
291
|
|
288
292
|
if rule.expr.first == :matches
|
289
293
|
debug("prod") {"Rule is regexp: #{rule}"}
|
290
|
-
|
291
|
-
error("No record of what token #{lhs} can start with") unless rule.first
|
292
294
|
return
|
293
295
|
end
|
294
296
|
|
297
|
+
error("No record of what token #{lhs.inspect} can start with") unless rule.first
|
298
|
+
|
295
299
|
if rule.alt?
|
296
300
|
# A First/Follow conflict appears when _eps is in the first
|
297
301
|
# of one rule and there is a token in the first and
|
298
302
|
# follow of the same rule
|
299
|
-
if rule.first.include?(:_eps) && !(overlap = ((rule.first & (rule.follow || [])) - [:eps])).empty?
|
303
|
+
if Array(rule.first).include?(:_eps) && !(overlap = ((Array(rule.first) & (rule.follow || [])) - [:eps])).empty?
|
300
304
|
error("First/Follow Conflict: #{overlap.first.inspect} is both first and follow of #{rule.sym}")
|
301
305
|
end
|
302
306
|
|
data/lib/ebnf/ll1/lexer.rb
CHANGED
@@ -98,8 +98,8 @@ module EBNF::LL1
|
|
98
98
|
# @yieldparam [Lexer] lexer
|
99
99
|
# @return [Lexer]
|
100
100
|
# @raise [Lexer::Error] on invalid input
|
101
|
-
def self.tokenize(input, terminals, options
|
102
|
-
lexer = self.new(input, terminals, options)
|
101
|
+
def self.tokenize(input, terminals, **options, &block)
|
102
|
+
lexer = self.new(input, terminals, **options)
|
103
103
|
block_given? ? block.call(lexer) : lexer
|
104
104
|
end
|
105
105
|
|
@@ -115,17 +115,24 @@ module EBNF::LL1
|
|
115
115
|
# Whitespace between tokens, including comments
|
116
116
|
# @option options[Integer] :high_water passed to scanner
|
117
117
|
# @option options[Integer] :low_water passed to scanner
|
118
|
-
def initialize(input = nil, terminals = nil, options
|
118
|
+
def initialize(input = nil, terminals = nil, **options)
|
119
119
|
@options = options.dup
|
120
120
|
@whitespace = @options[:whitespace]
|
121
121
|
@terminals = terminals.map do |term|
|
122
|
-
term.is_a?(Array)
|
122
|
+
if term.is_a?(Array) && term.length ==3
|
123
|
+
# Last element is options
|
124
|
+
Terminal.new(term[0], term[1], **term[2])
|
125
|
+
elsif term.is_a?(Array)
|
126
|
+
Terminal.new(*term)
|
127
|
+
else
|
128
|
+
term
|
129
|
+
end
|
123
130
|
end
|
124
131
|
|
125
132
|
raise Error, "Terminal patterns not defined" unless @terminals && @terminals.length > 0
|
126
133
|
|
127
134
|
@lineno = 1
|
128
|
-
@scanner = Scanner.new(input, options)
|
135
|
+
@scanner = Scanner.new(input, **options)
|
129
136
|
end
|
130
137
|
|
131
138
|
##
|
@@ -300,7 +307,7 @@ module EBNF::LL1
|
|
300
307
|
# Cause strings and codepoints to be unescaped.
|
301
308
|
# @option options [Regexp] :partial_regexp
|
302
309
|
# A regular expression matching the beginning of this terminal; useful for terminals that match things longer than the scanner low water mark.
|
303
|
-
def initialize(type, regexp, options
|
310
|
+
def initialize(type, regexp, **options)
|
304
311
|
@type, @regexp, @options = type, regexp, options
|
305
312
|
@partial_regexp = options[:partial_regexp]
|
306
313
|
@map = options.fetch(:map, {})
|
@@ -353,8 +360,8 @@ module EBNF::LL1
|
|
353
360
|
# Scanner instance with access to matched groups
|
354
361
|
# @param [Hash{Symbol => Object}] options
|
355
362
|
# @return [Token]
|
356
|
-
def token(type, value, options
|
357
|
-
Token.new(type, value,
|
363
|
+
def token(type, value, **options)
|
364
|
+
Token.new(type, value, lineno: lineno, **options)
|
358
365
|
end
|
359
366
|
|
360
367
|
##
|
@@ -398,7 +405,7 @@ module EBNF::LL1
|
|
398
405
|
# @param [String] value
|
399
406
|
# @param [Hash{Symbol => Object}] options
|
400
407
|
# @option options [Integer] :lineno (nil)
|
401
|
-
def initialize(type, value, options
|
408
|
+
def initialize(type, value, **options)
|
402
409
|
@type = type.to_s.to_sym if type
|
403
410
|
@value = value.to_s
|
404
411
|
@options = options.dup
|
@@ -514,7 +521,7 @@ module EBNF::LL1
|
|
514
521
|
# @option options [String] :input (nil)
|
515
522
|
# @option options [String] :token (nil)
|
516
523
|
# @option options [Integer] :lineno (nil)
|
517
|
-
def initialize(message, options
|
524
|
+
def initialize(message, **options)
|
518
525
|
@input = options[:input]
|
519
526
|
@token = options[:token]
|
520
527
|
@lineno = options[:lineno]
|
data/lib/ebnf/ll1/parser.rb
CHANGED
@@ -51,10 +51,10 @@ module EBNF::LL1
|
|
51
51
|
# @yieldparam [Proc] block
|
52
52
|
# Block passed to initialization for yielding to calling parser.
|
53
53
|
# Should conform to the yield specs for #initialize
|
54
|
-
def terminal(term, regexp, options
|
54
|
+
def terminal(term, regexp, **options, &block)
|
55
55
|
@patterns ||= []
|
56
56
|
# Passed in order to define evaulation sequence
|
57
|
-
@patterns << EBNF::LL1::Lexer::Terminal.new(term, regexp, options)
|
57
|
+
@patterns << EBNF::LL1::Lexer::Terminal.new(term, regexp, **options)
|
58
58
|
@terminal_handlers ||= {}
|
59
59
|
@terminal_handlers[term] = block if block_given?
|
60
60
|
end
|
@@ -122,7 +122,14 @@ module EBNF::LL1
|
|
122
122
|
|
123
123
|
def method_missing(method, *args, &block)
|
124
124
|
if @delegate ||= nil
|
125
|
-
|
125
|
+
# special handling when last arg is **options
|
126
|
+
params = @delegate.method(method).parameters
|
127
|
+
if params.any? {|t, _| t == :keyrest} && args.last.is_a?(Hash)
|
128
|
+
opts = args.pop
|
129
|
+
@delegate.send(method, *args, **opts, &block)
|
130
|
+
else
|
131
|
+
@delegate.send(method, *args, &block)
|
132
|
+
end
|
126
133
|
else
|
127
134
|
super
|
128
135
|
end
|
@@ -219,7 +226,7 @@ module EBNF::LL1
|
|
219
226
|
# or errors raised during processing callbacks. Internal
|
220
227
|
# errors are raised using {Error}.
|
221
228
|
# @see http://cs.adelaide.edu.au/~charles/lt/Lectures/07-ErrorRecovery.pdf
|
222
|
-
def parse(input = nil, start = nil, options
|
229
|
+
def parse(input = nil, start = nil, **options, &block)
|
223
230
|
@options = options.dup
|
224
231
|
@options[:debug] ||= case
|
225
232
|
when @options[:progress] then 2
|
@@ -229,7 +236,7 @@ module EBNF::LL1
|
|
229
236
|
@first = options[:first] ||= {}
|
230
237
|
@follow = options[:follow] ||= {}
|
231
238
|
@cleanup = options[:cleanup] ||= {}
|
232
|
-
@lexer = input.is_a?(Lexer) ? input : Lexer.new(input, self.class.patterns,
|
239
|
+
@lexer = input.is_a?(Lexer) ? input : Lexer.new(input, self.class.patterns, **@options)
|
233
240
|
@productions = []
|
234
241
|
@parse_callback = block
|
235
242
|
@recovering = false
|
@@ -467,7 +474,7 @@ module EBNF::LL1
|
|
467
474
|
# @option options [URI, #to_s] :production
|
468
475
|
# @option options [Token] :token
|
469
476
|
# @see {#debug}
|
470
|
-
def error(node, message, options
|
477
|
+
def error(node, message, **options)
|
471
478
|
lineno = @lineno || (options[:token].lineno if options[:token].respond_to?(:lineno))
|
472
479
|
m = "ERROR "
|
473
480
|
m += "[line: #{lineno}] " if lineno
|
@@ -476,7 +483,7 @@ module EBNF::LL1
|
|
476
483
|
m += ", production = #{options[:production].inspect}" if options[:production]
|
477
484
|
@error_log << m unless @recovering
|
478
485
|
@recovering = true
|
479
|
-
debug(node, m,
|
486
|
+
debug(node, m, level: 0, **options)
|
480
487
|
if options[:raise] || @options[:validate]
|
481
488
|
raise Error.new(m, lineno: lineno, token: options[:token], production: options[:production])
|
482
489
|
end
|
@@ -491,20 +498,20 @@ module EBNF::LL1
|
|
491
498
|
# @option options [URI, #to_s] :production
|
492
499
|
# @option options [Token] :token
|
493
500
|
# @see {#debug}
|
494
|
-
def warn(node, message, options
|
501
|
+
def warn(node, message, **options)
|
495
502
|
m = "WARNING "
|
496
503
|
m += "[line: #{@lineno}] " if @lineno
|
497
504
|
m += message
|
498
505
|
m += " (found #{options[:token].inspect})" if options[:token]
|
499
506
|
m += ", production = #{options[:production].inspect}" if options[:production]
|
500
507
|
@error_log << m unless @recovering
|
501
|
-
debug(node, m,
|
508
|
+
debug(node, m, level: 1, **options)
|
502
509
|
end
|
503
510
|
|
504
511
|
##
|
505
512
|
# Progress output when parsing. Passed as level `2` debug messages.
|
506
513
|
#
|
507
|
-
# @overload progress(node, message, options)
|
514
|
+
# @overload progress(node, message, **options)
|
508
515
|
# @param [String] node Relevant location associated with message
|
509
516
|
# @param [String] message ("")
|
510
517
|
# @param [Hash] options
|
@@ -526,7 +533,7 @@ module EBNF::LL1
|
|
526
533
|
# if `@options[:debug]` is an Integer, the call is aborted if the
|
527
534
|
# `:level` option is less than than `:level`.
|
528
535
|
#
|
529
|
-
# @overload debug(node, message, options)
|
536
|
+
# @overload debug(node, message, **options)
|
530
537
|
# @param [Array<String>] args Relevant location associated with message
|
531
538
|
# @param [Hash] options
|
532
539
|
# @option options [Integer] :depth
|
@@ -751,7 +758,7 @@ module EBNF::LL1
|
|
751
758
|
# @option options [Symbol] :production (nil)
|
752
759
|
# @option options [String] :token (nil)
|
753
760
|
# @option options [Integer] :lineno (nil)
|
754
|
-
def initialize(message, options
|
761
|
+
def initialize(message, **options)
|
755
762
|
@production = options[:production]
|
756
763
|
@token = options[:token]
|
757
764
|
@lineno = options[:lineno] || (@token.lineno if @token.respond_to?(:lineno))
|
data/lib/ebnf/ll1/scanner.rb
CHANGED
@@ -20,11 +20,11 @@ module EBNF::LL1
|
|
20
20
|
##
|
21
21
|
# If we don't have an IO input, simply use StringScanner directly
|
22
22
|
# @private
|
23
|
-
def self.new(input, options
|
23
|
+
def self.new(input, **options)
|
24
24
|
input ||= ""
|
25
25
|
if input.respond_to?(:read)
|
26
26
|
scanner = self.allocate
|
27
|
-
scanner.send(:initialize, input, options)
|
27
|
+
scanner.send(:initialize, input, **options)
|
28
28
|
else
|
29
29
|
if input.encoding != Encoding::UTF_8
|
30
30
|
input = input.dup if input.frozen?
|
@@ -42,7 +42,7 @@ module EBNF::LL1
|
|
42
42
|
# @option options[Integer] :high_water (HIGH_WATER)
|
43
43
|
# @option options[Integer] :low_water (LOW_WATER)
|
44
44
|
# @return [Scanner]
|
45
|
-
def initialize(input, options
|
45
|
+
def initialize(input, **options)
|
46
46
|
@options = options.merge(high_water: HIGH_WATER, low_water: LOW_WATER)
|
47
47
|
|
48
48
|
@input = input
|
data/lib/ebnf/rule.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ebnf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Gregg Kellogg
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-12-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sxp
|
@@ -16,42 +16,42 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '1.
|
19
|
+
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '1.
|
26
|
+
version: '1.1'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rdf
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '3.
|
33
|
+
version: '3.1'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '3.
|
40
|
+
version: '3.1'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rdf-spec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '3.
|
47
|
+
version: '3.1'
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '3.
|
54
|
+
version: '3.1'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: haml
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -72,56 +72,56 @@ dependencies:
|
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '3.
|
75
|
+
version: '3.9'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '3.
|
82
|
+
version: '3.9'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: rspec-its
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: '1.
|
89
|
+
version: '1.3'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: '1.
|
96
|
+
version: '1.3'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: yard
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.9
|
103
|
+
version: '0.9'
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.9
|
110
|
+
version: '0.9'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rake
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
117
|
+
version: '13.0'
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: '
|
124
|
+
version: '13.0'
|
125
125
|
description: EBNF is a Ruby parser for W3C EBNF and a parser generator for compliant
|
126
126
|
LL(1) grammars.
|
127
127
|
email: public-rdf-ruby@w3.org
|
@@ -175,15 +175,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
175
175
|
requirements:
|
176
176
|
- - ">="
|
177
177
|
- !ruby/object:Gem::Version
|
178
|
-
version: 2.
|
178
|
+
version: '2.4'
|
179
179
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
180
180
|
requirements:
|
181
181
|
- - ">="
|
182
182
|
- !ruby/object:Gem::Version
|
183
183
|
version: '0'
|
184
184
|
requirements: []
|
185
|
-
|
186
|
-
rubygems_version: 2.7.6
|
185
|
+
rubygems_version: 3.0.6
|
187
186
|
signing_key:
|
188
187
|
specification_version: 4
|
189
188
|
summary: EBNF parser and parser generator.
|