You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

174 lines
4.6KB

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