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