language.js 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. const prefixRE = (words) => {
  2. return new RegExp("^(?:" + words.join("|") + ")", "i");
  3. }
  4. const wordRE = (words) => {
  5. return new RegExp("^(?:" + words.join("|") + ")$", "i");
  6. }
  7. const builtins = wordRE([
  8. // useful helpers
  9. "rep",
  10. // string manipulation
  11. "str/upper",
  12. "str/lower",
  13. "str/capitalize",
  14. "wd", "se",
  15. // arithmetic
  16. "add", "sub", "mul",
  17. // tuple stuff
  18. "tuple/len", "tuple/concat", "tuple/flatten", "tuple/join",
  19. "tuple/index", "tuple/rep", "tuple/replace", "tuple/fold",
  20. "tuple/map",
  21. ]);
  22. const keywords = wordRE([
  23. "puts",
  24. "case",
  25. "let",
  26. "in",
  27. "fix",
  28. "record",
  29. ]);
  30. const normal = (stream, state) => {
  31. let ch = stream.next();
  32. if (ch == "(") {
  33. if (stream.eat("*")) {
  34. comment(stream, state);
  35. return "comment";
  36. }
  37. }
  38. if (ch == "\"" || ch == "'")
  39. return (state.cur = string(ch))(stream, state);
  40. if (ch == "[" && /[\[=]/.test(stream.peek()))
  41. return (state.cur = bracketed(readBracket(stream), "string"))(stream, state);
  42. if (/\d/.test(ch)) {
  43. stream.eatWhile(/[\w.%]/);
  44. return "number";
  45. }
  46. if (/[\w_]/.test(ch)) {
  47. stream.eatWhile(/[\w\\\-_.]/);
  48. return "variable";
  49. }
  50. return null;
  51. }
  52. const comment = (stream, state) => {
  53. let ch;
  54. while (ch = stream.next()) {
  55. if (ch == "*" && stream.next() == ")") {
  56. state.cur = normal;
  57. return "comment";
  58. }
  59. }
  60. state.cur = comment;
  61. };
  62. const bracketed = (level, style) => {
  63. return (stream, state) => {
  64. let curlev = null, ch;
  65. while ((ch = stream.next()) != null) {
  66. if (curlev == null) {
  67. if (ch == "]") curlev = 0;
  68. } else if (ch == "=") {
  69. ++curlev;
  70. } else if (ch == "]" && curlev == level) {
  71. state.cur = normal;
  72. break;
  73. } else {
  74. curlev = null;
  75. }
  76. }
  77. return style;
  78. };
  79. }
  80. const string = (quote) => {
  81. return (stream, state) => {
  82. let escaped = false, ch;
  83. while ((ch = stream.next()) != null) {
  84. if (ch == quote && !escaped) break;
  85. escaped = !escaped && ch == "\\";
  86. }
  87. if (!escaped)
  88. state.cur = normal;
  89. return "string";
  90. };
  91. }
  92. export const matzoLang = {
  93. startState: (basecol) => {
  94. return {cur: normal};
  95. },
  96. token: (stream, state) => {
  97. if (stream.eatSpace())
  98. return null;
  99. let style = state.cur(stream, state);
  100. const word = stream.current();
  101. if (style == "variable") {
  102. if (keywords.test(word))
  103. style = "keyword";
  104. else if (builtins.test(word))
  105. style = "builtin";
  106. }
  107. return style;
  108. },
  109. languageData: {
  110. commentTokens: {block: {open: "(\*", close: "\*)"}}
  111. }
  112. };