# -*- coding: utf-8 -*- #
# frozen_string_literal: true
module Rouge
module Lexers
class Idris < RegexLexer
title "Idris"
desc "The Idris programming language (idris-lang.org)"
tag 'idris'
aliases 'idr'
filenames '*.idr'
mimetypes 'text/x-idris'
def self.reserved_keywords
@reserved_keywords ||= %w(
_ data class instance namespace
infix[lr]? let where of with type
do if then else case in
)
end
def self.ascii
@ascii ||= %w(
NUL SOH [SE]TX EOT ENQ ACK BEL BS HT LF VT FF CR S[OI] DLE
DC[1-4] NAK SYN ETB CAN EM SUB ESC [FGRU]S SP DEL
)
end
def self.prelude_functions
@prelude_functions ||= %w(
abs acos all and any asin atan atan2 break ceiling compare concat
concatMap const cos cosh curry cycle div drop dropWhile elem
encodeFloat enumFrom enumFromThen enumFromThenTo enumFromTo exp
fail filter flip floor foldl foldl1 foldr foldr1 fromInteger fst
gcd getChar getLine head id init iterate last lcm length lines log
lookup map max maxBound maximum maybe min minBound minimum mod
negate not null or pi pred print product putChar putStr putStrLn
readFile recip repeat replicate return reverse scanl scanl1 sequence
sequence_ show sin sinh snd span splitAt sqrt succ sum tail take
takeWhile tan tanh uncurry unlines unwords unzip unzip3 words
writeFile zip zip3 zipWith zipWith3
)
end
state :basic do
rule %r/\s+/m, Text
rule %r/{-#/, Comment::Preproc, :comment_preproc
rule %r/{-/, Comment::Multiline, :comment
rule %r/^\|\|\|.*$/, Comment::Doc
rule %r/--(?![!#\$\%&*+.\/<=>?@\^\|_~]).*?$/, Comment::Single
end
# nested commenting
state :comment do
rule %r/-}/, Comment::Multiline, :pop!
rule %r/{-/, Comment::Multiline, :comment
rule %r/[^-{}]+/, Comment::Multiline
rule %r/[-{}]/, Comment::Multiline
end
state :comment_preproc do
rule %r/-}/, Comment::Preproc, :pop!
rule %r/{-/, Comment::Preproc, :comment
rule %r/[^-{}]+/, Comment::Preproc
rule %r/[-{}]/, Comment::Preproc
end
state :directive do
rule %r/\%(default)\s+(total|partial)/, Keyword # totality
rule %r/\%(access)\s+(public|abstract|private|export)/, Keyword # export
rule %r/\%(language)\s+(.*)/, Keyword # language
rule %r/\%(provide)\s+.*\s+(with)\s+/, Keyword # type
end
state :prelude do
rule %r/\b(Type|Exists|World|IO|IntTy|FTy|File|Mode|Dec|Bool|Ordering|Either|IsJust|List|Maybe|Nat|Stream|StrM|Not|Lazy|Inf)\s/, Keyword::Type
rule %r/\b(Eq|Ord|Num|MinBound|MaxBound|Integral|Applicative|Alternative|Cast|Foldable|Functor|Monad|Traversable|Uninhabited|Semigroup|Monoid)\s/, Name::Class
rule %r/\b(?:#{Idris.prelude_functions.join('|')})[ ]+(?![=:-])/, Name::Builtin
end
state :root do
mixin :basic
mixin :directive
rule %r/\bimport\b/, Keyword::Reserved, :import
rule %r/\bmodule\b/, Keyword::Reserved, :module
rule %r/\b(?:#{Idris.reserved_keywords.join('|')})\b/, Keyword::Reserved
rule %r/\b(Just|Nothing|Left|Right|True|False|LT|LTE|EQ|GT|GTE)\b/, Keyword::Constant
# function signature
rule %r/^[\w']+\s*:/, Name::Function
# should be below as you can override names defined in Prelude
mixin :prelude
rule %r/[_a-z][\w']*/, Name
rule %r/[A-Z][\w']*/, Keyword::Type
# lambda operator
rule %r(\\(?![:!#\$\%&*+.\\/<=>?@^\|~-]+)), Name::Function
# special operators
rule %r((<-|::|->|=>|=)(?![:!#\$\%&*+.\\/<=>?@^\|~-]+)), Operator
# constructor/type operators
rule %r(:[:!#\$\%&*+.\\/<=>?@^\|~-]*), Operator
# other operators
rule %r([:!#\$\%&*+.\\/<=>?@^\|~-]+), Operator
rule %r/\d+(\.\d+)?(e[+-]?\d+)?/i, Num::Float
rule %r/0o[0-7]+/i, Num::Oct
rule %r/0x[\da-f]+/i, Num::Hex
rule %r/\d+/, Num::Integer
rule %r/'/, Str::Char, :character
rule %r/"/, Str, :string
rule %r/\[\s*\]/, Keyword::Type
rule %r/\(\s*\)/, Name::Builtin
# Quasiquotations
rule %r/(\[)([_a-z][\w']*)(\|)/ do |m|
token Operator, m[1]
token Name, m[2]
token Operator, m[3]
push :quasiquotation
end
rule %r/[\[\](),;`{}]/, Punctuation
end
state :import do
rule %r/\s+/, Text
rule %r/"/, Str, :string
# import X as Y
rule %r/([A-Z][\w.]*)(\s+)(as)(\s+)([A-Z][a-zA-Z0-9_.]*)/ do
groups(
Name::Namespace, # X
Text, Keyword, # as
Text, Name # Y
)
pop!
end
# import X (functions)
rule %r/([A-Z][\w.]*)(\s+)(\()/ do
groups(
Name::Namespace, # X
Text,
Punctuation # (
)
goto :funclist
end
rule %r/[\w.]+/, Name::Namespace, :pop!
end
state :module do
rule %r/\s+/, Text
# module X
rule %r/([A-Z][\w.]*)/, Name::Namespace, :pop!
end
state :funclist do
mixin :basic
rule %r/[A-Z]\w*/, Keyword::Type
rule %r/(_[\w\']+|[a-z][\w\']*)/, Name::Function
rule %r/,/, Punctuation
rule %r/[:!#\$\%&*+.\\\/<=>?@^\|~-]+/, Operator
rule %r/\(/, Punctuation, :funclist
rule %r/\)/, Punctuation, :pop!
end
state :character do
rule %r/\\/ do
token Str::Escape
goto :character_end
push :escape
end
rule %r/./ do
token Str::Char
goto :character_end
end
end
state :character_end do
rule %r/'/, Str::Char, :pop!
rule %r/./, Error, :pop!
end
state :quasiquotation do
rule %r/\|\]/, Operator, :pop!
rule %r/[^\|]+/m, Text
rule %r/\|/, Text
end
state :string do
rule %r/"/, Str, :pop!
rule %r/\\/, Str::Escape, :escape
rule %r/[^\\"]+/, Str
end
state :escape do
rule %r/[abfnrtv"'&\\]/, Str::Escape, :pop!
rule %r/\^[\]\[A-Z@\^_]/, Str::Escape, :pop!
rule %r/#{Idris.ascii.join('|')}/, Str::Escape, :pop!
rule %r/o[0-7]+/i, Str::Escape, :pop!
rule %r/x[\da-fA-F]+/i, Str::Escape, :pop!
rule %r/\d+/, Str::Escape, :pop!
rule %r/\s+\\/, Str::Escape, :pop!
end
end
end
end