Class | CodeRay::Scanners::SQL |
In: |
lib/coderay/scanners/sql.rb
|
Parent: | Scanner |
by Josh Goebel
RESERVED_WORDS | = | %w( create database 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 end using collate show columns begin ) |
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 hex bin oct ) |
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 43 43: def scan_tokens tokens, options 44: 45: state = :initial 46: string_type = nil 47: string_content = '' 48: 49: until eos? 50: 51: kind = nil 52: match = nil 53: 54: if state == :initial 55: 56: if scan(/ \s+ | \\\n /x) 57: kind = :space 58: 59: elsif scan(/(?:--\s?|#).*/) 60: kind = :comment 61: 62: elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx) 63: kind = :comment 64: 65: elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x) 66: kind = :operator 67: 68: elsif scan(/(#{STRING_PREFIXES})?([`"'])/o) 69: prefix = self[1] 70: string_type = self[2] 71: tokens << [:open, :string] 72: tokens << [prefix, :modifier] if prefix 73: match = string_type 74: state = :string 75: kind = :delimiter 76: 77: elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x) 78: kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase] 79: 80: elsif scan(/0[xX][0-9A-Fa-f]+/) 81: kind = :hex 82: 83: elsif scan(/0[0-7]+(?![89.eEfF])/) 84: kind = :oct 85: 86: elsif scan(/(?>\d+)(?![.eEfF])/) 87: kind = :integer 88: 89: elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) 90: kind = :float 91: 92: else 93: getch 94: kind = :error 95: 96: end 97: 98: elsif state == :string 99: if match = scan(/[^\\"'`]+/) 100: string_content << match 101: next 102: elsif match = scan(/["'`]/) 103: if string_type == match 104: if peek(1) == string_type # doubling means escape 105: string_content << string_type << getch 106: next 107: end 108: unless string_content.empty? 109: tokens << [string_content, :content] 110: string_content = '' 111: end 112: tokens << [matched, :delimiter] 113: tokens << [:close, :string] 114: state = :initial 115: string_type = nil 116: next 117: else 118: string_content << match 119: end 120: next 121: elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) 122: unless string_content.empty? 123: tokens << [string_content, :content] 124: string_content = '' 125: end 126: kind = :char 127: elsif match = scan(/ \\ . /mox) 128: string_content << match 129: next 130: elsif scan(/ \\ | $ /x) 131: unless string_content.empty? 132: tokens << [string_content, :content] 133: string_content = '' 134: end 135: kind = :error 136: state = :initial 137: else 138: raise "else case \" reached; %p not handled." % peek(1), tokens 139: end 140: 141: else 142: raise 'else-case reached', tokens 143: 144: end 145: 146: match ||= matched 147: unless kind 148: raise_inspect 'Error token %p in line %d' % 149: [[match, kind], line], tokens, state 150: end 151: raise_inspect 'Empty token', tokens unless match 152: 153: tokens << [match, kind] 154: 155: end 156: tokens 157: 158: end