annotate vendor/gems/coderay-1.0.0/lib/coderay/scanners/sql.rb @ 1169:492ff72268e3 bug_521

Close obsolete branch bug_521
author Chris Cannam
date Thu, 18 Oct 2012 10:42:48 +0100
parents cbb26bc654de
children
rev   line source
Chris@909 1 module CodeRay module Scanners
Chris@909 2
Chris@909 3 # by Josh Goebel
Chris@909 4 class SQL < Scanner
Chris@909 5
Chris@909 6 register_for :sql
Chris@909 7
Chris@909 8 KEYWORDS = %w(
Chris@909 9 all and any as before begin between by case check collate
Chris@909 10 each else end exists
Chris@909 11 for foreign from full group having if in inner is join
Chris@909 12 like not of on or order outer over references
Chris@909 13 then to union using values when where
Chris@909 14 left right distinct
Chris@909 15 )
Chris@909 16
Chris@909 17 OBJECTS = %w(
Chris@909 18 database databases table tables column columns fields index constraint
Chris@909 19 constraints transaction function procedure row key view trigger
Chris@909 20 )
Chris@909 21
Chris@909 22 COMMANDS = %w(
Chris@909 23 add alter comment create delete drop grant insert into select update set
Chris@909 24 show prompt begin commit rollback replace truncate
Chris@909 25 )
Chris@909 26
Chris@909 27 PREDEFINED_TYPES = %w(
Chris@909 28 char varchar varchar2 enum binary text tinytext mediumtext
Chris@909 29 longtext blob tinyblob mediumblob longblob timestamp
Chris@909 30 date time datetime year double decimal float int
Chris@909 31 integer tinyint mediumint bigint smallint unsigned bit
Chris@909 32 bool boolean hex bin oct
Chris@909 33 )
Chris@909 34
Chris@909 35 PREDEFINED_FUNCTIONS = %w( sum cast substring abs pi count min max avg now )
Chris@909 36
Chris@909 37 DIRECTIVES = %w(
Chris@909 38 auto_increment unique default charset initially deferred
Chris@909 39 deferrable cascade immediate read write asc desc after
Chris@909 40 primary foreign return engine
Chris@909 41 )
Chris@909 42
Chris@909 43 PREDEFINED_CONSTANTS = %w( null true false )
Chris@909 44
Chris@909 45 IDENT_KIND = WordList::CaseIgnoring.new(:ident).
Chris@909 46 add(KEYWORDS, :keyword).
Chris@909 47 add(OBJECTS, :type).
Chris@909 48 add(COMMANDS, :class).
Chris@909 49 add(PREDEFINED_TYPES, :predefined_type).
Chris@909 50 add(PREDEFINED_CONSTANTS, :predefined_constant).
Chris@909 51 add(PREDEFINED_FUNCTIONS, :predefined).
Chris@909 52 add(DIRECTIVES, :directive)
Chris@909 53
Chris@909 54 ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx
Chris@909 55 UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
Chris@909 56
Chris@909 57 STRING_PREFIXES = /[xnb]|_\w+/i
Chris@909 58
Chris@909 59 def scan_tokens encoder, options
Chris@909 60
Chris@909 61 state = :initial
Chris@909 62 string_type = nil
Chris@909 63 string_content = ''
Chris@909 64 name_expected = false
Chris@909 65
Chris@909 66 until eos?
Chris@909 67
Chris@909 68 if state == :initial
Chris@909 69
Chris@909 70 if match = scan(/ \s+ | \\\n /x)
Chris@909 71 encoder.text_token match, :space
Chris@909 72
Chris@909 73 elsif match = scan(/(?:--\s?|#).*/)
Chris@909 74 encoder.text_token match, :comment
Chris@909 75
Chris@909 76 elsif match = scan(%r( /\* (!)? (?: .*? \*/ | .* ) )mx)
Chris@909 77 encoder.text_token match, self[1] ? :directive : :comment
Chris@909 78
Chris@909 79 elsif match = scan(/ [*\/=<>:;,!&^|()\[\]{}~%] | [-+\.](?!\d) /x)
Chris@909 80 name_expected = true if match == '.' && check(/[A-Za-z_]/)
Chris@909 81 encoder.text_token match, :operator
Chris@909 82
Chris@909 83 elsif match = scan(/(#{STRING_PREFIXES})?([`"'])/o)
Chris@909 84 prefix = self[1]
Chris@909 85 string_type = self[2]
Chris@909 86 encoder.begin_group :string
Chris@909 87 encoder.text_token prefix, :modifier if prefix
Chris@909 88 match = string_type
Chris@909 89 state = :string
Chris@909 90 encoder.text_token match, :delimiter
Chris@909 91
Chris@909 92 elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
Chris@909 93 encoder.text_token match, name_expected ? :ident : (match[0] == ?@ ? :variable : IDENT_KIND[match])
Chris@909 94 name_expected = false
Chris@909 95
Chris@909 96 elsif match = scan(/0[xX][0-9A-Fa-f]+/)
Chris@909 97 encoder.text_token match, :hex
Chris@909 98
Chris@909 99 elsif match = scan(/0[0-7]+(?![89.eEfF])/)
Chris@909 100 encoder.text_token match, :octal
Chris@909 101
Chris@909 102 elsif match = scan(/[-+]?(?>\d+)(?![.eEfF])/)
Chris@909 103 encoder.text_token match, :integer
Chris@909 104
Chris@909 105 elsif match = scan(/[-+]?(?:\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+)/)
Chris@909 106 encoder.text_token match, :float
Chris@909 107
Chris@909 108 elsif match = scan(/\\N/)
Chris@909 109 encoder.text_token match, :predefined_constant
Chris@909 110
Chris@909 111 else
Chris@909 112 encoder.text_token getch, :error
Chris@909 113
Chris@909 114 end
Chris@909 115
Chris@909 116 elsif state == :string
Chris@909 117 if match = scan(/[^\\"'`]+/)
Chris@909 118 string_content << match
Chris@909 119 next
Chris@909 120 elsif match = scan(/["'`]/)
Chris@909 121 if string_type == match
Chris@909 122 if peek(1) == string_type # doubling means escape
Chris@909 123 string_content << string_type << getch
Chris@909 124 next
Chris@909 125 end
Chris@909 126 unless string_content.empty?
Chris@909 127 encoder.text_token string_content, :content
Chris@909 128 string_content = ''
Chris@909 129 end
Chris@909 130 encoder.text_token match, :delimiter
Chris@909 131 encoder.end_group :string
Chris@909 132 state = :initial
Chris@909 133 string_type = nil
Chris@909 134 else
Chris@909 135 string_content << match
Chris@909 136 end
Chris@909 137 elsif match = scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
Chris@909 138 unless string_content.empty?
Chris@909 139 encoder.text_token string_content, :content
Chris@909 140 string_content = ''
Chris@909 141 end
Chris@909 142 encoder.text_token match, :char
Chris@909 143 elsif match = scan(/ \\ . /mox)
Chris@909 144 string_content << match
Chris@909 145 next
Chris@909 146 elsif match = scan(/ \\ | $ /x)
Chris@909 147 unless string_content.empty?
Chris@909 148 encoder.text_token string_content, :content
Chris@909 149 string_content = ''
Chris@909 150 end
Chris@909 151 encoder.text_token match, :error
Chris@909 152 state = :initial
Chris@909 153 else
Chris@909 154 raise "else case \" reached; %p not handled." % peek(1), encoder
Chris@909 155 end
Chris@909 156
Chris@909 157 else
Chris@909 158 raise 'else-case reached', encoder
Chris@909 159
Chris@909 160 end
Chris@909 161
Chris@909 162 end
Chris@909 163
Chris@909 164 if state == :string
Chris@909 165 encoder.end_group state
Chris@909 166 end
Chris@909 167
Chris@909 168 encoder
Chris@909 169
Chris@909 170 end
Chris@909 171
Chris@909 172 end
Chris@909 173
Chris@909 174 end end