--- /dev/null
+# http://pastie.textmate.org/50774/\r
+module CodeRay module Scanners\r
+ \r
+ class JavaScript < Scanner\r
+\r
+ register_for :javascript\r
+ \r
+ RESERVED_WORDS = [\r
+ 'asm', 'break', 'case', 'continue', 'default', 'do', 'else',\r
+ 'for', 'goto', 'if', 'return', 'switch', 'while',\r
+# 'struct', 'union', 'enum', 'typedef',\r
+# 'static', 'register', 'auto', 'extern',\r
+# 'sizeof',\r
+ 'typeof',\r
+# 'volatile', 'const', # C89\r
+# 'inline', 'restrict', # C99 \r
+ 'var', 'function','try','new','in',\r
+ 'instanceof','throw','catch'\r
+ ]\r
+\r
+ PREDEFINED_CONSTANTS = [\r
+ 'void', 'null', 'this',\r
+ 'true', 'false','undefined',\r
+ ]\r
+\r
+ IDENT_KIND = WordList.new(:ident).\r
+ add(RESERVED_WORDS, :reserved).\r
+ add(PREDEFINED_CONSTANTS, :pre_constant)\r
+\r
+ ESCAPE = / [rbfnrtv\n\\\/'"] | x[a-fA-F0-9]{1,2} | [0-7]{1,3} /x\r
+ UNICODE_ESCAPE = / u[a-fA-F0-9]{4} | U[a-fA-F0-9]{8} /x\r
+\r
+ def scan_tokens tokens, options\r
+\r
+ state = :initial\r
+ string_type = nil\r
+ regexp_allowed = true\r
+\r
+ until eos?\r
+\r
+ kind = :error\r
+ match = nil\r
+\r
+ if state == :initial\r
+ \r
+ if scan(/ \s+ | \\\n /x)\r
+ kind = :space\r
+ \r
+ elsif scan(%r! // [^\n\\]* (?: \\. [^\n\\]* )* | /\* (?: .*? \*/ | .* ) !mx)\r
+ kind = :comment\r
+ regexp_allowed = false\r
+\r
+ elsif match = scan(/ \# \s* if \s* 0 /x)\r
+ match << scan_until(/ ^\# (?:elif|else|endif) .*? $ | \z /xm) unless eos?\r
+ kind = :comment\r
+ regexp_allowed = false\r
+\r
+ elsif regexp_allowed and scan(/\//)\r
+ tokens << [:open, :regexp]\r
+ state = :regex\r
+ kind = :delimiter\r
+ \r
+ elsif scan(/ [-+*\/=<>?:;,!&^|()\[\]{}~%] | \.(?!\d) /x)\r
+ kind = :operator\r
+ regexp_allowed=true\r
+ \r
+ elsif match = scan(/ [$A-Za-z_][A-Za-z_0-9]* /x)\r
+ kind = IDENT_KIND[match]\r
+# if kind == :ident and check(/:(?!:)/)\r
+# match << scan(/:/)\r
+# kind = :label\r
+# end\r
+ regexp_allowed=false\r
+ \r
+ elsif match = scan(/["']/)\r
+ tokens << [:open, :string]\r
+ string_type = matched\r
+ state = :string\r
+ kind = :delimiter\r
+ \r
+# elsif scan(/#\s*(\w*)/)\r
+# kind = :preprocessor # FIXME multiline preprocs\r
+# state = :include_expected if self[1] == 'include'\r
+# \r
+# elsif scan(/ L?' (?: [^\'\n\\] | \\ #{ESCAPE} )? '? /ox)\r
+# kind = :char\r
+ \r
+ elsif scan(/0[xX][0-9A-Fa-f]+/)\r
+ kind = :hex\r
+ regexp_allowed=false\r
+ \r
+ elsif scan(/(?:0[0-7]+)(?![89.eEfF])/)\r
+ kind = :oct\r
+ regexp_allowed=false\r
+ \r
+ elsif scan(/(?:\d+)(?![.eEfF])/)\r
+ kind = :integer\r
+ regexp_allowed=false\r
+ \r
+ elsif scan(/\d[fF]?|\d*\.\d+(?:[eE][+-]?\d+)?[fF]?|\d+[eE][+-]?\d+[fF]?/)\r
+ kind = :float\r
+ regexp_allowed=false\r
+\r
+ else\r
+ getch\r
+ end\r
+ \r
+ elsif state == :regex\r
+ if scan(/[^\\\/]+/)\r
+ kind = :content\r
+ elsif scan(/\\\/|\\\\/)\r
+ kind = :content\r
+ elsif scan(/\//)\r
+ tokens << [matched, :delimiter]\r
+ tokens << [:close, :regexp]\r
+ state = :initial\r
+ next\r
+ else\r
+ getch\r
+ kind = :content\r
+ end\r
+ \r
+ elsif state == :string\r
+ if scan(/[^\\"']+/)\r
+ kind = :content\r
+ elsif scan(/["']/)\r
+ if string_type==matched\r
+ tokens << [matched, :delimiter]\r
+ tokens << [:close, :string]\r
+ state = :initial\r
+ string_type=nil\r
+ next\r
+ else\r
+ kind = :content\r
+ end\r
+ elsif scan(/ \\ (?: #{ESCAPE} | #{UNICODE_ESCAPE} ) /mox)\r
+ kind = :char\r
+ elsif scan(/ \\ | $ /x)\r
+ kind = :error\r
+ state = :initial\r
+ else\r
+ raise "else case \" reached; %p not handled." % peek(1), tokens\r
+ end\r
+ \r
+# elsif state == :include_expected\r
+# if scan(/<[^>\n]+>?|"[^"\n\\]*(?:\\.[^"\n\\]*)*"?/)\r
+# kind = :include\r
+# state = :initial\r
+# \r
+# elsif match = scan(/\s+/)\r
+# kind = :space\r
+# state = :initial if match.index ?\n\r
+# \r
+# else\r
+# getch\r
+# \r
+# end\r
+# \r
+ else\r
+ raise 'else-case reached', tokens\r
+ \r
+ end\r
+ \r
+ match ||= matched\r
+# raise [match, kind], tokens if kind == :error\r
+ \r
+ tokens << [match, kind]\r
+ \r
+ end\r
+ tokens\r
+ \r
+ end\r
+\r
+ end\r
+\r
+end end
\ No newline at end of file