blob: 6bc5b94991765fd96f3ef37c5d3de9f9e601f8bf [file] [log] [blame]
# -*- coding: utf-8 -*- #
module Rouge
module Lexers
class Swift < RegexLexer
tag 'swift'
filenames '*.swift'
title "Swift"
desc 'Multi paradigm, compiled programming language developed by Apple for iOS and OS X development. (developer.apple.com/swift)'
id_head = /_|(?!\p{Mc})\p{Alpha}|[^\u0000-\uFFFF]/
id_rest = /[\p{Alnum}_]|[^\u0000-\uFFFF]/
id = /#{id_head}#{id_rest}*/
keywords = Set.new %w(
break case continue default do else fallthrough if in for return switch where while try catch throw guard defer repeat
as dynamicType is new super self Self Type __COLUMN__ __FILE__ __FUNCTION__ __LINE__
associativity didSet get infix inout left mutating none nonmutating operator override postfix precedence prefix right set unowned weak willSet throws rethrows associatedtype
)
declarations = Set.new %w(
class deinit enum extension final func import init internal lazy let optional private protocol public required static struct subscript typealias var dynamic indirect associatedtype
)
constants = Set.new %w(
true false nil
)
start { push :bol }
# beginning of line
state :bol do
rule /#.*/, Comment::Preproc
mixin :inline_whitespace
rule(//) { pop! }
end
state :inline_whitespace do
rule /\s+/m, Text
mixin :has_comments
end
state :whitespace do
rule /\n+/m, Text, :bol
rule %r(\/\/.*?$), Comment::Single, :bol
mixin :inline_whitespace
end
state :has_comments do
rule %r(/[*]), Comment::Multiline, :nested_comment
end
state :nested_comment do
mixin :has_comments
rule %r([*]/), Comment::Multiline, :pop!
rule %r([^*/]+)m, Comment::Multiline
rule /./, Comment::Multiline
end
state :root do
mixin :whitespace
rule /\$(([1-9]\d*)?\d)/, Name::Variable
rule %r{[()\[\]{}:;,?]}, Punctuation
rule %r([-/=+*%<>!&|^.~]+), Operator
rule /@?"/, Str, :dq
rule /'(\\.|.)'/, Str::Char
rule /(\d+\*|\d*\.\d+)(e[+-]?[0-9]+)?/i, Num::Float
rule /\d+e[+-]?[0-9]+/i, Num::Float
rule /0_?[0-7]+(?:_[0-7]+)*/, Num::Oct
rule /0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*/, Num::Hex
rule /0b[01]+(?:_[01]+)*/, Num::Bin
rule %r{[\d]+(?:_\d+)*}, Num::Integer
rule /@#{id}(\([^)]+\))?/, Keyword::Declaration
rule /(private|internal)(\([ ]*)(\w+)([ ]*\))/ do |m|
if m[3] == 'set'
token Keyword::Declaration
else
groups Keyword::Declaration, Keyword::Declaration, Error, Keyword::Declaration
end
end
rule /(unowned\([ ]*)(\w+)([ ]*\))/ do |m|
if m[2] == 'safe' || m[2] == 'unsafe'
token Keyword::Declaration
else
groups Keyword::Declaration, Error, Keyword::Declaration
end
end
rule /#available\([^)]+\)/, Keyword::Declaration
rule /(#selector\()([^)]+?(?:[(].*?[)])?)(\))/ do
groups Keyword::Declaration, Name::Function, Keyword::Declaration
end
rule /(let|var)\b(\s*)(#{id})/ do
groups Keyword, Text, Name::Variable
end
rule /(?!\b(if|while|for|private|internal|unowned|switch|case)\b)\b#{id}(?=(\?|!)?\s*[(])/ do |m|
if m[0] =~ /^[[:upper:]]/
token Keyword::Type
else
token Name::Function
end
end
rule /as[?!]?(?=\s)/, Keyword
rule /try[!]?(?=\s)/, Keyword
rule /(#?(?!default)(?![[:upper:]])#{id})(\s*)(:)/ do
groups Name::Variable, Text, Punctuation
end
rule id do |m|
if keywords.include? m[0]
token Keyword
elsif declarations.include? m[0]
token Keyword::Declaration
elsif constants.include? m[0]
token Keyword::Constant
elsif m[0] =~ /^[[:upper:]]/
token Keyword::Type
else
token Name
end
end
end
state :dq do
rule /\\[\\0tnr'"]/, Str::Escape
rule /\\[(]/, Str::Escape, :interp
rule /\\u\{\h{1,8}\}/, Str::Escape
rule /[^\\"]+/, Str
rule /"/, Str, :pop!
end
state :interp do
rule /[(]/, Punctuation, :interp_inner
rule /[)]/, Str::Escape, :pop!
mixin :root
end
state :interp_inner do
rule /[(]/, Punctuation, :push
rule /[)]/, Punctuation, :pop!
mixin :root
end
end
end
end