bibtex-ruby 2.0.3 → 2.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of bibtex-ruby might be problematic. Click here for more details.

Files changed (52) hide show
  1. data/Gemfile.lock +2 -2
  2. data/History.txt +7 -0
  3. data/Manifest +3 -37
  4. data/Rakefile +1 -1
  5. data/features/issues/multiline_strings.feature +14 -0
  6. data/lib/bibtex/bibtex.y +9 -6
  7. data/lib/bibtex/filters.rb +5 -3
  8. data/lib/bibtex/filters/latex.rb +1 -1
  9. data/lib/bibtex/filters/linebreaks.rb +11 -0
  10. data/lib/bibtex/lexer.rb +254 -236
  11. data/lib/bibtex/parser.rb +9 -6
  12. data/lib/bibtex/version.rb +1 -1
  13. data/test/benchmark.rb +4 -1
  14. data/test/bibtex/test_lexer.rb +12 -2
  15. data/test/bibtex/test_parser.rb +21 -0
  16. metadata +14 -48
  17. data/Rakefile.compiled.rbc +0 -1994
  18. data/features/step_definitions/bibtex_steps.rbc +0 -2996
  19. data/features/step_definitions/name_steps.rbc +0 -544
  20. data/features/support/env.rbc +0 -144
  21. data/lib/bibtex.rbc +0 -725
  22. data/lib/bibtex/bibliography.rbc +0 -6729
  23. data/lib/bibtex/compatibility.rbc +0 -290
  24. data/lib/bibtex/elements.rbc +0 -5966
  25. data/lib/bibtex/entry.rbc +0 -11305
  26. data/lib/bibtex/error.rbc +0 -1000
  27. data/lib/bibtex/extensions.rbc +0 -127
  28. data/lib/bibtex/filters.rbc +0 -1178
  29. data/lib/bibtex/filters/latex.rbc +0 -361
  30. data/lib/bibtex/lexer.rbc +0 -5559
  31. data/lib/bibtex/name_parser.rbc +0 -2510
  32. data/lib/bibtex/names.rbc +0 -4710
  33. data/lib/bibtex/parser.rbc +0 -3336
  34. data/lib/bibtex/replaceable.rbc +0 -593
  35. data/lib/bibtex/utilities.rbc +0 -743
  36. data/lib/bibtex/value.rbc +0 -4291
  37. data/lib/bibtex/version.rbc +0 -209
  38. data/test/bibtex/test_bibliography.rbc +0 -4268
  39. data/test/bibtex/test_elements.rbc +0 -1554
  40. data/test/bibtex/test_entry.rbc +0 -11767
  41. data/test/bibtex/test_filters.rbc +0 -1017
  42. data/test/bibtex/test_lexer.rbc +0 -373
  43. data/test/bibtex/test_name_parser.rbc +0 -608
  44. data/test/bibtex/test_names.rbc +0 -797
  45. data/test/bibtex/test_parser.rbc +0 -2819
  46. data/test/bibtex/test_string.rbc +0 -706
  47. data/test/bibtex/test_utilities.rbc +0 -851
  48. data/test/bibtex/test_value.rbc +0 -4993
  49. data/test/helper.rbc +0 -430
  50. data/test/profile.dot +0 -191
  51. data/test/test_bibtex.rbc +0 -1785
  52. data/test/test_export.rbc +0 -908
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bibtex-ruby (2.0.2)
4
+ bibtex-ruby (2.0.4)
5
5
  latex-decode (>= 0.0.6)
6
6
  multi_json (~> 1.0)
7
7
 
@@ -34,7 +34,7 @@ GEM
34
34
  linecache19 (0.5.12)
35
35
  ruby_core_source (>= 0.1.4)
36
36
  minitest (2.3.1)
37
- multi_json (1.0.3)
37
+ multi_json (1.0.4)
38
38
  mynyml-redgreen (0.7.1)
39
39
  term-ansicolor (>= 1.0.4)
40
40
  racc (1.4.6)
@@ -1,3 +1,10 @@
1
+ 2.0.4 / 2011-12-20
2
+ ==================
3
+
4
+ * Added lexer option :strip to strip newlines from literals (thanks to @JLimperg)
5
+ * Added :linebreaks filter
6
+
7
+
1
8
  2.0.3 / 2011-12-13
