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

by Josh Goebel

Methods

Constants

KEYWORDS = %w( all and any as before begin between by case check collate each else end exists for foreign from full group having if in inner is join like not of on or order outer over references then to union using values when where left right distinct )
OBJECTS = %w( database databases table tables column columns fields index constraint constraints transaction function procedure row key view trigger )
COMMANDS = %w( add alter comment create delete drop grant insert into select update set show prompt begin commit rollback replace truncate )
PREDEFINED_TYPES = %w( char varchar varchar2 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 substring abs pi count min max avg now )
DIRECTIVES = %w( auto_increment unique default charset initially deferred deferrable cascade immediate read write asc desc after primary foreign return engine )
PREDEFINED_CONSTANTS = %w( null true false )
IDENT_KIND = WordList::CaseIgnoring.new(:ident). add(KEYWORDS, :keyword). add(OBJECTS, :type). add(COMMANDS, :class). add(PREDEFINED_TYPES, :predefined_type). add(PREDEFINED_CONSTANTS, :predefined_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 59
 59:     def scan_tokens encoder, options
 60:       
 61:       state = :initial
 62:       string_type = nil
 63:       string_content = ''
 64:       name_expected = false
 65:       
 66:       until eos?
 67:         
 68:         if state == :initial
 69:           
 70:           if match = scan(/ \s+ | \\\n /x)
 71:             encoder.text_token match, :space
 72:           
 73:           elsif match = scan(/(?:--\s?|#).*/)
 74:             encoder.text_token match, :comment
 75:             
 76:           elsif match = scan(%r( /\* (!)? (?: .*? \*/ | .* ) )mx)
 77:             encoder.text_token match, self[1] ? :directive : :comment
 78:             
 79:           elsif match = scan(/ [*\/=<>:;,!&^|()\[\]{}~%] | [-+\.](?!\d) /x)
 80:             name_expected = true if match == '.' && check(/[A-Za-z_]/)
 81:             encoder.text_token match, :operator
 82:             
 83:           elsif match = scan(/(#{STRING_PREFIXES})?([`"'])/o)
 84:             prefix = self[1]
 85:             string_type = self[2]
 86:             encoder.begin_group :string
 87:             encoder.text_token prefix, :modifier if prefix
 88:             match = string_type
 89:             state = :string
 90:             encoder.text_token match, :delimiter
 91:             
 92:           elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
 93:             encoder.text_token match, name_expected ? :ident : (match[0] == ?@ ? :variable : IDENT_KIND[match])
 94:             name_expected = false
 95:             
 96:           elsif match = scan(/0[xX][0-9A-Fa-f]+/)
 97:             encoder.text_token match, :hex
 98:             
 99:           elsif match = scan(/0[0-7]+(?![89.eEfF])/)
100:             encoder.text_token match, :octal
101:             
102:           elsif match = scan(/[-+]?(?>\d+)(?![.eEfF])/)
103:             encoder.text_token match, :integer
104:             
105:           elsif match = scan(/[-+]?(?:\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+)/)
106:             encoder.text_token match, :float
107:           
108:           elsif match = scan(/\\N/)
109:             encoder.text_token match, :predefined_constant
110:             
111:           else
112:             encoder.text_token getch, :error
113:             
114:           end
115:           
116:         elsif state == :string
117:           if match = scan(/[^\\"'`]+/)
118:             string_content << match
119:             next
120:           elsif match = scan(/["'`]/)
121:             if string_type == match
122:               if peek(1) == string_type  # doubling means escape
123:                 string_content << string_type << getch
124:                 next
125:               end
126:               unless string_content.empty?
127:                 encoder.text_token string_content, :content
128:                 string_content = ''
129:               end
130:               encoder.text_token match, :delimiter
131:               encoder.end_group :string
132:               state = :initial
133:               string_type = nil
134:             else
135:               string_content << match
136:             end
137:           elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
138:             unless string_content.empty?
139:               encoder.text_token string_content, :content
140:               string_content = ''
141:             end
142:             encoder.text_token match, :char
143:           elsif match = scan(/ \\ . /mox)
144:             string_content << match
145:             next
146:           elsif match = scan(/ \\ | $ /x)
147:             unless string_content.empty?
148:               encoder.text_token string_content, :content
149:               string_content = ''
150:             end
151:             encoder.text_token match, :error
152:             state = :initial
153:           else
154:             raise "else case \" reached; %p not handled." % peek(1), encoder
155:           end
156:           
157:         else
158:           raise 'else-case reached', encoder
159:           
160:         end
161:         
162:       end
163:       
164:       if state == :string
165:         encoder.end_group state
166:       end
167:       
168:       encoder
169:       
170:     end

[Validate]