| Class | CodeRay::Scanners::SQL |
| In: |
lib/coderay/scanners/sql.rb
|
| Parent: | Scanner |
by Josh Goebel
| RESERVED_WORDS | = | %w( and as avg before begin between by case collate columns create database databases delete distinct drop else end engine exists fields from full group having if index inner insert into is join key like not on or order outer primary prompt replace select set show table tables then trigger union update using values when where ) |
| PREDEFINED_TYPES | = | %w( bigint bin binary bit blob bool boolean char date datetime decimal double enum float hex int integer longblob longtext mediumblob mediumint mediumtext oct smallint text time timestamp tinyblob tinyint tinytext unsigned varchar year ) |
| 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 | = | / [rbfntv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} | . /mx |
| UNICODE_ESCAPE | = | / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x |
| STRING_PREFIXES | = | /[xnb]|_\w+/i |
# 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 scan(/(#{STRING_PREFIXES})?([`"'])/o)
67: prefix = self[1]
68: string_type = self[2]
69: tokens << [:open, :string]
70: tokens << [prefix, :modifier] if prefix
71: match = string_type
72: state = :string
73: kind = :delimiter
74:
75: elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x)
76: kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase]
77:
78: elsif scan(/0[xX][0-9A-Fa-f]+/)
79: kind = :hex
80:
81: elsif scan(/0[0-7]+(?![89.eEfF])/)
82: kind = :oct
83:
84: elsif scan(/(?>\d+)(?![.eEfF])/)
85: kind = :integer
86:
87: elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/)
88: kind = :float
89:
90: else
91: getch
92: kind = :error
93:
94: end
95:
96: elsif state == :string
97: if match = scan(/[^\\"'`]+/)
98: string_content << match
99: next
100: elsif match = scan(/["'`]/)
101: if string_type == match
102: if peek(1) == string_type # doubling means escape
103: string_content << string_type << getch
104: next
105: end
106: unless string_content.empty?
107: tokens << [string_content, :content]
108: string_content = ''
109: end
110: tokens << [matched, :delimiter]
111: tokens << [:close, :string]
112: state = :initial
113: string_type = nil
114: next
115: else
116: string_content << match
117: end
118: next
119: elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
120: unless string_content.empty?
121: tokens << [string_content, :content]
122: string_content = ''
123: end
124: kind = :char
125: elsif match = scan(/ \\ . /mox)
126: string_content << match
127: next
128: elsif scan(/ \\ | $ /x)
129: unless string_content.empty?
130: tokens << [string_content, :content]
131: string_content = ''
132: end
133: kind = :error
134: state = :initial
135: else
136: raise "else case \" reached; %p not handled." % peek(1), tokens
137: end
138:
139: else
140: raise 'else-case reached', tokens
141:
142: end
143:
144: match ||= matched
145: unless kind
146: raise_inspect 'Error token %p in line %d' %
147: [[match, kind], line], tokens, state
148: end
149: raise_inspect 'Empty token', tokens unless match
150:
151: tokens << [match, kind]
152:
153: end
154: tokens
155:
156: end