1 |
|
2 |
|
3 |
|
4 |
|
5 |
|
6 |
|
7 |
|
8 | (function(mod) {
|
9 | if (typeof exports == "object" && typeof module == "object")
|
10 | mod(require("../../lib/codemirror"));
|
11 | else if (typeof define == "function" && define.amd)
|
12 | define(["../../lib/codemirror"], mod);
|
13 | else
|
14 | mod(CodeMirror);
|
15 | })(function(CodeMirror) {
|
16 | "use strict";
|
17 |
|
18 | CodeMirror.defineMode("scheme", function () {
|
19 | var BUILTIN = "builtin", COMMENT = "comment", STRING = "string",
|
20 | ATOM = "atom", NUMBER = "number", BRACKET = "bracket";
|
21 | var INDENT_WORD_SKIP = 2;
|
22 |
|
23 | function makeKeywords(str) {
|
24 | var obj = {}, words = str.split(" ");
|
25 | for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
|
26 | return obj;
|
27 | }
|
28 |
|
29 | var keywords = makeKeywords("λ case-lambda call/cc class define-class exit-handler field import inherit init-field interface let*-values let-values let/ec mixin opt-lambda override protect provide public rename require require-for-syntax syntax syntax-case syntax-error unit/sig unless when with-syntax and begin call-with-current-continuation call-with-input-file call-with-output-file case cond define define-syntax delay do dynamic-wind else for-each if lambda let let* let-syntax letrec letrec-syntax map or syntax-rules abs acos angle append apply asin assoc assq assv atan boolean? caar cadr call-with-input-file call-with-output-file call-with-values car cdddar cddddr cdr ceiling char->integer char-alphabetic? char-ci<=? char-ci<? char-ci=? char-ci>=? char-ci>? char-downcase char-lower-case? char-numeric? char-ready? char-upcase char-upper-case? char-whitespace? char<=? char<? char=? char>=? char>? char? close-input-port close-output-port complex? cons cos current-input-port current-output-port denominator display eof-object? eq? equal? eqv? eval even? exact->inexact exact? exp expt #f floor force gcd imag-part inexact->exact inexact? input-port? integer->char integer? interaction-environment lcm length list list->string list->vector list-ref list-tail list? load log magnitude make-polar make-rectangular make-string make-vector max member memq memv min modulo negative? newline not null-environment null? number->string number? numerator odd? open-input-file open-output-file output-port? pair? peek-char port? positive? procedure? quasiquote quote quotient rational? rationalize read read-char real-part real? remainder reverse round scheme-report-environment set! set-car! set-cdr! sin sqrt string string->list string->number string->symbol string-append string-ci<=? string-ci<? string-ci=? string-ci>=? string-ci>? string-copy string-fill! string-length string-ref string-set! string<=? string<? string=? string>=? string>? string? substring symbol->string symbol? #t tan transcript-off transcript-on truncate values vector vector->list vector-fill! vector-length vector-ref vector-set! with-input-from-file with-output-to-file write write-char zero?");
|
30 | var indentKeys = makeKeywords("define let letrec let* lambda");
|
31 |
|
32 | function stateStack(indent, type, prev) {
|
33 | this.indent = indent;
|
34 | this.type = type;
|
35 | this.prev = prev;
|
36 | }
|
37 |
|
38 | function pushStack(state, indent, type) {
|
39 | state.indentStack = new stateStack(indent, type, state.indentStack);
|
40 | }
|
41 |
|
42 | function popStack(state) {
|
43 | state.indentStack = state.indentStack.prev;
|
44 | }
|
45 |
|
46 | var binaryMatcher = new RegExp(/^(?:[-+]i|[-+][01]+#*(?:\/[01]+#*)?i|[-+]?[01]+#*(?:\/[01]+#*)?@[-+]?[01]+#*(?:\/[01]+#*)?|[-+]?[01]+#*(?:\/[01]+#*)?[-+](?:[01]+#*(?:\/[01]+#*)?)?i|[-+]?[01]+#*(?:\/[01]+#*)?)(?=[()\s;"]|$)/i);
|
47 | var octalMatcher = new RegExp(/^(?:[-+]i|[-+][0-7]+#*(?:\/[0-7]+#*)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?@[-+]?[0-7]+#*(?:\/[0-7]+#*)?|[-+]?[0-7]+#*(?:\/[0-7]+#*)?[-+](?:[0-7]+#*(?:\/[0-7]+#*)?)?i|[-+]?[0-7]+#*(?:\/[0-7]+#*)?)(?=[()\s;"]|$)/i);
|
48 | var hexMatcher = new RegExp(/^(?:[-+]i|[-+][\da-f]+#*(?:\/[\da-f]+#*)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?@[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?[-+](?:[\da-f]+#*(?:\/[\da-f]+#*)?)?i|[-+]?[\da-f]+#*(?:\/[\da-f]+#*)?)(?=[()\s;"]|$)/i);
|
49 | var decimalMatcher = new RegExp(/^(?:[-+]i|[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)i|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)@[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)|[-+]?(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)[-+](?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*)?i|(?:(?:(?:\d+#+\.?#*|\d+\.\d*#*|\.\d+#*|\d+)(?:[esfdl][-+]?\d+)?)|\d+#*\/\d+#*))(?=[()\s;"]|$)/i);
|
50 |
|
51 | function isBinaryNumber (stream) {
|
52 | return stream.match(binaryMatcher);
|
53 | }
|
54 |
|
55 | function isOctalNumber (stream) {
|
56 | return stream.match(octalMatcher);
|
57 | }
|
58 |
|
59 | function isDecimalNumber (stream, backup) {
|
60 | if (backup === true) {
|
61 | stream.backUp(1);
|
62 | }
|
63 | return stream.match(decimalMatcher);
|
64 | }
|
65 |
|
66 | function isHexNumber (stream) {
|
67 | return stream.match(hexMatcher);
|
68 | }
|
69 |
|
70 | return {
|
71 | startState: function () {
|
72 | return {
|
73 | indentStack: null,
|
74 | indentation: 0,
|
75 | mode: false,
|
76 | sExprComment: false,
|
77 | sExprQuote: false
|
78 | };
|
79 | },
|
80 |
|
81 | token: function (stream, state) {
|
82 | if (state.indentStack == null && stream.sol()) {
|
83 |
|
84 | state.indentation = stream.indentation();
|
85 | }
|
86 |
|
87 |
|
88 | if (stream.eatSpace()) {
|
89 | return null;
|
90 | }
|
91 | var returnType = null;
|
92 |
|
93 | switch(state.mode){
|
94 | case "string":
|
95 | var next, escaped = false;
|
96 | while ((next = stream.next()) != null) {
|
97 | if (next == "\"" && !escaped) {
|
98 |
|
99 | state.mode = false;
|
100 | break;
|
101 | }
|
102 | escaped = !escaped && next == "\\";
|
103 | }
|
104 | returnType = STRING;
|
105 | break;
|
106 | case "comment":
|
107 | var next, maybeEnd = false;
|
108 | while ((next = stream.next()) != null) {
|
109 | if (next == "#" && maybeEnd) {
|
110 |
|
111 | state.mode = false;
|
112 | break;
|
113 | }
|
114 | maybeEnd = (next == "|");
|
115 | }
|
116 | returnType = COMMENT;
|
117 | break;
|
118 | case "s-expr-comment":
|
119 | state.mode = false;
|
120 | if(stream.peek() == "(" || stream.peek() == "["){
|
121 |
|
122 | state.sExprComment = 0;
|
123 | }else{
|
124 |
|
125 | stream.eatWhile(/[^\s\(\)\[\]]/);
|
126 | returnType = COMMENT;
|
127 | break;
|
128 | }
|
129 | default:
|
130 | var ch = stream.next();
|
131 |
|
132 | if (ch == "\"") {
|
133 | state.mode = "string";
|
134 | returnType = STRING;
|
135 |
|
136 | } else if (ch == "'") {
|
137 | if (stream.peek() == "(" || stream.peek() == "["){
|
138 | if (typeof state.sExprQuote != "number") {
|
139 | state.sExprQuote = 0;
|
140 | }
|
141 | returnType = ATOM;
|
142 | } else {
|
143 | stream.eatWhile(/[\w_\-!$%&*+\.\/:<=>?@\^~]/);
|
144 | returnType = ATOM;
|
145 | }
|
146 | } else if (ch == '#') {
|
147 | if (stream.eat("|")) {
|
148 | state.mode = "comment";
|
149 | returnType = COMMENT;
|
150 | } else if (stream.eat(/[tf]/i)) {
|
151 | returnType = ATOM;
|
152 | } else if (stream.eat(';')) {
|
153 | state.mode = "s-expr-comment";
|
154 | returnType = COMMENT;
|
155 | } else {
|
156 | var numTest = null, hasExactness = false, hasRadix = true;
|
157 | if (stream.eat(/[ei]/i)) {
|
158 | hasExactness = true;
|
159 | } else {
|
160 | stream.backUp(1);
|
161 | }
|
162 | if (stream.match(/^#b/i)) {
|
163 | numTest = isBinaryNumber;
|
164 | } else if (stream.match(/^#o/i)) {
|
165 | numTest = isOctalNumber;
|
166 | } else if (stream.match(/^#x/i)) {
|
167 | numTest = isHexNumber;
|
168 | } else if (stream.match(/^#d/i)) {
|
169 | numTest = isDecimalNumber;
|
170 | } else if (stream.match(/^[-+0-9.]/, false)) {
|
171 | hasRadix = false;
|
172 | numTest = isDecimalNumber;
|
173 |
|
174 | } else if (!hasExactness) {
|
175 | stream.eat('#');
|
176 | }
|
177 | if (numTest != null) {
|
178 | if (hasRadix && !hasExactness) {
|
179 |
|
180 | stream.match(/^#[ei]/i);
|
181 | }
|
182 | if (numTest(stream))
|
183 | returnType = NUMBER;
|
184 | }
|
185 | }
|
186 | } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) {
|
187 | returnType = NUMBER;
|
188 | } else if (ch == ";") {
|
189 | stream.skipToEnd();
|
190 | returnType = COMMENT;
|
191 | } else if (ch == "(" || ch == "[") {
|
192 | var keyWord = ''; var indentTemp = stream.column(), letter;
|
193 | |
194 |
|
195 |
|
196 |
|
197 |
|
198 |
|
199 |
|
200 | while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) {
|
201 | keyWord += letter;
|
202 | }
|
203 |
|
204 | if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) {
|
205 |
|
206 | pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
|
207 | } else {
|
208 |
|
209 | stream.eatSpace();
|
210 | if (stream.eol() || stream.peek() == ";") {
|
211 |
|
212 |
|
213 | pushStack(state, indentTemp + 1, ch);
|
214 | } else {
|
215 | pushStack(state, indentTemp + stream.current().length, ch);
|
216 | }
|
217 | }
|
218 | stream.backUp(stream.current().length - 1);
|
219 |
|
220 | if(typeof state.sExprComment == "number") state.sExprComment++;
|
221 | if(typeof state.sExprQuote == "number") state.sExprQuote++;
|
222 |
|
223 | returnType = BRACKET;
|
224 | } else if (ch == ")" || ch == "]") {
|
225 | returnType = BRACKET;
|
226 | if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
|
227 | popStack(state);
|
228 |
|
229 | if(typeof state.sExprComment == "number"){
|
230 | if(--state.sExprComment == 0){
|
231 | returnType = COMMENT;
|
232 | state.sExprComment = false;
|
233 | }
|
234 | }
|
235 | if(typeof state.sExprQuote == "number"){
|
236 | if(--state.sExprQuote == 0){
|
237 | returnType = ATOM;
|
238 | state.sExprQuote = false;
|
239 | }
|
240 | }
|
241 | }
|
242 | } else {
|
243 | stream.eatWhile(/[\w_\-!$%&*+\.\/:<=>?@\^~]/);
|
244 |
|
245 | if (keywords && keywords.propertyIsEnumerable(stream.current())) {
|
246 | returnType = BUILTIN;
|
247 | } else returnType = "variable";
|
248 | }
|
249 | }
|
250 | return (typeof state.sExprComment == "number") ? COMMENT : ((typeof state.sExprQuote == "number") ? ATOM : returnType);
|
251 | },
|
252 |
|
253 | indent: function (state) {
|
254 | if (state.indentStack == null) return state.indentation;
|
255 | return state.indentStack.indent;
|
256 | },
|
257 |
|
258 | closeBrackets: {pairs: "()[]{}\"\""},
|
259 | lineComment: ";;"
|
260 | };
|
261 | });
|
262 |
|
263 | CodeMirror.defineMIME("text/x-scheme", "scheme");
|
264 |
|
265 | });
|