smalltalk.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. (function(mod) {
  2. if (typeof exports == "object" && typeof module == "object") // CommonJS
  3. mod(require("../../lib/codemirror"));
  4. else if (typeof define == "function" && define.amd) // AMD
  5. define(["../../lib/codemirror"], mod);
  6. else // Plain browser env
  7. mod(CodeMirror);
  8. })(function(CodeMirror) {
  9. "use strict";
  10. CodeMirror.defineMode('smalltalk', function(config) {
  11. var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/;
  12. var keywords = /true|false|nil|self|super|thisContext/;
  13. var Context = function(tokenizer, parent) {
  14. this.next = tokenizer;
  15. this.parent = parent;
  16. };
  17. var Token = function(name, context, eos) {
  18. this.name = name;
  19. this.context = context;
  20. this.eos = eos;
  21. };
  22. var State = function() {
  23. this.context = new Context(next, null);
  24. this.expectVariable = true;
  25. this.indentation = 0;
  26. this.userIndentationDelta = 0;
  27. };
  28. State.prototype.userIndent = function(indentation) {
  29. this.userIndentationDelta = indentation > 0 ? (indentation / config.indentUnit - this.indentation) : 0;
  30. };
  31. var next = function(stream, context, state) {
  32. var token = new Token(null, context, false);
  33. var aChar = stream.next();
  34. if (aChar === '"') {
  35. token = nextComment(stream, new Context(nextComment, context));
  36. } else if (aChar === '\'') {
  37. token = nextString(stream, new Context(nextString, context));
  38. } else if (aChar === '#') {
  39. if (stream.peek() === '\'') {
  40. stream.next();
  41. token = nextSymbol(stream, new Context(nextSymbol, context));
  42. } else {
  43. if (stream.eatWhile(/[^ .{}\[\]()]/))
  44. token.name = 'string-2';
  45. else
  46. token.name = 'meta';
  47. }
  48. } else if (aChar === '$') {
  49. if (stream.next() === '<') {
  50. stream.eatWhile(/[^ >]/);
  51. stream.next();
  52. }
  53. token.name = 'string-2';
  54. } else if (aChar === '|' && state.expectVariable) {
  55. token.context = new Context(nextTemporaries, context);
  56. } else if (/[\[\]{}()]/.test(aChar)) {
  57. token.name = 'bracket';
  58. token.eos = /[\[{(]/.test(aChar);
  59. if (aChar === '[') {
  60. state.indentation++;
  61. } else if (aChar === ']') {
  62. state.indentation = Math.max(0, state.indentation - 1);
  63. }
  64. } else if (specialChars.test(aChar)) {
  65. stream.eatWhile(specialChars);
  66. token.name = 'operator';
  67. token.eos = aChar !== ';'; // ; cascaded message expression
  68. } else if (/\d/.test(aChar)) {
  69. stream.eatWhile(/[\w\d]/);
  70. token.name = 'number';
  71. } else if (/[\w_]/.test(aChar)) {
  72. stream.eatWhile(/[\w\d_]/);
  73. token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
  74. } else {
  75. token.eos = state.expectVariable;
  76. }
  77. return token;
  78. };
  79. var nextComment = function(stream, context) {
  80. stream.eatWhile(/[^"]/);
  81. return new Token('comment', stream.eat('"') ? context.parent : context, true);
  82. };
  83. var nextString = function(stream, context) {
  84. stream.eatWhile(/[^']/);
  85. return new Token('string', stream.eat('\'') ? context.parent : context, false);
  86. };
  87. var nextSymbol = function(stream, context) {
  88. stream.eatWhile(/[^']/);
  89. return new Token('string-2', stream.eat('\'') ? context.parent : context, false);
  90. };
  91. var nextTemporaries = function(stream, context) {
  92. var token = new Token(null, context, false);
  93. var aChar = stream.next();
  94. if (aChar === '|') {
  95. token.context = context.parent;
  96. token.eos = true;
  97. } else {
  98. stream.eatWhile(/[^|]/);
  99. token.name = 'variable';
  100. }
  101. return token;
  102. };
  103. return {
  104. startState: function() {
  105. return new State;
  106. },
  107. token: function(stream, state) {
  108. state.userIndent(stream.indentation());
  109. if (stream.eatSpace()) {
  110. return null;
  111. }
  112. var token = state.context.next(stream, state.context, state);
  113. state.context = token.context;
  114. state.expectVariable = token.eos;
  115. return token.name;
  116. },
  117. blankLine: function(state) {
  118. state.userIndent(0);
  119. },
  120. indent: function(state, textAfter) {
  121. var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
  122. return (state.indentation + i) * config.indentUnit;
  123. },
  124. electricChars: ']'
  125. };
  126. });
  127. CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});
  128. });