smalltalk.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. // CodeMirror, copyright (c) by Marijn Haverbeke and others
  2. // Distributed under an MIT license: https://codemirror.net/LICENSE
  3. ;(function (mod) {
  4. if (typeof exports == 'object' && typeof module == 'object')
  5. // CommonJS
  6. mod(require('../../lib/codemirror'))
  7. else if (typeof define == 'function' && define.amd)
  8. // AMD
  9. define(['../../lib/codemirror'], mod)
  10. // Plain browser env
  11. else mod(CodeMirror)
  12. })(function (CodeMirror) {
  13. 'use strict'
  14. CodeMirror.defineMode('smalltalk', function (config) {
  15. var specialChars = /[+\-\/\\*~<>=@%|&?!.,:;^]/
  16. var keywords = /true|false|nil|self|super|thisContext/
  17. var Context = function (tokenizer, parent) {
  18. this.next = tokenizer
  19. this.parent = parent
  20. }
  21. var Token = function (name, context, eos) {
  22. this.name = name
  23. this.context = context
  24. this.eos = eos
  25. }
  26. var State = function () {
  27. this.context = new Context(next, null)
  28. this.expectVariable = true
  29. this.indentation = 0
  30. this.userIndentationDelta = 0
  31. }
  32. State.prototype.userIndent = function (indentation) {
  33. this.userIndentationDelta = indentation > 0 ? indentation / config.indentUnit - this.indentation : 0
  34. }
  35. var next = function (stream, context, state) {
  36. var token = new Token(null, context, false)
  37. var aChar = stream.next()
  38. if (aChar === '"') {
  39. token = nextComment(stream, new Context(nextComment, context))
  40. } else if (aChar === "'") {
  41. token = nextString(stream, new Context(nextString, context))
  42. } else if (aChar === '#') {
  43. if (stream.peek() === "'") {
  44. stream.next()
  45. token = nextSymbol(stream, new Context(nextSymbol, context))
  46. } else {
  47. if (stream.eatWhile(/[^\s.{}\[\]()]/)) token.name = 'string-2'
  48. else 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. })