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 }