fcl.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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('fcl', function (config) {
  15. var indentUnit = config.indentUnit
  16. var keywords = {
  17. term: true,
  18. method: true,
  19. accu: true,
  20. rule: true,
  21. then: true,
  22. is: true,
  23. and: true,
  24. or: true,
  25. if: true,
  26. default: true,
  27. }
  28. var start_blocks = {
  29. var_input: true,
  30. var_output: true,
  31. fuzzify: true,
  32. defuzzify: true,
  33. function_block: true,
  34. ruleblock: true,
  35. }
  36. var end_blocks = {
  37. end_ruleblock: true,
  38. end_defuzzify: true,
  39. end_function_block: true,
  40. end_fuzzify: true,
  41. end_var: true,
  42. }
  43. var atoms = {
  44. true: true,
  45. false: true,
  46. nan: true,
  47. real: true,
  48. min: true,
  49. max: true,
  50. cog: true,
  51. cogs: true,
  52. }
  53. var isOperatorChar = /[+\-*&^%:=<>!|\/]/
  54. function tokenBase(stream, state) {
  55. var ch = stream.next()
  56. if (/[\d\.]/.test(ch)) {
  57. if (ch == '.') {
  58. stream.match(/^[0-9]+([eE][\-+]?[0-9]+)?/)
  59. } else if (ch == '0') {
  60. stream.match(/^[xX][0-9a-fA-F]+/) || stream.match(/^0[0-7]+/)
  61. } else {
  62. stream.match(/^[0-9]*\.?[0-9]*([eE][\-+]?[0-9]+)?/)
  63. }
  64. return 'number'
  65. }
  66. if (ch == '/' || ch == '(') {
  67. if (stream.eat('*')) {
  68. state.tokenize = tokenComment
  69. return tokenComment(stream, state)
  70. }
  71. if (stream.eat('/')) {
  72. stream.skipToEnd()
  73. return 'comment'
  74. }
  75. }
  76. if (isOperatorChar.test(ch)) {
  77. stream.eatWhile(isOperatorChar)
  78. return 'operator'
  79. }
  80. stream.eatWhile(/[\w\$_\xa1-\uffff]/)
  81. var cur = stream.current().toLowerCase()
  82. if (keywords.propertyIsEnumerable(cur) || start_blocks.propertyIsEnumerable(cur) || end_blocks.propertyIsEnumerable(cur)) {
  83. return 'keyword'
  84. }
  85. if (atoms.propertyIsEnumerable(cur)) return 'atom'
  86. return 'variable'
  87. }
  88. function tokenComment(stream, state) {
  89. var maybeEnd = false,
  90. ch
  91. while ((ch = stream.next())) {
  92. if ((ch == '/' || ch == ')') && maybeEnd) {
  93. state.tokenize = tokenBase
  94. break
  95. }
  96. maybeEnd = ch == '*'
  97. }
  98. return 'comment'
  99. }
  100. function Context(indented, column, type, align, prev) {
  101. this.indented = indented
  102. this.column = column
  103. this.type = type
  104. this.align = align
  105. this.prev = prev
  106. }
  107. function pushContext(state, col, type) {
  108. return (state.context = new Context(state.indented, col, type, null, state.context))
  109. }
  110. function popContext(state) {
  111. if (!state.context.prev) return
  112. var t = state.context.type
  113. if (t == 'end_block') state.indented = state.context.indented
  114. return (state.context = state.context.prev)
  115. }
  116. // Interface
  117. return {
  118. startState: function (basecolumn) {
  119. return {
  120. tokenize: null,
  121. context: new Context((basecolumn || 0) - indentUnit, 0, 'top', false),
  122. indented: 0,
  123. startOfLine: true,
  124. }
  125. },
  126. token: function (stream, state) {
  127. var ctx = state.context
  128. if (stream.sol()) {
  129. if (ctx.align == null) ctx.align = false
  130. state.indented = stream.indentation()
  131. state.startOfLine = true
  132. }
  133. if (stream.eatSpace()) return null
  134. var style = (state.tokenize || tokenBase)(stream, state)
  135. if (style == 'comment') return style
  136. if (ctx.align == null) ctx.align = true
  137. var cur = stream.current().toLowerCase()
  138. if (start_blocks.propertyIsEnumerable(cur)) pushContext(state, stream.column(), 'end_block')
  139. else if (end_blocks.propertyIsEnumerable(cur)) popContext(state)
  140. state.startOfLine = false
  141. return style
  142. },
  143. indent: function (state, textAfter) {
  144. if (state.tokenize != tokenBase && state.tokenize != null) return 0
  145. var ctx = state.context
  146. var closing = end_blocks.propertyIsEnumerable(textAfter)
  147. if (ctx.align) return ctx.column + (closing ? 0 : 1)
  148. else return ctx.indented + (closing ? 0 : indentUnit)
  149. },
  150. electricChars: 'ryk',
  151. fold: 'brace',
  152. blockCommentStart: '(*',
  153. blockCommentEnd: '*)',
  154. lineComment: '//',
  155. }
  156. })
  157. CodeMirror.defineMIME('text/x-fcl', 'fcl')
  158. })