Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement an Objective-C++ lexer #1378

Merged
merged 3 commits into from
Jan 8, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions lib/rouge/demos/objective_cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
@import Foundation;
#import <array>
#include <vector>

@interface IntegerArray : NSObject {
std::vector<NSUInteger> _numbers;
}
@property(readonly) NSUInteger count;

- (instancetype)initWithNumbers:(NSUInteger *)numbers count:(NSUInteger)count;
- (NSUInteger)numberAtIndex:(NSUInteger)index;
@end

int main(int argc, char **argv) {
auto numbers = std::array<NSUInteger, 3>{1, 2, 3};
NSLog(@"%@", [[IntegerArray alloc] initWithNumbers:numbers.data() count:numbers.size()]);
}
175 changes: 3 additions & 172 deletions lib/rouge/lexers/objective_c.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,187 +4,18 @@
module Rouge
module Lexers
load_lexer 'c.rb'
load_lexer 'objective_c/common.rb'

class ObjectiveC < C
extend 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
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
# -*- coding: utf-8 -*- #
# frozen_string_literal: true

module Rouge
module Lexers
module ObjectiveCCommon
id = /[a-z$_][a-z0-9$_]*/i

def 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 at_builtins
@at_builtins ||= %w(true false YES NO)
end

def builtins
@builtins ||= %w(YES NO nil)
pyrmont marked this conversation as resolved.
Show resolved Hide resolved
end

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 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
end
end
end
Loading