oedipus_lex 2.4.1 → 2.5.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ab5673d633e7abae710deb96e4b764b2518bed0e
4
- data.tar.gz: 9e16b31d4ffeaad609fe27812e69f8dfa3b0b8ff
3
+ metadata.gz: 61879597d87d6ef9e59b495a38e10617e03f3277
4
+ data.tar.gz: e5e415035c15bc8c02007a3479f0bbd2fd0d8621
5
5
  SHA512:
6
- metadata.gz: c3948a898e603ccb19494bdcb753f1ae5f799d21660c42a8ba80611884e18a94f615ef1511c79d1ac5f592e6ea7288ab673b6729988e8f8a07d37c881e9f6c6f
7
- data.tar.gz: 7876d02faa16c81ef199ceec5b342cf9bd69e9e0d6c4970328e8e92c49abc3904dd06e1b1a40734fe5cc80314030e2b5cc21d7a2ec60afb60ff66f532a93572c
6
+ metadata.gz: dd4aea54ccd7eb1731bdc5639d4932fe1eadb5b188cf9a79a75971599adeadbfbc867b5790fcb09cf8bdad68f09f715154852a251953b0aa37a66f142c6bc423
7
+ data.tar.gz: 0beb1c01b05a3e567bc0c0702c2c675096a96e0801604e89d28ef7197e7e02fd154a5c1facff60447d068211d2013e04a67e8be260bdcfb2420222a072ff4e97
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -1,3 +1,18 @@
1
+ === 2.5.0 / 2016-11-30
2
+
3
+ * 5 minor enhancements:
4
+
5
+ * Added #location to generated template, provides file:line:column per options.
6
+ * Added LexerError and made ScanError subclass it.
7
+ * Added column option.
8
+ * Errors try to provide location now.
9
+ * Re-bootstrapped.
10
+
11
+ * 2 bug fixes:
12
+
13
+ * Fixed some whitespace generation when using :column.
14
+ * Fixed wiring on column. (steakknife)
15
+
1
16
  === 2.4.1 / 2016-01-21
2
17
 
3
18
  * 1 minor enhancement:
@@ -49,6 +49,7 @@ resource for CS learning. Books... books are good. I like books.
49
49
  | /debug/i
50
50
  | /do_parse/i
51
51
  | /lineno/i
52
+ | /column/i
52
53
 
53
54
  inner_section = /inner/ NL (misc_line)*
54
55
 
@@ -129,6 +130,8 @@ Specify `lineno` to generate automatic line number handling at the
129
130
  beginning of `next_token`. This was the default in 1.0.0 and you must
130
131
  now activate it.
131
132
 
133
+ Specify `column` to generate automatic column number handling.
134
+
132
135
  ==== Inner
133
136
 
134
137
  The inner section is just code, like header or footer, but inner gets
@@ -4,7 +4,7 @@ require "erb"
4
4
  require "oedipus_lex.rex"
5
5
 
6
6
  class OedipusLex
7
- VERSION = "2.4.1"
7
+ VERSION = "2.5.0"
8
8
 
9
9
  attr_accessor :class_name
10
10
  attr_accessor :header
@@ -270,7 +270,8 @@ class OedipusLex
270
270
  % end
271
271
 
272
272
  % end
273
- class ScanError < StandardError ; end
273
+ class LexerError < StandardError ; end
274
+ class ScanError < LexerError ; end
274
275
 
275
276
  % if option[:lineno] then
276
277
  attr_accessor :lineno
@@ -298,8 +299,8 @@ class OedipusLex
298
299
  idx = ss.string.rindex("\n", old_pos) || -1
299
300
  old_pos - idx - 1
300
301
  end
301
- % end
302
302
 
303
+ % end
303
304
  % if option[:do_parse] then
304
305
  def do_parse
305
306
  while token = next_token do
@@ -331,6 +332,20 @@ class OedipusLex
331
332
  end
332
333
  end
333
334
 
335
+ def location
336
+ [
337
+ (filename || "<input>"),
338
+ % if option[:lineno] then
339
+ lineno,
340
+ % elsif option[:column] then
341
+ "?",
342
+ % end
343
+ % if option[:column] then
344
+ column,
345
+ % end
346
+ ].compact.join(":")
347
+ end
348
+
334
349
  def next_token
335
350
  % starts.each do |s|
336
351
  <%= s %>
@@ -358,17 +373,17 @@ class OedipusLex
358
373
  % end # the_states.each
359
374
  else
360
375
  text = ss.string[ss.pos .. -1]
