smalltalk.js 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. CodeMirror.defineMode('smalltalk', function(config) {
  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. if (stream.next() === '<') {
  34. stream.eatWhile(/[^ >]/);
  35. stream.next();
  36. }
  37. token.name = 'string-2';
  38. } else if (aChar === '|' && state.expectVariable) {
  39. token.context = new Context(nextTemporaries, context);
  40. } else if (/[\[\]{}()]/.test(aChar)) {
  41. token.name = 'bracket';
  42. token.eos = /[\[{(]/.test(aChar);
  43. if (aChar === '[') {
  44. state.indentation++;
  45. } else if (aChar === ']') {
  46. state.indentation = Math.max(0, state.indentation - 1);
  47. }
  48. } else if (specialChars.test(aChar)) {
  49. stream.eatWhile(specialChars);
  50. token.name = 'operator';
  51. token.eos = aChar !== ';'; // ; cascaded message expression
  52. } else if (/\d/.test(aChar)) {
  53. stream.eatWhile(/[\w\d]/);
  54. token.name = 'number';
  55. } else if (/[\w_]/.test(aChar)) {
  56. stream.eatWhile(/[\w\d_]/);
  57. token.name = state.expectVariable ? (keywords.test(stream.current()) ? 'keyword' : 'variable') : null;
  58. } else {
  59. token.eos = state.expectVariable;
  60. }
  61. return token;
  62. };
  63. var nextComment = function(stream, context) {
  64. stream.eatWhile(/[^"]/);
  65. return new Token('comment', stream.eat('"') ? context.parent : context, true);
  66. };
  67. var nextString = function(stream, context) {
  68. stream.eatWhile(/[^']/);
  69. return new Token('string', stream.eat('\'') ? context.parent : context, false);
  70. };
  71. var nextTemporaries = function(stream, context) {
  72. var token = new Token(null, context, false);
  73. var aChar = stream.next();
  74. if (aChar === '|') {
  75. token.context = context.parent;
  76. token.eos = true;
  77. } else {
  78. stream.eatWhile(/[^|]/);
  79. token.name = 'variable';
  80. }
  81. return token;
  82. };
  83. return {
  84. startState: function() {
  85. return new State;
  86. },
  87. token: function(stream, state) {
  88. state.userIndent(stream.indentation());
  89. if (stream.eatSpace()) {
  90. return null;
  91. }
  92. var token = state.context.next(stream, state.context, state);
  93. state.context = token.context;
  94. state.expectVariable = token.eos;
  95. return token.name;
  96. },
  97. blankLine: function(state) {
  98. state.userIndent(0);
  99. },
  100. indent: function(state, textAfter) {
  101. var i = state.context.next === next && textAfter && textAfter.charAt(0) === ']' ? -1 : state.userIndentationDelta;
  102. return (state.indentation + i) * config.indentUnit;
  103. },
  104. electricChars: ']'
  105. };
  106. });
  107. CodeMirror.defineMIME('text/x-stsrc', {name: 'smalltalk'});