Class: Dentaku::TokenScanner

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

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(category, regexp, converter = nil, condition = nil) ⇒ TokenScanner

Returns a new instance of TokenScanner.



6
7
8
9
10
11
# File 'lib/dentaku/token_scanner.rb', line 6

def initialize(category, regexp, converter=nil, condition=nil)
  @category  = category
  @regexp    = %r{\A(#{ regexp })}i
  @converter = converter
  @condition = condition || ->(*) { true }
end

Class Method Details

.available_scannersObject



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/dentaku/token_scanner.rb', line 27

def available_scanners
  [
    :null,
    :whitespace,
    :numeric,
    :double_quoted_string,
    :single_quoted_string,
    :negate,
    :operator,
    :grouping,
    :case_statement,
    :comparator,
    :combinator,
    :boolean,
    :function,
    :identifier
  ]
end

.booleanObject



124
125
126
# File 'lib/dentaku/token_scanner.rb', line 124

def boolean
  new(:logical, '(true|false)\b', lambda { |raw| raw.strip.downcase == 'true' })
end

.case_statementObject



109
110
111
112
# File 'lib/dentaku/token_scanner.rb', line 109

def case_statement
  names = { open: 'case', close: 'end', then: 'then', when: 'when', else: 'else' }.invert
  new(:case, '(case|end|then|when|else)\b', lambda { |raw| names[raw.downcase] })
end

.combinatorObject



120
121
122
# File 'lib/dentaku/token_scanner.rb', line 120

def combinator
  new(:combinator, '(and|or)\b', lambda { |raw| raw.strip.downcase.to_sym })
end

.comparatorObject



114
115
116
117
118
# File 'lib/dentaku/token_scanner.rb', line 114

def comparator
  names = { le: '<=', ge: '>=', ne: '!=', lt: '<', gt: '>', eq: '=' }.invert
  alternate = { ne: '<>', eq: '==' }.invert
  new(:comparator, '<=|>=|!=|<>|<|>|==|=', lambda { |raw| names[raw] || alternate[raw] })
end

.double_quoted_stringObject



80
81
82
# File 'lib/dentaku/token_scanner.rb', line 80

def double_quoted_string
  new(:string, '"[^"]*"', lambda { |raw| raw.gsub(/^"|"$/, '') })
end

.functionObject



128
129
130
131
132
133
# File 'lib/dentaku/token_scanner.rb', line 128

def function
  new(:function, '\w+\s*\(', lambda do |raw|
    function_name = raw.gsub('(', '')
    [Token.new(:function, function_name.strip.downcase.to_sym, function_name), Token.new(:grouping, :open, '(')]
  end)
end

.groupingObject



104
105
106
107
# File 'lib/dentaku/token_scanner.rb', line 104

def grouping
  names = { open: '(', close: ')', comma: ',' }.invert
  new(:grouping, '\(|\)|,', lambda { |raw| names[raw] })
end

.identifierObject



135
136
137
# File 'lib/dentaku/token_scanner.rb', line 135

def identifier
  new(:identifier, '\w+\b', lambda { |raw| raw.strip.downcase })
end

.negateObject



88
89
90
91
92
93
94
95
96
97
# File 'lib/dentaku/token_scanner.rb', line 88

def negate
  new(:operator, '-', lambda { |raw| :negate }, lambda { |last_token|
    last_token.nil?             ||
    last_token.is?(:operator)   ||
    last_token.is?(:comparator) ||
    last_token.is?(:combinator) ||
    last_token.value == :open   ||
    last_token.value == :comma
  })
end

.nullObject



72
73
74
# File 'lib/dentaku/token_scanner.rb', line 72

def null
  new(:null, 'null\b')
end

.numericObject



76
77
78
# File 'lib/dentaku/token_scanner.rb', line 76

def numeric
  new(:numeric, '(\d+(\.\d+)?|\.\d+)\b', lambda { |raw| raw =~ /\./ ? BigDecimal.new(raw) : raw.to_i })
end

.operatorObject



99
100
101
102
# File 'lib/dentaku/token_scanner.rb', line 99

def operator
  names = { pow: '^', add: '+', subtract: '-', multiply: '*', divide: '/', mod: '%' }.invert
  new(:operator, '\^|\+|-|\*|\/|%', lambda { |raw| names[raw] })
end

.register_default_scannersObject



46
47
48
# File 'lib/dentaku/token_scanner.rb', line 46

def register_default_scanners
  register_scanners(available_scanners)
end

.register_scanner(id, scanner) ⇒ Object



56
57
58
# File 'lib/dentaku/token_scanner.rb', line 56

def register_scanner(id, scanner)
  @scanners[id] = scanner
end

.register_scanners(scanner_ids) ⇒ Object



50
51
52
53
54
# File 'lib/dentaku/token_scanner.rb', line 50

def register_scanners(scanner_ids)
  @scanners = scanner_ids.each_with_object({}) do |id, scanners|
    scanners[id] = self.send(id)
  end
end

.scannersObject



64
65
66
# File 'lib/dentaku/token_scanner.rb', line 64

def scanners
  @scanners.values
end

.scanners=(scanner_ids) ⇒ Object



60
61
62
# File 'lib/dentaku/token_scanner.rb', line 60

def scanners=(scanner_ids)
  @scanners.select! { |k,v| scanner_ids.include?(k) }
end

.single_quoted_stringObject



84
85
86
# File 'lib/dentaku/token_scanner.rb', line 84

def single_quoted_string
  new(:string, "'[^']*'", lambda { |raw| raw.gsub(/^'|'$/, '') })
end

.whitespaceObject



68
69
70
# File 'lib/dentaku/token_scanner.rb', line 68

def whitespace
  new(:whitespace, '\s+')
end

Instance Method Details

#scan(string, last_token = nil) ⇒ Object



13
14
15
16
17
18
19
20
21
22
23
24
# File 'lib/dentaku/token_scanner.rb', line 13

def scan(string, last_token=nil)
  if (m = @regexp.match(string)) && @condition.call(last_token)
    value = raw = m.to_s
    value = @converter.call(raw) if @converter

    return Array(value).map do |v|
      Token === v ? v : Token.new(@category, v, raw)
    end
  end

  false
end