kpeg 1.3.1 → 1.3.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69daab2a8357318c67653138ac1279d035305af374c0840164b535d3110a9a34
4
- data.tar.gz: 703023a2c28f68a26cf1b84255e4aede05880eb6356ced93ec244bad471f05f7
3
+ metadata.gz: abed16806bd433f58dd9911eb8c68f2d50e4a56af15b4e2a7f4eba333727a969
4
+ data.tar.gz: 28e547321489a71fa5fc8058d9b236123d1e4da143fe6e7d4f437a8f8bd2c27f
5
5
  SHA512:
6
- metadata.gz: f98d1334465ea3728004aea43b5abe33d8deae27c4100beaa091a87292ac0197a4580207b3036da616054d5dab8f931621597fc6c2294698eb32842be37e5458
7
- data.tar.gz: acbd264cfd9de363de5eac6107baa58ef43535b5a071fee6da11ff2b33cdd6c2a378664b137b9bb359504b12b0e2f2060fca8cfde53d8196309c68f3132e6e0f
6
+ metadata.gz: 96523e0c2694a0f5e5af682e22ecbebf268d40add7dd97e25db90725c686982d220fb77c22962bf21025cbddfe570763c01b3720304a8b57d99508e9eab0d00a
7
+ data.tar.gz: 94716fa06ffb6e5a9322753ae60de879ad4aab8bdeb854590e9b5a201cb73b35aeec7378a5907b38e8571433586f28c323251a66c274368ce687f4994614b041
data/Rakefile CHANGED
@@ -1,19 +1,6 @@
1
1
  # -*- ruby -*-
2
2
 
3
3
  require 'rubygems'
4
- require 'hoe'
5
-
6
- Hoe.plugin :gemspec
7
- Hoe.plugin :git
8
- Hoe.plugin :minitest
9
- Hoe.plugin :travis
10
-
11
- Hoe.spec 'kpeg' do
12
- self.readme_file = "README.rdoc"
13
- developer 'Evan Phoenix', 'evan@fallingsnow.net'
14
-
15
- dependency 'minitest', '~> 5.0', :dev
16
- end
17
4
 
18
5
  task :test => :parser
19
6
 
@@ -39,9 +26,14 @@ PARSER_FILES.map do |parser_file|
39
26
  file parser_file => 'lib/kpeg/compiled_parser.rb'
40
27
  file parser_file => 'lib/kpeg/code_generator.rb'
41
28
  file parser_file => 'lib/kpeg/position.rb'
29
+ file parser_file => parser_file.sub(/\.rb$/, '.kpeg')
42
30
  end
43
31
 
44
32
  desc "build the parser"
45
33
  task :parser => PARSER_FILES
46
34
 
35
+ task :gem do
36
+ sh "gem build"
37
+ end
38
+
47
39
  # vim: syntax=ruby
data/kpeg.gemspec CHANGED
@@ -1,42 +1,36 @@
1
1
  # -*- encoding: utf-8 -*-
2
- # stub: kpeg 1.0.0.20140103162640 ruby lib
3
2
 
4
3
  Gem::Specification.new do |s|
5
4
  s.name = "kpeg"
6
- s.version = "1.0.0.20140103162640"
5
+ s.version = "1.3.2"
7
6
 
8
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.metadata = { "bug_tracker_uri" => "https://github.com/evanphx/kpeg/issues", "homepage_uri" => "https://github.com/evanphx/kpeg" } if s.respond_to? :metadata=
9
+ s.require_paths = ["lib"]
9
10
  s.authors = ["Evan Phoenix"]
10
- s.date = "2014-01-04"
11
+ s.date = "2022-11-02"
11
12
  s.description = "KPeg is a simple PEG library for Ruby. It provides an API as well as native\ngrammar to build the grammar.\n\nKPeg strives to provide a simple, powerful API without being too exotic.\n\nKPeg supports direct left recursion of rules via the\n{OMeta memoization}[http://www.vpri.org/pdf/tr2008003_experimenting.pdf] trick."
12
13
  s.email = ["evan@fallingsnow.net"]
13
14
  s.executables = ["kpeg"]
