smalltalk.js 3.4 KB

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