rlex 0.5.3 → 0.6.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.
data/.gitignore CHANGED
@@ -1,5 +1,6 @@
1
1
  *.gem
2
2
  *.rbc
3
+ *~
3
4
  .bundle
4
5
  .config
5
6
  .yardoc
data/.yardopts CHANGED
@@ -1 +1 @@
1
- --no-private lib - LICENSE
1
+ --no-private lib - LICENSE CHANGELOG.md
@@ -0,0 +1,22 @@
1
+ # Changes
2
+
3
+ ## Version 0.6.0
4
+
5
+ Produced tokens now include line number and column position of the matched text
6
+
7
+ ## Version 0.5.4
8
+
9
+ Update gem spec to reflect development dependency on `rspec`
10
+
11
+ ## Version 0.5.3
12
+
13
+ Add `require` statements internally so `require 'rlex'` is sufficient to use
14
+ the gem
15
+
16
+ ## Version 0.5.2
17
+
18
+ YARD docs generated correctly
19
+
20
+ ## Version 0.5.0
21
+
22
+ Initial version
@@ -100,10 +100,11 @@ module Rlex
100
100
  #
101
101
  def keyword(name = nil, kword)
102
102
  # @todo Validate the keyword name
103
- name = kword if name == nil
104
- pattern = Regexp.new(Regexp.escape kword.to_s)
103
+ kword_str = kword.to_s
104
+ name = kword.to_sym if name == nil
105
+ pattern = Regexp.new(Regexp.escape kword_str)
105
106
  rule name, pattern
106
- @keywords[kword.to_s] = Token.new name.to_sym, kword.to_s
107
+ @keywords[kword_str] = Token.new name.to_sym, kword_str
107
108
  return name.to_sym
108
109
  end
109
110
 
@@ -117,6 +118,8 @@ module Rlex
117
118
  # @return [String] The specified input
118
119
  #
119
120
  def start(input)
121
+ @line = 1
122
+ @col = 0
120
123
  @scanner = StringScanner.new input
121
124
  return input
122
125
  end
@@ -134,9 +137,11 @@ module Rlex
134
137
  return next_token if ignore_prefix?
135
138
  rule = greediest_rule
136
139
  if rule
137
- prefix = @scanner.scan(rule.pattern)
140
+ prefix = fetch_prefix_and_update_pos(rule.pattern)
138
141
  keyword = @keywords[prefix]
139
- return keyword ? keyword : Token.new(rule.name, prefix)
142
+ type = keyword ? keyword.type : rule.name
143
+ token = keyword ? keyword.value : prefix
144
+ return Token.new(type, token, @line, @col - token.size)
140
145
  end
141
146
  raise "unexpected input <#{@scanner.peek(5)}>"
142
147
  end
@@ -149,7 +154,7 @@ module Rlex
149
154
  # @private
150
155
  def ignore_prefix?
151
156
  @ignored.each do |pattern|
152
- prefix = @scanner.scan(pattern)
157
+ prefix = fetch_prefix_and_update_pos(pattern)
153
158
  return true if prefix
154
159
  end
155
160
  return false
@@ -168,5 +173,21 @@ module Rlex
168
173
  end
169
174
  return r
170
175
  end
176
+
177
+ # @private
178
+ def fetch_prefix_and_update_pos(pattern)
179
+ prefix = @scanner.scan(pattern)
180
+ return nil if not prefix
181
+ parts = prefix.split("\n", -1) # arg -1 allows empty lines
182
+ if parts.count == 1
183
+ # Staying on the same line
184
+ @col += prefix.length
185
+ else
186
+ # On a new line
187
+ @line += parts.count - 1
188
+ @col = parts.last.length
189
+ end
190
+ return prefix
191
+ end
171
192
  end
172
193
  end
@@ -6,11 +6,13 @@ module Rlex
6
6
  # @attr_reader [Symbol] type Type of the token, such as the name of
7
7
  # the rule used to match it
8
8
  # @attr_reader [String] value Text matched from the input
9
+ # @attr_reader [Integer] line Line number of the matched text
10
+ # @attr_reader [Integer] col Column position of the matched text
9
11
  #
10
- Token = Struct.new :type, :value
12
+ Token = Struct.new :type, :value, :line, :col
11
13
 
12
14
  # Special token used when the lexer has reached the end of the
13
15
  # specified input.
14
16
  #
15
- EOF_TOKEN = Token.new :eof, ""
17
+ EOF_TOKEN = Token.new :eof, "", -1, -1
16
18
  end
@@ -1,4 +1,4 @@
1
1
  module Rlex
