smalltalk.js 4.4 KB

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