To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.

Statistics Download as Zip
| Branch: | Tag: | Revision:

root / vendor / gems / coderay-0.9.7 / lib / coderay / scanners / sql.rb @ 442:753f1380d6bc

History | View | Annotate | Download (4.62 KB)

1
module CodeRay module Scanners
2
  
3
  # by Josh Goebel
4
  class SQL < Scanner
5

    
6
    register_for :sql
7
    
8
    RESERVED_WORDS = %w(
9
      create database table index trigger drop primary key set select
10
      insert update delete replace into
11
      on from values before and or if exists case when
12
      then else as group order by avg where
13
      join inner outer union engine not
14
      like end using collate show columns begin
15
    )
16
    
17
    PREDEFINED_TYPES = %w(
18
      char varchar enum binary text tinytext mediumtext
19
      longtext blob tinyblob mediumblob longblob timestamp
20
      date time datetime year double decimal float int
21
      integer tinyint mediumint bigint smallint unsigned bit
22
      bool boolean hex bin oct
23
    )
24
    
25
    PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg )
26
    
27
    DIRECTIVES = %w( auto_increment unique default charset )
28

    
29
    PREDEFINED_CONSTANTS = %w( null true false )
30
    
31
    IDENT_KIND = CaseIgnoringWordList.new(:ident).
32
      add(RESERVED_WORDS, :reserved).
33
      add(PREDEFINED_TYPES, :pre_type).
34
      add(PREDEFINED_CONSTANTS, :pre_constant).
35
      add(PREDEFINED_FUNCTIONS, :predefined).
36
      add(DIRECTIVES, :directive)
37
    
38
    ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx
39
    UNICODE_ESCAPE =  / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
40
    
41
    STRING_PREFIXES = /[xnb]|_\w+/i
42
    
43
    def scan_tokens tokens, options
44
      
45
      state = :initial
46
      string_type = nil
47
      string_content = ''
48
      
49
      until eos?
50
        
51
        kind = nil
52
        match = nil
53
        
54
        if state == :initial
55
          
56
          if scan(/ \s+ | \\\n /x)
57
            kind = :space
58
          
59
          elsif scan(/(?:--\s?|#).*/)
60
            kind = :comment
61
            
62
          elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx)
63
            kind = :comment
64
            
65
          elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x)
66
            kind = :operator
67
            
68
          elsif scan(/(#{STRING_PREFIXES})?([`"'])/o)
69
            prefix = self[1]
70
            string_type = self[2]
71
            tokens << [:open, :string]
72
            tokens << [prefix, :modifier] if prefix
73
            match = string_type
74
            state = :string
75
            kind = :delimiter
76
            
77
          elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
78
            kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase]
79
            
80
          elsif scan(/0[xX][0-9A-Fa-f]+/)
81
            kind = :hex
82
            
83
          elsif scan(/0[0-7]+(?![89.eEfF])/)
84
            kind = :oct
85
            
86
          elsif scan(/(?>\d+)(?![.eEfF])/)
87
            kind = :integer
88
            
89
          elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
90
            kind = :float
91
            
92
          else
93
            getch
94
            kind = :error
95
            
96
          end
97
          
98
        elsif state == :string
99
          if match = scan(/[^\\"'`]+/)
100
            string_content << match
101
            next
102
          elsif match = scan(/["'`]/)
103
            if string_type == match
104
              if peek(1) == string_type  # doubling means escape
105
                string_content << string_type << getch
106
                next
107
              end
108
              unless string_content.empty?
109
                tokens << [string_content, :content]
110
                string_content = ''
111
              end
112
              tokens << [matched, :delimiter]
113
              tokens << [:close, :string]
114
              state = :initial
115
              string_type = nil
116
              next
117
            else
118
              string_content << match
119
            end
120
            next
121
          elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
122
            unless string_content.empty?
123
              tokens << [string_content, :content]
124
              string_content = ''
125
            end
126
            kind = :char
127
          elsif match = scan(/ \\ . /mox)
128
            string_content << match
129
            next
130
          elsif scan(/ \\ | $ /x)
131
            unless string_content.empty?
132
              tokens << [string_content, :content]
133
              string_content = ''
134
            end
135
            kind = :error
136
            state = :initial
137
          else
138
            raise "else case \" reached; %p not handled." % peek(1), tokens
139
          end
140
          
141
        else
142
          raise 'else-case reached', tokens
143
          
144
        end
145
        
146
        match ||= matched
147
        unless kind
148
          raise_inspect 'Error token %p in line %d' %
149
            [[match, kind], line], tokens, state
150
        end
151
        raise_inspect 'Empty token', tokens unless match
152
        
153
        tokens << [match, kind]
154
        
155
      end
156
      tokens
157
      
158
    end
159
    
160
  end
161
  
162
end end