svgui/pyjs/lib/json.js
changeset 728 e0424e96e3fd
parent 721 ecf4d203c4d4
equal deleted inserted replaced
727:3edd2f19bce2 728:e0424e96e3fd
       
     1 json_parse = (function () {
       
     2 
       
     3 // This is a function that can parse a JSON text, producing a JavaScript
       
     4 // data structure. It is a simple, recursive descent parser. It does not use
       
     5 // eval or regular expressions, so it can be used as a model for implementing
       
     6 // a JSON parser in other languages.
       
     7 
       
     8 // We are defining the function inside of another function to avoid creating
       
     9 // global variables.
       
    10 
       
    11     var at,     // The index of the current character
       
    12         ch,     // The current character
       
    13         escapee = {
       
    14             '"':  '"',
       
    15             '\\': '\\',
       
    16             '/':  '/',
       
    17             b:    '\b',
       
    18             f:    '\f',
       
    19             n:    '\n',
       
    20             r:    '\r',
       
    21             t:    '\t'
       
    22         },
       
    23         text,
       
    24 
       
    25         error = function (m) {
       
    26 
       
    27 // Call error when something is wrong.
       
    28 
       
    29             throw {
       
    30                 name:    'SyntaxError',
       
    31                 message: m,
       
    32                 at:      at,
       
    33                 text:    text
       
    34             };
       
    35         },
       
    36 
       
    37         next = function (c) {
       
    38 
       
    39 // If a c parameter is provided, verify that it matches the current character.
       
    40 
       
    41             if (c && c !== ch) {
       
    42                 error("Expected '" + c + "' instead of '" + ch + "'");
       
    43             }
       
    44 
       
    45 // Get the next character. When there are no more characters,
       
    46 // return the empty string.
       
    47 
       
    48             ch = text.charAt(at);
       
    49             at += 1;
       
    50             return ch;
       
    51         },
       
    52 
       
    53         number = function () {
       
    54 
       
    55 // Parse a number value.
       
    56 
       
    57             var number,
       
    58                 string = '';
       
    59 
       
    60             if (ch === '-') {
       
    61                 string = '-';
       
    62                 next('-');
       
    63             }
       
    64             while (ch >= '0' && ch <= '9') {
       
    65                 string += ch;
       
    66                 next();
       
    67             }
       
    68             if (ch === '.') {
       
    69                 string += '.';
       
    70                 while (next() && ch >= '0' && ch <= '9') {
       
    71                     string += ch;
       
    72                 }
       
    73             }
       
    74             if (ch === 'e' || ch === 'E') {
       
    75                 string += ch;
       
    76                 next();
       
    77                 if (ch === '-' || ch === '+') {
       
    78                     string += ch;
       
    79                     next();
       
    80                 }
       
    81                 while (ch >= '0' && ch <= '9') {
       
    82                     string += ch;
       
    83                     next();
       
    84                 }
       
    85             }
       
    86             number = +string;
       
    87             if (isNaN(number)) {
       
    88                 error("Bad number");
       
    89             } else {
       
    90                 return number;
       
    91             }
       
    92         },
       
    93 
       
    94         string = function () {
       
    95 
       
    96 // Parse a string value.
       
    97 
       
    98             var hex,
       
    99                 i,
       
   100                 string = '',
       
   101                 uffff;
       
   102 
       
   103 // When parsing for string values, we must look for " and \ characters.
       
   104 
       
   105             if (ch === '"') {
       
   106                 while (next()) {
       
   107                     if (ch === '"') {
       
   108                         next();
       
   109                         return string;
       
   110                     } else if (ch === '\\') {
       
   111                         next();
       
   112                         if (ch === 'u') {
       
   113                             uffff = 0;
       
   114                             for (i = 0; i < 4; i += 1) {
       
   115                                 hex = parseInt(next(), 16);
       
   116                                 if (!isFinite(hex)) {
       
   117                                     break;
       
   118                                 }
       
   119                                 uffff = uffff * 16 + hex;
       
   120                             }
       
   121                             string += String.fromCharCode(uffff);
       
   122                         } else if (typeof escapee[ch] === 'string') {
       
   123                             string += escapee[ch];
       
   124                         } else {
       
   125                             break;
       
   126                         }
       
   127                     } else {
       
   128                         string += ch;
       
   129                     }
       
   130                 }
       
   131             }
       
   132             error("Bad string");
       
   133         },
       
   134 
       
   135         white = function () {
       
   136 
       
   137 // Skip whitespace.
       
   138 
       
   139             while (ch && ch <= ' ') {
       
   140                 next();
       
   141             }
       
   142         },
       
   143 
       
   144         word = function () {
       
   145 
       
   146 // true, false, or null.
       
   147 
       
   148             switch (ch) {
       
   149             case 't':
       
   150                 next('t');
       
   151                 next('r');
       
   152                 next('u');
       
   153                 next('e');
       
   154                 return true;
       
   155             case 'f':
       
   156                 next('f');
       
   157                 next('a');
       
   158                 next('l');
       
   159                 next('s');
       
   160                 next('e');
       
   161                 return false;
       
   162             case 'n':
       
   163                 next('n');
       
   164                 next('u');
       
   165                 next('l');
       
   166                 next('l');
       
   167                 return null;
       
   168             }
       
   169             error("Unexpected '" + ch + "'");
       
   170         },
       
   171 
       
   172         value,  // Place holder for the value function.
       
   173 
       
   174         array = function () {
       
   175 
       
   176 // Parse an array value.
       
   177 
       
   178             var array = [];
       
   179 
       
   180             if (ch === '[') {
       
   181                 next('[');
       
   182                 white();
       
   183                 if (ch === ']') {
       
   184                     next(']');
       
   185                     return array;   // empty array
       
   186                 }
       
   187                 while (ch) {
       
   188                     array.push(value());
       
   189                     white();
       
   190                     if (ch === ']') {
       
   191                         next(']');
       
   192                         return array;
       
   193                     }
       
   194                     next(',');
       
   195                     white();
       
   196                 }
       
   197             }
       
   198             error("Bad array");
       
   199         },
       
   200 
       
   201         object = function () {
       
   202 
       
   203 // Parse an object value.
       
   204 
       
   205             var key,
       
   206                 object = {};
       
   207 
       
   208             if (ch === '{') {
       
   209                 next('{');
       
   210                 white();
       
   211                 if (ch === '}') {
       
   212                     next('}');
       
   213                     return object;   // empty object
       
   214                 }
       
   215                 while (ch) {
       
   216                     key = string();
       
   217                     white();
       
   218                     next(':');
       
   219                     if (Object.hasOwnProperty.call(object, key)) {
       
   220                         error('Duplicate key "' + key + '"');
       
   221                     }
       
   222                     object[key] = value();
       
   223                     white();
       
   224                     if (ch === '}') {
       
   225                         next('}');
       
   226                         return object;
       
   227                     }
       
   228                     next(',');
       
   229                     white();
       
   230                 }
       
   231             }
       
   232             error("Bad object");
       
   233         };
       
   234 
       
   235     value = function () {
       
   236 
       
   237 // Parse a JSON value. It could be an object, an array, a string, a number,
       
   238 // or a word.
       
   239 
       
   240         white();
       
   241         switch (ch) {
       
   242         case '{':
       
   243             return object();
       
   244         case '[':
       
   245             return array();
       
   246         case '"':
       
   247             return string();
       
   248         case '-':
       
   249             return number();
       
   250         default:
       
   251             return ch >= '0' && ch <= '9' ? number() : word();
       
   252         }
       
   253     };
       
   254 
       
   255 // Return the json_parse function. It will have access to all of the above
       
   256 // functions and variables.
       
   257 
       
   258     return function (source, reviver) {
       
   259         var result;
       
   260 
       
   261         text = source;
       
   262         at = 0;
       
   263         ch = ' ';
       
   264         result = value();
       
   265         white();
       
   266         if (ch) {
       
   267             error("Syntax error");
       
   268         }
       
   269 
       
   270 // If there is a reviver function, we recursively walk the new structure,
       
   271 // passing each name/value pair to the reviver function for possible
       
   272 // transformation, starting with a temporary root object that holds the result
       
   273 // in an empty key. If there is not a reviver function, we simply return the
       
   274 // result.
       
   275 
       
   276         return typeof reviver === 'function' ? (function walk(holder, key) {
       
   277             var k, v, value = holder[key];
       
   278             if (value && typeof value === 'object') {
       
   279                 for (k in value) {
       
   280                     if (Object.hasOwnProperty.call(value, k)) {
       
   281                         v = walk(value, k);
       
   282                         if (v !== undefined) {
       
   283                             value[k] = v;
       
   284                         } else {
       
   285                             delete value[k];
       
   286                         }
       
   287                     }
       
   288                 }
       
   289             }
       
   290             return reviver.call(holder, key, value);
       
   291         }({'': result}, '')) : result;
       
   292     };
       
   293 }());