openrat-cms

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README

scheme.js (13437B)


      1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
      2 // Distributed under an MIT license: http://codemirror.net/LICENSE
      3 
      4 /**
      5  * Author: Koh Zi Han, based on implementation by Koh Zi Chun
      6  */
      7 
      8 (function(mod) {
      9   if (typeof exports == "object" && typeof module == "object") // CommonJS
     10     mod(require("../../lib/codemirror"));
     11   else if (typeof define == "function" && define.amd) // AMD
     12     define(["../../lib/codemirror"], mod);
     13   else // Plain browser env
     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) { // represents a state stack object
     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             };
     78         },
     79 
     80         token: function (stream, state) {
     81             if (state.indentStack == null && stream.sol()) {
     82                 // update indentation, but only if indentStack is empty
     83                 state.indentation = stream.indentation();
     84             }
     85 
     86             // skip spaces
     87             if (stream.eatSpace()) {
     88                 return null;
     89             }
     90             var returnType = null;
     91 
     92             switch(state.mode){
     93                 case "string": // multi-line string parsing mode
     94                     var next, escaped = false;
     95                     while ((next = stream.next()) != null) {
     96                         if (next == "\"" && !escaped) {
     97 
     98                             state.mode = false;
     99                             break;
    100                         }
    101                         escaped = !escaped && next == "\\";
    102                     }
    103                     returnType = STRING; // continue on in scheme-string mode
    104                     break;
    105                 case "comment": // comment parsing mode
    106                     var next, maybeEnd = false;
    107                     while ((next = stream.next()) != null) {
    108                         if (next == "#" && maybeEnd) {
    109 
    110                             state.mode = false;
    111                             break;
    112                         }
    113                         maybeEnd = (next == "|");
    114                     }
    115                     returnType = COMMENT;
    116                     break;
    117                 case "s-expr-comment": // s-expr commenting mode
    118                     state.mode = false;
    119                     if(stream.peek() == "(" || stream.peek() == "["){
    120                         // actually start scheme s-expr commenting mode
    121                         state.sExprComment = 0;
    122                     }else{
    123                         // if not we just comment the entire of the next token
    124                         stream.eatWhile(/[^/s]/); // eat non spaces
    125                         returnType = COMMENT;
    126                         break;
    127                     }
    128                 default: // default parsing mode
    129                     var ch = stream.next();
    130 
    131                     if (ch == "\"") {
    132                         state.mode = "string";
    133                         returnType = STRING;
    134 
    135                     } else if (ch == "'") {
    136                         returnType = ATOM;
    137                     } else if (ch == '#') {
    138                         if (stream.eat("|")) {                    // Multi-line comment
    139                             state.mode = "comment"; // toggle to comment mode
    140                             returnType = COMMENT;
    141                         } else if (stream.eat(/[tf]/i)) {            // #t/#f (atom)
    142                             returnType = ATOM;
    143                         } else if (stream.eat(';')) {                // S-Expr comment
    144                             state.mode = "s-expr-comment";
    145                             returnType = COMMENT;
    146                         } else {
    147                             var numTest = null, hasExactness = false, hasRadix = true;
    148                             if (stream.eat(/[ei]/i)) {
    149                                 hasExactness = true;
    150                             } else {
    151                                 stream.backUp(1);       // must be radix specifier
    152                             }
    153                             if (stream.match(/^#b/i)) {
    154                                 numTest = isBinaryNumber;
    155                             } else if (stream.match(/^#o/i)) {
    156                                 numTest = isOctalNumber;
    157                             } else if (stream.match(/^#x/i)) {
    158                                 numTest = isHexNumber;
    159                             } else if (stream.match(/^#d/i)) {
    160                                 numTest = isDecimalNumber;
    161                             } else if (stream.match(/^[-+0-9.]/, false)) {
    162                                 hasRadix = false;
    163                                 numTest = isDecimalNumber;
    164                             // re-consume the intial # if all matches failed
    165                             } else if (!hasExactness) {
    166                                 stream.eat('#');
    167                             }
    168                             if (numTest != null) {
    169                                 if (hasRadix && !hasExactness) {
    170                                     // consume optional exactness after radix
    171                                     stream.match(/^#[ei]/i);
    172                                 }
    173                                 if (numTest(stream))
    174                                     returnType = NUMBER;
    175                             }
    176                         }
    177                     } else if (/^[-+0-9.]/.test(ch) && isDecimalNumber(stream, true)) { // match non-prefixed number, must be decimal
    178                         returnType = NUMBER;
    179                     } else if (ch == ";") { // comment
    180                         stream.skipToEnd(); // rest of the line is a comment
    181                         returnType = COMMENT;
    182                     } else if (ch == "(" || ch == "[") {
    183                       var keyWord = ''; var indentTemp = stream.column(), letter;
    184                         /**
    185                         Either
    186                         (indent-word ..
    187                         (non-indent-word ..
    188                         (;something else, bracket, etc.
    189                         */
    190 
    191                         while ((letter = stream.eat(/[^\s\(\[\;\)\]]/)) != null) {
    192                             keyWord += letter;
    193                         }
    194 
    195                         if (keyWord.length > 0 && indentKeys.propertyIsEnumerable(keyWord)) { // indent-word
    196 
    197                             pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
    198                         } else { // non-indent word
    199                             // we continue eating the spaces
    200                             stream.eatSpace();
    201                             if (stream.eol() || stream.peek() == ";") {
    202                                 // nothing significant after
    203                                 // we restart indentation 1 space after
    204                                 pushStack(state, indentTemp + 1, ch);
    205                             } else {
    206                                 pushStack(state, indentTemp + stream.current().length, ch); // else we match
    207                             }
    208                         }
    209                         stream.backUp(stream.current().length - 1); // undo all the eating
    210 
    211                         if(typeof state.sExprComment == "number") state.sExprComment++;
    212 
    213                         returnType = BRACKET;
    214                     } else if (ch == ")" || ch == "]") {
    215                         returnType = BRACKET;
    216                         if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : "[")) {
    217                             popStack(state);
    218 
    219                             if(typeof state.sExprComment == "number"){
    220                                 if(--state.sExprComment == 0){
    221                                     returnType = COMMENT; // final closing bracket
    222                                     state.sExprComment = false; // turn off s-expr commenting mode
    223                                 }
    224                             }
    225                         }
    226                     } else {
    227                         stream.eatWhile(/[\w_\-!$%&*+\.\/:<=>?@\^~]/);
    228 
    229                         if (keywords && keywords.propertyIsEnumerable(stream.current())) {
    230                             returnType = BUILTIN;
    231                         } else returnType = "variable";
    232                     }
    233             }
    234             return (typeof state.sExprComment == "number") ? COMMENT : returnType;
    235         },
    236 
    237         indent: function (state) {
    238             if (state.indentStack == null) return state.indentation;
    239             return state.indentStack.indent;
    240         },
    241 
    242         closeBrackets: {pairs: "()[]{}\"\""},
    243         lineComment: ";;"
    244     };
    245 });
    246 
    247 CodeMirror.defineMIME("text/x-scheme", "scheme");
    248 
    249 });