2
2
  # Project version
3
- VERSION = "0.5.3"
3
+ VERSION = "0.6.0"
4
4
  end
@@ -17,4 +17,6 @@ Gem::Specification.new do |gem|
17
17
  gem.name = "rlex"
18
18
  gem.require_paths = ["lib"]
19
19
  gem.version = Rlex::VERSION
20
+
21
+ gem.add_development_dependency "rspec"
20
22
  end
@@ -32,10 +32,9 @@ describe Lexer do
32
32
  @lexer.ignore /\s+/
33
33
  @lexer.keyword :special
34
34
  @lexer.start " \t\nspecialspecial special "
35
- special = Token.new :special, "special"
36
- @lexer.next_token.should eq special
37
- @lexer.next_token.should eq special
38
- @lexer.next_token.should eq special
35
+ @lexer.next_token.should eq Token.new(:special, "special", 2, 0)
36
+ @lexer.next_token.should eq Token.new(:special, "special", 2, 7)
37
+ @lexer.next_token.should eq Token.new(:special, "special", 2, 17)
39
38
  @lexer.next_token.should eq EOF_TOKEN
40
39
  end
41
40
 
@@ -43,10 +42,10 @@ describe Lexer do
43
42
  @lexer.ignore /\s+/
44
43
  @lexer.rule :word, /\w+/
45
44
  @lexer.start "sentence with four tokens"
46
- @lexer.next_token.should eq Token.new :word, "sentence"
47
- @lexer.next_token.should eq Token.new :word, "with"
48
- @lexer.next_token.should eq Token.new :word, "four"
49
- @lexer.next_token.should eq Token.new :word, "tokens"
45
+ @lexer.next_token.should eq Token.new(:word, "sentence", 1, 0)
46
+ @lexer.next_token.should eq Token.new(:word, "with", 1, 9)
47
+ @lexer.next_token.should eq Token.new(:word, "four", 1, 14)
48
+ @lexer.next_token.should eq Token.new(:word, "tokens", 1, 19)
50
49
  @lexer.next_token.should eq EOF_TOKEN
51
50
  end
52
51
 
@@ -57,11 +56,22 @@ describe Lexer do
57
56
  @lexer.keyword :rparen, ")"
58
57
  @lexer.rule :word, /\w+/
59
58
  @lexer.start "ifu ( if ) ifu"
60
- @lexer.next_token.should eq Token.new :word, "ifu"
61
- @lexer.next_token.should eq Token.new :lparen, "("
62
- @lexer.next_token.should eq Token.new :if, "if"
63
- @lexer.next_token.should eq Token.new :rparen, ")"
64
- @lexer.next_token.should eq Token.new :word, "ifu"
59
+ @lexer.next_token.should eq Token.new(:word, "ifu", 1, 0)
60
+ @lexer.next_token.should eq Token.new(:lparen, "(", 1, 4)
61
+ @lexer.next_token.should eq Token.new(:if, "if", 1, 6)
62
+ @lexer.next_token.should eq Token.new(:rparen, ")", 1, 9)
63
+ @lexer.next_token.should eq Token.new(:word, "ifu", 1, 11)
64
+ @lexer.next_token.should eq EOF_TOKEN
65
+ end
66
+
67
+ it "should recognize keywords even if declared after rules which also match" do
68
+ @lexer.ignore /\s+/
69
+ @lexer.rule :word, /\w+/
70
+ @lexer.keyword :keyword
71
+ @lexer.start "word keyword keywordmore"
72
+ @lexer.next_token.should eq Token.new(:word, "word", 1, 0)
73
+ @lexer.next_token.should eq Token.new(:keyword, "keyword", 1, 5)
74
+ @lexer.next_token.should eq Token.new(:word, "keywordmore", 1, 13)
65
75
  @lexer.next_token.should eq EOF_TOKEN
66
76
  end
67
77
  end
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rlex
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.5.3
5
+ version: 0.6.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - Rasmus Borgsmidt
@@ -10,9 +10,19 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-04-25 00:00:00 Z
14
- dependencies: []
15
-
13
+ date: 2012-05-16 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: rspec
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :development
25
+ version_requirements: *id001
16
26
  description: Implements a simple lexer using a StringScanner
17
27
  email:
18
28
  - rasmus@borgsmidt.dk
@@ -26,6 +36,7 @@ files:
26
36
  - .gitignore
27
37
  - .rspec
28
38
  - .yardopts
39
+ - CHANGELOG.md
29
40
  - Gemfile
30
41
  - LICENSE
31
42
  - README.md