361
- raise ScanError, "can not match (#{state.inspect}): '#{text}'"
376
+ raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
362
377
  end
363
378
  % end # all_states
364
379
  else
365
- raise ScanError, "undefined state: '#{state}'"
380
+ raise ScanError, "undefined state at #{location}: '#{state}'"
366
381
  end # token = case state
367
382
 
368
383
  next unless token # allow functions to trigger redo w/ nil
369
384
  end # while
370
385
 
371
- raise "bad lexical result: #{token.inspect}" unless
386
+ raise LexerError, "bad lexical result at #{location}: #{token.inspect}" unless
372
387
  token.nil? || (Array === token && token.size >= 2)
373
388
 
374
389
  # auto-switch state
@@ -4,6 +4,7 @@ option
4
4
 
5
5
  do_parse
6
6
  lineno
7
+ column
7
8
 
8
9
  macro
9
10
  ST /(?:(:\S+|\w+\??))/
@@ -31,6 +32,7 @@ rule
31
32
  :option /debug/i { [:option, text] }
32
33
  :option /do_parse/i { [:option, text] }
33
34
  :option /lineno/i { [:option, text] }
35
+ :option /column/i { [:option, text] }
34
36
 
35
37
  :inner /.*/ { [:inner, text] }
36
38
 
@@ -1,7 +1,7 @@
1
1
  # encoding: UTF-8
2
2
  #--
3
3
  # This file is automatically generated. Do not modify it.
4
- # Generated by: oedipus_lex version 2.3.0.
4
+ # Generated by: oedipus_lex version 2.4.1.
5
5
  # Source: lib/oedipus_lex.rex
6
6
  #++
7
7
 
@@ -12,7 +12,8 @@ class OedipusLex
12
12
  RE = /(\/(?:\\.|[^\/])+\/[ion]?)/