2
9
  ==================
3
10
 
data/Manifest CHANGED
@@ -5,7 +5,6 @@ LICENSE
5
5
  Manifest
6
6
  README.md
7
7
  Rakefile
8
- Rakefile.compiled.rbc
9
8
  auto.watchr
10
9
  bibtex-ruby.gemspec
11
10
  examples
@@ -19,6 +18,7 @@ features/issues
19
18
  features/issues/braced_strings.feature
20
19
  features/issues/crossref.feature
21
20
  features/issues/latex_filter.feature
21
+ features/issues/multiline_strings.feature
22
22
  features/issues/number_keys.feature
23
23
  features/issues/parse_months.feature
24
24
  features/issues/slash_keys.feature
@@ -29,78 +29,48 @@ features/query.feature
29
29
  features/replacement.feature
30
30
  features/step_definitions
31
31
  features/step_definitions/bibtex_steps.rb
32
- features/step_definitions/bibtex_steps.rbc
33
32
  features/step_definitions/name_steps.rb
34
- features/step_definitions/name_steps.rbc
35
33
  features/strings.feature
36
34
  features/support
37
35
  features/support/env.rb
38
- features/support/env.rbc
39
36
  lib
40
37
  lib/bibtex
41
38
  lib/bibtex/bibliography.rb
42
- lib/bibtex/bibliography.rbc
43
39
  lib/bibtex/bibtex.y
44
40
  lib/bibtex/compatibility.rb
45
- lib/bibtex/compatibility.rbc
46
41
  lib/bibtex/elements.rb
47
- lib/bibtex/elements.rbc
48
42
  lib/bibtex/entry.rb
49
- lib/bibtex/entry.rbc
50
43
  lib/bibtex/error.rb
51
- lib/bibtex/error.rbc
52
44
  lib/bibtex/extensions.rb
53
- lib/bibtex/extensions.rbc
54
45
  lib/bibtex/filters
55
46
  lib/bibtex/filters/latex.rb
56
- lib/bibtex/filters/latex.rbc
47
+ lib/bibtex/filters/linebreaks.rb
57
48
  lib/bibtex/filters.rb
58
- lib/bibtex/filters.rbc
59
49
  lib/bibtex/lexer.rb
60
- lib/bibtex/lexer.rbc
61
50
  lib/bibtex/name_parser.rb
62
- lib/bibtex/name_parser.rbc
63
51
  lib/bibtex/names.rb
64
- lib/bibtex/names.rbc
65
52
  lib/bibtex/names.y
66
53
  lib/bibtex/parser.rb
67
- lib/bibtex/parser.rbc
68
54
  lib/bibtex/replaceable.rb
69
- lib/bibtex/replaceable.rbc
70
55
  lib/bibtex/ruby.rb
71
56
  lib/bibtex/utilities.rb
72
- lib/bibtex/utilities.rbc
73
57
  lib/bibtex/value.rb
74
- lib/bibtex/value.rbc
75
58
  lib/bibtex/version.rb
76
- lib/bibtex/version.rbc
77
59
  lib/bibtex.rb
78
- lib/bibtex.rbc
79
60
  test
80
61
  test/benchmark.rb
81
62
  test/bibtex
82
63
  test/bibtex/test_bibliography.rb
83
- test/bibtex/test_bibliography.rbc
84
64
  test/bibtex/test_elements.rb
85
- test/bibtex/test_elements.rbc
86
65
  test/bibtex/test_entry.rb
87
- test/bibtex/test_entry.rbc
88
66
  test/bibtex/test_filters.rb
89
- test/bibtex/test_filters.rbc
90
67
  test/bibtex/test_lexer.rb
91
- test/bibtex/test_lexer.rbc
92
68
  test/bibtex/test_name_parser.rb
93
- test/bibtex/test_name_parser.rbc
94
69
  test/bibtex/test_names.rb
95
- test/bibtex/test_names.rbc
96
70
  test/bibtex/test_parser.rb
97
- test/bibtex/test_parser.rbc
98
71
  test/bibtex/test_string.rb