14
- s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc", "examples/phone_number/README.md", "examples/upper/README.md"]
15
- s.files = [".autotest", ".travis.yml", "History.txt", "LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "bin/kpeg", "examples/calculator/calculator.kpeg", "examples/calculator/calculator.rb", "examples/foreign_reference/literals.kpeg", "examples/foreign_reference/matcher.kpeg", "examples/foreign_reference/matcher.rb", "examples/lua_string/driver.rb", "examples/lua_string/lua_string.kpeg", "examples/lua_string/lua_string.kpeg.rb", "examples/phone_number/README.md", "examples/phone_number/phone_number.kpeg", "examples/phone_number/phone_number.rb", "examples/upper/README.md", "examples/upper/upper.kpeg", "examples/upper/upper.rb", "kpeg.gemspec", "lib/hoe/kpeg.rb", "lib/kpeg.rb", "lib/kpeg/code_generator.rb", "lib/kpeg/compiled_parser.rb", "lib/kpeg/format_parser.kpeg", "lib/kpeg/format_parser.rb", "lib/kpeg/grammar.rb", "lib/kpeg/grammar_renderer.rb", "lib/kpeg/match.rb", "lib/kpeg/parser.rb", "lib/kpeg/position.rb", "lib/kpeg/string_escape.kpeg", "lib/kpeg/string_escape.rb", "test/inputs/comments.kpeg", "test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_format_parser_round_trip.rb", "test/test_kpeg_grammar.rb", "test/test_kpeg_grammar_renderer.rb", "vim/syntax_kpeg/ftdetect/kpeg.vim", "vim/syntax_kpeg/syntax/kpeg.vim", "test/test_kpeg_string_escape.rb", ".gemtest"]
15
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc", "examples/phone_number/README.md", "examples/tiny_markdown/sample.md", "examples/upper/README.md"]
16
+ s.files = [".autotest", "Gemfile", "History.txt", "LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "bin/kpeg", "examples/calculator/calculator.kpeg", "examples/calculator/calculator.rb", "examples/foreign_reference/literals.kpeg", "examples/foreign_reference/matcher.kpeg", "examples/foreign_reference/matcher.rb", "examples/lua_string/driver.rb", "examples/lua_string/lua_string.kpeg", "examples/lua_string/lua_string.kpeg.rb", "examples/phone_number/README.md", "examples/phone_number/phone_number.kpeg", "examples/phone_number/phone_number.rb", "examples/tiny_markdown/Rakefile", "examples/tiny_markdown/driver.rb", "examples/tiny_markdown/node.rb", "examples/tiny_markdown/sample.md", "examples/tiny_markdown/tiny_markdown.kpeg", "examples/tiny_markdown/tiny_markdown.kpeg.rb", "examples/upper/README.md", "examples/upper/upper.kpeg", "examples/upper/upper.rb", "kpeg.gemspec", "lib/hoe/kpeg.rb", "lib/kpeg.rb", "lib/kpeg/code_generator.rb", "lib/kpeg/compiled_parser.rb", "lib/kpeg/format_parser.kpeg", "lib/kpeg/format_parser.rb", "lib/kpeg/grammar.rb", "lib/kpeg/grammar_renderer.rb", "lib/kpeg/match.rb", "lib/kpeg/parser.rb", "lib/kpeg/position.rb", "lib/kpeg/string_escape.kpeg", "lib/kpeg/string_escape.rb", "test/inputs/comments.kpeg", "test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_format_parser_round_trip.rb", "test/test_kpeg_grammar.rb", "test/test_kpeg_grammar_renderer.rb", "test/test_kpeg_string_escape.rb", "vim/syntax_kpeg/ftdetect/kpeg.vim", "vim/syntax_kpeg/syntax/kpeg.vim"]
16
17
  s.homepage = "https://github.com/evanphx/kpeg"
17
- s.licenses = ["MIT"]
18
+ s.licenses = ["BSD-3-Clause"]
18
19
  s.rdoc_options = ["--main", "README.rdoc"]
19
- s.require_paths = ["lib"]
20
- s.rubyforge_project = "kpeg"
21
- s.rubygems_version = "2.1.10"
20
+ s.rubygems_version = "3.3.7"
22
21
  s.summary = "KPeg is a simple PEG library for Ruby"
23
- s.test_files = ["test/test_kpeg.rb", "test/test_kpeg_code_generator.rb", "test/test_kpeg_compiled_parser.rb", "test/test_kpeg_format.rb", "test/test_kpeg_format_parser_round_trip.rb", "test/test_kpeg_grammar.rb", "test/test_kpeg_grammar_renderer.rb", "test/test_kpeg_string_escape.rb"]
24
22
 
25
23
  if s.respond_to? :specification_version then
26
24
  s.specification_version = 4
25
+ end
27
26
 
28
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
29
- s.add_development_dependency(%q<minitest>, ["~> 5.2"])
30
- s.add_development_dependency(%q<rdoc>, ["~> 4.0"])
31
- s.add_development_dependency(%q<hoe>, ["~> 3.7"])
32
- else
33
- s.add_dependency(%q<minitest>, ["~> 5.2"])
34
- s.add_dependency(%q<rdoc>, ["~> 4.0"])
35
- s.add_dependency(%q<hoe>, ["~> 3.7"])
36
- end
27
+ if s.respond_to? :add_runtime_dependency then
28
+ s.add_development_dependency(%q<minitest>, ["~> 5.16"])
29
+ s.add_development_dependency(%q<rdoc>, [">= 4.0", "< 7"])
30
+ s.add_development_dependency(%q<rake>, [">= 0.8", "< 15.0"])
37
31
  else
38
- s.add_dependency(%q<minitest>, ["~> 5.2"])
39
- s.add_dependency(%q<rdoc>, ["~> 4.0"])
40
- s.add_dependency(%q<hoe>, ["~> 3.7"])
32
+ s.add_dependency(%q<minitest>, ["~> 5.16"])
33
+ s.add_dependency(%q<rdoc>, [">= 4.0", "< 7"])
34
+ s.add_dependency(%q<rake>, [">= 0.8", "< 15.0"])
41
35
  end
42
36
  end
@@ -52,6 +52,7 @@ module KPeg
52
52
  @string = string
53
53
  @string_size = string ? string.size : 0
54
54
  @pos = pos
55
+ @position_line_offsets = nil
55
56
  end
56
57
 
57
58
  def show_pos
@@ -76,30 +77,22 @@ module KPeg
76
77
  end
77
78
 
78
79
  def failure_caret
79
- l = current_line @failing_rule_offset
80
- c = current_column @failing_rule_offset
81
-
82
- line = lines[l-1]
83
- "#{line}\n#{' ' * (c - 1)}^"
80
+ p = current_pos_info @failing_rule_offset
81
+ "#{p.line.chomp}\n#{' ' * (p.col - 1)}^"
84
82
  end
85
83
 
86
84
  def failure_character
87
- l = current_line @failing_rule_offset
88
- c = current_column @failing_rule_offset
89
- lines[l-1][c-1, 1]
85
+ current_character @failing_rule_offset
90
86
  end
91
87
 
92
88
  def failure_oneline
93
- l = current_line @failing_rule_offset
94
- c = current_column @failing_rule_offset
95
-
96
- char = lines[l-1][c-1, 1]
89
+ p = current_pos_info @failing_rule_offset
97
90
 
98
91
  if @failed_rule.kind_of? Symbol
99
92
  info = self.class::Rules[@failed_rule]
100
- "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
93
+ "@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'"
101
94
  else
102
- "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
95
+ "@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'"
103
96
  end
104
97
  end
105
98
 
@@ -112,10 +105,9 @@ module KPeg
112
105
 
113
106
  def show_error(io=STDOUT)
114
107
  error_pos = @failing_rule_offset
115
- line_no = current_line(error_pos)
116
- col_no = current_column(error_pos)
108
+ p = current_pos_info(error_pos)
117
109
 
118
- io.puts "On line #{line_no}, column #{col_no}:"
110
+ io.puts "On line #{p.lno}, column #{p.col}:"
119
111
 
120
112
  if @failed_rule.kind_of? Symbol
121
113
  info = self.class::Rules[@failed_rule]
@@ -124,10 +116,9 @@ module KPeg
124
116
  io.puts "Failed to match rule '#{@failed_rule}'"
125
117
  end
126
118
 
127
- io.puts "Got: #{string[error_pos,1].inspect}"
128
- line = lines[line_no-1]
129
- io.puts "=> #{line}"
130
- io.print(" " * (col_no + 3))
119
+ io.puts "Got: #{p.char.inspect}"
120
+ io.puts "=> #{p.line}"
121
+ io.print(" " * (p.col + 2))
131
122
  io.puts "^"
132
123
  end
133
124
 
@@ -53,7 +53,7 @@ require 'kpeg/grammar'
53
53
  | "x" < /[a-f\d]{2}/i > { [text.to_i(16)].pack("U") }
54
54
  # TODO use /\h{2}/ after 1.8 support is dropped
55
55
  dbl_seq = < /[^\\"]+/ > { text }
56
- dbl_not_quote = ("\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }
56
+ dbl_not_quote = ("\\" dbl_escapes | dbl_seq)*:ary { Array(ary) }
57
57
  dbl_string = "\"" dbl_not_quote:s "\"" { @g.str(s.join) }
58
58
  sgl_escape_quote = "\\'" { "'" }
59
59
  sgl_seq = < /[^']/ > { text }
@@ -20,45 +20,75 @@ class KPeg::FormatParser
20
20
  attr_accessor :result, :pos
21
21
 
22
22
  def current_column(target=pos)
23
- if c = string.rindex("\n", target-1)
24
- return target - c - 1
23
+ if string[target] == "\n" && (c = string.rindex("\n", target-1) || -1)
24
+ return target - c
25
+ elsif c = string.rindex("\n", target)
26
+ return target - c
25
27
  end
26
28
 
27
29
  target + 1
28
30
  end
29
31
 
32
+ def position_line_offsets
33
+ unless @position_line_offsets
34
+ @position_line_offsets = []
35
+ total = 0
36
+ string.each_line do |line|
37
+ total += line.size
38
+ @position_line_offsets << total
39
+ end
40
+ end
41
+ @position_line_offsets
42
+ end
43
+
30
44
  if [].respond_to? :bsearch_index
31
45
  def current_line(target=pos)
32
- unless @line_offsets
33
- @line_offsets = []
34
- total = 0
35
- string.each_line do |line|
36
- total += line.size
37
- @line_offsets << total
38
- end
46
+ if line = position_line_offsets.bsearch_index {|x| x > target }
47
+ return line + 1
39
48
  end
40
-
41
- @line_offsets.bsearch_index {|x| x >= target } + 1 || -1
49
+ raise "Target position #{target} is outside of string"
42
50
  end
43
51
  else
44
52
  def current_line(target=pos)
45
- cur_offset = 0
46
- cur_line = 0
47
-
48
- string.each_line do |line|
49
- cur_line += 1
50
- cur_offset += line.size
51
- return cur_line if cur_offset >= target
53
+ if line = position_line_offsets.index {|x| x > target }
54
+ return line + 1
52
55
  end
53
56
 
54
- -1
57
+ raise "Target position #{target} is outside of string"
58
+ end
59
+ end
60
+
61
+ def current_character(target=pos)
62
+ if target < 0 || target >= string.size
63
+ raise "Target position #{target} is outside of string"
55
64
  end
65
+ string[target, 1]
66
+ end
67
+
68
+ KpegPosInfo = Struct.new(:pos, :lno, :col, :line, :char)
69
+
70
+ def current_pos_info(target=pos)
71
+ l = current_line target
72
+ c = current_column target
73
+ ln = get_line(l-1)
74
+ chr = string[target,1]
75
+ KpegPosInfo.new(target, l, c, ln, chr)
56
76
  end
57
77
 
58
78
  def lines
59
- lines = []
60
- string.each_line { |l| lines << l }
61
- lines
79
+ string.lines
80
+ end
81
+
82
+ def get_line(no)
83
+ loff = position_line_offsets
84
+ if no < 0
85
+ raise "Line No is out of range: #{no} < 0"
86
+ elsif no >= loff.size
87
+ raise "Line No is out of range: #{no} >= #{loff.size}"
88
+ end
89
+ lend = loff[no]-1
90
+ lstart = no > 0 ? loff[no-1] : 0
91
+ string[lstart..lend]
62
92
  end
63
93
 
64
94
 
@@ -72,6 +102,7 @@ class KPeg::FormatParser
72
102
  @string = string
73
103
  @string_size = string ? string.size : 0
74
104
  @pos = pos
105
+ @position_line_offsets = nil
75
106
  end
76
107
 
77
108
  def show_pos
@@ -96,30 +127,22 @@ class KPeg::FormatParser
96
127
  end
97
128
 
98
129
  def failure_caret
99
- l = current_line @failing_rule_offset
100
- c = current_column @failing_rule_offset
101
-
102
- line = lines[l-1]
103
- "#{line}\n#{' ' * (c - 1)}^"
130
+ p = current_pos_info @failing_rule_offset
131
+ "#{p.line.chomp}\n#{' ' * (p.col - 1)}^"
104
132
  end
105
133
 
106
134
  def failure_character
107
- l = current_line @failing_rule_offset
108
- c = current_column @failing_rule_offset
109
- lines[l-1][c-1, 1]
135
+ current_character @failing_rule_offset
110
136
  end
111
137
 
112
138
  def failure_oneline
113
- l = current_line @failing_rule_offset
114
- c = current_column @failing_rule_offset
115
-
116
- char = lines[l-1][c-1, 1]
139
+ p = current_pos_info @failing_rule_offset
117
140
 
118
141
  if @failed_rule.kind_of? Symbol
119
142
  info = self.class::Rules[@failed_rule]
120
- "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
143
+ "@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'"
121
144
  else
122
- "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
145
+ "@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'"
123
146
  end
124
147
  end
125
148
 
@@ -132,10 +155,9 @@ class KPeg::FormatParser
132
155
 
133
156
  def show_error(io=STDOUT)
134
157
  error_pos = @failing_rule_offset
135
- line_no = current_line(error_pos)
136
- col_no = current_column(error_pos)
158
+ p = current_pos_info(error_pos)
137
159
 
138
- io.puts "On line #{line_no}, column #{col_no}:"
160
+ io.puts "On line #{p.lno}, column #{p.col}:"
139
161
 
140
162
  if @failed_rule.kind_of? Symbol
141
163
  info = self.class::Rules[@failed_rule]
@@ -144,10 +166,9 @@ class KPeg::FormatParser
144
166
  io.puts "Failed to match rule '#{@failed_rule}'"
145
167
  end
146
168
 
147
- io.puts "Got: #{string[error_pos,1].inspect}"
148
- line = lines[line_no-1]
149
- io.puts "=> #{line}"
150
- io.print(" " * (col_no + 3))
169
+ io.puts "Got: #{p.char.inspect}"
170
+ io.puts "=> #{p.line}"
171
+ io.print(" " * (p.col + 2))
151
172
  io.puts "^"
152
173
  end
153
174
 
@@ -910,7 +931,7 @@ class KPeg::FormatParser
910
931
  return _tmp
911
932
  end
912
933
 
913
- # dbl_not_quote = ("\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }
934
+ # dbl_not_quote = ("\\" dbl_escapes | dbl_seq)*:ary { Array(ary) }
914
935
  def _dbl_not_quote
915
936
 
916
937
  _save = self.pos
@@ -929,7 +950,6 @@ class KPeg::FormatParser
929
950
  break
930
951
  end
931
952
  _tmp = apply(:_dbl_escapes)
932
- s = @result
933
953
  unless _tmp
934
954
  self.pos = _save3
935
955
  end
@@ -939,7 +959,6 @@ class KPeg::FormatParser
939
959
  break if _tmp
940
960
  self.pos = _save2
941
961
  _tmp = apply(:_dbl_seq)
942
- s = @result
943
962
  break if _tmp
944
963
  self.pos = _save2
945
964
  break
@@ -3158,7 +3177,7 @@ class KPeg::FormatParser
3158
3177
  Rules[:_dbl_escapes] = rule_info("dbl_escapes", "(\"n\" { \"\\n\" } | \"s\" { \" \" } | \"r\" { \"\\r\" } | \"t\" { \"\\t\" } | \"v\" { \"\\v\" } | \"f\" { \"\\f\" } | \"b\" { \"\\b\" } | \"a\" { \"\\a\" } | \"e\" { \"\\e\" } | \"\\\\\" { \"\\\\\" } | \"\\\"\" { \"\\\"\" } | num_escapes | < . > { text })")
3159
3178
  Rules[:_num_escapes] = rule_info("num_escapes", "(< /[0-7]{1,3}/ > { [text.to_i(8)].pack(\"U\") } | \"x\" < /[a-f\\d]{2}/i > { [text.to_i(16)].pack(\"U\") })")
3160
3179
  Rules[:_dbl_seq] = rule_info("dbl_seq", "< /[^\\\\\"]+/ > { text }")
3161
- Rules[:_dbl_not_quote] = rule_info("dbl_not_quote", "(\"\\\\\" dbl_escapes:s | dbl_seq:s)*:ary { Array(ary) }")
3180
+ Rules[:_dbl_not_quote] = rule_info("dbl_not_quote", "(\"\\\\\" dbl_escapes | dbl_seq)*:ary { Array(ary) }")
3162
3181
  Rules[:_dbl_string] = rule_info("dbl_string", "\"\\\"\" dbl_not_quote:s \"\\\"\" { @g.str(s.join) }")
3163
3182
  Rules[:_sgl_escape_quote] = rule_info("sgl_escape_quote", "\"\\\\'\" { \"'\" }")
3164
3183
  Rules[:_sgl_seq] = rule_info("sgl_seq", "< /[^']/ > { text }")
data/lib/kpeg/position.rb CHANGED
@@ -3,45 +3,75 @@ module KPeg
3
3
  # STANDALONE START
4
4
 
5
5
  def current_column(target=pos)
6
- if c = string.rindex("\n", target-1)
7
- return target - c - 1
6
+ if string[target] == "\n" && (c = string.rindex("\n", target-1) || -1)
7
+ return target - c
8
+ elsif c = string.rindex("\n", target)
9
+ return target - c
8
10
  end
9
11
 
10
12
  target + 1
11
13
  end
12
14
 
15
+ def position_line_offsets
16
+ unless @position_line_offsets
17
+ @position_line_offsets = []
18
+ total = 0
19
+ string.each_line do |line|
20
+ total += line.size
21
+ @position_line_offsets << total
22
+ end
23
+ end
24
+ @position_line_offsets
25
+ end
26
+
13
27
  if [].respond_to? :bsearch_index
14
28
  def current_line(target=pos)
15
- unless @line_offsets
16
- @line_offsets = []
17
- total = 0
18
- string.each_line do |line|
19
- total += line.size
20
- @line_offsets << total
21
- end
29
+ if line = position_line_offsets.bsearch_index {|x| x > target }
30
+ return line + 1
22
31
  end
23
-
24
- @line_offsets.bsearch_index {|x| x >= target } + 1 || -1
32
+ raise "Target position #{target} is outside of string"
25
33
  end
26
34
  else
27
35
  def current_line(target=pos)
28
- cur_offset = 0
29
- cur_line = 0
30
-
31
- string.each_line do |line|
32
- cur_line += 1
33
- cur_offset += line.size
34
- return cur_line if cur_offset >= target
36
+ if line = position_line_offsets.index {|x| x > target }
37
+ return line + 1
35
38
  end
36
39
 
37
- -1
40
+ raise "Target position #{target} is outside of string"
38
41
  end
39
42
  end
40
43
 
44
+ def current_character(target=pos)
45
+ if target < 0 || target >= string.size
46
+ raise "Target position #{target} is outside of string"
47
+ end
48
+ string[target, 1]
49
+ end
50
+
51
+ KpegPosInfo = Struct.new(:pos, :lno, :col, :line, :char)
52
+
53
+ def current_pos_info(target=pos)
54
+ l = current_line target
55
+ c = current_column target
56
+ ln = get_line(l-1)
57
+ chr = string[target,1]
58
+ KpegPosInfo.new(target, l, c, ln, chr)
59
+ end
60
+
41
61
  def lines
42
- lines = []
43
- string.each_line { |l| lines << l }
44
- lines
62
+ string.lines
63
+ end
64
+
65
+ def get_line(no)
66
+ loff = position_line_offsets
67
+ if no < 0
68
+ raise "Line No is out of range: #{no} < 0"
69
+ elsif no >= loff.size
70
+ raise "Line No is out of range: #{no} >= #{loff.size}"
71
+ end
72
+ lend = loff[no]-1
73
+ lstart = no > 0 ? loff[no-1] : 0
74
+ string[lstart..lend]
45
75
  end
46
76
 
47
77
  # STANDALONE END
@@ -28,45 +28,75 @@ class KPeg::StringEscape
28
28
  attr_accessor :result, :pos
29
29
 
30
30
  def current_column(target=pos)
31
- if c = string.rindex("\n", target-1)
32
- return target - c - 1
31
+ if string[target] == "\n" && (c = string.rindex("\n", target-1) || -1)
32
+ return target - c
33
+ elsif c = string.rindex("\n", target)
34
+ return target - c
33
35
  end
34
36
 
35
37
  target + 1
36
38
  end
37
39
 
40
+ def position_line_offsets
41
+ unless @position_line_offsets
42
+ @position_line_offsets = []
43
+ total = 0
44
+ string.each_line do |line|
45
+ total += line.size
46
+ @position_line_offsets << total
47
+ end
48
+ end
49
+ @position_line_offsets
50
+ end
51
+
38
52
  if [].respond_to? :bsearch_index
39
53
  def current_line(target=pos)
40
- unless @line_offsets
41
- @line_offsets = []
42
- total = 0
43
- string.each_line do |line|
44
- total += line.size
45
- @line_offsets << total
46
- end
54
+ if line = position_line_offsets.bsearch_index {|x| x > target }
55
+ return line + 1
47
56
  end
48
-
49
- @line_offsets.bsearch_index {|x| x >= target } + 1 || -1
57
+ raise "Target position #{target} is outside of string"
50
58
  end
51
59
  else
52
60
  def current_line(target=pos)
53
- cur_offset = 0
54
- cur_line = 0
55
-
56
- string.each_line do |line|
57
- cur_line += 1
58
- cur_offset += line.size
59
- return cur_line if cur_offset >= target
61
+ if line = position_line_offsets.index {|x| x > target }
62
+ return line + 1
60
63
  end
61
64
 
62
- -1
65
+ raise "Target position #{target} is outside of string"
66
+ end
67
+ end
68
+
69
+ def current_character(target=pos)
70
+ if target < 0 || target >= string.size
71
+ raise "Target position #{target} is outside of string"
63
72
  end
73
+ string[target, 1]
74
+ end
75
+
76
+ KpegPosInfo = Struct.new(:pos, :lno, :col, :line, :char)
77
+
78
+ def current_pos_info(target=pos)
79
+ l = current_line target
80
+ c = current_column target
81
+ ln = get_line(l-1)
82
+ chr = string[target,1]
83
+ KpegPosInfo.new(target, l, c, ln, chr)
64
84
  end
65
85
 
66
86
  def lines
67
- lines = []
68
- string.each_line { |l| lines << l }
69
- lines
87
+ string.lines
88
+ end
89
+
90
+ def get_line(no)
91
+ loff = position_line_offsets
92
+ if no < 0
93
+ raise "Line No is out of range: #{no} < 0"
94
+ elsif no >= loff.size
95
+ raise "Line No is out of range: #{no} >= #{loff.size}"
96
+ end
97
+ lend = loff[no]-1
98
+ lstart = no > 0 ? loff[no-1] : 0
99
+ string[lstart..lend]
70
100
  end
71
101
 
72
102
 
@@ -80,6 +110,7 @@ class KPeg::StringEscape
80
110
  @string = string
81
111
  @string_size = string ? string.size : 0
82
112
  @pos = pos
113
+ @position_line_offsets = nil
83
114
  end
84
115
 
85
116
  def show_pos
@@ -104,30 +135,22 @@ class KPeg::StringEscape
104
135
  end
105
136
 
106
137
  def failure_caret
107
- l = current_line @failing_rule_offset
108
- c = current_column @failing_rule_offset
109
-
110
- line = lines[l-1]
111
- "#{line}\n#{' ' * (c - 1)}^"
138
+ p = current_pos_info @failing_rule_offset
139
+ "#{p.line.chomp}\n#{' ' * (p.col - 1)}^"
112
140
  end
113
141
 
114
142
  def failure_character
115
- l = current_line @failing_rule_offset
116
- c = current_column @failing_rule_offset
117
- lines[l-1][c-1, 1]
143
+ current_character @failing_rule_offset
118
144
  end
119
145
 
120
146
  def failure_oneline
121
- l = current_line @failing_rule_offset
122
- c = current_column @failing_rule_offset
123
-
124
- char = lines[l-1][c-1, 1]
147
+ p = current_pos_info @failing_rule_offset
125
148
 
126
149
  if @failed_rule.kind_of? Symbol
127
150
  info = self.class::Rules[@failed_rule]
128
- "@#{l}:#{c} failed rule '#{info.name}', got '#{char}'"
151
+ "@#{p.lno}:#{p.col} failed rule '#{info.name}', got '#{p.char}'"
129
152
  else
130
- "@#{l}:#{c} failed rule '#{@failed_rule}', got '#{char}'"
153
+ "@#{p.lno}:#{p.col} failed rule '#{@failed_rule}', got '#{p.char}'"
131
154
  end
132
155
  end
133
156
 
@@ -140,10 +163,9 @@ class KPeg::StringEscape
140
163
 
141
164
  def show_error(io=STDOUT)
142
165
  error_pos = @failing_rule_offset
143
- line_no = current_line(error_pos)
144
- col_no = current_column(error_pos)
166
+ p = current_pos_info(error_pos)
145
167
 
146
- io.puts "On line #{line_no}, column #{col_no}:"
168
+ io.puts "On line #{p.lno}, column #{p.col}:"
147
169
 
148
170
  if @failed_rule.kind_of? Symbol
149
171
  info = self.class::Rules[@failed_rule]
@@ -152,10 +174,9 @@ class KPeg::StringEscape
152
174
  io.puts "Failed to match rule '#{@failed_rule}'"
153
175
  end
154
176
 
155
- io.puts "Got: #{string[error_pos,1].inspect}"
156
- line = lines[line_no-1]
157
- io.puts "=> #{line}"
158
- io.print(" " * (col_no + 3))
177
+ io.puts "Got: #{p.char.inspect}"
178
+ io.puts "=> #{p.line}"
179
+ io.print(" " * (p.col + 2))
159
180
  io.puts "^"
160
181
  end
161
182
 
data/test/test_kpeg.rb CHANGED
@@ -22,7 +22,7 @@ class TestKPeg < Minitest::Test
22
22
  end
23
23
 
24
24
  assert_match KPeg.match("hello", gram), "hello"
25
- assert_equal nil, KPeg.match("vador", gram)
25
+ assert_nil KPeg.match("vador", gram)
26
26
  end
27
27
 
28
28
  def test_reg
@@ -48,7 +48,7 @@ class TestKPeg < Minitest::Test
48
48
 
49
49
  assert_match KPeg.match("hello", gram), "hello"
50
50
  assert_match KPeg.match("chicken", gram), "chicken"
51
- assert_equal nil, KPeg.match("vador", gram)
51
+ assert_nil KPeg.match("vador", gram)
52
52
  end
53
53
 
54
54
  def test_maybe
@@ -78,7 +78,7 @@ class TestKPeg < Minitest::Test
78
78
  assert_match sm, "run"
79
79
  end
80
80
 
81
- assert_equal nil, KPeg.match("vador", gram)
81
+ assert_nil KPeg.match("vador", gram)
82
82
  end
83
83
 
84
84
  def test_kleene
@@ -124,9 +124,9 @@ class TestKPeg < Minitest::Test
124
124
  assert_match sm, "run"
125
125
  end
126
126
 
127
- assert_equal nil, KPeg.match("run", gram)
128
- assert_equal nil, KPeg.match("runrunrunrunrun", gram)
129
- assert_equal nil, KPeg.match("vador", gram)
127
+ assert_nil KPeg.match("run", gram)
128
+ assert_nil KPeg.match("runrunrunrunrun", gram)
129
+ assert_nil KPeg.match("vador", gram)
130
130
  end
131
131
 
132
132
  def test_seq
@@ -141,8 +141,8 @@ class TestKPeg < Minitest::Test
141
141
 
142
142
  assert_equal m.value, ["hello", ", world"]
143
143
 
144
- assert_equal nil, KPeg.match("vador", gram)
145
- assert_equal nil, KPeg.match("hello, vador", gram)
144
+ assert_nil KPeg.match("vador", gram)
145
+ assert_nil KPeg.match("hello, vador", gram)
146
146
  end
147
147
 
148
148
  def test_andp
@@ -346,7 +346,7 @@ class TestKPeg < Minitest::Test
346
346
  parser = KPeg::Parser.new "hello", gram
347
347
  m = parser.parse
348
348
 
349
- assert_equal nil, m
349
+ assert_nil m
350
350
  end
351
351
 
352
352
  def test_math_grammar
@@ -1079,7 +1079,7 @@ end
1079
1079
 
1080
1080
  code = cg.make("")
1081
1081
  assert code.parse
1082
- assert_equal nil, code.result
1082
+ assert_nil code.result
1083
1083
  end
1084
1084
 
1085
1085
 
@@ -21,11 +21,40 @@ class TestKPegCompiledParser < Minitest::Test
21
21
  KPeg.compile gram, "CompTestParser", self
22
22
 
23
23
  def test_current_column
24
- r = TestParser.new "hello\nsir"
24
+ r = TestParser.new "hello\nsir\nand goodbye"
25
+ assert_equal 1, r.current_column(0)
25
26
  assert_equal 2, r.current_column(1)
26
27
  assert_equal 6, r.current_column(5)
27
- assert_equal 1, r.current_column(7)
28
- assert_equal 4, r.current_column(10)
28
+ assert_equal 2, r.current_column(7)
29
+ assert_equal 4, r.current_column(9)
30
+ assert_equal 1, r.current_column(10)
31
+ assert_equal 11, r.current_column(20)
32
+ assert_equal 13, r.current_column(22)
33
+ end
34
+
35
+ def test_current_line
36
+ r = TestParser.new "hello\nsir\nand goodbye"
37
+ assert_equal 1, r.current_line(0)
38
+ assert_equal 1, r.current_line(1)
39
+ assert_equal 1, r.current_line(5)
40
+ assert_equal 2, r.current_line(7)
41
+ assert_equal 2, r.current_line(9)
42
+ assert_equal 3, r.current_line(10)
43
+ assert_equal 3, r.current_line(20)
44
+ assert_raises { r.current_line(22) }
45
+ end
46
+
47
+
48
+ def test_current_character
49
+ r = TestParser.new "hello\nsir\nand goodbye"
50
+ assert_equal ?h, r.current_character(0)
51
+ assert_equal ?e, r.current_character(1)
52
+ assert_equal ?\n, r.current_character(5)
53
+ assert_equal ?i, r.current_character(7)
54
+ assert_equal ?\n, r.current_character(9)
55
+ assert_equal ?a, r.current_character(10)
56
+ assert_equal ?e, r.current_character(20)
57
+ assert_raises { r.current_character(22) }
29
58
  end
30
59
 
31
60
  def test_failed_rule
@@ -36,7 +65,7 @@ class TestKPegCompiledParser < Minitest::Test
36
65
  end
37
66
 
38
67
  def test_failure_info
39
- r = TestParser.new "9"
68
+ r = TestParser.new "9\n1"
40
69
  assert !r.parse, "shouldn't parse"
41
70
 
42
71
  expected = "line 1, column 1: failed rule 'letter' = '[a-z]'"
@@ -45,21 +74,21 @@ class TestKPegCompiledParser < Minitest::Test
45
74
  end
46
75
 
47
76
  def test_failure_caret
48
- r = TestParser.new "9"
77
+ r = TestParser.new "9\n1"
49
78
  assert !r.parse, "shouldn't parse"
50
79
 
51
80
  assert_equal "9\n^", r.failure_caret
52
81
  end
53
82
 
54
83
  def test_failure_character
55
- r = TestParser.new "9"
84
+ r = TestParser.new "9\n1"
56
85
  assert !r.parse, "shouldn't parse"
57
86
 
58
87
  assert_equal "9", r.failure_character
59
88
  end
60
89
 
61
90
  def test_failure_oneline
62
- r = TestParser.new "9"
91
+ r = TestParser.new "9\n1"
63
92
  assert !r.parse, "shouldn't parse"
64
93
 
65
94
  expected = "@1:1 failed rule 'letter', got '9'"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kpeg
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Evan Phoenix
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-10 00:00:00.000000000 Z
11
+ date: 2022-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -16,14 +16,14 @@ dependencies:
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '5.14'
19
+ version: '5.16'
20
20
  type: :development
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: '5.14'
26
+ version: '5.16'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: rdoc
29
29
  requirement: !ruby/object:Gem::Requirement
@@ -45,19 +45,25 @@ dependencies:
45
45
  - !ruby/object:Gem::Version
46
46
  version: '7'
47
47
  - !ruby/object:Gem::Dependency
48
- name: hoe
48
+ name: rake
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ">="
52
52
  - !ruby/object:Gem::Version
53
- version: '3.23'
53
+ version: '0.8'
54
+ - - "<"
55
+ - !ruby/object:Gem::Version
56
+ version: '15.0'
54
57
  type: :development
55
58
  prerelease: false
56
59
  version_requirements: !ruby/object:Gem::Requirement
57
60
  requirements:
58
- - - "~>"
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0.8'
64
+ - - "<"
59
65
  - !ruby/object:Gem::Version
60
- version: '3.23'
66
+ version: '15.0'
61
67
  description: |-
62
68
  KPeg is a simple PEG library for Ruby. It provides an API as well as native
63
69
  grammar to build the grammar.
@@ -80,7 +86,6 @@ extra_rdoc_files:
80
86
  - examples/upper/README.md
81
87
  files:
82
88
  - ".autotest"
83
- - ".hoeignore"
84
89
  - Gemfile
85
90
  - History.txt
86
91
  - LICENSE
@@ -135,10 +140,10 @@ files:
135
140
  - vim/syntax_kpeg/syntax/kpeg.vim
136
141
  homepage: https://github.com/evanphx/kpeg
137
142
  licenses:
138
- - MIT
143
+ - BSD-3-Clause
139
144
  metadata:
140
- homepage_uri: https://github.com/evanphx/kpeg
141
145
  bug_tracker_uri: https://github.com/evanphx/kpeg/issues
146
+ homepage_uri: https://github.com/evanphx/kpeg
142
147
  post_install_message:
143
148
  rdoc_options:
144
149
  - "--main"
@@ -156,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
156
161
  - !ruby/object:Gem::Version
157
162
  version: '0'
158
163
  requirements: []
159
- rubygems_version: 3.2.15
164
+ rubygems_version: 3.3.7
160
165
  signing_key:
161
166
  specification_version: 4
162
167
  summary: KPeg is a simple PEG library for Ruby
data/.hoeignore DELETED
@@ -1,12 +0,0 @@
1
- .hoeignore
2
- .gitignore
3
- .travis.yml
4
- .git/
5
- t/
6
- tmp/
7
- scratch/
8
- test/
9
- examples/
10
- Gemfile.lock
11
- *.jar
12
- *.bundle