Class | CodeRay::Scanners::SQL |
In: |
lib/coderay/scanners/sql.rb
|
Parent: | Scanner |
by Josh Goebel
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 |
# 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