Class: LXL::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/lxl.rb

Overview

Lexical Types

;  Statement separator
,  Argument separator
(  Tuple open
)  Tuple close
w  Whitespace
o  Operator
s  String
r  Range
p  Percentage
f  Float
i  Integer
t  Token

F Function
C Constant

Constant Summary collapse

RUBY_OPERATORS =
['+', '-', '*', '/', '<=', '>=', '==', '!=', '<', '>', '+', '**']
EXCEL_OPERATORS =
['+', '-', '*', '/', '<=', '>=', '=',  '<>', '<', '>', '&', '^' ]

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(namespace = self.class.namespace_class.new) ⇒ Parser

Initialize namespace and parser.



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
# File 'lib/lxl.rb', line 214

def initialize(namespace=self.class.namespace_class.new)
  @namespace = namespace
  ops = EXCEL_OPERATORS.collect { |v| Regexp.quote(v) }.join('|')
  xlr = LXL::Range::EXCEL_RANGE
  @lexer = self.class.lexer_class.new([
    [/\A;+/, ?;],              # Statement separator

    [/\A,+/, ?,],              # Argument separator

    [/\A\(/, ?(],              # Tuple open

    [/\A\)/, ?)],              # Tuple close

    [/\A\s+/, ?w],             # Whitespace

    [/\A(#{ops})/, ?o],        # Operator

    [/\A("([^"]|"")*")/m, ?s], # String

    [xlr, ?r],                 # Range

    [/\A\d+(\.\d+)?%/, ?p],    # Percentage

    [/\A\d+\.\d+/, ?f],        # Float

    [/\A\d+/, ?i],             # Integer

    [/\A\w+/, ?t],             # Token

  ], false)
end

Class Method Details

.eval(formula) ⇒ Object

Evaluate a formula.



190
191
192
# File 'lib/lxl.rb', line 190

def self.eval(formula)
  self.new.eval(formula)
end

.lexer_classObject

Default lexer class.



196
197
198
# File 'lib/lxl.rb', line 196

def self.lexer_class
  LXL::Lexer
end

.namespace_classObject

Default namespace class.



202
203
204
# File 'lib/lxl.rb', line 202

def self.namespace_class
  LXL::Namespace
end

.range_classObject

Default range class.



208
209
210
# File 'lib/lxl.rb', line 208

def self.range_class
  LXL::Range
end

Instance Method Details

#eval(formula) ⇒ Object

Evaluate a formula.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
# File 'lib/lxl.rb', line 236

def eval(formula)
  formulas = Array.new << Array.new
  formula = formula.to_s.gsub(/(\n)(\s*=)/,'\1;\2') # infer statement separators

  types,tokens = tokenize(formula)
  tokens.each_index { |i| tokens[i] == ';' ? formulas << Array.new : formulas.last << [types[i], tokens[i]] }
  formulas.collect! { |f|
    types  = f.collect { |t| t.first }
    tokens = f.collect { |t| t.last  }
    token = tokens.join.strip
    if token =~ /\A=/
      tokens.each_index { |i| tokens[i] = translate_quotes(tokens[i]) if types[i] == ?s }
      token = tokens.join.strip.gsub(/\A=+/,'')
    else
      token = translate_quotes(quote(tokens.join.strip))
    end
  }
  formulas.delete_if { |f| f == '""' }
  formulas.collect! { |f| Kernel.eval(f, binding) }
  formulas.size == 1 ? formulas.first : formulas
end