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 })();