annotate vendor/gems/coderay-0.9.7/lib/coderay/scanners/sql.rb @ 855:7294e8db2515 bug_162

Close obsolete branch bug_162
author Chris Cannam
date Thu, 14 Jul 2011 11:59:19 +0100
parents 0579821a129a
children
rev   line source
Chris@210 1 module CodeRay module Scanners
Chris@210 2
Chris@210 3 # by Josh Goebel
Chris@210 4 class SQL < Scanner
Chris@210 5
Chris@210 6 register_for :sql
Chris@210 7
Chris@210 8 RESERVED_WORDS = %w(
Chris@210 9 create database table index trigger drop primary key set select
Chris@210 10 insert update delete replace into
Chris@210 11 on from values before and or if exists case when
Chris@210 12 then else as group order by avg where
Chris@210 13 join inner outer union engine not
Chris@210 14 like end using collate show columns begin
Chris@210 15 )
Chris@210 16
Chris@210 17 PREDEFINED_TYPES = %w(
Chris@210 18 char varchar enum binary text tinytext mediumtext
Chris@210 19 longtext blob tinyblob mediumblob longblob timestamp
Chris@210 20 date time datetime year double decimal float int
Chris@210 21 integer tinyint mediumint bigint smallint unsigned bit
Chris@210 22 bool boolean hex bin oct
Chris@210 23 )
Chris@210 24
Chris@210 25 PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg )
Chris@210 26
Chris@210 27 DIRECTIVES = %w( auto_increment unique default charset )
Chris@210 28
Chris@210 29 PREDEFINED_CONSTANTS = %w( null true false )
Chris@210 30
Chris@210 31 IDENT_KIND = CaseIgnoringWordList.new(:ident).
Chris@210 32 add(RESERVED_WORDS, :reserved).
Chris@210 33 add(PREDEFINED_TYPES, :pre_type).
Chris@210 34 add(PREDEFINED_CONSTANTS, :pre_constant).
Chris@210 35 add(PREDEFINED_FUNCTIONS, :predefined).
Chris@210 36 add(DIRECTIVES, :directive)
Chris@210 37
Chris@210 38 ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx
Chris@210 39 UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
Chris@210 40
Chris@210 41 STRING_PREFIXES = /[xnb]|_\w+/i
Chris@210 42
Chris@210 43 def scan_tokens tokens, options
Chris@210 44
Chris@210 45 state = :initial
Chris@210 46 string_type = nil
Chris@210 47 string_content = ''
Chris@210 48
Chris@210 49 until eos?
Chris@210 50
Chris@210 51 kind = nil
Chris@210 52 match = nil
Chris@210 53
Chris@210 54 if state == :initial
Chris@210 55
Chris@210 56 if scan(/ \s+ | \\\n /x)
Chris@210 57 kind = :space
Chris@210 58
Chris@210 59 elsif scan(/(?:--\s?|#).*/)
Chris@210 60 kind = :comment
Chris@210 61
Chris@210 62 elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx)
Chris@210 63 kind = :comment
Chris@210 64
Chris@210 65 elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x)
Chris@210 66 kind = :operator
Chris@210 67
Chris@210 68 elsif scan(/(#{STRING_PREFIXES})?([`"'])/o)
Chris@210 69 prefix = self[1]
Chris@210 70 string_type = self[2]
Chris@210 71 tokens << [:open, :string]
Chris@210 72 tokens << [prefix, :modifier] if prefix
Chris@210 73 match = string_type
Chris@210 74 state = :string
Chris@210 75 kind = :delimiter
Chris@210 76
Chris@210 77 elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
Chris@210 78 kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase]
Chris@210 79
Chris@210 80 elsif scan(/0[xX][0-9A-Fa-f]+/)
Chris@210 81 kind = :hex
Chris@210 82
Chris@210 83 elsif scan(/0[0-7]+(?![89.eEfF])/)
Chris@210 84 kind = :oct
Chris@210 85
Chris@210 86 elsif scan(/(?>\d+)(?![.eEfF])/)
Chris@210 87 kind = :integer
Chris@210 88
Chris@210 89 elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
Chris@210 90 kind = :float
Chris@210 91
Chris@210 92 else
Chris@210 93 getch
Chris@210 94 kind = :error
Chris@210 95
Chris@210 96 end
Chris@210 97
Chris@210 98 elsif state == :string
Chris@210 99 if match = scan(/[^\\"'`]+/)
Chris@210 100 string_content << match
Chris@210 101 next
Chris@210 102 elsif match = scan(/["'`]/)
Chris@210 103 if string_type == match
Chris@210 104 if peek(1) == string_type # doubling means escape
Chris@210 105 string_content << string_type << getch
Chris@210 106 next
Chris@210 107 end
Chris@210 108 unless string_content.empty?
Chris@210 109 tokens << [string_content, :content]
Chris@210 110 string_content = ''
Chris@210 111 end
Chris@210 112 tokens << [matched, :delimiter]
Chris@210 113 tokens << [:close, :string]
Chris@210 114 state = :initial
Chris@210 115 string_type = nil
Chris@210 116 next
Chris@210 117 else
Chris@210 118 string_content << match
Chris@210 119 end
Chris@210 120 next
Chris@210 121 elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
Chris@210 122 unless string_content.empty?
Chris@210 123 tokens << [string_content, :content]
Chris@210 124 string_content = ''
Chris@210 125 end
Chris@210 126 kind = :char
Chris@210 127 elsif match = scan(/ \\ . /mox)
Chris@210 128 string_content << match
Chris@210 129 next
Chris@210 130 elsif scan(/ \\ | $ /x)
Chris@210 131 unless string_content.empty?
Chris@210 132 tokens << [string_content, :content]
Chris@210 133 string_content = ''
Chris@210 134 end
Chris@210 135 kind = :error
Chris@210 136 state = :initial
Chris@210 137 else
Chris@210 138 raise "else case \" reached; %p not handled." % peek(1), tokens
Chris@210 139 end
Chris@210 140
Chris@210 141 else
Chris@210 142 raise 'else-case reached', tokens
Chris@210 143
Chris@210 144 end
Chris@210 145
Chris@210 146 match ||= matched
Chris@210 147 unless kind
Chris@210 148 raise_inspect 'Error token %p in line %d' %
Chris@210 149 [[match, kind], line], tokens, state
Chris@210 150 end
Chris@210 151 raise_inspect 'Empty token', tokens unless match
Chris@210 152
Chris@210 153 tokens << [match, kind]
Chris@210 154
Chris@210 155 end
Chris@210 156 tokens
Chris@210 157
Chris@210 158 end
Chris@210 159
Chris@210 160 end
Chris@210 161
Chris@210 162 end end