bibtex-ruby 2.0.3 → 2.0.4
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/Gemfile.lock +2 -2
- data/History.txt +7 -0
- data/Manifest +3 -37
- data/Rakefile +1 -1
- data/features/issues/multiline_strings.feature +14 -0
- data/lib/bibtex/bibtex.y +9 -6
- data/lib/bibtex/filters.rb +5 -3
- data/lib/bibtex/filters/latex.rb +1 -1
- data/lib/bibtex/filters/linebreaks.rb +11 -0
- data/lib/bibtex/lexer.rb +254 -236
- data/lib/bibtex/parser.rb +9 -6
- data/lib/bibtex/version.rb +1 -1
- data/test/benchmark.rb +4 -1
- data/test/bibtex/test_lexer.rb +12 -2
- data/test/bibtex/test_parser.rb +21 -0
- metadata +14 -48
- data/Rakefile.compiled.rbc +0 -1994
- data/features/step_definitions/bibtex_steps.rbc +0 -2996
- data/features/step_definitions/name_steps.rbc +0 -544
- data/features/support/env.rbc +0 -144
- data/lib/bibtex.rbc +0 -725
- data/lib/bibtex/bibliography.rbc +0 -6729
- data/lib/bibtex/compatibility.rbc +0 -290
- data/lib/bibtex/elements.rbc +0 -5966
- data/lib/bibtex/entry.rbc +0 -11305
- data/lib/bibtex/error.rbc +0 -1000
- data/lib/bibtex/extensions.rbc +0 -127
- data/lib/bibtex/filters.rbc +0 -1178
- data/lib/bibtex/filters/latex.rbc +0 -361
- data/lib/bibtex/lexer.rbc +0 -5559
- data/lib/bibtex/name_parser.rbc +0 -2510
- data/lib/bibtex/names.rbc +0 -4710
- data/lib/bibtex/parser.rbc +0 -3336
- data/lib/bibtex/replaceable.rbc +0 -593
- data/lib/bibtex/utilities.rbc +0 -743
- data/lib/bibtex/value.rbc +0 -4291
- data/lib/bibtex/version.rbc +0 -209
- data/test/bibtex/test_bibliography.rbc +0 -4268
- data/test/bibtex/test_elements.rbc +0 -1554
- data/test/bibtex/test_entry.rbc +0 -11767
- data/test/bibtex/test_filters.rbc +0 -1017
- data/test/bibtex/test_lexer.rbc +0 -373
- data/test/bibtex/test_name_parser.rbc +0 -608
- data/test/bibtex/test_names.rbc +0 -797
- data/test/bibtex/test_parser.rbc +0 -2819
- data/test/bibtex/test_string.rbc +0 -706
- data/test/bibtex/test_utilities.rbc +0 -851
- data/test/bibtex/test_value.rbc +0 -4993
- data/test/helper.rbc +0 -430
- data/test/profile.dot +0 -191
- data/test/test_bibtex.rbc +0 -1785
- data/test/test_export.rbc +0 -908
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
bibtex-ruby (2.0.
|
|
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.
|
|
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)
|
data/History.txt
CHANGED
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/
|
|
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/
|
|
120
|
-
test/test_export.rb
|
|
121
|
-
test/test_export.rbc
|
|
87
|
+
test/test_export.rb
|
data/Rakefile
CHANGED
|
@@ -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."
|
data/lib/bibtex/bibtex.y
CHANGED
|
@@ -90,10 +90,10 @@ require 'bibtex/lexer'
|
|
|
90
90
|
|
|
91
91
|
attr_reader :lexer, :options
|
|
92
92
|
|
|
93
|
-
|
|
94
|
-
|
|
93
|
+
DEFAULTS = { :include => [:errors], :debug => ENV['DEBUG'] == true }.freeze
|
|
94
|
+
|
|
95
95
|
def initialize(options = {})
|
|
96
|
-
|
|
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
|
-
|
|
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
|
-
|
|
118
|
-
|
|
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 -*-
|
data/lib/bibtex/filters.rb
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
36
|
+
def self.resolve(filter)
|
|
35
37
|
case
|
|
36
38
|
when filter.respond_to?(:apply)
|
|
37
39
|
filter
|
data/lib/bibtex/filters/latex.rb
CHANGED
data/lib/bibtex/lexer.rb
CHANGED
|
@@ -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.
|
|
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.
|
|
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
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
|
|
23
|
+
#
|
|
24
|
+
# The BibTeX::Lexer handles the lexical analysis of BibTeX bibliographies.
|
|
25
|
+
#
|
|
26
|
+
class Lexer
|
|
27
|
+
extend Forwardable
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
attr_reader :options, :stack, :mode, :scanner
|
|
30
|
+
attr_writer :mode
|
|
31
|
+
|
|
32
32
|
def_delegator :@scanner, :string, :data
|
|
33
33
|
|
|
34
|
-
|
|
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
|
-
|
|
47
|
+
class << self
|
|
48
|
+
attr_accessor :defaults
|
|
49
|
+
end
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
-
|
|
68
|
+
end
|
|
54
69
|
|
|
55
70
|
def reset
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
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
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
75
|
-
|
|
89
|
+
# Returns the next token from the parse stack.
|
|
90
|
+
def next_token; @stack.shift; end
|
|
76
91
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
99
|
+
end
|
|
85
100
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
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
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
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
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
129
|
+
else
|
|
130
|
+
@stack.push(value)
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
self
|
|
134
|
+
end
|
|
114
135
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
141
|
+
self.data = string || @scanner.string
|
|
142
|
+
|
|
143
|
+
until @scanner.eos?
|
|
144
|
+
send("parse_#{MODE[@mode]}")
|
|
145
|
+
end
|
|
125
146
|
|
|
126
|
-
|
|
127
|
-
|
|
147
|
+
push([false, '$end'])
|
|
148
|
+
end
|
|
128
149
|
|
|
129
150
|
private
|
|
130
151
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
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
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
255
|
-
|
|
272
|
+
end
|
|
273
|
+
end
|
|
256
274
|
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
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
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
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
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
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
|
-
|
|
295
|
-
|
|
312
|
+
end
|
|
313
|
+
|
|
296
314
|
end
|