Class CodeRay::Scanners::SQL
In: lib/coderay/scanners/sql.rb
Parent: Scanner

by Josh Goebel

Methods

Constants

RESERVED_WORDS = %w( create database table index trigger drop primary key set select insert update delete replace into on from values before and or if exists case when then else as group order by avg where join inner outer union engine not like end using collate show columns begin )
PREDEFINED_TYPES = %w( char varchar enum binary text tinytext mediumtext longtext blob tinyblob mediumblob longblob timestamp date time datetime year double decimal float int integer tinyint mediumint bigint smallint unsigned bit bool boolean hex bin oct )
PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg )
DIRECTIVES = %w( auto_increment unique default charset )
PREDEFINED_CONSTANTS = %w( null true false )
IDENT_KIND = CaseIgnoringWordList.new(:ident). add(RESERVED_WORDS, :reserved). add(PREDEFINED_TYPES, :pre_type). add(PREDEFINED_CONSTANTS, :pre_constant). add(PREDEFINED_FUNCTIONS, :predefined). add(DIRECTIVES, :directive)
ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
STRING_PREFIXES = /[xnb]|_\w+/i

Public Instance methods

[Source]

     # File lib/coderay/scanners/sql.rb, line 43
 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

[Validate]