99
- test/bibtex/test_string.rbc
100
72
  test/bibtex/test_utilities.rb
101
- test/bibtex/test_utilities.rbc
102
73
  test/bibtex/test_value.rb
103
- test/bibtex/test_value.rbc
104
74
  test/fixtures
105
75
  test/fixtures/bibdesk.bib
106
76
  test/fixtures/comment.bib
@@ -112,10 +82,6 @@ test/fixtures/no_bibtex.bib
112
82
  test/fixtures/preamble.bib
113
83
  test/fixtures/roundtrip.bib
114
84
  test/helper.rb
115
- test/helper.rbc
116
- test/profile.dot
117
85
  test/profile.rb
118
86
  test/test_bibtex.rb
119
- test/test_bibtex.rbc
120
- test/test_export.rb
121
- test/test_export.rbc
87
+ test/test_export.rb
data/Rakefile CHANGED
@@ -69,7 +69,7 @@ end
69
69
  desc 'Updates the Manifest file'
70
70
  task :manifest => ['clean', 'racc'] do
71
71
  m = File.open('Manifest', 'w')
72
- m.print FileList['**/*'].join("\n")
72
+ m.print FileList['**/*'].reject{ |f| f.end_with?('rbc') }.join("\n")
73
73
  m.close
74
74
  end
75
75
 
@@ -0,0 +1,14 @@
1
+ Feature: Multiline values on single lines
2
+ As a hacker who works with bibliographies
3
+ I would find it practical to have multiline values turned to single lines by default
4
+ Because this is what most BibTeX files will assume.
5
+
6
+ Scenario: Multiline value
7
+ When I parse the following file:
8
+ """
9
+ @article{stuff,
10
+ title = "This very long title must be wrapped and continues
11
+ on the next line."
12
+ }
13
+ """
14
+ Then the entry with key "stuff" should have a field "title" with the value "This very long title must be wrapped and continues on the next line."
@@ -90,10 +90,10 @@ require 'bibtex/lexer'
90
90
 
91
91
  attr_reader :lexer, :options
92
92
 
93
- DEFAULTS = { :include => [:errors], :debug => ENV['DEBUG'] == true }.freeze
94
-
93
+ DEFAULTS = { :include => [:errors], :debug => ENV['DEBUG'] == true }.freeze
94
+
95
95
  def initialize(options = {})
96
- @options = DEFAULTS.merge(options)
96
+ @options = DEFAULTS.merge(options)
97
97
  @lexer = Lexer.new(@options)
98
98
  end
99
99
 
@@ -102,7 +102,7 @@ require 'bibtex/lexer'
102
102
  @lexer.analyse(input)
103
103
 
104
104
  do_parse
105
- #yyparse(@lexer,:each)
105
+ #yyparse(@lexer,:each)
106
106
  end
107
107
 
108
108
  def next_token
@@ -114,8 +114,11 @@ require 'bibtex/lexer'
114
114
  end
115
115
 
116
116
  def on_error(tid, val, vstack)
117
- Log.error("Failed to parse BibTeX on value %s (%s) %s" % [val.inspect, token_to_str(tid) || '?', vstack.inspect])
118
- #raise(ParseError, "Failed to parse BibTeX on value %s (%s) %s" % [val.inspect, token_to_str(tid) || '?', vstack.inspect])
117
+ message =
118
+ "Failed to parse BibTeX on value #{val.inspect} (#{token_to_str(tid) || '?'}) #{ vstack.inspect}"
119
+
120
+ BibTeX.log.error message
121
+ raise ParseError, message
119
122
  end
120
123
 
121
124
  # -*- racc -*-
@@ -6,7 +6,7 @@ module BibTeX
6
6
 
7
7
  class << self
8
8
  # Hook called by Ruby if Filter is subclassed
9
- def inherited (base)
9
+ def inherited(base)
10
10
  base.class_eval { include Singleton }
11
11
  subclasses << base
12
12
  end
@@ -17,7 +17,9 @@ module BibTeX
17
17
  end
18
18
  end
19
19
 
20
- def apply (value); value; end
20
+ def apply(value)
21
+ value
22
+ end
21
23
 
