Skip to content

Commit

Permalink
Implement an Objective-C++ lexer
Browse files Browse the repository at this point in the history
In addition, factor out the common Objective-C bits into a shared module
  • Loading branch information
saagarjha committed Dec 17, 2019
1 parent 7e04388 commit 714d4ff
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 172 deletions.
175 changes: 3 additions & 172 deletions lib/rouge/lexers/objective_c.rb
Expand Up @@ -4,187 +4,18 @@
module Rouge
module Lexers
load_lexer 'c.rb'
load_lexer 'objective_c/common.rb'

class ObjectiveC < C
include ObjectiveCCommon

tag 'objective_c'
title "Objective-C"
desc 'an extension of C commonly used to write Apple software'
aliases 'objc', 'obj-c', 'obj_c', 'objectivec'
filenames '*.m', '*.h'

mimetypes 'text/x-objective_c', 'application/x-objective_c'

def self.at_keywords
@at_keywords ||= %w(
selector private protected public encode synchronized try
throw catch finally end property synthesize dynamic optional
interface implementation import
)
end

def self.at_builtins
@at_builtins ||= %w(true false YES NO)
end

def self.builtins
@builtins ||= %w(YES NO nil)
end

id = /[a-z$_][a-z0-9$_]*/i

prepend :statements do
rule %r/@"/, Str, :string
rule %r/@'(\\[0-7]{1,3}|\\x[a-fA-F0-9]{1,2}|\\.|[^\\'\n]')/,
Str::Char
rule %r/@(\d+[.]\d*|[.]\d+|\d+)e[+-]?\d+l?/i,
Num::Float
rule %r/@(\d+[.]\d*|[.]\d+|\d+f)f?/i, Num::Float
rule %r/@0x\h+[lL]?/, Num::Hex
rule %r/@0[0-7]+l?/i, Num::Oct
rule %r/@\d+l?/, Num::Integer
rule %r/\bin\b/, Keyword

rule %r/@(?:interface|implementation)\b/, Keyword, :classname
rule %r/@(?:class|protocol)\b/, Keyword, :forward_classname

rule %r/@([[:alnum:]]+)/ do |m|
if self.class.at_keywords.include? m[1]
token Keyword
elsif self.class.at_builtins.include? m[1]
token Name::Builtin
else
token Error
end
end

rule %r/[?]/, Punctuation, :ternary
rule %r/\[/, Punctuation, :message
rule %r/@\[/, Punctuation, :array_literal
rule %r/@\{/, Punctuation, :dictionary_literal
end

state :ternary do
rule %r/:/, Punctuation, :pop!
mixin :statements
end

state :message_shared do
rule %r/\]/, Punctuation, :pop!
rule %r/\{/, Punctuation, :pop!
rule %r/;/, Error

mixin :statements
end

state :message do
rule %r/(#{id})(\s*)(:)/ do
groups(Name::Function, Text, Punctuation)
goto :message_with_args
end

rule %r/(#{id})(\s*)(\])/ do
groups(Name::Function, Text, Punctuation)
pop!
end

mixin :message_shared
end

state :message_with_args do
rule %r/\{/, Punctuation, :function
rule %r/(#{id})(\s*)(:)/ do
groups(Name::Function, Text, Punctuation)
pop!
end

mixin :message_shared
end

state :array_literal do
rule %r/]/, Punctuation, :pop!
rule %r/,/, Punctuation
mixin :statements
end

state :dictionary_literal do
rule %r/}/, Punctuation, :pop!
rule %r/,/, Punctuation
mixin :statements
end

state :classname do
mixin :whitespace

rule %r/(#{id})(\s*)(:)(\s*)(#{id})/ do
groups(Name::Class, Text,
Punctuation, Text,
Name::Class)
pop!
end

rule %r/(#{id})(\s*)([(])(\s*)(#{id})(\s*)([)])/ do
groups(Name::Class, Text,
Punctuation, Text,
Name::Label, Text,
Punctuation)
pop!
end

rule id, Name::Class, :pop!
end

state :forward_classname do
mixin :whitespace

rule %r/(#{id})(\s*)(,)(\s*)/ do
groups(Name::Class, Text, Punctuation, Text)
push
end

rule %r/(#{id})(\s*)(;?)/ do
groups(Name::Class, Text, Punctuation)
pop!
end
end

prepend :root do
rule %r(
([-+])(\s*)
([(].*?[)])?(\s*)
(?=#{id}:?)
)ix do |m|
token Keyword, m[1]
token Text, m[2]
recurse(m[3]) if m[3]
token Text, m[4]
push :method_definition
end
end

state :method_definition do
rule %r/,/, Punctuation
rule %r/[.][.][.]/, Punctuation
rule %r/([(].*?[)])(#{id})/ do |m|
recurse m[1]; token Name::Variable, m[2]
end

rule %r/(#{id})(\s*)(:)/m do
groups(Name::Function, Text, Punctuation)
end

rule %r/;/, Punctuation, :pop!

rule %r/{/ do
token Punctuation
goto :function
end

mixin :inline_whitespace
rule %r(//.*?\n), Comment::Single
rule %r/\s+/m, Text

rule(//) { pop! }
end
end
end
end
184 changes: 184 additions & 0 deletions lib/rouge/lexers/objective_c/common.rb
@@ -0,0 +1,184 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
module ObjectiveCCommon
def self.at_keywords
@at_keywords ||= %w(
selector private protected public encode synchronized try
throw catch finally end property synthesize dynamic optional
interface implementation import
)
end

def self.at_builtins
@at_builtins ||= %w(true false YES NO)
end

def self.builtins
@builtins ||= %w(YES NO nil)
end

id = /[a-z$_][a-z0-9$_]*/i

def self.included(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, :classname
rule %r/@(?:class|protocol)\b/, base::Keyword, :forward_classname

rule %r/@([[:alnum:]]+)/ do |m|
if ObjectiveCCommon::at_keywords.include? m[1]
token base::Keyword
elsif ObjectiveCCommon::at_builtins.include? m[1]
token base::Name::Builtin
else
token 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 :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
end
end
end
22 changes: 22 additions & 0 deletions lib/rouge/lexers/objective_cpp.rb
@@ -0,0 +1,22 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
load_lexer 'cpp.rb'
load_lexer 'objective_c/common.rb'

class ObjectiveCpp < Cpp
include ObjectiveCCommon

tag 'objective_cpp'
title "Objective-C++"
desc 'an extension of C++ uncommonly used to write Apple software'
aliases 'objcpp', 'obj-cpp', 'obj_cpp', 'objectivecpp',
'objc++', 'obj-c++', 'obj_c++', 'objectivec++'
filenames '*.mm', '*.h'

mimetypes 'text/x-objective-c++', 'application/x-objective-c'
end
end
end

0 comments on commit 714d4ff

Please sign in to comment.