/ src / theme / languages / r.js
r.js
  1  /*! `r` grammar compiled for Highlight.js 11.10.0 */
  2    (function(){
  3      var hljsGrammar = (function () {
  4    'use strict';
  5  
  6    /*
  7    Language: R
  8    Description: R is a free software environment for statistical computing and graphics.
  9    Author: Joe Cheng <joe@rstudio.org>
 10    Contributors: Konrad Rudolph <konrad.rudolph@gmail.com>
 11    Website: https://www.r-project.org
 12    Category: common,scientific
 13    */
 14  
 15    /** @type LanguageFn */
 16    function r(hljs) {
 17      const regex = hljs.regex;
 18      // Identifiers in R cannot start with `_`, but they can start with `.` if it
 19      // is not immediately followed by a digit.
 20      // R also supports quoted identifiers, which are near-arbitrary sequences
 21      // delimited by backticks (`…`), which may contain escape sequences. These are
 22      // handled in a separate mode. See `test/markup/r/names.txt` for examples.
 23      // FIXME: Support Unicode identifiers.
 24      const IDENT_RE = /(?:(?:[a-zA-Z]|\.[._a-zA-Z])[._a-zA-Z0-9]*)|\.(?!\d)/;
 25      const NUMBER_TYPES_RE = regex.either(
 26        // Special case: only hexadecimal binary powers can contain fractions
 27        /0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/,
 28        // Hexadecimal numbers without fraction and optional binary power
 29        /0[xX][0-9a-fA-F]+(?:[pP][+-]?\d+)?[Li]?/,
 30        // Decimal numbers
 31        /(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?[Li]?/
 32      );
 33      const OPERATORS_RE = /[=!<>:]=|\|\||&&|:::?|<-|<<-|->>|->|\|>|[-+*\/?!$&|:<=>@^~]|\*\*/;
 34      const PUNCTUATION_RE = regex.either(
 35        /[()]/,
 36        /[{}]/,
 37        /\[\[/,
 38        /[[\]]/,
 39        /\\/,
 40        /,/
 41      );
 42  
 43      return {
 44        name: 'R',
 45  
 46        keywords: {
 47          $pattern: IDENT_RE,
 48          keyword:
 49            'function if in break next repeat else for while',
 50          literal:
 51            'NULL NA TRUE FALSE Inf NaN NA_integer_|10 NA_real_|10 '
 52            + 'NA_character_|10 NA_complex_|10',
 53          built_in:
 54            // Builtin constants
 55            'LETTERS letters month.abb month.name pi T F '
 56            // Primitive functions
 57            // These are all the functions in `base` that are implemented as a
 58            // `.Primitive`, minus those functions that are also keywords.
 59            + 'abs acos acosh all any anyNA Arg as.call as.character '
 60            + 'as.complex as.double as.environment as.integer as.logical '
 61            + 'as.null.default as.numeric as.raw asin asinh atan atanh attr '
 62            + 'attributes baseenv browser c call ceiling class Conj cos cosh '
 63            + 'cospi cummax cummin cumprod cumsum digamma dim dimnames '
 64            + 'emptyenv exp expression floor forceAndCall gamma gc.time '
 65            + 'globalenv Im interactive invisible is.array is.atomic is.call '
 66            + 'is.character is.complex is.double is.environment is.expression '
 67            + 'is.finite is.function is.infinite is.integer is.language '
 68            + 'is.list is.logical is.matrix is.na is.name is.nan is.null '
 69            + 'is.numeric is.object is.pairlist is.raw is.recursive is.single '
 70            + 'is.symbol lazyLoadDBfetch length lgamma list log max min '
 71            + 'missing Mod names nargs nzchar oldClass on.exit pos.to.env '
 72            + 'proc.time prod quote range Re rep retracemem return round '
 73            + 'seq_along seq_len seq.int sign signif sin sinh sinpi sqrt '
 74            + 'standardGeneric substitute sum switch tan tanh tanpi tracemem '
 75            + 'trigamma trunc unclass untracemem UseMethod xtfrm',
 76        },
 77  
 78        contains: [
 79          // Roxygen comments
 80          hljs.COMMENT(
 81            /#'/,
 82            /$/,
 83            { contains: [
 84              {
 85                // Handle `@examples` separately to cause all subsequent code
 86                // until the next `@`-tag on its own line to be kept as-is,
 87                // preventing highlighting. This code is example R code, so nested
 88                // doctags shouldn’t be treated as such. See
 89                // `test/markup/r/roxygen.txt` for an example.
 90                scope: 'doctag',
 91                match: /@examples/,
 92                starts: {
 93                  end: regex.lookahead(regex.either(
 94                    // end if another doc comment
 95                    /\n^#'\s*(?=@[a-zA-Z]+)/,
 96                    // or a line with no comment
 97                    /\n^(?!#')/
 98                  )),
 99                  endsParent: true
100                }
101              },
102              {
103                // Handle `@param` to highlight the parameter name following
104                // after.
105                scope: 'doctag',
106                begin: '@param',
107                end: /$/,
108                contains: [
109                  {
110                    scope: 'variable',
111                    variants: [
112                      { match: IDENT_RE },
113                      { match: /`(?:\\.|[^`\\])+`/ }
114                    ],
115                    endsParent: true
116                  }
117                ]
118              },
119              {
120                scope: 'doctag',
121                match: /@[a-zA-Z]+/
122              },
123              {
124                scope: 'keyword',
125                match: /\\[a-zA-Z]+/
126              }
127            ] }
128          ),
129  
130          hljs.HASH_COMMENT_MODE,
131  
132          {
133            scope: 'string',
134            contains: [ hljs.BACKSLASH_ESCAPE ],
135            variants: [
136              hljs.END_SAME_AS_BEGIN({
137                begin: /[rR]"(-*)\(/,
138                end: /\)(-*)"/
139              }),
140              hljs.END_SAME_AS_BEGIN({
141                begin: /[rR]"(-*)\{/,
142                end: /\}(-*)"/
143              }),
144              hljs.END_SAME_AS_BEGIN({
145                begin: /[rR]"(-*)\[/,
146                end: /\](-*)"/
147              }),
148              hljs.END_SAME_AS_BEGIN({
149                begin: /[rR]'(-*)\(/,
150                end: /\)(-*)'/
151              }),
152              hljs.END_SAME_AS_BEGIN({
153                begin: /[rR]'(-*)\{/,
154                end: /\}(-*)'/
155              }),
156              hljs.END_SAME_AS_BEGIN({
157                begin: /[rR]'(-*)\[/,
158                end: /\](-*)'/
159              }),
160              {
161                begin: '"',
162                end: '"',
163                relevance: 0
164              },
165              {
166                begin: "'",
167                end: "'",
168                relevance: 0
169              }
170            ],
171          },
172  
173          // Matching numbers immediately following punctuation and operators is
174          // tricky since we need to look at the character ahead of a number to
175          // ensure the number is not part of an identifier, and we cannot use
176          // negative look-behind assertions. So instead we explicitly handle all
177          // possible combinations of (operator|punctuation), number.
178          // TODO: replace with negative look-behind when available
179          // { begin: /(?<![a-zA-Z0-9._])0[xX][0-9a-fA-F]+\.[0-9a-fA-F]*[pP][+-]?\d+i?/ },
180          // { begin: /(?<![a-zA-Z0-9._])0[xX][0-9a-fA-F]+([pP][+-]?\d+)?[Li]?/ },
181          // { begin: /(?<![a-zA-Z0-9._])(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?[Li]?/ }
182          {
183            relevance: 0,
184            variants: [
185              {
186                scope: {
187                  1: 'operator',
188                  2: 'number'
189                },
190                match: [
191                  OPERATORS_RE,
192                  NUMBER_TYPES_RE
193                ]
194              },
195              {
196                scope: {
197                  1: 'operator',
198                  2: 'number'
199                },
200                match: [
201                  /%[^%]*%/,
202                  NUMBER_TYPES_RE
203                ]
204              },
205              {
206                scope: {
207                  1: 'punctuation',
208                  2: 'number'
209                },
210                match: [
211                  PUNCTUATION_RE,
212                  NUMBER_TYPES_RE
213                ]
214              },
215              {
216                scope: { 2: 'number' },
217                match: [
218                  /[^a-zA-Z0-9._]|^/, // not part of an identifier, or start of document
219                  NUMBER_TYPES_RE
220                ]
221              }
222            ]
223          },
224  
225          // Operators/punctuation when they're not directly followed by numbers
226          {
227            // Relevance boost for the most common assignment form.
228            scope: { 3: 'operator' },
229            match: [
230              IDENT_RE,
231              /\s+/,
232              /<-/,
233              /\s+/
234            ]
235          },
236  
237          {
238            scope: 'operator',
239            relevance: 0,
240            variants: [
241              { match: OPERATORS_RE },
242              { match: /%[^%]*%/ }
243            ]
244          },
245  
246          {
247            scope: 'punctuation',
248            relevance: 0,
249            match: PUNCTUATION_RE
250          },
251  
252          {
253            // Escaped identifier
254            begin: '`',
255            end: '`',
256            contains: [ { begin: /\\./ } ]
257          }
258        ]
259      };
260    }
261  
262    return r;
263  
264  })();
265  
266      hljs.registerLanguage('r', hljsGrammar);
267    })();