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