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

by Josh Goebel

Methods

Included Modules

Streamable

Constants

RESERVED_WORDS = %w( all alter and any as asc at authid avg begin between body bulk by case char check close cluster coalesce collect comment commit compress connect constant create current currval cursor day declare default delete desc distinct do drop else elsif end exception exclusive execute exists exit extends extract fetch for forall from function goto group having heap hour if immediate in index indicator insert interface intersect interval into is isolation java level like limited lock loop max min minus minute mlslabel mod mode month natural naturaln new nextval nocopy not nowait null nullif number_base ocirowid of on opaque open operator option or order organization others out package partition pctfree pls_integer positive positiven pragma prior private procedure public raise range raw real record ref release return reverse rollback row rowid rownum rowtype savepoint second select separate set share space sql sqlcode sqlerrm start stddev subtype successful sum synonym sysdate table then timezone_region timezone_abbr timezone_minute to trigger true type uid union unique update use user validate values variance view when whenever where while with work write year zone )
PREDEFINED_TYPES = %w( array bigint bit binary blob boolean binary_integer char character clob date decimal double float char_base int integer nchar nclob smallint timestamp long number timestamp_hour timestamp_minute varchar varying smallint varchar2 nvarchar money time )
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)
RESERVED_WORDS = %w( create 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 )
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 )
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 = / [rbfnrtv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x

Public Instance methods

[Source]

     # File lib/coderay/scanners/sql.Keith.rb, line 53
 53:     def scan_tokens tokens, options
 54: 
 55:       state = :initial
 56:       
 57:       until eos?
 58: 
 59:         kind = nil
 60:         match = nil
 61:         
 62:         case state
 63: 
 64:         when :initial
 65: 
 66:           if scan(/ \s+ | \\\n /x)
 67:             kind = :space
 68: 
 69:           elsif scan(%r! -- [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)
 70:             kind = :comment
 71: 
 72:           elsif scan(/ [-+*\/=<>?:;,!&^|()~%]+ | \.(?!\d) /x)
 73:             kind = :operator
 74: 
 75:           elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
 76:             kind = IDENT_KIND[match]
 77:             if kind == :ident and check(/:(?!:)/)
 78:               match << scan(/:/)
 79:               kind = :label
 80:             end
 81: 
 82:           elsif match = scan(/'/)
 83:             tokens << [:open, :string]
 84:             state = :string
 85:             kind = :delimiter
 86: 
 87:           elsif scan(/(?:\d+)(?![.eEfF])/)
 88:             kind = :integer
 89: 
 90:           elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
 91:             kind = :float
 92: 
 93:           else
 94:             getch
 95:             kind = :error
 96: 
 97:           end
 98: 
 99:         when :string
100:           if scan(/[^\\\n']+/)
101:             kind = :content
102:           elsif scan(/'/)
103:             tokens << ["'", :delimiter]
104:             tokens << [:close, :string]
105:             state = :initial
106:             next
107:           elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
108:             kind = :char
109:           elsif scan(/ \\ | $ /x)
110:             tokens << [:close, :string]
111:             kind = :error
112:             state = :initial
113:           else
114:             raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
115:           end
116: 
117:         else
118:           raise_inspect 'Unknown state', tokens
119: 
120:         end
121: 
122:         match ||= matched
123:         if $DEBUG and not kind
124:           raise_inspect 'Error token %p in line %d' %
125:             [[match, kind], line], tokens
126:         end
127:         raise_inspect 'Empty token', tokens unless match
128: 
129:         tokens << [match, kind]
130: 
131:       end
132: 
133:       if state == :string
134:         tokens << [:close, :string]
135:       end
136: 
137:       tokens
138:     end

[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 match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
 67:             kind = IDENT_KIND[match.downcase]
 68:             
 69:           elsif match = scan(/[`"']/)
 70:             tokens << [:open, :string]
 71:             string_type = matched
 72:             state = :string
 73:             kind = :delimiter
 74:             
 75:           elsif scan(/0[xX][0-9A-Fa-f]+/)
 76:             kind = :hex
 77:             
 78:           elsif scan(/0[0-7]+(?![89.eEfF])/)
 79:             kind = :oct
 80:             
 81:           elsif scan(/\d+(?![.eEfF])/)
 82:             kind = :integer
 83:             
 84:           elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
 85:             kind = :float
 86: 
 87:           else
 88:             getch
 89:             kind = :error
 90:             
 91:           end
 92:           
 93:         elsif state == :string
 94:           if match = scan(/[^\\"'`]+/)
 95:             string_content << match
 96:             next
 97:           elsif match = scan(/["'`]/)
 98:             if string_type == match
 99:               if peek(1) == string_type  # doubling means escape
100:                 string_content << string_type << getch
101:                 next
102:               end
103:               unless string_content.empty?
104:                 tokens << [string_content, :content]
105:                 string_content = ''
106:               end
107:               tokens << [matched, :delimiter]
108:               tokens << [:close, :string]
109:               state = :initial
110:               string_type = nil
111:               next
112:             else
113:               string_content << match
114:             end
115:             next
116:           elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
117:             unless string_content.empty?
118:               tokens << [string_content, :content]
119:               string_content = ''
120:             end
121:             kind = :char
122:           elsif match = scan(/ \\ . /mox)
123:             string_content << match
124:             next
125:           elsif scan(/ \\ | $ /x)
126:             unless string_content.empty?
127:               tokens << [string_content, :content]
128:               string_content = ''
129:             end
130:             kind = :error
131:             state = :initial
132:           else
133:             raise "else case \" reached; %p not handled." % peek(1), tokens
134:           end
135:           
136:         else
137:           raise 'else-case reached', tokens
138:           
139:         end
140:         
141:         match ||= matched
142: #        raise [match, kind], tokens if kind == :error
143:         
144:         tokens << [match, kind]
145:         
146:       end
147: #      RAILS_DEFAULT_LOGGER.info tokens.inspect
148:       tokens
149:       
150:     end

[Validate]