summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/coderay/scanners/tcl.rb137
1 files changed, 137 insertions, 0 deletions
diff --git a/lib/coderay/scanners/tcl.rb b/lib/coderay/scanners/tcl.rb
new file mode 100644
index 0000000..7ae6d7c
--- /dev/null
+++ b/lib/coderay/scanners/tcl.rb
@@ -0,0 +1,137 @@
+module CodeRay
+ module Scanners
+
+ # by Eric Thomas
+ class Tcl < Scanner
+
+ register_for :tcl
+
+ # Taken from http://www.xilinx.com/itp/xilinx10/isehelp/ite_r_tcl_reserved_words.htm
+ RESERVED_WORDS = %w(after append array auto_execok auto_import auto_load
+ auto_load_index auto_qualify binary bgerrro break
+ catch cd clock close concat continue dde default
+ else elseif encoding eof error eval exec exit expr
+ fblocked fconfigure fcopy file fileevent flush for
+ foreach format gets glob global history if incr
+ interp join lappend lindex list llength load lrange
+ lrange lreplace lsearch lsort namespace open package
+ pid pkg_mkIndex proc puts pwd read regexp regsub
+ rename resource return scan seek set socket source
+ split string subst switch tclLog tell time trace
+ unknown unset update uplevel upvar vwait while)
+
+ PREDEFINED_TYPES = %w(variable)
+
+ # should we include 0 or 1?
+ PREDEFINED_CONSTANTS = %w(true false yes no on off 1 0)
+
+ IDENT_KIND = WordList.new(:ident).
+ add(RESERVED_WORDS, :reserved).
+ add(PREDEFINED_TYPES, :pre_type).
+ add(PREDEFINED_CONSTANTS, :pre_constant)
+
+ ESCAPE = / [rbfntv\n\\'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x
+
+ def scan_tokens tokens, options
+ state = :initial
+
+ until eos?
+ kind = nil
+ match = nil
+
+ case state
+ when :initial
+
+ if scan(/ \s+ | \\\n /x)
+ kind = :space
+
+ elsif scan(/#.*/)
+ kind = :comment
+
+ elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%]+ | \.(?!\d) /x)
+ kind = :operator
+
+ elsif scan(/\$\S+/)
+ kind = :variable
+
+ elsif match = scan(/ [A-Za-z_][A-Za-z_0-9]* /x)
+ kind = IDENT_KIND[match]
+ if kind == :ident and check(/:(?!:)/)
+ match << scan(/:/)
+ kind = :label
+ end
+
+ elsif match = scan(/L?"/)
+ tokens << [:open, :string]
+ if match[0] == ?L
+ tokens << ['L', :modifier]
+ match = '"'
+ end
+ state = :string
+ kind = :delimiter
+
+ elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox)
+ kind = :char
+
+ 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+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)
+ kind = :float
+
+ else
+ getch
+ kind = :error
+
+ end
+
+ when :string
+ if scan(/[^\\\n"]+/)
+ kind = :content
+ elsif scan(/"/)
+ tokens << ['"', :delimiter]
+ tokens << [:close, :string]
+ state = :initial
+ next
+ elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)
+ kind = :char
+ elsif scan(/ \\ | $ /x)
+ tokens << [:close, :string]
+ kind = :error
+ state = :initial
+ else
+ raise_inspect "else case \" reached; %p not handled." % peek(1), tokens
+ end
+
+ else
+ raise_inspect 'Unknown state', tokens
+
+ end
+
+ match ||= matched
+ if $DEBUG and not kind
+ raise_inspect 'Error token %p in line %d' %
+ [[match, kind], line], tokens
+ end
+ raise_inspect 'Empty token', tokens unless match
+
+ tokens << [match, kind]
+
+ end
+
+ if state == :string
+ tokens << [:close, :string]
+ end
+
+ tokens
+ end
+ end
+ end
+end