lib/rouge/lexers/r.rb in rouge-1.10.1 vs lib/rouge/lexers/r.rb in rouge-1.11.0

- old
+ new

@@ -5,52 +5,85 @@ class R < RegexLexer title "R" desc 'The R statistics language (r-project.org)' tag 'r' aliases 'r', 'R', 's', 'S' - filenames '*.R', '.Rhistory', '.Rprofile' + filenames '*.R', '*.r', '.Rhistory', '.Rprofile' mimetypes 'text/x-r-source', 'text/x-r', 'text/x-R' mimetypes 'text/x-r', 'application/x-r' - def self.keywords - @keywords ||= %w( - if else for while repeat in next break return switch function - ) - end + KEYWORDS = %w(if else for while repeat in next break function) + KEYWORD_CONSTANTS = %w( + NULL Inf TRUE FALSE NaN NA + NA_integer_ NA_real_ NA_complex_ NA_character_ + ) + + BUILTIN_CONSTANTS = %w(LETTERS letters month.abb month.name pi T F) + + # These are all the functions in `base` that are implemented as a + # `.Primitive`, minus those functions that are also keywords. + PRIMITIVE_FUNCTIONS = %w( + abs acos acosh all any anyNA Arg as.call as.character + as.complex as.double as.environment as.integer as.logical + as.null.default as.numeric as.raw asin asinh atan atanh attr + attributes baseenv browser c call ceiling class Conj cos cosh + cospi cummax cummin cumprod cumsum digamma dim dimnames + emptyenv exp expression floor forceAndCall gamma gc.time + globalenv Im interactive invisible is.array is.atomic is.call + is.character is.complex is.double is.environment is.expression + is.finite is.function is.infinite is.integer is.language + is.list is.logical is.matrix is.na is.name is.nan is.null + is.numeric is.object is.pairlist is.raw is.recursive is.single + is.symbol lazyLoadDBfetch length lgamma list log max min + missing Mod names nargs nzchar oldClass on.exit pos.to.env + proc.time prod quote range Re rep retracemem return round + seq_along seq_len seq.int sign signif sin sinh sinpi sqrt + standardGeneric substitute sum switch tan tanh tanpi tracemem + trigamma trunc unclass untracemem UseMethod xtfrm + ) + def self.analyze_text(text) return 1 if text.shebang? 'Rscript' end state :root do + rule /#'.*?\n/, Comment::Doc rule /#.*?\n/, Comment::Single - rule /\s+/m, Text - rule /[.]?[a-zA-Z_][\w.]*/ do |m| - if self.class.keywords.include? m[0] - token Keyword - else - token Name - end - end + rule /\s+/m, Text::Whitespace - rule /`.*?`/, Str::Backtick + rule /`[^`]+?`/, Name rule /'(\\.|.)*?'/m, Str::Single rule /"(\\.|.)*?"/m, Str::Double - rule /\b(NULL|Inf|TRUE|FALSE|NaN)\b/, Keyword::Constant - rule /\bNA(_(integer|real|complex|character)_)?\b/, - Keyword::Constant - rule /\b[TF]\b/, Keyword::Variable + rule /%[^%]*?%/, Operator rule /0[xX][a-fA-F0-9]+([pP][0-9]+)?[Li]?/, Num::Hex rule /[+-]?(\d+([.]\d+)?|[.]\d+)([eE][+-]?\d+)?[Li]?/, Num + # Only recognize built-in functions when they are actually used as a + # function call, i.e. followed by an opening parenthesis. + # `Name::Builtin` would be more logical, but is usually not + # highlighted specifically; thus use `Name::Function`. + rule /\b(?<!.)(#{PRIMITIVE_FUNCTIONS.join('|')})(?=\()/, Name::Function + + rule /[a-zA-Z.]([a-zA-Z_][\w.]*)?/ do |m| + if KEYWORDS.include? m[0] + token Keyword + elsif KEYWORD_CONSTANTS.include? m[0] + token Keyword::Constant + elsif BUILTIN_CONSTANTS.include? m[0] + token Name::Builtin + else + token Name + end + end + rule /[\[\]{}();,]/, Punctuation rule %r([-<>?*+^/!=~$@:%&|]), Operator - rule /[.][.][.]/, Keyword end end end end