diff options
author | murphy <murphy@rubychan.de> | 2009-04-20 21:19:41 +0000 |
---|---|---|
committer | murphy <murphy@rubychan.de> | 2009-04-20 21:19:41 +0000 |
commit | 32701fcf0c5f0e54d7172ceb86e44664aa4bae10 (patch) | |
tree | 5185f2c879f0478a89b2dcbc2a0a632ddaf838b9 /lib/coderay/scanners/sql.rb | |
parent | cf0b7a2a80808c06cb51ad2ee8971082d96cd41e (diff) | |
download | coderay-32701fcf0c5f0e54d7172ceb86e44664aa4bae10.tar.gz |
New: *PHP and SQL Scanners*
* Both not well tested yet, preview versions.
* Some example code for both languages.
* PHP scanner original by Stefan Walk.
* SQL scanner using code by Keith Pitt and Josh Goebel.
Diffstat (limited to 'lib/coderay/scanners/sql.rb')
-rw-r--r-- | lib/coderay/scanners/sql.rb | 159 |
1 files changed, 159 insertions, 0 deletions
diff --git a/lib/coderay/scanners/sql.rb b/lib/coderay/scanners/sql.rb new file mode 100644 index 0000000..9ba0b4d --- /dev/null +++ b/lib/coderay/scanners/sql.rb @@ -0,0 +1,159 @@ +module CodeRay module Scanners + + # by Josh Goebel + class SQL < Scanner + + register_for :sql + + RESERVED_WORDS = %w( + create table index trigger drop primary key set select + insert update delete replace into + on from values before and or if exists case when + then else as group order by avg where + join inner outer union engine not + like end using collate show columns begin + ) + + PREDEFINED_TYPES = %w( + char varchar enum binary text tinytext mediumtext + longtext blob tinyblob mediumblob longblob timestamp + date time datetime year double decimal float int + integer tinyint mediumint bigint smallint unsigned bit + bool boolean hex bin oct + ) + + 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 = / [rbfnrtv\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 + + def scan_tokens tokens, options + + state = :initial + string_type = nil + string_content = '' + + until eos? + + kind = nil + match = nil + + if state == :initial + + if scan(/ \s+ | \\\n /x) + kind = :space + + elsif scan(/^(?:--\s?|#).*/) + kind = :comment + + elsif scan(%r! /\* (?: .*? \*/ | .* ) !mx) + kind = :comment + + elsif scan(/ [-+*\/=<>;,!&^|()\[\]{}~%] | \.(?!\d) /x) + kind = :operator + + elsif scan(/(#{STRING_PREFIXES})?([`"'])/o) + prefix = self[1] + string_type = self[2] + tokens << [:open, :string] + tokens << [prefix, :modifier] if prefix + match = string_type + state = :string + kind = :delimiter + + elsif match = scan(/ @? [A-Za-z_][A-Za-z_0-9]* /x) + kind = match[0] == ?@ ? :variable : IDENT_KIND[match.downcase] + + elsif scan(/0[xX][0-9A-Fa-f]+/) + kind = :hex + + elsif scan(/0[0-7]+(?![89.eEfF])/) + kind = :oct + + elsif scan(/(?>\d+)(?![.eEfF])/) + kind = :integer + + elsif scan(/\d[fF]|\d*\.\d+(?:[eE][+-]?\d+)?|\d+[eE][+-]?\d+/) + kind = :float + + else + getch + kind = :error + + end + + elsif state == :string + if match = scan(/[^\\"'`]+/) + string_content << match + next + elsif match = scan(/["'`]/) + if string_type == match + if peek(1) == string_type # doubling means escape + string_content << string_type << getch + next + end + unless string_content.empty? + tokens << [string_content, :content] + string_content = '' + end + tokens << [matched, :delimiter] + tokens << [:close, :string] + state = :initial + string_type = nil + next + else + string_content << match + end + next + elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox) + unless string_content.empty? + tokens << [string_content, :content] + string_content = '' + end + kind = :char + elsif match = scan(/ \\ . /mox) + string_content << match + next + elsif scan(/ \\ | $ /x) + unless string_content.empty? + tokens << [string_content, :content] + string_content = '' + end + kind = :error + state = :initial + else + raise "else case \" reached; %p not handled." % peek(1), tokens + end + + else + raise 'else-case reached', tokens + + end + + match ||= matched +# raise [match, kind], tokens if kind == :error + + tokens << [match, kind] + + end +# RAILS_DEFAULT_LOGGER.info tokens.inspect + tokens + + end + + end + +end end
\ No newline at end of file |