julia.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. ;(function (mod) {
  4. if (typeof exports == 'object' && typeof module == 'object')
  5. // CommonJS
  6. mod(require('../../lib/codemirror'))
  7. else if (typeof define == 'function' && define.amd)
  8. // AMD
  9. define(['../../lib/codemirror'], mod)
  10. // Plain browser env
  11. else mod(CodeMirror)
  12. })(function (CodeMirror) {
  13. 'use strict'
  14. CodeMirror.defineMode('julia', function (config, parserConf) {
  15. function wordRegexp(words, end, pre) {
  16. if (typeof pre === 'undefined') {
  17. pre = ''
  18. }
  19. if (typeof end === 'undefined') {
  20. end = '\\b'
  21. }
  22. return new RegExp('^' + pre + '((' + words.join(')|(') + '))' + end)
  23. }
  24. var octChar = '\\\\[0-7]{1,3}'
  25. var hexChar = '\\\\x[A-Fa-f0-9]{1,2}'
  26. var sChar = '\\\\[abefnrtv0%?\'"\\\\]'
  27. var uChar = '([^\\u0027\\u005C\\uD800-\\uDFFF]|[\\uD800-\\uDFFF][\\uDC00-\\uDFFF])'
  28. var asciiOperatorsList = ['[<>]:', '[<>=]=', '<<=?', '>>>?=?', '=>', '--?>', '<--[->]?', '\\/\\/', '\\.{2,3}', '[\\.\\\\%*+\\-<>!\\/^|&]=?', '\\?', '\\$', '~', ':']
  29. var operators =
  30. parserConf.operators ||
  31. wordRegexp(
  32. [
  33. '[<>]:',
  34. '[<>=]=',
  35. '<<=?',
  36. '>>>?=?',
  37. '=>',
  38. '--?>',
  39. '<--[->]?',
  40. '\\/\\/',
  41. '[\\\\%*+\\-<>!\\/^|&\\u00F7\\u22BB]=?',
  42. '\\?',
  43. '\\$',
  44. '~',
  45. ':',
  46. '\\u00D7',
  47. '\\u2208',
  48. '\\u2209',
  49. '\\u220B',
  50. '\\u220C',
  51. '\\u2218',
  52. '\\u221A',
  53. '\\u221B',
  54. '\\u2229',
  55. '\\u222A',
  56. '\\u2260',
  57. '\\u2264',
  58. '\\u2265',
  59. '\\u2286',
  60. '\\u2288',
  61. '\\u228A',
  62. '\\u22C5',
  63. '\\b(in|isa)\\b(?!.?\\()',
  64. ],
  65. ''
  66. )
  67. var delimiters = parserConf.delimiters || /^[;,()[\]{}]/
  68. var identifiers = parserConf.identifiers || /^[_A-Za-z\u00A1-\u2217\u2219-\uFFFF][\w\u00A1-\u2217\u2219-\uFFFF]*!*/
  69. var chars = wordRegexp([octChar, hexChar, sChar, uChar], "'")
  70. var openersList = ['begin', 'function', 'type', 'struct', 'immutable', 'let', 'macro', 'for', 'while', 'quote', 'if', 'else', 'elseif', 'try', 'finally', 'catch', 'do']
  71. var closersList = ['end', 'else', 'elseif', 'catch', 'finally']
  72. var keywordsList = [
  73. 'if',
  74. 'else',
  75. 'elseif',
  76. 'while',
  77. 'for',
  78. 'begin',
  79. 'let',
  80. 'end',
  81. 'do',
  82. 'try',
  83. 'catch',
  84. 'finally',
  85. 'return',
  86. 'break',
  87. 'continue',
  88. 'global',
  89. 'local',
  90. 'const',
  91. 'export',
  92. 'import',
  93. 'importall',
  94. 'using',
  95. 'function',
  96. 'where',
  97. 'macro',
  98. 'module',
  99. 'baremodule',
  100. 'struct',
  101. 'type',
  102. 'mutable',
  103. 'immutable',
  104. 'quote',
  105. 'typealias',
  106. 'abstract',
  107. 'primitive',
  108. 'bitstype',
  109. ]
  110. var builtinsList = ['true', 'false', 'nothing', 'NaN', 'Inf']
  111. CodeMirror.registerHelper('hintWords', 'julia', keywordsList.concat(builtinsList))
  112. var openers = wordRegexp(openersList)
  113. var closers = wordRegexp(closersList)
  114. var keywords = wordRegexp(keywordsList)
  115. var builtins = wordRegexp(builtinsList)
  116. var macro = /^@[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/
  117. var symbol = /^:[_A-Za-z\u00A1-\uFFFF][\w\u00A1-\uFFFF]*!*/
  118. var stringPrefixes = /^(`|([_A-Za-z\u00A1-\uFFFF]*"("")?))/
  119. var macroOperators = wordRegexp(asciiOperatorsList, '', '@')
  120. var symbolOperators = wordRegexp(asciiOperatorsList, '', ':')
  121. function inArray(state) {
  122. return state.nestedArrays > 0
  123. }
  124. function inGenerator(state) {
  125. return state.nestedGenerators > 0
  126. }
  127. function currentScope(state, n) {
  128. if (typeof n === 'undefined') {
  129. n = 0
  130. }
  131. if (state.scopes.length <= n) {
  132. return null
  133. }
  134. return state.scopes[state.scopes.length - (n + 1)]
  135. }
  136. // tokenizers
  137. function tokenBase(stream, state) {
  138. // Handle multiline comments
  139. if (stream.match('#=', false)) {
  140. state.tokenize = tokenComment
  141. return state.tokenize(stream, state)
  142. }
  143. // Handle scope changes
  144. var leavingExpr = state.leavingExpr
  145. if (stream.sol()) {
  146. leavingExpr = false
  147. }
  148. state.leavingExpr = false
  149. if (leavingExpr) {
  150. if (stream.match(/^'+/)) {
  151. return 'operator'
  152. }
  153. }
  154. if (stream.match(/\.{4,}/)) {
  155. return 'error'
  156. } else if (stream.match(/\.{1,3}/)) {
  157. return 'operator'
  158. }
  159. if (stream.eatSpace()) {
  160. return null
  161. }
  162. var ch = stream.peek()
  163. // Handle single line comments
  164. if (ch === '#') {
  165. stream.skipToEnd()
  166. return 'comment'
  167. }
  168. if (ch === '[') {
  169. state.scopes.push('[')
  170. state.nestedArrays++
  171. }
  172. if (ch === '(') {
  173. state.scopes.push('(')
  174. state.nestedGenerators++
  175. }
  176. if (inArray(state) && ch === ']') {
  177. while (state.scopes.length && currentScope(state) !== '[') {
  178. state.scopes.pop()
  179. }
  180. state.scopes.pop()
  181. state.nestedArrays--
  182. state.leavingExpr = true
  183. }
  184. if (inGenerator(state) && ch === ')') {
  185. while (state.scopes.length && currentScope(state) !== '(') {
  186. state.scopes.pop()
  187. }
  188. state.scopes.pop()
  189. state.nestedGenerators--
  190. state.leavingExpr = true
  191. }
  192. if (inArray(state)) {
  193. if (state.lastToken == 'end' && stream.match(':')) {
  194. return 'operator'
  195. }
  196. if (stream.match('end')) {
  197. return 'number'
  198. }
  199. }
  200. var match
  201. if ((match = stream.match(openers, false))) {
  202. state.scopes.push(match[0])
  203. }
  204. if (stream.match(closers, false)) {
  205. state.scopes.pop()
  206. }
  207. // Handle type annotations
  208. if (stream.match(/^::(?![:\$])/)) {
  209. state.tokenize = tokenAnnotation
  210. return state.tokenize(stream, state)
  211. }
  212. // Handle symbols
  213. if (!leavingExpr && (stream.match(symbol) || stream.match(symbolOperators))) {
  214. return 'builtin'
  215. }
  216. // Handle parametric types
  217. //if (stream.match(/^{[^}]*}(?=\()/)) {
  218. // return "builtin";
  219. //}
  220. // Handle operators and Delimiters
  221. if (stream.match(operators)) {
  222. return 'operator'
  223. }
  224. // Handle Number Literals
  225. if (stream.match(/^\.?\d/, false)) {
  226. var imMatcher = RegExp(/^im\b/)
  227. var numberLiteral = false
  228. if (stream.match(/^0x\.[0-9a-f_]+p[\+\-]?[_\d]+/i)) {
  229. numberLiteral = true
  230. }
  231. // Integers
  232. if (stream.match(/^0x[0-9a-f_]+/i)) {
  233. numberLiteral = true
  234. } // Hex
  235. if (stream.match(/^0b[01_]+/i)) {
  236. numberLiteral = true
  237. } // Binary
  238. if (stream.match(/^0o[0-7_]+/i)) {
  239. numberLiteral = true
  240. } // Octal
  241. // Floats
  242. if (stream.match(/^(?:(?:\d[_\d]*)?\.(?!\.)(?:\d[_\d]*)?|\d[_\d]*\.(?!\.)(?:\d[_\d]*))?([Eef][\+\-]?[_\d]+)?/i)) {
  243. numberLiteral = true
  244. }
  245. if (stream.match(/^\d[_\d]*(e[\+\-]?\d+)?/i)) {
  246. numberLiteral = true
  247. } // Decimal
  248. if (numberLiteral) {
  249. // Integer literals may be "long"
  250. stream.match(imMatcher)
  251. state.leavingExpr = true
  252. return 'number'
  253. }
  254. }
  255. // Handle Chars
  256. if (stream.match("'")) {
  257. state.tokenize = tokenChar
  258. return state.tokenize(stream, state)
  259. }
  260. // Handle Strings
  261. if (stream.match(stringPrefixes)) {
  262. state.tokenize = tokenStringFactory(stream.current())
  263. return state.tokenize(stream, state)
  264. }
  265. if (stream.match(macro) || stream.match(macroOperators)) {
  266. return 'meta'
  267. }
  268. if (stream.match(delimiters)) {
  269. return null
  270. }
  271. if (stream.match(keywords)) {
  272. return 'keyword'
  273. }
  274. if (stream.match(builtins)) {
  275. return 'builtin'
  276. }
  277. var isDefinition =
  278. state.isDefinition || state.lastToken == 'function' || state.lastToken == 'macro' || state.lastToken == 'type' || state.lastToken == 'struct' || state.lastToken == 'immutable'
  279. if (stream.match(identifiers)) {
  280. if (isDefinition) {
  281. if (stream.peek() === '.') {
  282. state.isDefinition = true
  283. return 'variable'
  284. }
  285. state.isDefinition = false
  286. return 'def'
  287. }
  288. state.leavingExpr = true
  289. return 'variable'
  290. }
  291. // Handle non-detected items
  292. stream.next()
  293. return 'error'
  294. }
  295. function tokenAnnotation(stream, state) {
  296. stream.match(/.*?(?=[,;{}()=\s]|$)/)
  297. if (stream.match('{')) {
  298. state.nestedParameters++
  299. } else if (stream.match('}') && state.nestedParameters > 0) {
  300. state.nestedParameters--
  301. }
  302. if (state.nestedParameters > 0) {
  303. stream.match(/.*?(?={|})/) || stream.next()
  304. } else if (state.nestedParameters == 0) {
  305. state.tokenize = tokenBase
  306. }
  307. return 'builtin'
  308. }
  309. function tokenComment(stream, state) {
  310. if (stream.match('#=')) {
  311. state.nestedComments++
  312. }
  313. if (!stream.match(/.*?(?=(#=|=#))/)) {
  314. stream.skipToEnd()
  315. }
  316. if (stream.match('=#')) {
  317. state.nestedComments--
  318. if (state.nestedComments == 0) state.tokenize = tokenBase
  319. }
  320. return 'comment'
  321. }
  322. function tokenChar(stream, state) {
  323. var isChar = false,
  324. match
  325. if (stream.match(chars)) {
  326. isChar = true
  327. } else if ((match = stream.match(/\\u([a-f0-9]{1,4})(?=')/i))) {
  328. var value = parseInt(match[1], 16)
  329. if (value <= 55295 || value >= 57344) {
  330. // (U+0,U+D7FF), (U+E000,U+FFFF)
  331. isChar = true
  332. stream.next()
  333. }
  334. } else if ((match = stream.match(/\\U([A-Fa-f0-9]{5,8})(?=')/))) {
  335. var value = parseInt(match[1], 16)
  336. if (value <= 1114111) {
  337. // U+10FFFF
  338. isChar = true
  339. stream.next()
  340. }
  341. }
  342. if (isChar) {
  343. state.leavingExpr = true
  344. state.tokenize = tokenBase
  345. return 'string'
  346. }
  347. if (!stream.match(/^[^']+(?=')/)) {
  348. stream.skipToEnd()
  349. }
  350. if (stream.match("'")) {
  351. state.tokenize = tokenBase
  352. }
  353. return 'error'
  354. }
  355. function tokenStringFactory(delimiter) {
  356. if (delimiter.substr(-3) === '"""') {
  357. delimiter = '"""'
  358. } else if (delimiter.substr(-1) === '"') {
  359. delimiter = '"'
  360. }
  361. function tokenString(stream, state) {
  362. if (stream.eat('\\')) {
  363. stream.next()
  364. } else if (stream.match(delimiter)) {
  365. state.tokenize = tokenBase
  366. state.leavingExpr = true
  367. return 'string'
  368. } else {
  369. stream.eat(/[`"]/)
  370. }
  371. stream.eatWhile(/[^\\`"]/)
  372. return 'string'
  373. }
  374. return tokenString
  375. }
  376. var external = {
  377. startState: function () {
  378. return {
  379. tokenize: tokenBase,
  380. scopes: [],
  381. lastToken: null,
  382. leavingExpr: false,
  383. isDefinition: false,
  384. nestedArrays: 0,
  385. nestedComments: 0,
  386. nestedGenerators: 0,
  387. nestedParameters: 0,
  388. firstParenPos: -1,
  389. }
  390. },
  391. token: function (stream, state) {
  392. var style = state.tokenize(stream, state)
  393. var current = stream.current()
  394. if (current && style) {
  395. state.lastToken = current
  396. }
  397. return style
  398. },
  399. indent: function (state, textAfter) {
  400. var delta = 0
  401. if (
  402. textAfter === ']' ||
  403. textAfter === ')' ||
  404. /^end\b/.test(textAfter) ||
  405. /^else/.test(textAfter) ||
  406. /^catch\b/.test(textAfter) ||
  407. /^elseif\b/.test(textAfter) ||
  408. /^finally/.test(textAfter)
  409. ) {
  410. delta = -1
  411. }
  412. return (state.scopes.length + delta) * config.indentUnit
  413. },
  414. electricInput: /\b(end|else|catch|finally)\b/,
  415. blockCommentStart: '#=',
  416. blockCommentEnd: '=#',
  417. lineComment: '#',
  418. closeBrackets: '()[]{}""',
  419. fold: 'indent',
  420. }
  421. return external
  422. })
  423. CodeMirror.defineMIME('text/x-julia', 'julia')
  424. })