oedipus_lex 2.4.1 → 2.5.0

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
  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