Class: BibTeX::Lexer

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/bibtex/lexer.rb

Overview

The BibTeX::Lexer handles the lexical analysis of BibTeX bibliographies.

Constant Summary collapse

MODE =
Hash.new(:meta).merge({
  :bibtex  => :bibtex,  :entry    => :bibtex,
  :string  => :bibtex,  :preamble => :bibtex,
  :comment => :bibtex,  :meta     => :meta,
  :literal => :literal, :content  => :content
}).freeze

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(options = {}) ⇒ Lexer

Creates a new instance. Possible options and their respective default values are:

  • :include => [:errors] A list that may contain :meta_content, and :errors; depending on whether or not these are present, the respective tokens are included in the parse tree.

  • :strict => true In strict mode objects can start anywhere; therefore the `@' symbol is not possible except inside literals or @comment objects; for a more lenient lexer set to false and objects are expected to start after a new line (leading white space is permitted).

  • :strip => true When enabled, newlines will be stripped from quoted string values.


91
92
93
94
# File 'lib/bibtex/lexer.rb', line 91

def initialize(options = {})
  @options = Lexer.defaults.merge(options)
  reset
end

Class Attribute Details

.defaultsObject (readonly)

Returns the value of attribute defaults


74
75
76
# File 'lib/bibtex/lexer.rb', line 74

def defaults
  @defaults
end

.patternsObject (readonly)

Returns the value of attribute patterns


74
75
76
# File 'lib/bibtex/lexer.rb', line 74

def patterns
  @patterns
end

Instance Attribute Details

#modeObject

Returns the value of attribute mode


29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def mode
  @mode
end

#optionsObject (readonly)

Returns the value of attribute options


29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def options
  @options
end

#scannerObject (readonly)

Returns the value of attribute scanner


29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def scanner
  @scanner
end

#stackObject (readonly)

Returns the value of attribute stack


29
30
31
# File 'lib/bibtex/lexer.rb', line 29

def stack
  @stack
end

Instance Method Details

#active?(object) ⇒ Boolean

Returns true if the lexer is currently parsing the given object type.

Returns:

  • (Boolean)

127
128
129
# File 'lib/bibtex/lexer.rb', line 127

def active?(object)
  @active_object == object
end

#allow_missing_keys?Boolean

Returns:

  • (Boolean)

136
137
138
# File 'lib/bibtex/lexer.rb', line 136

def allow_missing_keys?
  !!@options[:allow_missing_keys]
end

#analyse(string = nil) ⇒ Object

Start the lexical analysis.

Raises:


168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/bibtex/lexer.rb', line 168

def analyse(string = nil)
  raise(ArgumentError, 'Lexer: failed to start analysis: no source given!') unless
    string || @scanner

  self.data = string || @scanner.string

  until @scanner.eos?
    send("parse_#{MODE[@mode]}")
  end

  push([false, '$end'])
end

#bibtex_mode?Boolean

Returns true if the lexer is currenty parsing a BibTeX object.

Returns:

  • (Boolean)

118
119
120
# File 'lib/bibtex/lexer.rb', line 118

def bibtex_mode?
  MODE[@mode] == :bibtex
end

#data=(data) ⇒ Object

Sets the source for the lexical analysis and resets the internal state.


107
108
109
110
# File 'lib/bibtex/lexer.rb', line 107

def data=(data)
  @scanner = StringScanner.new(data)
  reset
end

#next_tokenObject

Returns the next token from the parse stack.


115
# File 'lib/bibtex/lexer.rb', line 115

def next_token; @stack.shift; end

#push(value) ⇒ Object

Pushes a value onto the parse stack. Returns the Lexer.


145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/bibtex/lexer.rb', line 145

def push(value)
  case value[0]
  when :CONTENT, :STRING_LITERAL
    value[1].gsub!(/\n\s*/, ' ') if strip_line_breaks?

    if !@stack.empty? && value[0] == @stack[-1][0]
      @stack[-1][1] << value[1]
    else
      @stack.push(value)
    end
  when :ERROR
    @stack.push(value) if @include_errors
    leave_object
  when :META_CONTENT
    @stack.push(value) if @include_meta_content
  else
    @stack.push(value)
  end

  self
end

#resetObject


96
97
98
99
100
101
102
103
104
# File 'lib/bibtex/lexer.rb', line 96

def reset
  @stack, @brace_level, @mode, @active_object = [], 0, :meta, nil

  # cache options for speed
  @include_meta_content = @options[:include].include?(:meta_content)
  @include_errors = @options[:include].include?(:errors)

  self
end

#strict?Boolean

Returns true if the lexer is currently in strict mode.

Returns:

  • (Boolean)

132
133
134
# File 'lib/bibtex/lexer.rb', line 132

def strict?
  !!@options[:strict]
end

#strip_line_breaks?Boolean

Returns:

  • (Boolean)

140
141
142
# File 'lib/bibtex/lexer.rb', line 140

def strip_line_breaks?
  !!options[:strip] && !active?(:comment)
end

#symbolsObject


112
# File 'lib/bibtex/lexer.rb', line 112

def symbols; @stack.map(&:first); end