Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(192)

Unified Diff: frog/server/dart_json.dart

Issue 9374030: Move json to lib/json/{json.dart, json_frog.dart} (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: '' Created 8 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « frog/reader.dart ('k') | frog/server/frog_server.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: frog/server/dart_json.dart
===================================================================
--- frog/server/dart_json.dart (revision 4099)
+++ frog/server/dart_json.dart (working copy)
@@ -1,604 +0,0 @@
-// Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-#library("json");
-
-// TODO(devoncarew): this file is a copy of client/json/dart_json.dart and should be deleted as
-// soon as it is no longer referenced from frog_server.dart.
-
-// Pure Dart implementation of JSON protocol.
-
-/**
- * Utility class to parse JSON and serialize objects to JSON.
- */
-class JSON {
- /**
- * Parses [:json:] and build the corresponding object.
- */
- static parse(String json) {
- return JsonParser.parse(json);
- }
-
- /**
- * Serializes [:object:] into JSON string.
- */
- static String stringify(Object object) {
- return JsonStringifier.stringify(object);
- }
-}
-
-//// Implementation ///////////////////////////////////////////////////////////
-
-/**
- * Union-like class for JSON tokens.
- */
-class JsonToken {
- static final int STRING = 0;
- static final int NUMBER = 1;
- static final int NULL = 2;
- static final int FALSE = 3;
- static final int TRUE = 4;
- static final int RBRACKET = 5;
- static final int LBRACKET = 6;
- static final int RBRACE = 7;
- static final int LBRACE = 8;
- static final int COLON = 9;
- static final int COMMA = 10;
-
- final int kind;
- final String _s;
- final num _n;
-
- String get str() {
- assert(kind == STRING);
- return _s;
- }
-
- num get number() {
- assert(kind == NUMBER);
- return _n;
- }
-
- const JsonToken._internal(this.kind, this._s, this._n);
-
- factory JsonToken.string(String s) {
- return new JsonToken._internal(STRING, s, 0);
- }
- factory JsonToken.number(num n) {
- return new JsonToken._internal(NUMBER, '', n);
- }
- factory JsonToken.atom(int kind) {
- return new JsonToken._internal(kind, '', 0);
- }
-
- String toString() {
- switch (kind) {
- case STRING:
- return 'STRING(${str})';
-
- case NUMBER:
- return 'NUMBER(${number})';
-
- case NULL:
- return 'ATOM(null)';
-
- case FALSE:
- return 'ATOM(false)';
-
- case TRUE:
- return 'ATOM(true)';
-
- case RBRACKET:
- return 'ATOM(])';
-
- case LBRACKET:
- return 'ATOM([)';
-
- case RBRACE:
- return 'ATOM(})';
-
- case LBRACE:
- return 'ATOM({)';
-
- case COLON:
- return 'ATOM(:)';
-
- case COMMA:
- return 'ATOM(,)';
- }
- }
-}
-
-typedef bool Predicate(int c);
-
-class JsonTokenizer {
- static final int BACKSPACE = 8; // '\b'.charCodeAt(0)
- static final int TAB = 9; // '\t'.charCodeAt(0)
- static final int NEW_LINE = 10; // '\n'.charCodeAt(0)
- static final int FORM_FEED = 12; // '\f'.charCodeAt(0)
- static final int LINE_FEED = 13; // '\r'.charCodeAt(0)
- static final int SPACE = 32; // ' '.charCodeAt(0)
- static final int QUOTE = 34; // '"'.charCodeAt(0)
- static final int PLUS = 43; // '+'.charCodeAt(0)
- static final int COMMA = 44; // ','.charCodeAt(0)
- static final int MINUS = 45; // '-'.charCodeAt(0)
- static final int DOT = 46; // '.'.charCodeAt(0)
- static final int SLASH = 47; // '/'.charCodeAt(0)
- static final int ZERO = 48; // '0'.charCodeAt(0)
- static final int NINE = 57; // '9'.charCodeAt(0)
- static final int COLON = 58; // ':'.charCodeAt(0)
- static final int A_BIG = 65; // 'A'.charCodeAt(0)
- static final int E_BIG = 69; // 'E'.charCodeAt(0)
- static final int Z_BIG = 90; // 'Z'.charCodeAt(0)
- static final int LBRACKET = 91; // '['.charCodeAt(0)
- static final int BACKSLASH = 92; // '\\'.charCodeAt(0)
- static final int RBRACKET = 93; // ']'.charCodeAt(0)
- static final int A_SMALL = 97; // 'a'.charCodeAt(0)
- static final int B_SMALL = 98; // 'b'.charCodeAt(0)
- static final int E_SMALL = 101; // 'e'.charCodeAt(0)
- static final int N_SMALL = 110; // 'n'.charCodeAt(0)
- static final int R_SMALL = 114; // 'r'.charCodeAt(0)
- static final int Z_SMALL = 122; // 'z'.charCodeAt(0)
- static final int LBRACE = 123; // '{'.charCodeAt(0)
- static final int RBRACE = 125; // '}'.charCodeAt(0)
-
- JsonTokenizer(String s) : _s = s + ' ', _pos = 0, _len = s.length + 1 {}
-
- /**
- * Fetches next token or [:null:] if the stream has been exhausted.
- */
- JsonToken next() {
- while (_pos < _len && isWhitespace(_s.charCodeAt(_pos))) {
- _pos++;
- }
- if (_pos == _len) {
- return null;
- }
-
- final int cur = _s.charCodeAt(_pos);
- switch (true) {
- case cur == QUOTE:
- _pos++;
- List<int> charCodes = new List<int>();
- while (_pos < _len) {
- int c = _s.charCodeAt(_pos);
- if (c == QUOTE) {
- break;
- }
- if (c == BACKSLASH) {
- _pos++;
- if (_pos == _len) {
- throw '\\ at the end';
- }
-
- switch (_s[_pos]) {
- case '"':
- c = QUOTE;
- break;
- case '\\':
- c = BACKSLASH;
- break;
- case '/':
- c = SLASH;
- break;
- case 'b':
- c = BACKSPACE;
- break;
- case 'n':
- c = NEW_LINE;
- break;
- case 'r':
- c = LINE_FEED;
- break;
- case 'f':
- c = FORM_FEED;
- break;
- case 't':
- c = TAB;
- break;
- case 'u':
- if (_pos + 5 > _len) {
- throw 'Invalid unicode esacape sequence: \\' +
- _s.substring(_pos, _len);
- }
- final codeString = _s.substring(_pos + 1, _pos + 5);
- c = Math.parseInt('0x' + codeString);
- if (c >= 128) {
- // TODO(jmessery): the VM doesn't support 2-byte strings yet
- // see runtime/lib/string.cc:49
- // So instead we replace these characters with '?'
- c = '?'.charCodeAt(0);
- }
- _pos += 4;
- break;
- default:
- throw 'Invalid esacape sequence: \\' + _s[_pos];
- }
- }
- charCodes.add(c);
- _pos++;
- }
- if (_pos == _len) {
- throw 'Unmatched quote';
- }
-
- final String body = new String.fromCharCodes(charCodes);
- _pos++;
- return new JsonToken.string(body);
-
- case cur == MINUS || isDigit(cur):
- skipDigits() {
- _scanWhile((int c) => isDigit(c), 'Invalid number');
- }
-
- int c = cur;
- final int startPos = _pos;
- int value = 0;
- bool isNegative = false;
- if (c == MINUS) {
- isNegative = true;
- _pos++;
- c = _s.charCodeAt(_pos);
- }
- while (isDigit(c)) {
- value = value * 10 + c - ZERO;
- _pos++;
- c = _s.charCodeAt(_pos);
- }
-
- if (c != DOT) {
- if (c != E_SMALL && cur != E_BIG) {
- if (isNegative) value = -value;
- return new JsonToken.number(value);
- }
- } else {
- _pos++;
- skipDigits();
- c = _s.charCodeAt(_pos);
- }
-
- if (c == E_SMALL || c == E_BIG) {
- // TODO: consider keeping E+ as an integer.
- _pos++;
- c = _s.charCodeAt(_pos);
- if (c == PLUS || c == MINUS) {
- _pos++;
- }
- skipDigits();
- }
-
- final String body = _s.substring(startPos, _pos);
- return new JsonToken.number(Math.parseDouble(body));
-
- case cur == LBRACE:
- _pos++;
- return new JsonToken.atom(JsonToken.LBRACE);
-
- case cur == RBRACE:
- _pos++;
- return new JsonToken.atom(JsonToken.RBRACE);
-
- case cur == LBRACKET:
- _pos++;
- return new JsonToken.atom(JsonToken.LBRACKET);
-
- case cur == RBRACKET:
- _pos++;
- return new JsonToken.atom(JsonToken.RBRACKET);
-
- case cur == COMMA:
- _pos++;
- return new JsonToken.atom(JsonToken.COMMA);
-
- case cur == COLON:
- _pos++;
- return new JsonToken.atom(JsonToken.COLON);
-
- case isLetter(cur):
- final int startPos = _pos;
- _pos++;
- while (_pos < _len && isLetter(_s.charCodeAt(_pos))) {
- _pos++;
- }
- final String body = _s.substring(startPos, _pos);
- switch (body) {
- case 'null':
- return new JsonToken.atom(JsonToken.NULL);
-
- case 'false':
- return new JsonToken.atom(JsonToken.FALSE);
-
- case 'true':
- return new JsonToken.atom(JsonToken.TRUE);
-
- default:
- throw 'Unexpected sequence ${body}';
- }
- // TODO: Bogous, to please DartVM.
- return null;
-
- default:
- throw 'Invalid token';
- }
- }
-
- final String _s;
- int _pos;
- final int _len;
-
- void _scanWhile(Predicate predicate, String errorMsg) {
- while (_pos < _len && predicate(_s.charCodeAt(_pos))) {
- _pos++;
- }
- if (_pos == _len) {
- throw errorMsg;
- }
- }
-
- // TODO other kind of whitespace.
- static bool isWhitespace(int c) {
- return c == SPACE || c == TAB || c == NEW_LINE || c == LINE_FEED;
- }
- static bool isDigit(int c) {
- return (ZERO <= c) && (c <= NINE);
- }
- static bool isLetter(int c) {
- return ((A_SMALL <= c) && (c <= Z_SMALL)) || ((A_BIG <= c) && (c <= Z_BIG));
- }
-}
-
-class JsonParser {
- static parse(String json) {
- return new JsonParser._internal(json)._parseToplevel();
- }
-
- final JsonTokenizer _tokenizer;
-
- JsonParser._internal(String json) : _tokenizer = new JsonTokenizer(json) {}
-
- _parseToplevel() {
- JsonToken token = _tokenizer.next();
- final result = _parseValue(token);
- token = _tokenizer.next();
- if (token !== null) {
- throw 'Junk at the end';
- }
- return result;
- }
-
- _parseValue(final JsonToken token) {
- if (token === null) {
- throw 'Nothing to parse';
- }
- switch (token.kind) {
- case JsonToken.STRING:
- return token.str;
-
- case JsonToken.NUMBER:
- return token.number;
-
- case JsonToken.NULL:
- return null;
-
- case JsonToken.FALSE:
- return false;
-
- case JsonToken.TRUE:
- return true;
-
- case JsonToken.LBRACE:
- return _parseObject();
-
- case JsonToken.LBRACKET:
- return _parseList();
-
- default:
- throw 'Unexpected token: ${token}';
- }
- }
-
- _parseObject() {
- Map<String, Object> object = new Map<String, Object>();
-
- _parseSequence(JsonToken.RBRACE, (JsonToken token) {
- _assertTokenKind(token, JsonToken.STRING);
- final String key = token.str;
-
- token = _tokenizer.next();
- _assertTokenKind(token, JsonToken.COLON);
-
- token = _tokenizer.next();
- final value = _parseValue(token);
-
- object[key] = value;
- });
-
- return object;
- }
-
- _parseList() {
- List<Object> list = new List<Object>();
-
- _parseSequence(JsonToken.RBRACKET, (JsonToken token) {
- final value = _parseValue(token);
- list.add(value);
- });
-
- return list;
- }
-
- void _parseSequence(int endTokenKind, void parseElement(JsonToken token)) {
- JsonToken token = _tokenizer.next();
- if (token === null) {
- throw 'Unexpected end of stream';
- }
- if (token.kind == endTokenKind) {
- return;
- }
-
- parseElement(token);
-
- token = _tokenizer.next();
- if (token === null) {
- throw 'Expected either comma or terminator';
- }
- while (token.kind != endTokenKind) {
- _assertTokenKind(token, JsonToken.COMMA);
-
- token = _tokenizer.next();
- parseElement(token);
-
- token = _tokenizer.next();
- }
- }
-
- void _assertTokenKind(JsonToken token, int kind) {
- if (token === null || token.kind != kind) {
- throw 'Unexpected token kind: token = ${token}, expected kind = ${kind}';
- }
- }
-
- // TODO: consider factor out error throwing code and build more complicated
- // data structure to provide more info for a caller.
-}
-
-// TODO: proper base class.
-class JsonUnsupportedObjectType {
- const JsonUnsupportedObjectType();
-}
-
-class JsonStringifier {
- static String stringify(final object) {
- JsonStringifier stringifier = new JsonStringifier._internal();
- stringifier._stringify(object);
- return stringifier._result;
- }
-
- JsonStringifier._internal()
- : _sb = new StringBuffer(), _seen = new List<Object>() {}
- StringBuffer _sb;
- List<Object> _seen; // TODO: that should be identity set.
- String get _result() { return _sb.toString(); }
-
- static String _numberToString(num x) {
- // TODO: need some more investigation what to do with precision
- // of double values.
- switch (true) {
- case x is int:
- return x.toString();
-
- case x is double:
- return x.toString();
-
- default:
- return x.toDouble().toString();
- }
- }
-
- // TODO: add others.
- static bool _needsEscape(int charCode) {
- return JsonTokenizer.QUOTE == charCode || JsonTokenizer.BACKSLASH == charCode
- || JsonTokenizer.NEW_LINE == charCode || JsonTokenizer.LINE_FEED == charCode;
- }
-
- static void _escape(StringBuffer sb, String s) {
- // TODO: support \u code points.
- // TODO: use writeCodePoint when implemented.
- // TODO: use for each if implemented.
- final int length = s.length;
- bool needsEscape = false;
- final charCodes = new List<int>();
- for (int i = 0; i < length; i++) {
- int charCode = s.charCodeAt(i);
- if (_needsEscape(charCode)) {
- charCodes.add(JsonTokenizer.BACKSLASH);
- needsEscape = true;
-
- if (JsonTokenizer.NEW_LINE == charCode) {
- charCode = JsonTokenizer.N_SMALL;
- } else if (JsonTokenizer.LINE_FEED == charCode) {
- charCode = JsonTokenizer.R_SMALL;
- }
- }
- charCodes.add(charCode);
- }
- sb.add(needsEscape ? new String.fromCharCodes(charCodes) : s);
- }
-
- void _checkCycle(final object) {
- // TODO: use Iterables.
- for (int i = 0; i < _seen.length; i++) {
- if (_seen[i] === object) {
- throw 'Cyclic structure';
- }
- }
- _seen.add(object);
- }
-
- void _stringify(final object) {
- switch (true) {
- case object is num:
- // TODO: use writeOn.
- _sb.add(_numberToString(object));
- return;
-
- case object === true:
- _sb.add('true');
- return;
-
- case object === false:
- _sb.add('false');
- return;
-
- case object === null:
- _sb.add('null');
- return;
-
- case object is String:
- _sb.add('"');
- _escape(_sb, object);
- _sb.add('"');
- return;
-
- case object is List:
- _checkCycle(object);
- List a = object;
- _sb.add('[');
- if (a.length > 0) {
- _stringify(a[0]);
- // TODO: switch to Iterables.
- for (int i = 1; i < a.length; i++) {
- _sb.add(',');
- _stringify(a[i]);
- }
- }
- _sb.add(']');
- _seen.removeLast();
- return;
-
- case object is Map:
- _checkCycle(object);
- Map<String, Object> m = object;
- _sb.add('{');
- bool first = true;
- m.forEach((String key, Object value) {
- if (!first) {
- _sb.add(',"');
- } else {
- _sb.add('"');
- }
- _escape(_sb, key);
- _sb.add('":');
- _stringify(value);
- first = false;
- });
- _sb.add('}');
- _seen.removeLast();
- return;
-
- default:
- throw const JsonUnsupportedObjectType();
- }
- }
-}
« no previous file with comments | « frog/reader.dart ('k') | frog/server/frog_server.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698