kpeg 1.3.1 → 1.3.2

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