1 module config.jsonparser; 2 3 import source.jsonlexer; 4 import source.parserutil; 5 6 import config.value; 7 8 Value parseJSON(ref JsonLexer lexer) { 9 lexer.match(TokenType.Begin); 10 11 auto ret = lexer.parseJsonValue(); 12 13 if (lexer.front.type != TokenType.End) { 14 // There are leftovers, error? 15 } 16 17 return ret; 18 } 19 20 unittest { 21 import source.context; 22 auto context = new Context(); 23 24 auto testJSON(string s) { 25 import source.name, source.location; 26 auto base = context.registerMixin(Location.init, s ~ '\0'); 27 auto lexer = lex(base, context); 28 return lexer.parseJSON(); 29 } 30 31 Value[] emptyArray; 32 Value[string] emptyObject; 33 34 assert(testJSON("null") == null); 35 assert(testJSON("true") == true); 36 assert(testJSON("false") == false); 37 assert(testJSON(`""`) == ""); 38 assert(testJSON(`''`) == ""); 39 assert(testJSON(`"pouic"`) == "pouic"); 40 assert(testJSON(`'"'`) == "\""); 41 assert(testJSON(`0`) == 0); 42 assert(testJSON(`1`) == 1); 43 assert(testJSON(`0x42`) == 0x42); 44 assert(testJSON(`0b10101`) == 21); 45 assert(testJSON(`[]`) == emptyArray); 46 assert(testJSON(`[true, false]`) == [true, false]); 47 assert(testJSON(`["foo", 'bar']`) == ["foo", "bar"]); 48 assert(testJSON(`["fizz", 'buzz',]`) == ["fizz", "buzz"]); 49 assert(testJSON(`["Dave", null]`) == [Value("Dave"), Value(null)]); 50 assert(testJSON(`{}`) == emptyObject); 51 52 assert(testJSON(`{foo: true, bar: false}`) == ["foo": true, "bar": false]); 53 assert(testJSON(`{x: true, "y": false, 'z': null}`) == [ 54 "x": Value(true), 55 "y": Value(false), 56 "z": Value(null), 57 ]); 58 } 59 60 Value parseJsonValue(ref JsonLexer lexer) { 61 auto t = lexer.front; 62 63 switch (t.type) with (TokenType) { 64 case Null: 65 lexer.popFront(); 66 return Value(null); 67 68 case True: 69 lexer.popFront(); 70 return Value(true); 71 72 case False: 73 lexer.popFront(); 74 return Value(false); 75 76 case StringLiteral: 77 lexer.popFront(); 78 return Value(t.name.toString(lexer.context)); 79 80 case IntegerLiteral: 81 lexer.popFront(); 82 83 import source.strtoint; 84 return Value(strToInt(t.toString(lexer.context))); 85 86 case FloatLiteral: 87 assert(0, "Not implemented"); 88 89 case OpenBracket: 90 return lexer.parseJsonArray(); 91 92 case OpenBrace: 93 return lexer.parseJsonObject(); 94 95 default: 96 // TODO: actually handle this. 97 lexer.match(Begin); 98 assert(0,"Expected JSON value"); 99 } 100 } 101 102 Value parseJsonArray(ref JsonLexer lexer) { 103 lexer.match(TokenType.OpenBracket); 104 105 Value[] values; 106 while (lexer.front.type != TokenType.CloseBracket) { 107 values ~= lexer.parseJsonValue(); 108 if (lexer.front.type != TokenType.Comma) { 109 break; 110 } 111 112 lexer.popFront(); 113 } 114 115 lexer.match(TokenType.CloseBracket); 116 return Value(values); 117 } 118 119 Value parseJsonObject(ref JsonLexer lexer) { 120 lexer.match(TokenType.OpenBrace); 121 122 Value[string] values; 123 while (lexer.front.type != TokenType.CloseBrace) { 124 auto location = lexer.front.location; 125 auto type = lexer.front.type; 126 127 if (type != TokenType.Identifier && type != TokenType.StringLiteral) { 128 import source.exception; 129 throw new CompileException(location, "Expected an identifier or a string"); 130 } 131 132 auto name = lexer.front.name; 133 auto key = name.toString(lexer.context); 134 135 lexer.popFront(); 136 lexer.match(TokenType.Colon); 137 138 values[key] = lexer.parseJsonValue(); 139 if (lexer.front.type != TokenType.Comma) { 140 break; 141 } 142 143 lexer.popFront(); 144 } 145 146 lexer.match(TokenType.CloseBrace); 147 return Value(values); 148 }