comparison vendor/plugins/coderay-0.9.2/lib/coderay/scanners/sql.rb @ 0:513646585e45

* Import Redmine trunk SVN rev 3859
author Chris Cannam
date Fri, 23 Jul 2010 15:52:44 +0100
parents
children
comparison
equal deleted inserted replaced
-1:000000000000 0:513646585e45
1 module CodeRay module Scanners
2
3 # by Josh Goebel
4 class SQL < Scanner
5
6 register_for :sql
7
8 RESERVED_WORDS = %w(
9 create database table index trigger drop primary key set select
10 insert update delete replace into
11 on from values before and or if exists case when
12 then else as group order by avg where
13 join inner outer union engine not
14 like end using collate show columns begin
15 )
16
17 PREDEFINED_TYPES = %w(
18 char varchar enum binary text tinytext mediumtext
19 longtext blob tinyblob mediumblob longblob timestamp
20 date time datetime year double decimal float int
21 integer tinyint mediumint bigint smallint unsigned bit
22 bool boolean hex bin oct
23 )
24
25 PREDEFINED_FUNCTIONS = %w( sum cast abs pi count min max avg )
26
27 DIRECTIVES = %w( auto_increment unique default charset )
28
29 PREDEFINED_CONSTANTS = %w( null true false )
30
31 IDENT_KIND = CaseIgnoringWordList.new(:ident).
32 add(RESERVED_WORDS, :reserved).
33 add(PREDEFINED_TYPES, :pre_type).
34 add(PREDEFINED_CONSTANTS, :pre_constant).
35 add(PREDEFINED_FUNCTIONS, :predefined).
36 add(DIRECTIVES, :directive)
37
38 ESCAPE = / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx
39 UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
40
41 STRING_PREFIXES = /[xnb]|_\w+/i
42
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
159
160 end
161
162 end end