Mercurial > pub > ImplabNet
comparison Implab/JSON/JSONParser.cs @ 55:c0bf853aa04f
Added initial JSON support
+JSONParser
+JSONWriter
author | cin |
---|---|
date | Sun, 15 Jun 2014 19:39:11 +0400 |
parents | |
children | 7759c80cad95 |
comparison
equal
deleted
inserted
replaced
51:2c332a9c64c0 | 55:c0bf853aa04f |
---|---|
1 using Implab; | |
2 using Implab.Parsing; | |
3 using System; | |
4 using System.Collections.Generic; | |
5 using System.Diagnostics; | |
6 using System.Linq; | |
7 using System.Text; | |
8 using System.Threading.Tasks; | |
9 | |
10 namespace Implab.JSON { | |
11 /// <summary> | |
12 /// internal | |
13 /// </summary> | |
14 public struct JSONParserContext { | |
15 public string memberName; | |
16 public JSONElementContext elementContext; | |
17 } | |
18 | |
19 /// <summary> | |
20 /// Pull парсер JSON данных. | |
21 /// </summary> | |
22 public class JSONParser : DFAutomaton<JSONParserContext> { | |
23 | |
24 enum MemberContext { | |
25 MemberName, | |
26 MemberValue | |
27 } | |
28 | |
29 static readonly EnumAlphabet<JsonTokenType> _alphabet = EnumAlphabet<JsonTokenType>.FullAlphabet; | |
30 static readonly DFAStateDescriptior[] _jsonDFA; | |
31 static readonly DFAStateDescriptior[] _objectDFA; | |
32 static readonly DFAStateDescriptior[] _arrayDFA; | |
33 | |
34 static JSONParser() { | |
35 var jsonExpression = Token.New(JsonTokenType.BeginObject, JsonTokenType.BeginArray).Tag(0); | |
36 | |
37 var valueExpression = Token.New(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String); | |
38 var memberExpression = Token.New(JsonTokenType.String).Cat(Token.New(JsonTokenType.NameSeparator)).Cat(valueExpression); | |
39 var objectExpression = memberExpression | |
40 .Cat( | |
41 Token.New(JsonTokenType.ValueSeparator) | |
42 .Cat(memberExpression) | |
43 .EClosure() | |
44 ) | |
45 .Optional() | |
46 .Cat(Token.New(JsonTokenType.EndObject)) | |
47 .Tag(0); | |
48 var arrayExpression = valueExpression | |
49 .Cat( | |
50 Token.New(JsonTokenType.ValueSeparator) | |
51 .Cat(valueExpression) | |
52 .EClosure() | |
53 ) | |
54 .Optional() | |
55 .Cat(Token.New(JsonTokenType.EndArray)) | |
56 .Tag(0); | |
57 | |
58 _jsonDFA = BuildDFA(jsonExpression).States; | |
59 _objectDFA = BuildDFA(objectExpression).States; | |
60 _arrayDFA = BuildDFA(arrayExpression).States; | |
61 } | |
62 | |
63 static EDFADefinition<JsonTokenType> BuildDFA(Token expr) { | |
64 var builder = new DFABuilder(); | |
65 var dfa = new EDFADefinition<JsonTokenType>(_alphabet); | |
66 expr.Accept(builder); | |
67 | |
68 builder.BuildDFA(dfa); | |
69 return dfa; | |
70 } | |
71 | |
72 JSONScanner m_scanner; | |
73 MemberContext m_memberContext; | |
74 | |
75 JSONElementType m_elementType; | |
76 object m_elementValue; | |
77 | |
78 public JSONParser(string text) | |
79 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty } ) { | |
80 Safe.ArgumentNotEmpty(text, "text"); | |
81 m_scanner = new JSONScanner(); | |
82 m_scanner.Feed(text.ToCharArray()); | |
83 } | |
84 | |
85 public JSONElementType ElementType { | |
86 get { return m_elementType; } | |
87 } | |
88 | |
89 public string ElementName { | |
90 get { return m_context.info.memberName; } | |
91 } | |
92 | |
93 public object ElementValue { | |
94 get { return m_elementValue; } | |
95 } | |
96 | |
97 public bool Read() { | |
98 if (m_context.current == UNREACHEBLE_STATE) | |
99 throw new InvalidOperationException("The parser is in invalid state"); | |
100 object tokenValue; | |
101 JsonTokenType tokenType; | |
102 m_context.info.memberName = String.Empty; | |
103 while (m_scanner.ReadToken(out tokenValue, out tokenType)) { | |
104 Move((int)tokenType); | |
105 if (m_context.current == UNREACHEBLE_STATE) | |
106 UnexpectedToken(tokenValue, tokenType); | |
107 switch (tokenType) { | |
108 case JsonTokenType.BeginObject: | |
109 Switch( | |
110 _objectDFA, | |
111 INITIAL_STATE, | |
112 new JSONParserContext { | |
113 memberName = m_context.info.memberName, | |
114 elementContext = JSONElementContext.Object | |
115 } | |
116 ); | |
117 m_elementValue = null; | |
118 m_memberContext = MemberContext.MemberName; | |
119 m_elementType = JSONElementType.BeginObject; | |
120 return true; | |
121 case JsonTokenType.EndObject: | |
122 Restore(); | |
123 m_elementValue = null; | |
124 m_elementType = JSONElementType.EndObject; | |
125 return true; | |
126 case JsonTokenType.BeginArray: | |
127 Switch( | |
128 _arrayDFA, | |
129 INITIAL_STATE, | |
130 new JSONParserContext { | |
131 memberName = m_context.info.memberName, | |
132 elementContext = JSONElementContext.Array | |
133 } | |
134 ); | |
135 m_elementValue = null; | |
136 m_memberContext = MemberContext.MemberValue; | |
137 m_elementType = JSONElementType.BeginArray; | |
138 return true; | |
139 case JsonTokenType.EndArray: | |
140 Restore(); | |
141 m_elementValue = null; | |
142 m_elementType = JSONElementType.EndArray; | |
143 return true; | |
144 case JsonTokenType.String: | |
145 if (m_memberContext == MemberContext.MemberName) { | |
146 m_context.info.memberName = (string)tokenValue; | |
147 break; | |
148 } else { | |
149 m_elementType = JSONElementType.Value; | |
150 m_elementValue = tokenValue; | |
151 return true; | |
152 } | |
153 case JsonTokenType.Number: | |
154 m_elementType = JSONElementType.Value; | |
155 m_elementValue = tokenValue; | |
156 return true; | |
157 case JsonTokenType.Literal: | |
158 m_elementType = JSONElementType.Value; | |
159 m_elementValue = ParseLiteral((string)tokenValue); | |
160 return true; | |
161 case JsonTokenType.NameSeparator: | |
162 m_memberContext = MemberContext.MemberValue; | |
163 break; | |
164 case JsonTokenType.ValueSeparator: | |
165 m_memberContext = m_context.info.elementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue; | |
166 break; | |
167 default: | |
168 UnexpectedToken(tokenValue, tokenType); | |
169 break; | |
170 } | |
171 } | |
172 if (m_context.info.elementContext != JSONElementContext.None) | |
173 throw new ParserException("Unexpedted end of data"); | |
174 return false; | |
175 } | |
176 | |
177 object ParseLiteral(string literal) { | |
178 switch (literal) { | |
179 case "null": | |
180 return null; | |
181 case "false" : | |
182 return false; | |
183 case "true": | |
184 return true; | |
185 default: | |
186 UnexpectedToken(literal, JsonTokenType.Literal); | |
187 return null; // avoid compliler error | |
188 } | |
189 } | |
190 | |
191 void UnexpectedToken(object value, JsonTokenType tokenType) { | |
192 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value)); | |
193 } | |
194 | |
195 } | |
196 | |
197 } |