annotate vendor/plugins/coderay-0.9.2/lib/coderay/scanners/sql.rb @ 874:12771bc38f20 feature_123

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