13
13
  ACT = /(\{.*|:?\w+)/
14
14
 
15
- class ScanError < StandardError ; end
15
+ class LexerError < StandardError ; end
16
+ class ScanError < LexerError ; end
16
17
 
17
18
  attr_accessor :lineno
18
19
  attr_accessor :filename
@@ -31,6 +32,13 @@ class OedipusLex
31
32
  yield
32
33
  end
33
34
 
35
+ attr_accessor :old_pos
36
+
37
+ def column
38
+ idx = ss.string.rindex("\n", old_pos) || -1
39
+ old_pos - idx - 1
40
+ end
41
+
34
42
  def do_parse
35
43
  while token = next_token do
36
44
  type, *vals = token
@@ -58,35 +66,44 @@ class OedipusLex
58
66
  end
59
67
  end
60
68
 
69
+ def location
70
+ [
71
+ (filename || "<input>"),
72
+ lineno,
73
+ column,
74
+ ].compact.join(":")
75
+ end
76
+
61
77
  def next_token
62
- self.lineno += 1 if ss.peek(1) == "\n"
63
78
 
64
79
  token = nil
65
80
 
66
81
  until ss.eos? or token do
82
+ self.lineno += 1 if ss.peek(1) == "\n"
83
+ self.old_pos = ss.pos
67
84
  token =
68
85
  case state
69
86
  when nil, :option, :inner, :start, :macro, :rule, :group then
70
87
  case
71
- when text = ss.scan(/options?.*/) then
88
+ when ss.skip(/options?.*/) then
72
89
  [:state, :option]
73
- when text = ss.scan(/inner.*/) then
90
+ when ss.skip(/inner.*/) then
74
91
  [:state, :inner]
75
- when text = ss.scan(/macros?.*/) then
92
+ when ss.skip(/macros?.*/) then
76
93
  [:state, :macro]
77
- when text = ss.scan(/rules?.*/) then
94
+ when ss.skip(/rules?.*/) then
78
95
  [:state, :rule]
79
- when text = ss.scan(/start.*/) then
96
+ when ss.skip(/start.*/) then
80
97
  [:state, :start]
81
- when text = ss.scan(/end/) then
98
+ when ss.skip(/end/) then
82
99
  [:state, :END]
83
- when text = ss.scan(/\A((?:.|\n)*)class ([\w:]+.*)/) then
100
+ when ss.skip(/\A((?:.|\n)*)class ([\w:]+.*)/) then
84
101
  action { [:class, *matches] }
85
- when text = ss.scan(/\n+/) then
102
+ when ss.skip(/\n+/) then
86
103
  # do nothing
87
104
  when text = ss.scan(/\s*(\#.*)/) then
88
105
  action { [:comment, text] }
89
- when (state == :option) && (text = ss.scan(/\s+/)) then
106
+ when (state == :option) && (ss.skip(/\s+/)) then
90
107
  # do nothing
91
108
  when (state == :option) && (text = ss.scan(/stub/i)) then
92
109
  action { [:option, text] }
@@ -96,44 +113,46 @@ class OedipusLex
96
113
  action { [:option, text] }
97
114
  when (state == :option) && (text = ss.scan(/lineno/i)) then
98
115
  action { [:option, text] }
116
+ when (state == :option) && (text = ss.scan(/column/i)) then
117
+ action { [:option, text] }
99
118
  when (state == :inner) && (text = ss.scan(/.*/)) then
100
119
  action { [:inner, text] }
101
120
  when (state == :start) && (text = ss.scan(/.*/)) then
102
121
  action { [:start, text] }
103
- when (state == :macro) && (text = ss.scan(/\s+(\w+)\s+#{RE}/o)) then
122
+ when (state == :macro) && (ss.skip(/\s+(\w+)\s+#{RE}/o)) then
104
123
  action { [:macro, *matches] }
105
- when (state == :rule) && (text = ss.scan(/\s*#{ST}?[\ \t]*#{RE}[\ \t]*#{ACT}?/o)) then
124
+ when (state == :rule) && (ss.skip(/\s*#{ST}?[\ \t]*#{RE}[\ \t]*#{ACT}?/o)) then
106
125
  action { [:rule, *matches] }
107
- when (state == :rule) && (text = ss.scan(/\s*:[\ \t]*#{RE}/o)) then
126
+ when (state == :rule) && (ss.skip(/\s*:[\ \t]*#{RE}/o)) then
108
127
  action { [:grouphead, *matches] }
109
- when (state == :group) && (text = ss.scan(/\s*:[\ \t]*#{RE}/o)) then
128
+ when (state == :group) && (ss.skip(/\s*:[\ \t]*#{RE}/o)) then
110
129
  action { [:grouphead, *matches] }
111
- when (state == :group) && (text = ss.scan(/\s*\|\s*#{ST}?[\ \t]*#{RE}[\ \t]*#{ACT}?/o)) then
130
+ when (state == :group) && (ss.skip(/\s*\|\s*#{ST}?[\ \t]*#{RE}[\ \t]*#{ACT}?/o)) then
112
131
  action { [:group, *matches] }
113
- when (state == :group) && (text = ss.scan(/\s*#{ST}?[\ \t]*#{RE}[\ \t]*#{ACT}?/o)) then
132
+ when (state == :group) && (ss.skip(/\s*#{ST}?[\ \t]*#{RE}[\ \t]*#{ACT}?/o)) then
114
133
  action { [:groupend, *matches] }
115
134
  else
116
135
  text = ss.string[ss.pos .. -1]
117
- raise ScanError, "can not match (#{state.inspect}): '#{text}'"
136
+ raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
118
137
  end
119
138
  when :END then
120
139
  case
121
- when text = ss.scan(/\n+/) then
140
+ when ss.skip(/\n+/) then
122
141
  # do nothing
123
142
  when text = ss.scan(/.*/) then
124
143
  action { [:end, text] }
125
144
  else
126
145
  text = ss.string[ss.pos .. -1]
127
- raise ScanError, "can not match (#{state.inspect}): '#{text}'"
146
+ raise ScanError, "can not match (#{state.inspect}) at #{location}: '#{text}'"
128
147
  end
129
148
  else
130
- raise ScanError, "undefined state: '#{state}'"
149
+ raise ScanError, "undefined state at #{location}: '#{state}'"
131
150
  end # token = case state
132
151
 
133
152
  next unless token # allow functions to trigger redo w/ nil
134
153
  end # while
135
154
 
136
- raise "bad lexical result: #{token.inspect}" unless
155
+ raise LexerError, "bad lexical result at #{location}: #{token.inspect}" unless
137
156
  token.nil? || (Array === token && token.size >= 2)
138
157
 
139
158
  # auto-switch state
@@ -82,6 +82,26 @@ class TestOedipusLex < Minitest::Test
82
82
  assert_equal expected_msg, e.message
83
83
  end
84
84
 
85
+ def assert_token_error grammar, input, expected_msg
86
+ _, mod = eval_lexer grammar
87
+
88
+ calc = mod::Calculator.new
89
+
90
+ def calc.do_parse
91
+ tokens = []
92
+ while token = next_token
93
+ tokens << token
94
+ end
95
+ tokens
96
+ end
97
+
98
+ e = assert_raises mod::Calculator::LexerError do
99
+ calc.parse input
100
+ end
101
+
102
+ assert_equal expected_msg, e.message
103
+ end
104
+
85
105
  def test_simple_scanner
86
106
  src = <<-'REX'
87
107
  class Calculator
@@ -136,7 +156,7 @@ class TestOedipusLex < Minitest::Test
136
156
  end
137
157
  REX
138
158
 
139
- assert_generate_error src, "can not match (:rule): '"
159
+ assert_generate_error src, "can not match (:rule) at <input>:4:0: '"
140
160
  end
141
161
 
142
162
  def test_simple_scanner_macro
@@ -760,9 +780,50 @@ class TestOedipusLex < Minitest::Test
760
780
  assert_lexer src, txt, exp
761
781
 
762
782
  txt = "aa"
763
- exp = [[:A, 'a'], [:B, 'b'], [:A, 'a'], [:B, 'b'], [:A, 'a']]
764
783
 
765
- assert_lexer_error src, txt, "can not match (:B): 'a'"
784
+ assert_lexer_error src, txt, "can not match (:B) at <input>: 'a'"
785
+ end
786
+
787
+ def test_error_undefined_state
788
+ src = <<-'REX'
789
+ class Calculator
790
+ rule
791
+ /a/ { self.state = :C ; [:A, text] }
792
+ :B /b/ { self.state = nil ; [:B, text] }
793
+ end
794
+ REX
795
+
796
+ txt = "aa"
797
+
798
+ assert_lexer_error src, txt, "undefined state at <input>: 'C'"
799
+ end
800
+
801
+ def test_error_bad_token
802
+ src = <<-'REX'
803
+ class Calculator
804
+ rule
805
+ /a/ { self.state = :B ; :A }
806
+ :B /b/ { self.state = nil ; [:B, text] }
807
+ end
808
+ REX
809
+
810
+ txt = "aa"
811
+
812
+ assert_token_error src, txt, "bad lexical result at <input>: :A"
813
+ end
814
+
815
+ def test_error_bad_token_size
816
+ src = <<-'REX'
817
+ class Calculator
818
+ rule
819
+ /a/ { self.state = :B ; [:A] }
820
+ :B /b/ { self.state = nil ; [:B, text] }
821
+ end
822
+ REX
823
+
824
+ txt = "aa"
825
+
826
+ assert_token_error src, txt, "bad lexical result at <input>: [:A]"
766
827
  end
767
828
 
768
829
  def test_incrementing_lineno_on_nil_token
@@ -781,4 +842,36 @@ class TestOedipusLex < Minitest::Test
781
842
 
782
843
  assert_lexer src, txt, exp
783
844
  end
845
+
846
+ def assert_location exp, option = {}
847
+ self.option = option
848
+
849
+ src = "class Calculator\nrule\n /\\d+/ { [:number, text.to_i] }\nend\n"
850
+
851
+ _, mod = eval_lexer src
852
+
853
+ calc = mod::Calculator.new
854
+ def calc.do_parse
855
+ [next_token]
856
+ end
857
+
858
+ calc.filename = option[:filename] if option[:filename]
859
+ calc.parse "42"
860
+
861
+ assert_equal exp, calc.location
862
+ end
863
+
864
+ def test_location
865
+ t = true
866
+
867
+ assert_location "<input>"
868
+ assert_location "<input>:1", :lineno => t
869
+ assert_location "<input>:?:0", :column => t
870
+ assert_location "<input>:1:0", :lineno => t, :column => t
871
+
872
+ assert_location "blah", :filename => "blah"
873
+ assert_location "blah:1", :filename => "blah", :lineno => t
874
+ assert_location "blah:?:0", :filename => "blah", :column => t
875
+ assert_location "blah:1:0", :filename => "blah", :lineno => t, :column => t
876
+ end
784
877
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: oedipus_lex
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ryan Davis
@@ -10,9 +10,9 @@ bindir: bin
10
10
  cert_chain:
11
11
  - |
12
12
  -----BEGIN CERTIFICATE-----
13
- MIIDPjCCAiagAwIBAgIBAzANBgkqhkiG9w0BAQUFADBFMRMwEQYDVQQDDApyeWFu
13
+ MIIDijCCAnKgAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMRMwEQYDVQQDDApyeWFu
14
14
  ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
15
- GRYDY29tMB4XDTE1MDkxOTIwNTEyMloXDTE2MDkxODIwNTEyMlowRTETMBEGA1UE
15
+ GRYDY29tMB4XDTE2MDkyNjAxNTczNVoXDTE3MDkyNjAxNTczNVowRTETMBEGA1UE
16
16
  AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
17
17
  JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
18
18
  b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
@@ -20,31 +20,18 @@ cert_chain:
20
20
  oOvjtt5P8+GSK9zLzxQP0gVLS/D0FmoE44XuDr3iQkVS2ujU5zZL84mMNqNB1znh
21
21
  GiadM9GHRaDiaxuX0cIUBj19T01mVE2iymf9I6bEsiayK/n6QujtyCbTWsAS9Rqt
22
22
  qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
23
- gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
24
- HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBBQUAA4IB
25
- AQB+Hx8xUgrpZa4P8H8gR8zme5kISwQrG80MbpqJV6/G3/ZicRFhN5sjwu0uHGue
26
- bd9Cymf6oIRwHVarJux2M32T6bL07Hmi07w2QaPc3MnMKB/D46SRZ2JSSGPFRBTc
27
- SilobMRoGs/7B15uGFUEnNrCB/ltMqhwwSx1r++UQPfeySHEV9uqu03E5Vb7J37O
28
- 2Er6PLXHRiYsIycD1LkMi6YnixdITRHmrqJYE2rsjaIfpIehiusVAPHkNf7qbpHq
29
- qx3h45R1CAsObX0SQDIT+rRbQrtKz1GHIZTOFYvEJjUY1XmRTZupD3CJ8Q7sDqSy
30
- NLq5jm1fq6Y9Uolu3RJbmycf
23
+ gBEfoTEGr7Zii72cx+sCAwEAAaOBhDCBgTAJBgNVHRMEAjAAMAsGA1UdDwQEAwIE
24
+ sDAdBgNVHQ4EFgQUR8V72Z3+v+2P9abCnL4wjx32T+EwIwYDVR0RBBwwGoEYcnlh
25
+ bmQtcnVieUB6ZW5zcGlkZXIuY29tMCMGA1UdEgQcMBqBGHJ5YW5kLXJ1YnlAemVu
26
+ c3BpZGVyLmNvbTANBgkqhkiG9w0BAQUFAAOCAQEAIGzgp0aZ2W9+v96ujmBcQHoC
27
+ buy0iU68MVj2VlxMyfr1KPZIh1OyhU4UO4zrkREcH8ML70v9cYHNvOd9oynRHnvC
28
+ l2tj/fD3YJ0AEkJxGrYwRWQmvMfC4bJ02bC1+rVOUIXXKp3+cUmiN4sTniof8VFo
29
+ bo/YYP4c7erpERa+9hrqygg6WQbJlk2YRlH3JXPFjmu869i2dcbR5ZLOAeEy+axH
30
+ E4oJcnPkJAr0rw504JGtlZtONZQblwmRJOIdXzolaE3NRGUzGVOUSptZppAKiavY
31
+ fO6tdKQc/5RfA8oQEkg8hrxA5PQSz4TOFJGLpFvIapEk6tMruQ0bHgkhr9auXg==
31
32
  -----END CERTIFICATE-----
32
- date: 2016-01-21 00:00:00.000000000 Z
33
+ date: 2016-11-30 00:00:00.000000000 Z
33
34
  dependencies:
34
- - !ruby/object:Gem::Dependency
35
- name: minitest
36
- requirement: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ~>
39
- - !ruby/object:Gem::Version
40
- version: '5.8'
41
- type: :development
42
- prerelease: false
43
- version_requirements: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - ~>
46
- - !ruby/object:Gem::Version
47
- version: '5.8'
48
35
  - !ruby/object:Gem::Dependency
49
36
  name: rdoc
50
37
  requirement: !ruby/object:Gem::Requirement
@@ -65,14 +52,14 @@ dependencies:
65
52
  requirements:
66
53
  - - ~>
67
54
  - !ruby/object:Gem::Version
68
- version: '3.14'
55
+ version: '3.15'
69
56
  type: :development
70
57
  prerelease: false
71
58
  version_requirements: !ruby/object:Gem::Requirement
72
59
  requirements:
73
60
  - - ~>
74
61
  - !ruby/object:Gem::Version
75
- version: '3.14'
62
+ version: '3.15'
76
63
  description: |-
77
64
  Oedipus Lex is a lexer generator in the same family as Rexical and
78
65
  Rex. Oedipus Lex is my independent lexer fork of Rexical. Rexical was
metadata.gz.sig CHANGED
Binary file