def self.extended(base)
base.prepend :statements do
rule %r/@"/, base::Str, :string
rule %r/@'(\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|\\.|[^\\'\n]')/,
base::Str::Char
rule %r/@(\d+[.]\d*|[.]\d+|\d+)e[+-]?\d+l?/i,
base::Num::Float
rule %r/@(\d+[.]\d*|[.]\d+|\d+f)f?/i, base::Num::Float
rule %r/@0x\h+[lL]?/, base::Num::Hex
rule %r/@0[0-7]+l?/i, base::Num::Oct
rule %r/@\d+l?/, base::Num::Integer
rule %r/\bin\b/, base::Keyword
rule %r/@(?:interface|implementation)\b/, base::Keyword, :objc_classname
rule %r/@(?:class|protocol)\b/, base::Keyword, :forward_classname
rule %r/@([[:alnum:]]+)/ do |m|
if base.at_keywords.include? m[1]
token base::Keyword
elsif base.at_builtins.include? m[1]
token base::Name::Builtin
else
token base::Error
end
end
rule %r/[?]/, base::Punctuation, :ternary
rule %r/\[/, base::Punctuation, :message
rule %r/@\[/, base::Punctuation, :array_literal
rule %r/@\{/, base::Punctuation, :dictionary_literal
end
id = /[a-z$_][a-z0-9$_]*/i
base.state :ternary do
rule %r/:/, base::Punctuation, :pop!
mixin :statements
end
base.state :message_shared do
rule %r/\]/, base::Punctuation, :pop!
rule %r/\{/, base::Punctuation, :pop!
rule %r/;/, base::Error
mixin :statements
end
base.state :message do
rule %r/(#{id})(\s*)(:)/ do
groups(base::Name::Function, base::Text, base::Punctuation)
goto :message_with_args
end
rule %r/(#{id})(\s*)(\])/ do
groups(base::Name::Function, base::Text, base::Punctuation)
pop!
end
mixin :message_shared
end
base.state :message_with_args do
rule %r/\{/, base::Punctuation, :function
rule %r/(#{id})(\s*)(:)/ do
groups(base::Name::Function, base::Text, base::Punctuation)
pop!
end
mixin :message_shared
end
base.state :array_literal do
rule %r/]/, base::Punctuation, :pop!
rule %r/,/, base::Punctuation
mixin :statements
end
base.state :dictionary_literal do
rule %r/}/, base::Punctuation, :pop!
rule %r/,/, base::Punctuation
mixin :statements
end
base.state :objc_classname do
mixin :whitespace
rule %r/(#{id})(\s*)(:)(\s*)(#{id})/ do
groups(base::Name::Class, base::Text,
base::Punctuation, base::Text,
base::Name::Class)
pop!
end
rule %r/(#{id})(\s*)([(])(\s*)(#{id})(\s*)([)])/ do
groups(base::Name::Class, base::Text,
base::Punctuation, base::Text,
base::Name::Label, base::Text,
base::Punctuation)
pop!
end
rule id, base::Name::Class, :pop!
end
base.state :forward_classname do
mixin :whitespace
rule %r/(#{id})(\s*)(,)(\s*)/ do
groups(base::Name::Class, base::Text, base::Punctuation, base::Text)
push
end
rule %r/(#{id})(\s*)(;?)/ do
groups(base::Name::Class, base::Text, base::Punctuation)
pop!
end
end
base.prepend :root do
rule %r(
([-+])(\s*)
([(].*?[)])?(\s*)
(?=#{id}:?)
)ix do |m|
token base::Keyword, m[1]
token base::Text, m[2]
recurse(m[3]) if m[3]
token base::Text, m[4]
push :method_definition
end
end
base.state :method_definition do
rule %r/,/, base::Punctuation
rule %r/[.][.][.]/, base::Punctuation
rule %r/([(].*?[)])(#{id})/ do |m|
recurse m[1]; token base::Name::Variable, m[2]
end
rule %r/(#{id})(\s*)(:)/m do
groups(base::Name::Function, base::Text, base::Punctuation)
end
rule %r/;/, base::Punctuation, :pop!
rule %r/{/ do
token base::Punctuation
goto :function
end
mixin :inline_whitespace
rule %r(//.*?\n), base::Comment::Single
rule %r/\s+/m, base::Text
rule(//) { pop! }
end
end