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