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

by Josh Goebel

Methods

Constants

RESERVED_WORDS = %w( and as avg before begin between by case collate columns create database databases delete distinct drop else end engine exists fields from full group having if index inner insert into is join key like not on or order outer primary prompt replace select set show table tables then trigger union update using values when where )
PREDEFINED_TYPES = %w( bigint bin binary bit blob bool boolean char date datetime decimal double enum float hex int integer longblob longtext mediumblob mediumint mediumtext oct smallint text time timestamp tinyblob tinyint tinytext unsigned varchar year )
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 41
 41:     def scan_tokens tokens, options
 42:       
 43:       state = :initial
 44:       string_type = nil
 45:       string_content = ''
 46:       
 47:       until eos?
 48:         
 49:         kind = nil
 50:         match = nil
 51:         
 52:         if state == :initial
 53:           
 54:           if scan(/ \s+ | \\\n /x)
 55:             kind = :space
 56:           
 57:           elsif scan(/(?:--\s?|#).*/)
 58:             kind = :comment
 59:             
 60:           elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx)
 61:             kind = :comment
 62:             
 63:           elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x)
 64:             kind = :operator
 65:             
 66:           elsif scan(/(#{STRING_PREFIXES})?([`"'])/o)
 67:             prefix = self[1]
 68:             string_type = self[2]
 69:             tokens << [:open, :string]
 70:             tokens << [prefix, :modifier] if prefix
 71:             match = string_type
 72:             state = :string
 73:             kind = :delimiter
 74:             
 75:           elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
 76:             kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase]
 77:             
 78:           elsif scan(/0[xX][0-9A-Fa-f]+/)
 79:             kind = :hex
 80:             
 81:           elsif scan(/0[0-7]+(?![89.eEfF])/)
 82:             kind = :oct
 83:             
 84:           elsif scan(/(?>\d+)(?![.eEfF])/)
 85:             kind = :integer
 86:             
 87:           elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
 88:             kind = :float
 89:             
 90:           else
 91:             getch
 92:             kind = :error
 93:             
 94:           end
 95:           
 96:         elsif state == :string
 97:           if match = scan(/[^\\"'`]+/)
 98:             string_content << match
 99:             next
100:           elsif match = scan(/["'`]/)
101:             if string_type == match
102:               if peek(1) == string_type  # doubling means escape
103:                 string_content << string_type << getch
104:                 next
105:               end
106:               unless string_content.empty?
107:                 tokens << [string_content, :content]
108:                 string_content = ''
109:               end
110:               tokens << [matched, :delimiter]
111:               tokens << [:close, :string]
112:               state = :initial
113:               string_type = nil
114:               next
115:             else
116:               string_content << match
117:             end
118:             next
119:           elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
120:             unless string_content.empty?
121:               tokens << [string_content, :content]
122:               string_content = ''
123:             end
124:             kind = :char
125:           elsif match = scan(/ \\ . /mox)
126:             string_content << match
127:             next
128:           elsif scan(/ \\ | $ /x)
129:             unless string_content.empty?
130:               tokens << [string_content, :content]
131:               string_content = ''
132:             end
133:             kind = :error
134:             state = :initial
135:           else
136:             raise "else case \" reached; %p not handled." % peek(1), tokens
137:           end
138:           
139:         else
140:           raise 'else-case reached', tokens
141:           
142:         end
143:         
144:         match ||= matched
145:         unless kind
146:           raise_inspect 'Error token %p in line %d' %
147:             [[match, kind], line], tokens, state
148:         end
149:         raise_inspect 'Empty token', tokens unless match
150:         
151:         tokens << [match, kind]
152:         
153:       end
154:       tokens
155:       
156:     end

[Validate]