22
24
  alias convert apply
23
25
  alias << apply
@@ -31,7 +33,7 @@ module BibTeX
31
33
  require filter
32
34
  end
33
35
 
34
- def self.resolve (filter)
36
+ def self.resolve(filter)
35
37
  case
36
38
  when filter.respond_to?(:apply)
37
39
  filter
@@ -4,7 +4,7 @@ module BibTeX
4
4
  module Filters
5
5
 
6
6
  class LaTeX < Filter
7
- def apply (value)
7
+ def apply(value)
8
8
  ::LaTeX.decode(value)
9
9
  end
10
10
  end
@@ -0,0 +1,11 @@
1
+ module BibTeX
2
+ module Filters
3
+
4
+ class LineBreaks < Filter
5
+ def apply(value)
6
+ value.to_s.gsub(/\n\s*/, ' ')
7
+ end
8
+ end
9
+
10
+ end
11
+ end
@@ -9,280 +9,298 @@
9
9
  #
10
10
  # This program is distributed in the hope that it will be useful,
11
11
  # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
13
  # GNU General Public License for more details.
14
14
  #
15
15
  # You should have received a copy of the GNU General Public License
16
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
17
  #++
18
18
 
19
19
  require 'strscan'
20
20
 
21
21
  module BibTeX
22
-
23
- #
24
- # The BibTeX::Lexer handles the lexical analysis of BibTeX bibliographies.
25
- #
26
- class Lexer
27
- extend Forwardable
22
+
23
+ #
24
+ # The BibTeX::Lexer handles the lexical analysis of BibTeX bibliographies.
25
+ #
26
+ class Lexer
27
+ extend Forwardable
28
28
 
29
- attr_reader :options, :stack, :mode, :scanner
30
- attr_writer :mode
31
-
29
+ attr_reader :options, :stack, :mode, :scanner
30
+ attr_writer :mode
31
+
32
32
  def_delegator :@scanner, :string, :data
33
33
 
34
- DEFAULTS = { :include => [:errors], :strict => true }.freeze
34
+ @defaults = {
35
+ :include => [:errors],
36
+ :strict => true,
37
+ :strip => true
38
+ }.freeze
39
+
40
+ MODE = Hash.new(:meta).merge({
41
+ :bibtex => :bibtex, :entry => :bibtex,
42
+ :string => :bibtex, :preamble => :bibtex,
43
+ :comment => :bibtex, :meta => :meta,
44
+ :literal => :literal, :content => :content
45
+ }).freeze
35
46
 
36
- MODE = Hash.new(:meta).merge(:bibtex => :bibtex, :entry => :bibtex, :string => :bibtex, :preamble => :bibtex, :comment => :bibtex, :meta => :meta, :literal => :literal, :content => :content).freeze
47
+ class << self
48
+ attr_accessor :defaults
49
+ end
37
50
 
38
- #
39
- # Creates a new instance. Possible options and their respective
40
- # default values are:
41
- #
42
- # - :include => [:errors] A list that may contain :meta_content, and
43
- # :errors; depending on whether or not these are present, the respective
44
- # tokens are included in the parse tree.
45
- # - :strict => true In strict mode objects can start anywhere; therefore
46
- # the `@' symbol is not possible except inside literals or @comment
47
- # objects; for a more lenient lexer set to false and objects are
48
- # expected to start after a new line (leading white space is permitted).
49
- #
50
- def initialize(options = {})
51
- @options = DEFAULTS.merge(options)
51
+ #
52
+ # Creates a new instance. Possible options and their respective
53
+ # default values are:
54
+ #
55
+ # - :include => [:errors] A list that may contain :meta_content, and
56
+ # :errors; depending on whether or not these are present, the respective
57
+ # tokens are included in the parse tree.
58
+ # - :strict => true In strict mode objects can start anywhere; therefore
59
+ # the `@' symbol is not possible except inside literals or @comment
60
+ # objects; for a more lenient lexer set to false and objects are
61
+ # expected to start after a new line (leading white space is permitted).
62
+ # - :strip => true When enabled, newlines will be stripped from quoted
63
+ # string values.
64
+ #
65
+ def initialize(options = {})
66
+ @options = Lexer.defaults.merge(options)
52
67
  reset
