1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
|
# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
# Direct port of pygments Lexer.
# See: https://bitbucket.org/birkenfeld/pygments-main/src/7304e4759ae65343d89a51359ca538912519cc31/pygments/lexers/functional.py?at=default#cl-2362
class Elixir < RegexLexer
title "Elixir"
desc "Elixir language (elixir-lang.org)"
tag 'elixir'
aliases 'elixir', 'exs'
filenames '*.ex', '*.exs'
def self.detect?(text)
return true if text.shebang?('elixir')
end
mimetypes 'text/x-elixir', 'application/x-elixir'
state :root do
rule %r/\s+/m, Text
rule %r/#.*$/, Comment::Single
rule %r{\b(case|cond|end|bc|lc|if|unless|try|loop|receive|fn|defmodule|
defp?|defprotocol|defimpl|defrecord|defmacrop?|defdelegate|
defexception|defguardp?|defstruct|exit|raise|throw|after|rescue|catch|else)\b(?![?!])|
(?<!\.)\b(do|\-\>)\b}x, Keyword
rule %r/\b(import|require|use|recur|quote|unquote|super|refer)\b(?![?!])/, Keyword::Namespace
rule %r/(?<!\.)\b(and|not|or|when|xor|in)\b/, Operator::Word
rule %r{%=|\*=|\*\*=|\+=|\-=|\^=|\|\|=|
<=>|<(?!<|=)|>(?!<|=|>)|<=|>=|===|==|=~|!=|!~|(?=[\s])\?|
(?<=[\s])!+|&(&&?|(?!\d))|\|\||\^|\*|\+|\-|/|
\||\+\+|\-\-|\*\*|\/\/|\<\-|\<\>|<<|>>|=|\.|~~~}x, Operator
rule %r{(?<!:)(:)([a-zA-Z_]\w*([?!]|=(?![>=]))?|\<\>|===?|>=?|<=?|
<=>|&&?|%\(\)|%\[\]|%\{\}|\+\+?|\-\-?|\|\|?|\!|//|[%&`/\|]|
\*\*?|=?~|<\-)|([a-zA-Z_]\w*([?!])?)(:)(?!:)}, Str::Symbol
rule %r/:"/, Str::Symbol, :interpoling_symbol
rule %r/\b(nil|true|false)\b(?![?!])|\b[A-Z]\w*\b/, Name::Constant
rule %r/\b(__(FILE|LINE|MODULE|MAIN|FUNCTION)__)\b(?![?!])/, Name::Builtin::Pseudo
rule %r/[a-zA-Z_!]\w*[!\?]?/, Name
rule %r{::|[%(){};,/\|:\\\[\]]}, Punctuation
rule %r/@[a-zA-Z_]\w*|&\d/, Name::Variable
rule %r{\b\d(_?\d)*(\.(?![^\d\s])(_?\d)+)([eE][-+]?\d(_?\d)*)?\b}, Num::Float
rule %r{\b0x[0-9A-Fa-f](_?[0-9A-Fa-f])*\b}, Num::Hex
rule %r{\b0o[0-7](_?[0-7])*\b}, Num::Oct
rule %r{\b0b[01](_?[01])*\b}, Num::Bin
rule %r{\b\d(_?\d)*\b}, Num::Integer
mixin :strings
mixin :sigil_strings
end
state :strings do
rule %r/(%[A-Ba-z])?"""(?:.|\n)*?"""/, Str::Doc
rule %r/'''(?:.|\n)*?'''/, Str::Doc
rule %r/"/, Str::Double, :dqs
rule %r/'/, Str::Single, :sqs
rule %r{(?<!\w)\?(\\(x\d{1,2}|\h{1,2}(?!\h)\b|0[0-7]{0,2}(?![0-7])\b[^x0MC])|(\\[MC]-)+\w|[^\s\\])}, Str::Other
end
state :dqs do
mixin :escapes
mixin :interpoling
rule %r/[^#"\\]+/, Str::Double
rule %r/"/, Str::Double, :pop!
rule %r/[#\\]/, Str::Double
end
state :sqs do
mixin :escapes
mixin :interpoling
rule %r/[^#'\\]+/, Str::Single
rule %r/'/, Str::Single, :pop!
rule %r/[#\\]/, Str::Single
end
state :interpoling do
rule %r/#\{/, Str::Interpol, :interpoling_string
end
state :interpoling_string do
rule %r/\}/, Str::Interpol, :pop!
mixin :root
end
state :escapes do
rule %r/\\x\h{2}/, Str::Escape
rule %r/\\u\{?\d+\}?/, Str::Escape
rule %r/\\[\\abdefnrstv0"']/, Str::Escape
end
state :interpoling_symbol do
rule %r/"/, Str::Symbol, :pop!
mixin :interpoling
rule %r/[^#"]+/, Str::Symbol
end
state :sigil_strings do
# ~-sigiled strings
# ~(abc), ~[abc], ~<abc>, ~|abc|, ~r/abc/, etc
# Cribbed and adjusted from Ruby lexer
delimiter_map = { '{' => '}', '[' => ']', '(' => ')', '<' => '>' }
# Match a-z for custom sigils too
sigil_opens = Regexp.union(delimiter_map.keys + %w(| / ' "))
rule %r/~([A-Za-z])?(#{sigil_opens})/ do |m|
open = Regexp.escape(m[2])
close = Regexp.escape(delimiter_map[m[2]] || m[2])
interp = /[SRCW]/ === m[1]
toktype = Str::Other
puts " open: #{open.inspect}" if @debug
puts " close: #{close.inspect}" if @debug
# regexes
if 'Rr'.include? m[1]
toktype = Str::Regex
push :regex_flags
end
if 'Ww'.include? m[1]
push :list_flags
end
token toktype
push do
rule %r/#{close}/, toktype, :pop!
if interp
mixin :interpoling
rule %r/#/, toktype
else
rule %r/[\\#]/, toktype
end
uniq_chars = [open, close].uniq.join
rule %r/[^##{uniq_chars}\\]+/m, toktype
end
end
end
state :regex_flags do
rule %r/[fgimrsux]*/, Str::Regex, :pop!
end
state :list_flags do
rule %r/[csa]?/, Str::Other, :pop!
end
end
end
end
|