| # -*- coding: utf-8 -*- # |
| |
| module Rouge |
| module Lexers |
| class Coffeescript < RegexLexer |
| tag 'coffeescript' |
| aliases 'coffee', 'coffee-script' |
| filenames '*.coffee', 'Cakefile' |
| mimetypes 'text/coffeescript' |
| |
| title "CoffeeScript" |
| desc 'The Coffeescript programming language (coffeescript.org)' |
| |
| def self.analyze_text(text) |
| return 1 if text.shebang? 'coffee' |
| end |
| |
| def self.keywords |
| @keywords ||= Set.new %w( |
| for in of while break return continue switch when then if else |
| throw try catch finally new delete typeof instanceof super |
| extends this class by |
| ) |
| end |
| |
| def self.constants |
| @constants ||= Set.new %w( |
| true false yes no on off null NaN Infinity undefined |
| ) |
| end |
| |
| def self.builtins |
| @builtins ||= Set.new %w( |
| Array Boolean Date Error Function Math netscape Number Object |
| Packages RegExp String sun decodeURI decodeURIComponent |
| encodeURI encodeURIComponent eval isFinite isNaN parseFloat |
| parseInt document window |
| ) |
| end |
| |
| id = /[$a-zA-Z_][a-zA-Z0-9_]*/ |
| |
| state :comments_and_whitespace do |
| rule /\s+/m, Text |
| rule /###.*?###/m, Comment::Multiline |
| rule /#.*$/, Comment::Single |
| end |
| |
| state :multiline_regex do |
| # this order is important, so that #{ isn't interpreted |
| # as a comment |
| mixin :has_interpolation |
| mixin :comments_and_whitespace |
| |
| rule %r(///([gim]+\b|\B)), Str::Regex, :pop! |
| rule %r(/), Str::Regex |
| rule %r([^/#]+), Str::Regex |
| end |
| |
| state :slash_starts_regex do |
| mixin :comments_and_whitespace |
| rule %r(///) do |
| token Str::Regex |
| goto :multiline_regex |
| end |
| |
| rule %r( |
| /(\\.|[^\[/\\\n]|\[(\\.|[^\]\\\n])*\])+/ # a regex |
| ([gim]+\b|\B) |
| )x, Str::Regex, :pop! |
| |
| rule(//) { pop! } |
| end |
| |
| state :root do |
| rule(%r(^(?=\s|/|<!--))) { push :slash_starts_regex } |
| mixin :comments_and_whitespace |
| rule %r( |
| [+][+]|--|~|&&|\band\b|\bor\b|\bis\b|\bisnt\b|\bnot\b|[?]|:|=| |
| [|][|]|\\(?=\n)|(<<|>>>?|==?|!=?|[-<>+*`%&|^/])=? |
| )x, Operator, :slash_starts_regex |
| |
| rule /[-=]>/, Name::Function |
| |
| rule /(@)([ \t]*)(#{id})/ do |
| groups Name::Variable::Instance, Text, Name::Attribute |
| push :slash_starts_regex |
| end |
| |
| rule /([.])([ \t]*)(#{id})/ do |
| groups Punctuation, Text, Name::Attribute |
| push :slash_starts_regex |
| end |
| |
| rule /#{id}(?=\s*:)/, Name::Attribute, :slash_starts_regex |
| |
| rule /#{id}/ do |m| |
| if self.class.keywords.include? m[0] |
| token Keyword |
| elsif self.class.constants.include? m[0] |
| token Name::Constant |
| elsif self.class.builtins.include? m[0] |
| token Name::Builtin |
| else |
| token Name::Other |
| end |
| |
| push :slash_starts_regex |
| end |
| |
| rule /[{(\[;,]/, Punctuation, :slash_starts_regex |
| rule /[})\].]/, Punctuation |
| |
| rule /\d+[.]\d+([eE]\d+)?[fd]?/, Num::Float |
| rule /0x[0-9a-fA-F]+/, Num::Hex |
| rule /\d+/, Num::Integer |
| rule /"""/, Str, :tdqs |
| rule /'''/, Str, :tsqs |
| rule /"/, Str, :dqs |
| rule /'/, Str, :sqs |
| end |
| |
| state :strings do |
| # all coffeescript strings are multi-line |
| rule /[^#\\'"]+/m, Str |
| |
| rule /\\./, Str::Escape |
| rule /#/, Str |
| end |
| |
| state :double_strings do |
| rule /'/, Str |
| mixin :has_interpolation |
| mixin :strings |
| end |
| |
| state :single_strings do |
| rule /"/, Str |
| mixin :strings |
| end |
| |
| state :interpolation do |
| rule /}/, Str::Interpol, :pop! |
| mixin :root |
| end |
| |
| state :has_interpolation do |
| rule /[#][{]/, Str::Interpol, :interpolation |
| end |
| |
| state :dqs do |
| rule /"/, Str, :pop! |
| mixin :double_strings |
| end |
| |
| state :tdqs do |
| rule /"""/, Str, :pop! |
| rule /"/, Str |
| mixin :double_strings |
| end |
| |
| state :sqs do |
| rule /'/, Str, :pop! |
| mixin :single_strings |
| end |
| |
| state :tsqs do |
| rule /'''/, Str, :pop! |
| rule /'/, Str |
| mixin :single_strings |
| end |
| end |
| end |
| end |