53
- end
68
+ end
54
69
 
55
70
  def reset
56
- @stack, @brace_level, @mode, @active_object = [], 0, :meta, nil
57
- @scanner.reset if @scanner
58
-
59
- # cache options for speed
60
- @include_meta_content = @options[:include].include?(:meta_content)
61
- @include_errors = @options[:include].include?(:errors)
62
-
63
- self
71
+ @stack, @brace_level, @mode, @active_object = [], 0, :meta, nil
72
+ @scanner.reset if @scanner
73
+
74
+ # cache options for speed
75
+ @include_meta_content = @options[:include].include?(:meta_content)
76
+ @include_errors = @options[:include].include?(:errors)
77
+
78
+ self
64
79
  end
65
80
 
66
- # Sets the source for the lexical analysis and resets the internal state.
67
- def data=(data)
68
- @scanner = StringScanner.new(data)
69
- reset
70
- end
81
+ # Sets the source for the lexical analysis and resets the internal state.
82
+ def data=(data)
83
+ @scanner = StringScanner.new(data)
84
+ reset
85
+ end
71
86
 
72
87
  def symbols; @stack.map(&:first); end
73
88
 
74
- # Returns the next token from the parse stack.
75
- def next_token; @stack.shift; end
89
+ # Returns the next token from the parse stack.
90
+ def next_token; @stack.shift; end
76
91
 
77
- # Returns true if the lexer is currenty parsing a BibTeX object.
78
- def bibtex_mode?
79
- MODE[@mode] == :bibtex
80
- end
81
-
82
- [:meta, :literal, :content].each do |m|
92
+ # Returns true if the lexer is currenty parsing a BibTeX object.
93
+ def bibtex_mode?
94
+ MODE[@mode] == :bibtex
95
+ end
96
+
97
+ [:meta, :literal, :content].each do |m|
83
98
  define_method("#{m}_mode?") { @mode == m }
84
- end
99
+ end
85
100
 
86
- # Returns true if the lexer is currently parsing the given object type.
87
- def active?(object)
88
- @active_object == object
89
- end
90
-
91
- # Returns true if the lexer is currently in strict mode.
92
- def strict?; !!(@options[:strict]); end
93
-
94
- # Pushes a value onto the parse stack. Returns the Lexer.
95
- def push(value)
96
- case value[0]
101
+ # Returns true if the lexer is currently parsing the given object type.
102
+ def active?(object)
103
+ @active_object == object
104
+ end
105
+
106
+ # Returns true if the lexer is currently in strict mode.
107
+ def strict?; !!(@options[:strict]); end
108
+
109
+ def strip_line_breaks?
110
+ !!options[:strip] && !active?(:comment)
111
+ end
112
+
113
+ # Pushes a value onto the parse stack. Returns the Lexer.
114
+ def push(value)
115
+ case value[0]
97
116
  when :CONTENT, :STRING_LITERAL
98
- if !@stack.empty? && value[0] == @stack[-1][0]
99
- @stack[-1][1] << value[1]
100
- else
101
- @stack.push(value)
102
- end
103
- when :ERROR
104
- @stack.push(value) if @include_errors
105
- leave_object
106
- when :META_CONTENT
117
+ value[1].gsub!(/\n\s*/, ' ') if strip_line_breaks?
118
+
119
+ if !@stack.empty? && value[0] == @stack[-1][0]
120
+ @stack[-1][1] << value[1]
121
+ else
122
+ @stack.push(value)
123
+ end
124
+ when :ERROR
125
+ @stack.push(value) if @include_errors
126
+ leave_object
127
+ when :META_CONTENT
107
128
  @stack.push(value) if @include_meta_content
108
- else
109
- @stack.push(value)
110
- end
111
-
112
- self
113
- end
129
+ else
130
+ @stack.push(value)
131
+ end
132
+
133
+ self
134
+ end
114
135
 
115
- # Start the lexical analysis.
116
- def analyse(string = nil)
117
- raise(ArgumentError, 'Lexer: failed to start analysis: no source given!') unless
118
- string || @scanner
136
+ # Start the lexical analysis.
137
+ def analyse(string = nil)
138
+ raise(ArgumentError, 'Lexer: failed to start analysis: no source given!') unless
139
+ string || @scanner
119
140
 
