/* Language: R Description: R is a free software environment for statistical computing and graphics. Author: Joe Cheng Contributors: Konrad Rudolph Website: https://www.r-project.org Category: common,scientific */ /** @type LanguageFn */ function r(hljs) { const regex = hljs.regex; // Identifiers in R cannot start with `_`, but they can start with `.` if it // is not immediately followed by a digit. // R also supports quoted identifiers, which are near-arbitrary sequences // delimited by backticks (`…`), which may contain escape sequences. These are // handled in a separate mode. See `test/markup/r/names.txt` for examples. // FIXME: Support Unicode identifiers. const IDENT_RE = /(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/; const NUMBER_TYPES_RE = regex.either( // Special case: only hexadecimal binary powers can contain fractions /0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/, // Hexadecimal numbers without fraction and optional binary power /0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/, // Decimal numbers /(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/ ); const OPERATORS_RE = /[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/; const PUNCTUATION_RE = regex.either( /[()]/, /[{}]/, /\[\[/, /[[\]]/, /\\/, /,/ ); return { name: 'R', keywords: { $pattern: IDENT_RE, keyword: 'function if in break next repeat else for while', literal: 'NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 ' + 'NA_character_|10 NA_complex_|10', built_in: // Builtin constants 'LETTERS letters month.abb month.name pi T F ' // Primitive functions // These are all the functions in `base` that are implemented as a // `.Primitive`, minus those functions that are also keywords. + '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', }, contains: [ // Roxygen comments hljs.COMMENT( /#'/, /$/, { contains: [ { // Handle `@examples` separately to cause all subsequent code // until the next `@`-tag on its own line to be kept as-is, // preventing highlighting. This code is example R code, so nested // doctags shouldn’t be treated as such. See // `test/markup/r/roxygen.txt` for an example. scope: 'doctag', match: /@examples/, starts: { end: regex.lookahead(regex.either( // end if another doc comment /\n^#'\s*(?=@[a-zA-Z]+)/, // or a line with no comment /\n^(?!#')/ )), endsParent: true } }, { // Handle `@param` to highlight the parameter name following // after. scope: 'doctag', begin: '@param', end: /$/, contains: [ { scope: 'variable', variants: [ { match: IDENT_RE }, { match: /`(?:\\.|[^`\\])+`/ } ], endsParent: true } ] }, { scope: 'doctag', match: /@[a-zA-Z]+/ }, { scope: 'keyword', match: /\\[a-zA-Z]+/ } ] } ), hljs.HASH_COMMENT_MODE, { scope: 'string', contains: [ hljs.BACKSLASH_ESCAPE ], variants: [ hljs.END_SAME_AS_BEGIN({ begin: /[rR]"(-*)\(/, end: /\)(-*)"/ }), hljs.END_SAME_AS_BEGIN({ begin: /[rR]"(-*)\{/, end: /\}(-*)"/ }), hljs.END_SAME_AS_BEGIN({ begin: /[rR]"(-*)\[/, end: /\](-*)"/ }), hljs.END_SAME_AS_BEGIN({ begin: /[rR]'(-*)\(/, end: /\)(-*)'/ }), hljs.END_SAME_AS_BEGIN({ begin: /[rR]'(-*)\{/, end: /\}(-*)'/ }), hljs.END_SAME_AS_BEGIN({ begin: /[rR]'(-*)\[/, end: /\](-*)'/ }), { begin: '"', end: '"', relevance: 0 }, { begin: "'", end: "'", relevance: 0 } ], }, // Matching numbers immediately following punctuation and operators is // tricky since we need to look at the character ahead of a number to // ensure the number is not part of an identifier, and we cannot use // negative look-behind assertions. So instead we explicitly handle all // possible combinations of (operator|punctuation), number. // TODO: replace with negative look-behind when available // { begin: /(?