elixir.js 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. /*---------------------------------------------------------------------------------------------
  2. * Copyright (c) Microsoft Corporation. All rights reserved.
  3. * Licensed under the MIT License. See License.txt in the project root for license information.
  4. *--------------------------------------------------------------------------------------------*/
  5. define('vs/basic-languages/elixir/elixir',["require", "exports"], function (require, exports) {
  6. "use strict";
  7. Object.defineProperty(exports, "__esModule", { value: true });
  8. exports.language = exports.conf = void 0;
  9. exports.conf = {
  10. comments: {
  11. lineComment: '#'
  12. },
  13. brackets: [
  14. ['{', '}'],
  15. ['[', ']'],
  16. ['(', ')']
  17. ],
  18. surroundingPairs: [
  19. { open: '{', close: '}' },
  20. { open: '[', close: ']' },
  21. { open: '(', close: ')' },
  22. { open: "'", close: "'" },
  23. { open: '"', close: '"' }
  24. ],
  25. autoClosingPairs: [
  26. { open: "'", close: "'", notIn: ['string', 'comment'] },
  27. { open: '"', close: '"', notIn: ['comment'] },
  28. { open: '"""', close: '"""' },
  29. { open: '`', close: '`', notIn: ['string', 'comment'] },
  30. { open: '(', close: ')' },
  31. { open: '{', close: '}' },
  32. { open: '[', close: ']' },
  33. { open: '<<', close: '>>' }
  34. ],
  35. indentationRules: {
  36. increaseIndentPattern: /^\s*(after|else|catch|rescue|fn|[^#]*(do|<\-|\->|\{|\[|\=))\s*$/,
  37. decreaseIndentPattern: /^\s*((\}|\])\s*$|(after|else|catch|rescue|end)\b)/
  38. }
  39. };
  40. /**
  41. * A Monarch lexer for the Elixir language.
  42. *
  43. * References:
  44. *
  45. * * Monarch documentation - https://microsoft.github.io/monaco-editor/monarch.html
  46. * * Elixir lexer - https://github.com/elixir-makeup/makeup_elixir/blob/master/lib/makeup/lexers/elixir_lexer.ex
  47. * * TextMate lexer (elixir-tmbundle) - https://github.com/elixir-editors/elixir-tmbundle/blob/master/Syntaxes/Elixir.tmLanguage
  48. * * TextMate lexer (vscode-elixir-ls) - https://github.com/elixir-lsp/vscode-elixir-ls/blob/master/syntaxes/elixir.json
  49. */
  50. exports.language = {
  51. defaultToken: 'source',
  52. tokenPostfix: '.elixir',
  53. brackets: [
  54. { open: '[', close: ']', token: 'delimiter.square' },
  55. { open: '(', close: ')', token: 'delimiter.parenthesis' },
  56. { open: '{', close: '}', token: 'delimiter.curly' },
  57. { open: '<<', close: '>>', token: 'delimiter.angle.special' }
  58. ],
  59. // Below are lists/regexps to which we reference later.
  60. declarationKeywords: [
  61. 'def',
  62. 'defp',
  63. 'defn',
  64. 'defnp',
  65. 'defguard',
  66. 'defguardp',
  67. 'defmacro',
  68. 'defmacrop',
  69. 'defdelegate',
  70. 'defcallback',
  71. 'defmacrocallback',
  72. 'defmodule',
  73. 'defprotocol',
  74. 'defexception',
  75. 'defimpl',
  76. 'defstruct'
  77. ],
  78. operatorKeywords: ['and', 'in', 'not', 'or', 'when'],
  79. namespaceKeywords: ['alias', 'import', 'require', 'use'],
  80. otherKeywords: [
  81. 'after',
  82. 'case',
  83. 'catch',
  84. 'cond',
  85. 'do',
  86. 'else',
  87. 'end',
  88. 'fn',
  89. 'for',
  90. 'if',
  91. 'quote',
  92. 'raise',
  93. 'receive',
  94. 'rescue',
  95. 'super',
  96. 'throw',
  97. 'try',
  98. 'unless',
  99. 'unquote_splicing',
  100. 'unquote',
  101. 'with'
  102. ],
  103. constants: ['true', 'false', 'nil'],
  104. nameBuiltin: ['__MODULE__', '__DIR__', '__ENV__', '__CALLER__', '__STACKTRACE__'],
  105. // Matches any of the operator names:
  106. // <<< >>> ||| &&& ^^^ ~~~ === !== ~>> <~> |~> <|> == != <= >= && || \\ <> ++ -- |> =~ -> <- ~> <~ :: .. = < > + - * / | . ^ & !
  107. operator: /-[->]?|!={0,2}|\*|\/|\\\\|&{1,3}|\.\.?|\^(?:\^\^)?|\+\+?|<(?:-|<<|=|>|\|>|~>?)?|=~|={1,3}|>(?:=|>>)?|\|~>|\|>|\|{1,3}|~>>?|~~~|::/,
  108. // See https://hexdocs.pm/elixir/syntax-reference.html#variables
  109. variableName: /[a-z_][a-zA-Z0-9_]*[?!]?/,
  110. // See https://hexdocs.pm/elixir/syntax-reference.html#atoms
  111. atomName: /[a-zA-Z_][a-zA-Z0-9_@]*[?!]?|@specialAtomName|@operator/,
  112. specialAtomName: /\.\.\.|<<>>|%\{\}|%|\{\}/,
  113. aliasPart: /[A-Z][a-zA-Z0-9_]*/,
  114. moduleName: /@aliasPart(?:\.@aliasPart)*/,
  115. // Sigil pairs are: """ """, ''' ''', " ", ' ', / /, | |, < >, { }, [ ], ( )
  116. sigilSymmetricDelimiter: /"""|'''|"|'|\/|\|/,
  117. sigilStartDelimiter: /@sigilSymmetricDelimiter|<|\{|\[|\(/,
  118. sigilEndDelimiter: /@sigilSymmetricDelimiter|>|\}|\]|\)/,
  119. decimal: /\d(?:_?\d)*/,
  120. hex: /[0-9a-fA-F](_?[0-9a-fA-F])*/,
  121. octal: /[0-7](_?[0-7])*/,
  122. binary: /[01](_?[01])*/,
  123. // See https://hexdocs.pm/elixir/master/String.html#module-escape-characters
  124. escape: /\\u[0-9a-fA-F]{4}|\\x[0-9a-fA-F]{2}|\\./,
  125. // The keys below correspond to tokenizer states.
  126. // We start from the root state and match against its rules
  127. // until we explicitly transition into another state.
  128. // The `include` simply brings in all operations from the given state
  129. // and is useful for improving readability.
  130. tokenizer: {
  131. root: [
  132. { include: '@whitespace' },
  133. { include: '@comments' },
  134. // Keywords start as either an identifier or a string,
  135. // but end with a : so it's important to match this first.
  136. { include: '@keywordsShorthand' },
  137. { include: '@numbers' },
  138. { include: '@identifiers' },
  139. { include: '@strings' },
  140. { include: '@atoms' },
  141. { include: '@sigils' },
  142. { include: '@attributes' },
  143. { include: '@symbols' }
  144. ],
  145. // Whitespace
  146. whitespace: [[/\s+/, 'white']],
  147. // Comments
  148. comments: [[/(#)(.*)/, ['comment.punctuation', 'comment']]],
  149. // Keyword list shorthand
  150. keywordsShorthand: [
  151. [/(@atomName)(:)/, ['constant', 'constant.punctuation']],
  152. // Use positive look-ahead to ensure the string is followed by :
  153. // and should be considered a keyword.
  154. [
  155. /"(?=([^"]|#\{.*?\}|\\")*":)/,
  156. { token: 'constant.delimiter', next: '@doubleQuotedStringKeyword' }
  157. ],
  158. [
  159. /'(?=([^']|#\{.*?\}|\\')*':)/,
  160. { token: 'constant.delimiter', next: '@singleQuotedStringKeyword' }
  161. ]
  162. ],
  163. doubleQuotedStringKeyword: [
  164. [/":/, { token: 'constant.delimiter', next: '@pop' }],
  165. { include: '@stringConstantContentInterpol' }
  166. ],
  167. singleQuotedStringKeyword: [
  168. [/':/, { token: 'constant.delimiter', next: '@pop' }],
  169. { include: '@stringConstantContentInterpol' }
  170. ],
  171. // Numbers
  172. numbers: [
  173. [/0b@binary/, 'number.binary'],
  174. [/0o@octal/, 'number.octal'],
  175. [/0x@hex/, 'number.hex'],
  176. [/@decimal\.@decimal([eE]-?@decimal)?/, 'number.float'],
  177. [/@decimal/, 'number']
  178. ],
  179. // Identifiers
  180. identifiers: [
  181. // Tokenize identifier name in function-like definitions.
  182. // Note: given `def a + b, do: nil`, `a` is not a function name,
  183. // so we use negative look-ahead to ensure there's no operator.
  184. [
  185. /\b(defp?|defnp?|defmacrop?|defguardp?|defdelegate)(\s+)(@variableName)(?!\s+@operator)/,
  186. [
  187. 'keyword.declaration',
  188. 'white',
  189. {
  190. cases: {
  191. unquote: 'keyword',
  192. '@default': 'function'
  193. }
  194. }
  195. ]
  196. ],
  197. // Tokenize function calls
  198. [
  199. // In-scope call - an identifier followed by ( or .(
  200. /(@variableName)(?=\s*\.?\s*\()/,
  201. {
  202. cases: {
  203. // Tokenize as keyword in cases like `if(..., do: ..., else: ...)`
  204. '@declarationKeywords': 'keyword.declaration',
  205. '@namespaceKeywords': 'keyword',
  206. '@otherKeywords': 'keyword',
  207. '@default': 'function.call'
  208. }
  209. }
  210. ],
  211. [
  212. // Referencing function in a module
  213. /(@moduleName)(\s*)(\.)(\s*)(@variableName)/,
  214. ['type.identifier', 'white', 'operator', 'white', 'function.call']
  215. ],
  216. [
  217. // Referencing function in an Erlang module
  218. /(:)(@atomName)(\s*)(\.)(\s*)(@variableName)/,
  219. ['constant.punctuation', 'constant', 'white', 'operator', 'white', 'function.call']
  220. ],
  221. [
  222. // Piping into a function (tokenized separately as it may not have parentheses)
  223. /(\|>)(\s*)(@variableName)/,
  224. [
  225. 'operator',
  226. 'white',
  227. {
  228. cases: {
  229. '@otherKeywords': 'keyword',
  230. '@default': 'function.call'
  231. }
  232. }
  233. ]
  234. ],
  235. [
  236. // Function reference passed to another function
  237. /(&)(\s*)(@variableName)/,
  238. ['operator', 'white', 'function.call']
  239. ],
  240. // Language keywords, builtins, constants and variables
  241. [
  242. /@variableName/,
  243. {
  244. cases: {
  245. '@declarationKeywords': 'keyword.declaration',
  246. '@operatorKeywords': 'keyword.operator',
  247. '@namespaceKeywords': 'keyword',
  248. '@otherKeywords': 'keyword',
  249. '@constants': 'constant.language',
  250. '@nameBuiltin': 'variable.language',
  251. '_.*': 'comment.unused',
  252. '@default': 'identifier'
  253. }
  254. }
  255. ],
  256. // Module names
  257. [/@moduleName/, 'type.identifier']
  258. ],
  259. // Strings
  260. strings: [
  261. [/"""/, { token: 'string.delimiter', next: '@doubleQuotedHeredoc' }],
  262. [/'''/, { token: 'string.delimiter', next: '@singleQuotedHeredoc' }],
  263. [/"/, { token: 'string.delimiter', next: '@doubleQuotedString' }],
  264. [/'/, { token: 'string.delimiter', next: '@singleQuotedString' }]
  265. ],
  266. doubleQuotedHeredoc: [
  267. [/"""/, { token: 'string.delimiter', next: '@pop' }],
  268. { include: '@stringContentInterpol' }
  269. ],
  270. singleQuotedHeredoc: [
  271. [/'''/, { token: 'string.delimiter', next: '@pop' }],
  272. { include: '@stringContentInterpol' }
  273. ],
  274. doubleQuotedString: [
  275. [/"/, { token: 'string.delimiter', next: '@pop' }],
  276. { include: '@stringContentInterpol' }
  277. ],
  278. singleQuotedString: [
  279. [/'/, { token: 'string.delimiter', next: '@pop' }],
  280. { include: '@stringContentInterpol' }
  281. ],
  282. // Atoms
  283. atoms: [
  284. [/(:)(@atomName)/, ['constant.punctuation', 'constant']],
  285. [/:"/, { token: 'constant.delimiter', next: '@doubleQuotedStringAtom' }],
  286. [/:'/, { token: 'constant.delimiter', next: '@singleQuotedStringAtom' }]
  287. ],
  288. doubleQuotedStringAtom: [
  289. [/"/, { token: 'constant.delimiter', next: '@pop' }],
  290. { include: '@stringConstantContentInterpol' }
  291. ],
  292. singleQuotedStringAtom: [
  293. [/'/, { token: 'constant.delimiter', next: '@pop' }],
  294. { include: '@stringConstantContentInterpol' }
  295. ],
  296. // Sigils
  297. // See https://elixir-lang.org/getting-started/sigils.html
  298. // Sigils allow for typing values using their textual representation.
  299. // All sigils start with ~ followed by a letter indicating sigil type
  300. // and then a delimiter pair enclosing the textual representation.
  301. // Optional modifiers are allowed after the closing delimiter.
  302. // For instance a regular expressions can be written as:
  303. // ~r/foo|bar/ ~r{foo|bar} ~r/foo|bar/g
  304. //
  305. // In general lowercase sigils allow for interpolation
  306. // and escaped characters, whereas uppercase sigils don't
  307. //
  308. // During tokenization we want to distinguish some
  309. // specific sigil types, namely string and regexp,
  310. // so that they cen be themed separately.
  311. //
  312. // To reasonably handle all those combinations we leverage
  313. // dot-separated states, so if we transition to @sigilStart.interpol.s.{.}
  314. // then "sigilStart.interpol.s" state will match and also all
  315. // the individual dot-separated parameters can be accessed.
  316. sigils: [
  317. [/~[a-z]@sigilStartDelimiter/, { token: '@rematch', next: '@sigil.interpol' }],
  318. [/~[A-Z]@sigilStartDelimiter/, { token: '@rematch', next: '@sigil.noInterpol' }]
  319. ],
  320. sigil: [
  321. [/~([a-zA-Z])\{/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.{.}' }],
  322. [/~([a-zA-Z])\[/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.[.]' }],
  323. [/~([a-zA-Z])\(/, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.(.)' }],
  324. [/~([a-zA-Z])\</, { token: '@rematch', switchTo: '@sigilStart.$S2.$1.<.>' }],
  325. [
  326. /~([a-zA-Z])(@sigilSymmetricDelimiter)/,
  327. { token: '@rematch', switchTo: '@sigilStart.$S2.$1.$2.$2' }
  328. ]
  329. ],
  330. // The definitions below expect states to be of the form:
  331. //
  332. // sigilStart.<interpol-or-noInterpol>.<sigil-letter>.<start-delimiter>.<end-delimiter>
  333. // sigilContinue.<interpol-or-noInterpol>.<sigil-letter>.<start-delimiter>.<end-delimiter>
  334. //
  335. // The sigilStart state is used only to properly classify the token (as string/regex/sigil)
  336. // and immediately switches to the sigilContinue sate, which handles the actual content
  337. // and waits for the corresponding end delimiter.
  338. 'sigilStart.interpol.s': [
  339. [
  340. /~s@sigilStartDelimiter/,
  341. {
  342. token: 'string.delimiter',
  343. switchTo: '@sigilContinue.$S2.$S3.$S4.$S5'
  344. }
  345. ]
  346. ],
  347. 'sigilContinue.interpol.s': [
  348. [
  349. /(@sigilEndDelimiter)[a-zA-Z]*/,
  350. {
  351. cases: {
  352. '$1==$S5': { token: 'string.delimiter', next: '@pop' },
  353. '@default': 'string'
  354. }
  355. }
  356. ],
  357. { include: '@stringContentInterpol' }
  358. ],
  359. 'sigilStart.noInterpol.S': [
  360. [
  361. /~S@sigilStartDelimiter/,
  362. {
  363. token: 'string.delimiter',
  364. switchTo: '@sigilContinue.$S2.$S3.$S4.$S5'
  365. }
  366. ]
  367. ],
  368. 'sigilContinue.noInterpol.S': [
  369. // Ignore escaped sigil end
  370. [/(^|[^\\])\\@sigilEndDelimiter/, 'string'],
  371. [
  372. /(@sigilEndDelimiter)[a-zA-Z]*/,
  373. {
  374. cases: {
  375. '$1==$S5': { token: 'string.delimiter', next: '@pop' },
  376. '@default': 'string'
  377. }
  378. }
  379. ],
  380. { include: '@stringContent' }
  381. ],
  382. 'sigilStart.interpol.r': [
  383. [
  384. /~r@sigilStartDelimiter/,
  385. {
  386. token: 'regexp.delimiter',
  387. switchTo: '@sigilContinue.$S2.$S3.$S4.$S5'
  388. }
  389. ]
  390. ],
  391. 'sigilContinue.interpol.r': [
  392. [
  393. /(@sigilEndDelimiter)[a-zA-Z]*/,
  394. {
  395. cases: {
  396. '$1==$S5': { token: 'regexp.delimiter', next: '@pop' },
  397. '@default': 'regexp'
  398. }
  399. }
  400. ],
  401. { include: '@regexpContentInterpol' }
  402. ],
  403. 'sigilStart.noInterpol.R': [
  404. [
  405. /~R@sigilStartDelimiter/,
  406. {
  407. token: 'regexp.delimiter',
  408. switchTo: '@sigilContinue.$S2.$S3.$S4.$S5'
  409. }
  410. ]
  411. ],
  412. 'sigilContinue.noInterpol.R': [
  413. // Ignore escaped sigil end
  414. [/(^|[^\\])\\@sigilEndDelimiter/, 'regexp'],
  415. [
  416. /(@sigilEndDelimiter)[a-zA-Z]*/,
  417. {
  418. cases: {
  419. '$1==$S5': { token: 'regexp.delimiter', next: '@pop' },
  420. '@default': 'regexp'
  421. }
  422. }
  423. ],
  424. { include: '@regexpContent' }
  425. ],
  426. // Fallback to the generic sigil by default
  427. 'sigilStart.interpol': [
  428. [
  429. /~([a-zA-Z])@sigilStartDelimiter/,
  430. {
  431. token: 'sigil.delimiter',
  432. switchTo: '@sigilContinue.$S2.$S3.$S4.$S5'
  433. }
  434. ]
  435. ],
  436. 'sigilContinue.interpol': [
  437. [
  438. /(@sigilEndDelimiter)[a-zA-Z]*/,
  439. {
  440. cases: {
  441. '$1==$S5': { token: 'sigil.delimiter', next: '@pop' },
  442. '@default': 'sigil'
  443. }
  444. }
  445. ],
  446. { include: '@sigilContentInterpol' }
  447. ],
  448. 'sigilStart.noInterpol': [
  449. [
  450. /~([a-zA-Z])@sigilStartDelimiter/,
  451. {
  452. token: 'sigil.delimiter',
  453. switchTo: '@sigilContinue.$S2.$S3.$S4.$S5'
  454. }
  455. ]
  456. ],
  457. 'sigilContinue.noInterpol': [
  458. // Ignore escaped sigil end
  459. [/(^|[^\\])\\@sigilEndDelimiter/, 'sigil'],
  460. [
  461. /(@sigilEndDelimiter)[a-zA-Z]*/,
  462. {
  463. cases: {
  464. '$1==$S5': { token: 'sigil.delimiter', next: '@pop' },
  465. '@default': 'sigil'
  466. }
  467. }
  468. ],
  469. { include: '@sigilContent' }
  470. ],
  471. // Attributes
  472. attributes: [
  473. // Module @doc* attributes - tokenized as comments
  474. [
  475. /\@(module|type)?doc (~[sS])?"""/,
  476. {
  477. token: 'comment.block.documentation',
  478. next: '@doubleQuotedHeredocDocstring'
  479. }
  480. ],
  481. [
  482. /\@(module|type)?doc (~[sS])?"/,
  483. {
  484. token: 'comment.block.documentation',
  485. next: '@doubleQuotedStringDocstring'
  486. }
  487. ],
  488. [/\@(module|type)?doc false/, 'comment.block.documentation'],
  489. // Module attributes
  490. [/\@(@variableName)/, 'variable']
  491. ],
  492. doubleQuotedHeredocDocstring: [
  493. [/"""/, { token: 'comment.block.documentation', next: '@pop' }],
  494. { include: '@docstringContent' }
  495. ],
  496. doubleQuotedStringDocstring: [
  497. [/"/, { token: 'comment.block.documentation', next: '@pop' }],
  498. { include: '@docstringContent' }
  499. ],
  500. // Operators, punctuation, brackets
  501. symbols: [
  502. // Code point operator (either with regular character ?a or an escaped one ?\n)
  503. [/\?(\\.|[^\\\s])/, 'number.constant'],
  504. // Anonymous function arguments
  505. [/&\d+/, 'operator'],
  506. // Bitshift operators (must go before delimiters, so that << >> don't match first)
  507. [/<<<|>>>/, 'operator'],
  508. // Delimiter pairs
  509. [/[()\[\]\{\}]|<<|>>/, '@brackets'],
  510. // Triple dot is a valid name (must go before operators, so that .. doesn't match instead)
  511. [/\.\.\./, 'identifier'],
  512. // Punctuation => (must go before operators, so it's not tokenized as = then >)
  513. [/=>/, 'punctuation'],
  514. // Operators
  515. [/@operator/, 'operator'],
  516. // Punctuation
  517. [/[:;,.%]/, 'punctuation']
  518. ],
  519. // Generic helpers
  520. stringContentInterpol: [
  521. { include: '@interpolation' },
  522. { include: '@escapeChar' },
  523. { include: '@stringContent' }
  524. ],
  525. stringContent: [[/./, 'string']],
  526. stringConstantContentInterpol: [
  527. { include: '@interpolation' },
  528. { include: '@escapeChar' },
  529. { include: '@stringConstantContent' }
  530. ],
  531. stringConstantContent: [[/./, 'constant']],
  532. regexpContentInterpol: [
  533. { include: '@interpolation' },
  534. { include: '@escapeChar' },
  535. { include: '@regexpContent' }
  536. ],
  537. regexpContent: [
  538. // # may be a regular regexp char, so we use a heuristic
  539. // assuming a # surrounded by whitespace is actually a comment.
  540. [/(\s)(#)(\s.*)$/, ['white', 'comment.punctuation', 'comment']],
  541. [/./, 'regexp']
  542. ],
  543. sigilContentInterpol: [
  544. { include: '@interpolation' },
  545. { include: '@escapeChar' },
  546. { include: '@sigilContent' }
  547. ],
  548. sigilContent: [[/./, 'sigil']],
  549. docstringContent: [[/./, 'comment.block.documentation']],
  550. escapeChar: [[/@escape/, 'constant.character.escape']],
  551. interpolation: [
  552. [/#{/, { token: 'delimiter.bracket.embed', next: '@interpolationContinue' }]
  553. ],
  554. interpolationContinue: [
  555. [/}/, { token: 'delimiter.bracket.embed', next: '@pop' }],
  556. // Interpolation brackets may contain arbitrary code,
  557. // so we simply match against all the root rules,
  558. // until we reach interpolation end (the above matches).
  559. { include: '@root' }
  560. ]
  561. }
  562. };
  563. });