120
- self.data = string || @scanner.string
121
-
122
- until @scanner.eos?
123
- send("parse_#{MODE[@mode]}")
124
- end
141
+ self.data = string || @scanner.string
142
+
143
+ until @scanner.eos?
144
+ send("parse_#{MODE[@mode]}")
145
+ end
125
146
 
126
- push([false, '$end'])
127
- end
147
+ push([false, '$end'])
148
+ end
128
149
 
129
150
  private
130
151
 
131
- def parse_bibtex
132
- case
133
- when @scanner.scan(/[\s]+/o)
134
- when @scanner.scan(/\{/o)
135
- @brace_level += 1
136
- push([:LBRACE,'{'])
137
- @mode = :content if @brace_level > 1 || @brace_level == 1 && active?(:comment)
138
- when @scanner.scan(/\}/o)
139
- @brace_level -= 1
140
- push([:RBRACE,'}'])
141
- return leave_object if @brace_level == 0
142
- return error_unbalanced_braces if @brace_level < 0
143
- when @scanner.scan( /=/o)
144
- push([:EQ,'='])
145
- when @scanner.scan(/,/o)
146
- push([:COMMA,','])
147
- when @scanner.scan(/\d+/o)
148
- push([:NUMBER,@scanner.matched])
149
- when @scanner.scan(/[[:alpha:]\d \/:_!$\.%&*-]+/io)
150
- push([:NAME,@scanner.matched.rstrip])
151
- when @scanner.scan(/"/o)
152
- @mode = :literal
153
- when @scanner.scan(/#/o)
154
- push([:SHARP,'#'])
155
- when @scanner.scan(/@/o)
156
- enter_object
157
- when @scanner.scan(/./o)
158
- error_unexpected_token
159
- end
160
- end
161
-
162
- def parse_meta
163
- match = @scanner.scan_until(strict? ? /@[\t ]*/o : /(^|\n)[\t ]*@[\t ]*/o)
164
- if @scanner.matched
165
- push([:META_CONTENT,match.chop])
166
- enter_object
167
- else
168
- push([:META_CONTENT,@scanner.rest])
169
- @scanner.terminate
170
- end
171
- end
152
+ def parse_bibtex
153
+ case
154
+ when @scanner.scan(/[\s]+/o)
155
+ when @scanner.scan(/\{/o)
156
+ @brace_level += 1
157
+ push([:LBRACE,'{'])
158
+ @mode = :content if @brace_level > 1 || @brace_level == 1 && active?(:comment)
159
+ when @scanner.scan(/\}/o)
160
+ @brace_level -= 1
161
+ push([:RBRACE,'}'])
162
+ return leave_object if @brace_level == 0
163
+ return error_unbalanced_braces if @brace_level < 0
164
+ when @scanner.scan( /=/o)
165
+ push([:EQ,'='])
166
+ when @scanner.scan(/,/o)
167
+ push([:COMMA,','])
168
+ when @scanner.scan(/\d+/o)
169
+ push([:NUMBER,@scanner.matched])
170
+ when @scanner.scan(/[[:alpha:]\d \/:_!$\.%&*-]+/io)
171
+ push([:NAME,@scanner.matched.rstrip])
172
+ when @scanner.scan(/"/o)
173
+ @mode = :literal
174
+ when @scanner.scan(/#/o)
175
+ push([:SHARP,'#'])
176
+ when @scanner.scan(/@/o)
177
+ enter_object
178
+ when @scanner.scan(/./o)
179
+ error_unexpected_token
180
+ end
181
+ end
182
+
183
+ def parse_meta
184
+ match = @scanner.scan_until(strict? ? /@[\t ]*/o : /(^|\n)[\t ]*@[\t ]*/o)
185
+ if @scanner.matched
186
+ push([:META_CONTENT,match.chop])
187
+ enter_object
188
+ else
189
+ push([:META_CONTENT,@scanner.rest])
190
+ @scanner.terminate
191
+ end
192
+ end
172
193
 
173
- def parse_content
174
- match = @scanner.scan_until(/\{|\}/o)
175
- case @scanner.matched
176
- when '{'
177
- @brace_level += 1
178
- push([:CONTENT,match])
179
- when '}'
180
- @brace_level -= 1
181
- case
182
- when @brace_level == 0
183
- push([:CONTENT,match.chop])
184
- push([:RBRACE,'}'])
185
- leave_object
186
- when @brace_level == 1 && !active?(:comment)
187
- push([:CONTENT,match.chop])
188
- push([:RBRACE,'}'])
189
- @mode = :bibtex
190
- when @brace_level < 0
191
- push([:CONTENT,match.chop])
192
- error_unbalanced_braces
193
- else
194
- push([:CONTENT,match])
195
- end
196
- else
197
- push([:CONTENT,@scanner.rest])
198
- @scanner.terminate
199
- error_unterminated_content
200
- end
201
- end
202
-
203
- def parse_literal
204
- match = @scanner.scan_until(/[\{\}"]/o)
205
- case @scanner.matched
206
- when '{'
207
- @brace_level += 1
208
- push([:STRING_LITERAL,match])
209
- when '}'
210
- @brace_level -= 1
211
- if @brace_level < 1
212
- push([:STRING_LITERAL,match.chop])
213
- error_unbalanced_braces
214
- else
215
- push([:STRING_LITERAL,match])
216
- end
217
- when '"'
218
- if @brace_level == 1
219
- push([:STRING_LITERAL,match.chop])
220
- @mode = :bibtex
221
- else
222
- push([:STRING_LITERAL,match])
223
- end
224
- when "\n"
225
- push([:STRING_LITERAL,match.chop])
226
- error_unterminated_string
227
- else
228
- push([:STRING_LITERAL,@scanner.rest])
229
- @scanner.terminate
230
- error_unterminated_string
231
- end
232
- end
233
-
234
- # Called when the lexer encounters a new BibTeX object.
235
- def enter_object
236
- @brace_level = 0
237
- push [:AT,'@']
194
+ def parse_content
195
+ match = @scanner.scan_until(/\{|\}/o)
196
+ case @scanner.matched
197
+ when '{'
198
+ @brace_level += 1
199
+ push([:CONTENT,match])
200
+ when '}'
201
+ @brace_level -= 1
202
+ case
203
+ when @brace_level == 0
204
+ push([:CONTENT,match.chop])
205
+ push([:RBRACE,'}'])
206
+ leave_object
207
+ when @brace_level == 1 && !active?(:comment)
208
+ push([:CONTENT,match.chop])
209
+ push([:RBRACE,'}'])
210
+ @mode = :bibtex
211
+ when @brace_level < 0
212
+ push([:CONTENT,match.chop])
213
+ error_unbalanced_braces
214
+ else
215
+ push([:CONTENT,match])
216
+ end
217
+ else
218
+ push([:CONTENT,@scanner.rest])
219
+ @scanner.terminate
220
+ error_unterminated_content
221
+ end
222
+ end
223
+
224
+ def parse_literal
225
+ match = @scanner.scan_until(/[\{\}"]/o)
226
+ case @scanner.matched
227
+ when '{'
228
+ @brace_level += 1
229
+ push([:STRING_LITERAL,match])
230
+ when '}'
231
+ @brace_level -= 1
232
+ if @brace_level < 1
233
+ push([:STRING_LITERAL,match.chop])
234
+ error_unbalanced_braces
235
+ else
236
+ push([:STRING_LITERAL,match])
237
+ end
238
+ when '"'
239
+ if @brace_level == 1
240
+ push([:STRING_LITERAL,match.chop])
241
+ @mode = :bibtex
242
+ else
243
+ push([:STRING_LITERAL,match])
244
+ end
245
+ else
246
+ push([:STRING_LITERAL,@scanner.rest])
247
+ @scanner.terminate
248
+ error_unterminated_string
249
+ end
250
+ end
251
+
252
+ # Called when the lexer encounters a new BibTeX object.
253
+ def enter_object
254
+ @brace_level = 0
255
+ push [:AT,'@']
238
256
 
239
- case
240
- when @scanner.scan(/string/io)
241
- @mode = @active_object = :string
242
- push [:STRING, @scanner.matched]
243
- when @scanner.scan(/preamble/io)
244
- @mode = @active_object = :preamble
245
- push [:PREAMBLE, @scanner.matched]
246
- when @scanner.scan(/comment/io)
247
- @mode = @active_object = :comment
248
- push [:COMMENT, @scanner.matched]
249
- when @scanner.scan(/[a-z\d:_!\.$%&*-]+/io)
250
- @mode = @active_object = :entry
251
- push [:NAME, @scanner.matched]
257
+ case
258
+ when @scanner.scan(/string/io)
259
+ @mode = @active_object = :string
260
+ push [:STRING, @scanner.matched]
261
+ when @scanner.scan(/preamble/io)
262
+ @mode = @active_object = :preamble
263
+ push [:PREAMBLE, @scanner.matched]
264
+ when @scanner.scan(/comment/io)
265
+ @mode = @active_object = :comment
266
+ push [:COMMENT, @scanner.matched]
267
+ when @scanner.scan(/[a-z\d:_!\.$%&*-]+/io)
268
+ @mode = @active_object = :entry
269
+ push [:NAME, @scanner.matched]
252
270
  else
253
271
  error_unexpected_object
254
- end
255
- end
272
+ end
273
+ end
256
274
 
257
- # Called when parser leaves a BibTeX object.
258
- def leave_object
259
- @mode, @active_object, @brace_level = :meta, nil, 0
260
- end
275
+ # Called when parser leaves a BibTeX object.
276
+ def leave_object
277
+ @mode, @active_object, @brace_level = :meta, nil, 0
278
+ end
261
279
 
262
- def error_unbalanced_braces
263
- BibTeX.log.warn("Lexer: unbalanced braces at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
264
- backtrace [:E_UNBALANCED, @scanner.matched]
265
- end
266
-
267
- def error_unterminated_string
268
- BibTeX.log.warn("Lexer: unterminated string at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
269
- backtrace [:E_UNTERMINATED_STRING, @scanner.matched]
270
- end
280
+ def error_unbalanced_braces
281
+ BibTeX.log.warn("Lexer: unbalanced braces at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
282
+ backtrace [:E_UNBALANCED, @scanner.matched]
283
+ end
284
+
285
+ def error_unterminated_string
286
+ BibTeX.log.warn("Lexer: unterminated string at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
287
+ backtrace [:E_UNTERMINATED_STRING, @scanner.matched]
288
+ end
271
289
 
272
- def error_unterminated_content
273
- BibTeX.log.warn("Lexer: unterminated content at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
274
- backtrace [:E_UNTERMINATED_CONTENT, @scanner.matched]
275
- end
276
-
277
- def error_unexpected_token
278
- BibTeX.log.warn("Lexer: unexpected token `#{@scanner.matched}' at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
279
- backtrace [:E_UNEXPECTED_TOKEN, @scanner.matched]
280
- end
290
+ def error_unterminated_content
291
+ BibTeX.log.warn("Lexer: unterminated content at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
292
+ backtrace [:E_UNTERMINATED_CONTENT, @scanner.matched]
293
+ end
294
+
295
+ def error_unexpected_token
296
+ BibTeX.log.warn("Lexer: unexpected token `#{@scanner.matched}' at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
297
+ backtrace [:E_UNEXPECTED_TOKEN, @scanner.matched]
298
+ end
281
299
 
282
- def error_unexpected_object
283
- BibTeX.log.warn("Lexer: unexpected object at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
284
- backtrace [:E_UNEXPECTED_OBJECT, '@']
285
- end
300
+ def error_unexpected_object
301
+ BibTeX.log.warn("Lexer: unexpected object at #{@scanner.pos}; brace level #{@brace_level}; mode #{@mode.inspect}.")
302
+ backtrace [:E_UNEXPECTED_OBJECT, '@']
303
+ end
286
304
 
287
305
  def backtrace(error)
288
306
  bt = []
@@ -291,6 +309,6 @@ module BibTeX
291
309
  push [:ERROR,bt]
292
310
  end
293
311
 
294
- end
295
-
312
+ end
313
+
296
314
  end