##// END OF EJS Templates
refactoring complete, JSONParser rewritten
cin -
r180:c32688129f14 ref20160224
parent child
Show More
@@ -1,17 +1,19
1 1 syntax: glob
2 2 Implab.Test/bin/
3 3 *.user
4 4 Implab.Test/obj/
5 5 *.userprefs
6 6 Implab/bin/
7 7 Implab/obj/
8 8 TestResults/
9 9 Implab.Fx/obj/
10 10 Implab.Fx/bin/
11 11 Implab.Fx.Test/bin/
12 12 Implab.Fx.Test/obj/
13 13 _ReSharper.Implab/
14 14 Implab.Diagnostics.Interactive/bin/
15 15 Implab.Diagnostics.Interactive/obj/
16 16 MonoPlay/bin/
17 17 MonoPlay/obj/
18 Implab.Test/Implab.Format.Test/bin/
19 Implab.Test/Implab.Format.Test/obj/
@@ -1,313 +1,313
1 1 using Implab;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Linq;
5 5
6 6 namespace Implab.Automaton {
7 7 public class DFATable : IDFATableBuilder {
8 8 int m_stateCount;
9 9 int m_symbolCount;
10 10 int m_initialState;
11 11
12 12 readonly HashSet<int> m_finalStates = new HashSet<int>();
13 13 readonly HashSet<AutomatonTransition> m_transitions = new HashSet<AutomatonTransition>();
14 14
15 15
16 16 #region IDFADefinition implementation
17 17
18 18 public bool IsFinalState(int s) {
19 19 Safe.ArgumentInRange(s, 0, m_stateCount, "s");
20 20
21 21 return m_finalStates.Contains(s);
22 22 }
23 23
24 24 public IEnumerable<int> FinalStates {
25 25 get {
26 26 return m_finalStates;
27 27 }
28 28 }
29 29
30 30 public int StateCount {
31 31 get { return m_stateCount; }
32 32 }
33 33
34 34 public int AlphabetSize {
35 35 get { return m_symbolCount; }
36 36 }
37 37
38 38 public int InitialState {
39 39 get { return m_initialState; }
40 40 }
41 41
42 42 #endregion
43 43
44 44 public void SetInitialState(int s) {
45 45 Safe.ArgumentAssert(s >= 0, "s");
46 46 m_initialState = s;
47 47 }
48 48
49 49 public void MarkFinalState(int state) {
50 50 m_finalStates.Add(state);
51 51 }
52 52
53 53 public void Add(AutomatonTransition item) {
54 54 Safe.ArgumentAssert(item.s1 >= 0, "item");
55 55 Safe.ArgumentAssert(item.s2 >= 0, "item");
56 56 Safe.ArgumentAssert(item.edge >= 0, "item");
57 57
58 58 m_stateCount = Math.Max(m_stateCount, Math.Max(item.s1, item.s2) + 1);
59 59 m_symbolCount = Math.Max(m_symbolCount, item.edge);
60 60
61 61 m_transitions.Add(item);
62 62 }
63 63
64 64 public void Clear() {
65 65 m_stateCount = 0;
66 66 m_symbolCount = 0;
67 67 m_finalStates.Clear();
68 68 m_transitions.Clear();
69 69 }
70 70
71 71 public bool Contains(AutomatonTransition item) {
72 72 return m_transitions.Contains(item);
73 73 }
74 74
75 75 public void CopyTo(AutomatonTransition[] array, int arrayIndex) {
76 76 m_transitions.CopyTo(array, arrayIndex);
77 77 }
78 78
79 79 public bool Remove(AutomatonTransition item) {
80 m_transitions.Remove(item);
80 return m_transitions.Remove(item);
81 81 }
82 82
83 83 public int Count {
84 84 get {
85 85 return m_transitions.Count;
86 86 }
87 87 }
88 88
89 89 public bool IsReadOnly {
90 90 get {
91 91 return false;
92 92 }
93 93 }
94 94
95 95 public IEnumerator<AutomatonTransition> GetEnumerator() {
96 96 return m_transitions.GetEnumerator();
97 97 }
98 98
99 99 System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
100 100 return GetEnumerator();
101 101 }
102 102
103 103 public int[,] CreateTransitionTable() {
104 104 var table = new int[StateCount,AlphabetSize];
105 105
106 106 for (int i = 0; i < StateCount; i++)
107 107 for (int j = 0; i < AlphabetSize; j++)
108 108 table[i, j] = AutomatonConst.UNREACHABLE_STATE;
109 109
110 110 foreach (var t in this)
111 111 table[t.s1,t.edge] = t.s2;
112 112
113 113 return table;
114 114 }
115 115
116 116 public bool[] CreateFinalStateTable() {
117 117 var table = new bool[StateCount];
118 118
119 119 foreach (var s in FinalStates)
120 120 table[s] = true;
121 121
122 122 return table;
123 123 }
124 124
125 125 /// <summary>Формирует множества конечных состояний перед началом работы алгоритма минимизации.</summary>
126 126 /// <remarks>
127 127 /// В процессе построения минимального автомата требуется разделить множество состояний,
128 128 /// на два подмножества - конечные состояния и все остальные, после чего эти подмножества
129 129 /// будут резделены на более мелкие. Иногда требуется гарантировать различия конечных сосотяний,
130 130 /// для этого необходимо переопределить даннцю фукнцию, для получения множеств конечных состояний.
131 131 /// </remarks>
132 132 /// <returns>The final states.</returns>
133 133 protected virtual IEnumerable<HashSet<int>> GroupFinalStates() {
134 134 return new HashSet<int>[] { m_finalStates };
135 135 }
136 136
137 137 protected void Optimize(
138 138 IDFATableBuilder optimalDFA,
139 139 IDictionary<int,int> alphabetMap,
140 140 IDictionary<int,int> stateMap
141 141 ) {
142 142 Safe.ArgumentNotNull(optimalDFA, "dfa");
143 143 Safe.ArgumentNotNull(alphabetMap, "alphabetMap");
144 144 Safe.ArgumentNotNull(stateMap, "stateMap");
145 145
146 146
147 147 var setComparer = new CustomEqualityComparer<HashSet<int>>(
148 148 (x, y) => x.SetEquals(y),
149 149 s => s.Sum(x => x.GetHashCode())
150 150 );
151 151
152 152 var optimalStates = new HashSet<HashSet<int>>(setComparer);
153 153 var queue = new HashSet<HashSet<int>>(setComparer);
154 154
155 155 // получаем конечные состояния, сгруппированные по маркерам
156 156 optimalStates.UnionWith(
157 157 GroupFinalStates()
158 158 );
159 159
160 160 var state = new HashSet<int>(
161 161 Enumerable
162 162 .Range(0, m_stateCount - 1)
163 163 .Where(i => !m_finalStates.Contains(i))
164 164 );
165 165
166 166 optimalStates.Add(state);
167 167 queue.Add(state);
168 168
169 169 var rmap = m_transitions
170 170 .GroupBy(t => t.s2)
171 .ToLookup(
171 .ToDictionary(
172 172 g => g.Key, // s2
173 g => g.ToLookup(t => t.edge, t => t.s1)
173 g => g.GroupBy(t => t.edge, t => t.s1).ToDictionary(p => p.Key)
174 174 );
175 175
176 176 while (queue.Count > 0) {
177 177 var stateA = queue.First();
178 178 queue.Remove(stateA);
179 179
180 180 for (int c = 0; c < m_symbolCount; c++) {
181 181 var stateX = new HashSet<int>();
182 182 foreach(var a in stateA)
183 stateX.UnionWith(rmap[a][c]); // all states from wich 'c' leads to 'a'
183 stateX.UnionWith(rmap[a][c]); // all states from wich the symbol 'c' leads to the state 'a'
184 184
185 185 foreach (var stateY in optimalStates.ToArray()) {
186 186 if (stateX.Overlaps(stateY) && !stateY.IsSubsetOf(stateX)) {
187 187 var stateR1 = new HashSet<int>(stateY);
188 188 var stateR2 = new HashSet<int>(stateY);
189 189
190 190 stateR1.IntersectWith(stateX);
191 191 stateR2.ExceptWith(stateX);
192 192
193 193 optimalStates.Remove(stateY);
194 194 optimalStates.Add(stateR1);
195 195 optimalStates.Add(stateR2);
196 196
197 197 if (queue.Contains(stateY)) {
198 198 queue.Remove(stateY);
199 199 queue.Add(stateR1);
200 200 queue.Add(stateR2);
201 201 } else {
202 202 queue.Add(stateR1.Count <= stateR2.Count ? stateR1 : stateR2);
203 203 }
204 204 }
205 205 }
206 206 }
207 207 }
208 208
209 209 // карта получения оптимального состояния по соотвествующему ему простому состоянию
210 210 var nextState = 0;
211 211 foreach (var item in optimalStates) {
212 212 var id = nextState++;
213 213 foreach (var s in item)
214 214 stateMap[s] = id;
215 215 }
216 216
217 217 // получаем минимальный алфавит
218 218 // входные символы не различимы, если Move(s,a1) == Move(s,a2), для любого s
219 219 // для этого используем алгоритм кластеризации, сначала
220 220 // считаем, что все символы не различимы
221 221
222 222 var minClasses = new HashSet<HashSet<int>>(setComparer);
223 223 var alphaQueue = new Queue<HashSet<int>>();
224 224 alphaQueue.Enqueue(new HashSet<int>(Enumerable.Range(0,AlphabetSize)));
225 225
226 226 // для всех состояний, будем проверять каждый класс на различимость,
227 227 // т.е. символы различимы, если они приводят к разным состояниям
228 228 for (int s = 0 ; s < optimalStates.Count; s++) {
229 229 var newQueue = new Queue<HashSet<int>>();
230 230
231 231 foreach (var A in alphaQueue) {
232 232 // классы из одного символа делить бесполезно, переводим их сразу в
233 233 // результирующий алфавит
234 234 if (A.Count == 1) {
235 235 minClasses.Add(A);
236 236 continue;
237 237 }
238 238
239 239 // различаем классы символов, которые переводят в различные оптимальные состояния
240 240 // optimalState -> alphaClass
241 241 var classes = new Dictionary<int, HashSet<int>>();
242 242
243 243 foreach (var term in A) {
244 244 // ищем все переходы класса по символу term
245 245 var res = m_transitions.Where(t => stateMap[t.s1] == s && t.edge == term).Select(t => stateMap[t.s2]).ToArray();
246 246
247 247 var s2 = res.Length > 0 ? res[0] : -1;
248 248
249 249 HashSet<int> a2;
250 250 if (!classes.TryGetValue(s2, out a2)) {
251 251 a2 = new HashSet<int>();
252 252 newQueue.Enqueue(a2);
253 253 classes[s2] = a2;
254 254 }
255 255 a2.Add(term);
256 256 }
257 257 }
258 258
259 259 if (newQueue.Count == 0)
260 260 break;
261 261 alphaQueue = newQueue;
262 262 }
263 263
264 264 // после окончания работы алгоритма в очереди останутся минимальные различимые классы
265 265 // входных символов
266 266 foreach (var A in alphaQueue)
267 267 minClasses.Add(A);
268 268
269 269 // построение отображения алфавитов входных символов.
270 270 // поскольку символ DFAConst.UNCLASSIFIED_INPUT может иметь
271 271 // специальное значение, тогда сохраним минимальный класс,
272 272 // содержащий этот символ на томже месте.
273 273
274 274 var nextCls = 0;
275 275 foreach (var item in minClasses) {
276 276 if (nextCls == AutomatonConst.UNCLASSIFIED_INPUT)
277 277 nextCls++;
278 278
279 279 // сохраняем DFAConst.UNCLASSIFIED_INPUT
280 280 var cls = item.Contains(AutomatonConst.UNCLASSIFIED_INPUT) ? AutomatonConst.UNCLASSIFIED_INPUT : nextCls;
281 281
282 282 foreach (var a in item)
283 283 alphabetMap[a] = cls;
284 284
285 285 nextCls++;
286 286 }
287 287
288 288 // построение автомата
289 289 optimalDFA.SetInitialState(stateMap[m_initialState]);
290 290
291 291 foreach (var sf in m_finalStates.Select(s => stateMap[s]).Distinct())
292 292 optimalDFA.MarkFinalState(sf);
293 293
294 294 foreach (var t in m_transitions.Select(t => new AutomatonTransition(stateMap[t.s1],stateMap[t.s2],alphabetMap[t.edge])).Distinct())
295 295 optimalDFA.Add(t);
296 296 }
297 297
298 298 protected void PrintDFA<TInput, TState>(IAlphabet<TInput> inputAlphabet, IAlphabet<TState> stateAlphabet) {
299 299 Safe.ArgumentNotNull(inputAlphabet, "inputAlphabet");
300 300 Safe.ArgumentNotNull(stateAlphabet, "stateAlphabet");
301 301
302 302 foreach(var t in m_transitions)
303 303 Console.WriteLine(
304 304 "[{0}] -{{{1}}}-> [{2}]{3}",
305 305 String.Join(",", stateAlphabet.GetSymbols(t.s1)),
306 306 String.Join("", inputAlphabet.GetSymbols(t.edge)),
307 307 String.Join(",", stateAlphabet.GetSymbols(t.s2)),
308 308 m_finalStates.Contains(t.s2) ? "$" : ""
309 309 );
310 310 }
311 311
312 312 }
313 313 }
@@ -1,70 +1,66
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.Diagnostics;
4 4 using System.Globalization;
5 5 using System.Linq;
6 6 using System.Diagnostics.CodeAnalysis;
7 7
8 8 namespace Implab.Automaton {
9 9 /// <summary>
10 10 /// Алфавит символами которого являются элементы перечислений.
11 11 /// </summary>
12 12 /// <typeparam name="T">Тип перечислений</typeparam>
13 13 public class EnumAlphabet<T> : IndexedAlphabetBase<T> where T : struct, IConvertible {
14 14 [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
15 15 static readonly Lazy<T[]> _symbols = new Lazy<T[]>(GetSymbols);
16 16
17 17 [SuppressMessage("Microsoft.Design", "CA1000:DoNotDeclareStaticMembersOnGenericTypes")]
18 18 static readonly Lazy<EnumAlphabet<T>> _fullAlphabet = new Lazy<EnumAlphabet<T>>(CreateEnumAlphabet);
19 19
20 20 static EnumAlphabet<T> CreateEnumAlphabet() {
21 21 var symbols = _symbols.Value;
22 22
23 23 if (
24 24 symbols[symbols.Length - 1].ToInt32(CultureInfo.InvariantCulture) >= symbols.Length
25 25 || symbols[0].ToInt32(CultureInfo.InvariantCulture) != 0
26 26 )
27 27 throw new InvalidOperationException("The specified enumeration must be zero-based and continuously numbered");
28 28
29 29 return new EnumAlphabet<T>(symbols.Select(x => x.ToInt32(CultureInfo.InvariantCulture)).ToArray());
30 30 }
31 31
32 32 static T[] GetSymbols() {
33 33 if (!typeof(T).IsEnum)
34 34 throw new InvalidOperationException("Invalid generic parameter, enumeration is required");
35 35
36 36 if (Enum.GetUnderlyingType(typeof(T)) != typeof(Int32))
37 37 throw new InvalidOperationException("Only enums based on Int32 are supported");
38 38
39 39 return ((T[])Enum.GetValues(typeof(T)))
40 40 .OrderBy(x => x.ToInt32(CultureInfo.InvariantCulture))
41 41 .ToArray();
42 42 }
43 43
44 44 public static EnumAlphabet<T> FullAlphabet {
45 45 get {
46 46 return _fullAlphabet.Value;
47 47 }
48 48 }
49 49
50 50
51 51 public EnumAlphabet()
52 52 : base(_symbols.Value.Length) {
53 53 }
54 54
55 55 public EnumAlphabet(int[] map)
56 56 : base(map) {
57 57 Debug.Assert(map.Length == _symbols.Value.Length);
58 58 }
59 59
60 60
61 61 public override int GetSymbolIndex(T symbol) {
62 62 return symbol.ToInt32(CultureInfo.InvariantCulture);
63 63 }
64 64
65 public override IEnumerable<T> InputSymbols {
66 get { return _symbols.Value; }
67 }
68
69 65 }
70 66 }
@@ -1,50 +1,50
1 1 using Implab;
2 2 using System;
3 3 using System.Collections.Generic;
4 4 using System.Diagnostics;
5 5 using System.Linq;
6 6
7 7 namespace Implab.Automaton {
8 8 /// <summary>
9 9 /// Indexed alphabet is the finite set of symbols where each symbol has a zero-based unique index.
10 10 /// </summary>
11 11 /// <remarks>
12 12 /// Indexed alphabets are usefull in bulting efficient translations from source alphabet
13 13 /// to the input alphabet of the automaton. It's assumed that the index to the symbol match
14 14 /// is well known and documented.
15 15 /// </remarks>
16 16 public abstract class IndexedAlphabetBase<T> : MapAlphabet<T> {
17 17
18 18 protected IndexedAlphabetBase() :base(true, null) {
19 19 }
20 20
21 21 public abstract int GetSymbolIndex(T symbol);
22 22
23 23 /// <summary>
24 24 /// Gets the translation map from the index of the symbol to it's class this is usefull for the optimized input symbols transtaion.
25 25 /// </summary>
26 26 /// <remarks>
27 27 /// The map is continous and start from the symbol with zero code. The last symbol
28 28 /// in the map is the last classified symbol in the alphabet, i.e. the map can be
29 29 /// shorter then the whole alphabet.
30 30 /// </remarks>
31 31 /// <returns>The translation map.</returns>
32 32 public int[] GetTranslationMap() {
33 Dictionary<int,int> map = new Dictionary<int, int>();
33 var map = new Dictionary<int, int>();
34 34
35 int max;
35 int max = 0;
36 36 foreach (var p in Mappings) {
37 37 var index = GetSymbolIndex(p.Key);
38 38 max = Math.Max(max, index);
39 39 map[index] = p.Value;
40 40 }
41 41
42 42 var result = new int[max + 1];
43 43
44 44 for (int i = 0; i < result.Length; i++)
45 45 map.TryGetValue(i, out result[i]);
46 46
47 47 return result;
48 48 }
49 49 }
50 50 }
@@ -1,83 +1,82
1 1 using System.Collections.Generic;
2 2 using System.Linq;
3 3
4 4 namespace Implab.Automaton.RegularExpressions {
5 5 public class RegularDFA<TInput, TTag> : DFATable, ITaggedDFABuilder<TTag> {
6 6
7 7 readonly Dictionary<int,TTag[]> m_tags = new Dictionary<int, TTag[]>();
8 8 readonly IAlphabet<TInput> m_alphabet;
9 9
10 10 public RegularDFA(IAlphabet<TInput> alphabet) {
11 11 Safe.ArgumentNotNull(alphabet, "aplhabet");
12 12
13 13 m_alphabet = alphabet;
14 14 }
15 15
16 16
17 17 public IAlphabet<TInput> InputAlphabet {
18 18 get {
19 19 return m_alphabet;
20 20 }
21 21 }
22 22
23 23 public void MarkFinalState(int s, TTag[] tags) {
24 24 MarkFinalState(s);
25 25 SetStateTag(s, tags);
26 26 }
27 27
28 28 public void SetStateTag(int s, TTag[] tags) {
29 29 Safe.ArgumentNotNull(tags, "tags");
30 30 m_tags[s] = tags;
31 31 }
32 32
33 33 public TTag[] GetStateTag(int s) {
34 34 TTag[] tags;
35 35 return m_tags.TryGetValue(s, out tags) ? tags : new TTag[0];
36 36 }
37 37
38 38 public TTag[][] CreateTagTable() {
39 39 var table = new TTag[StateCount][];
40 40
41 41 foreach (var pair in m_tags)
42 42 table[pair.Key] = pair.Value;
43 43
44 44 return table;
45 45 }
46 46
47 47 /// <summary>
48 48 /// Optimize the specified alphabet.
49 49 /// </summary>
50 50 /// <param name="alphabet">Пустой алфавит, который будет зполнен в процессе оптимизации.</param>
51 51 public RegularDFA<TInput,TTag> Optimize(IAlphabetBuilder<TInput> alphabet) {
52 52 Safe.ArgumentNotNull(alphabet, "alphabet");
53 53
54 54 var dfa = new RegularDFA<TInput, TTag>(alphabet);
55 55
56 var states = new DummyAlphabet(StateCount);
57 56 var alphaMap = new Dictionary<int,int>();
58 57 var stateMap = new Dictionary<int,int>();
59 58
60 59 Optimize(dfa, alphaMap, stateMap);
61 60
62 61 // mark tags in the new DFA
63 62 foreach (var g in m_tags.Where(x => x.Key < StateCount).GroupBy(x => stateMap[x.Key], x => x.Value ))
64 63 dfa.SetStateTag(g.Key, g.SelectMany(x => x).ToArray());
65 64
66 65 // make the alphabet for the new DFA
67 66 foreach (var pair in alphaMap)
68 67 alphabet.DefineClass(m_alphabet.GetSymbols(pair.Key), pair.Value);
69 68
70 69 return dfa;
71 70 }
72 71
73 72 protected override IEnumerable<HashSet<int>> GroupFinalStates() {
74 73 var arrayComparer = new CustomEqualityComparer<TTag[]>(
75 74 (x,y) => x.Length == y.Length && x.All(it => y.Contains(it)),
76 75 x => x.Sum(it => x.GetHashCode())
77 76 );
78 77 return FinalStates.GroupBy(x => m_tags[x], arrayComparer).Select(g => new HashSet<int>(g));
79 78 }
80 79
81 80 }
82 81 }
83 82
@@ -1,44 +1,63
1 1 using System;
2 2 using System.Threading;
3 3
4 4 namespace Implab.Components {
5 /// <summary>
6 /// Creates an instace on-demand and allows it to be garbage collected.
7 /// </summary>
8 /// <remarks>
9 /// Usefull when dealing with memory-intensive objects which are frequently used.
10 /// This class is similar to <see cref="ObjectPool{T}"/> except is a singleton.
11 /// </remarks>
5 12 public class LazyAndWeak<T> where T : class {
6 13
7 14 readonly Func<T> m_factory;
8 15 readonly object m_lock;
9 16 WeakReference m_reference;
10 17
11 18
12 19 public LazyAndWeak(Func<T> factory, bool useLock) {
13 20 Safe.ArgumentNotNull(factory, "factory");
14 21 m_factory = factory;
15 22 m_lock = useLock ? new object() : null;
16 23 }
17 24
18 25 public LazyAndWeak(Func<T> factory) : this(factory, false) {
19 26 }
20 27
21 28 public T Value {
22 29 get {
23 30 while (true) {
24 31 var weak = m_reference;
25 32 T value;
26 33 if (weak != null) {
27 34 value = weak.Target as T;
28 35 if (value != null)
29 36 return value;
30 37 }
31 38
32 39 if (m_lock == null) {
33 40 value = m_factory();
34 41
35 42 if (Interlocked.CompareExchange(ref m_reference, new WeakReference(value), weak) == weak)
36 43 return value;
37 44 } else {
45 lock (m_lock) {
46 // double check
47 if (weak != null) {
48 value = weak.Target as T;
49 if (value != null)
50 return value;
51 }
52 // we are safe to write
53 value = m_factory();
54 m_reference = new WeakReference(value);
55 return value;
56 }
38 57 }
39 58 }
40 59 }
41 60 }
42 61 }
43 62 }
44 63
@@ -1,58 +1,58
1 1 using System;
2 using Implab.Parsing;
2 using Implab.Formats;
3 3
4 4 namespace Implab.Components {
5 5 public class RunnableComponent : Disposable, IRunnable, IInitializable {
6 6
7 7
8 8
9 9
10 10
11 11 IPromise m_pending;
12 12 Exception m_lastError;
13 13
14 14 protected RunnableComponent(bool initialized) {
15 15
16 16 }
17 17
18 18 #region IInitializable implementation
19 19
20 20 public void Init() {
21 21
22 22 }
23 23
24 24 #endregion
25 25
26 26 #region IRunnable implementation
27 27
28 28 public IPromise Start() {
29 29 throw new NotImplementedException();
30 30 }
31 31
32 32 protected virtual IPromise OnStart() {
33 33 return Promise.SUCCESS;
34 34 }
35 35
36 36 protected virtual void Run() {
37 37 }
38 38
39 39 public IPromise Stop() {
40 40 throw new NotImplementedException();
41 41 }
42 42
43 43 public ExecutionState State {
44 44 get {
45 45 throw new NotImplementedException();
46 46 }
47 47 }
48 48
49 49 public Exception LastError {
50 50 get {
51 51 throw new NotImplementedException();
52 52 }
53 53 }
54 54
55 55 #endregion
56 56 }
57 57 }
58 58
@@ -1,10 +1,11
1 1 namespace Implab.Formats.JSON {
2 2 /// <summary>
3 3 /// internal
4 4 /// </summary>
5 5 enum JSONElementContext {
6 6 None,
7 7 Object,
8 Array
8 Array,
9 Closed
9 10 }
10 11 }
@@ -1,111 +1,119
1 1 using System.Linq;
2 2 using Implab.Automaton.RegularExpressions;
3 3 using System;
4 4 using Implab.Automaton;
5 using Implab.Components;
5 6
6 7 namespace Implab.Formats.JSON {
7 8 class JSONGrammar : Grammar<char> {
8 9 public enum TokenType {
9 10 None,
10 11 BeginObject,
11 12 EndObject,
12 13 BeginArray,
13 14 EndArray,
14 15 String,
15 16 Number,
16 17 Literal,
17 18 NameSeparator,
18 19 ValueSeparator,
19 20
20 21 StringBound,
21 22 EscapedChar,
22 23 UnescapedChar,
23 24 EscapedUnicode
24 25 }
25 26
26 static Lazy<JSONGrammar> _instance = new Lazy<JSONGrammar>();
27 static LazyAndWeak<JSONGrammar> _instance = new LazyAndWeak<JSONGrammar>(() => new JSONGrammar());
27 28
28 29 public static JSONGrammar Instance {
29 30 get { return _instance.Value; }
30 31 }
31 32
32 33 readonly ScannerContext<TokenType> m_jsonExpression;
33 34 readonly ScannerContext<TokenType> m_stringExpression;
35 readonly CharAlphabet m_defaultAlphabet = new CharAlphabet();
34 36
35 37 public JSONGrammar() {
36 38 DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x));
37 39 var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9'));
38 40 var digit9 = SymbolRangeToken('1', '9');
39 41 var zero = SymbolToken('0');
40 42 var digit = zero.Or(digit9);
41 43 var dot = SymbolToken('.');
42 44 var minus = SymbolToken('-');
43 45 var sign = SymbolSetToken('-', '+');
44 46 var expSign = SymbolSetToken('e', 'E');
45 47 var letters = SymbolRangeToken('a', 'z');
46 48 var integer = zero.Or(digit9.Cat(digit.EClosure()));
47 49 var frac = dot.Cat(digit.Closure());
48 50 var exp = expSign.Cat(sign.Optional()).Cat(digit.Closure());
49 51 var quote = SymbolToken('"');
50 52 var backSlash = SymbolToken('\\');
51 53 var specialEscapeChars = SymbolSetToken('\\', '"', '/', 'b', 'f', 't', 'n', 'r');
52 54 var unicodeEspace = SymbolToken('u').Cat(hexDigit.Repeat(4));
53 55 var whitespace = SymbolSetToken('\n', '\r', '\t', ' ').EClosure();
54 56 var beginObject = whitespace.Cat(SymbolToken('{')).Cat(whitespace);
55 57 var endObject = whitespace.Cat(SymbolToken('}')).Cat(whitespace);
56 58 var beginArray = whitespace.Cat(SymbolToken('[')).Cat(whitespace);
57 59 var endArray = whitespace.Cat(SymbolToken(']')).Cat(whitespace);
58 60 var nameSep = whitespace.Cat(SymbolToken(':')).Cat(whitespace);
59 61 var valueSep = whitespace.Cat(SymbolToken(',')).Cat(whitespace);
60 62
61 63 var number = minus.Optional().Cat(integer).Cat(frac.Optional()).Cat(exp.Optional());
62 64 var literal = letters.Closure();
63 65 var unescaped = SymbolTokenExcept(Enumerable.Range(0, 0x20).Union(new int[] { '\\', '"' }).Select(x => (char)x));
64 66
65 67 var jsonExpression =
66 68 number.Tag(TokenType.Number)
67 69 .Or(literal.Tag(TokenType.Literal))
68 70 .Or(quote.Tag(TokenType.StringBound))
69 71 .Or(beginObject.Tag(TokenType.BeginObject))
70 72 .Or(endObject.Tag(TokenType.EndObject))
71 73 .Or(beginArray.Tag(TokenType.BeginArray))
72 74 .Or(endArray.Tag(TokenType.EndArray))
73 75 .Or(nameSep.Tag(TokenType.NameSeparator))
74 76 .Or(valueSep.Tag(TokenType.ValueSeparator));
75 77
76 78
77 79 var jsonStringExpression =
78 80 quote.Tag(TokenType.StringBound)
79 81 .Or(backSlash.Cat(specialEscapeChars).Tag(TokenType.EscapedChar))
80 82 .Or(backSlash.Cat(unicodeEspace).Tag(TokenType.EscapedUnicode))
81 83 .Or(unescaped.Closure().Tag(TokenType.UnescapedChar));
82 84
83 85
84 86 m_jsonExpression = BuildScannerContext<TokenType>(jsonExpression);
85 87 m_stringExpression = BuildScannerContext<TokenType>(jsonStringExpression);
86 88
87 89
88 90 }
89 91
92 protected override IAlphabetBuilder<char> AlphabetBuilder {
93 get {
94 return m_defaultAlphabet;
95 }
96 }
97
90 98 public ScannerContext<TokenType> JsonExpression {
91 99 get {
92 100 return m_jsonExpression;
93 101 }
94 102 }
95 103
96 104 public ScannerContext<TokenType> JsonStringExpression {
97 105 get {
98 106 return m_stringExpression;
99 107 }
100 108 }
101 109
102 110 Token SymbolRangeToken(char start, char stop) {
103 111 return SymbolToken(Enumerable.Range(start,stop - start).Cast<char>());
104 112 }
105 113
106 protected override IAlphabetBuilder<char> CreateAlphabet() {
114 protected override IndexedAlphabetBase<char> CreateAlphabet() {
107 115 return new CharAlphabet();
108 116 }
109 117
110 118 }
111 119 }
@@ -1,295 +1,293
1 1 using System;
2 2 using System.Diagnostics;
3 3 using System.IO;
4 4 using Implab.Automaton;
5 5 using Implab.Automaton.RegularExpressions;
6 6 using System.Linq;
7 7 using Implab.Components;
8 using System.Collections.Generic;
8 9
9 10 namespace Implab.Formats.JSON {
10 11 /// <summary>
11 /// internal
12 /// </summary>
13 public struct JSONParserContext {
14 public string memberName;
15 public JSONElementContext elementContext;
16 }
17
18 /// <summary>
19 12 /// Pull парсер JSON данных.
20 13 /// </summary>
21 14 /// <remarks>
22 15 /// Следует отметить отдельную интерпретацию свойства <see cref="Level"/>,
23 16 /// оно означает текущий уровень вложенности объектов, однако закрывающий
24 17 /// элемент объекта и массива имеет уровень меньше, чем сам объект.
25 18 /// <code>
26 19 /// { // Level = 1
27 20 /// "name" : "Peter", // Level = 1
28 21 /// "address" : { // Level = 2
29 22 /// city : "Stern" // Level = 2
30 23 /// } // Level = 1
31 24 /// } // Level = 0
32 25 /// </code>
33 26 /// </remarks>
34 27 public class JSONParser : Disposable {
35 28
36 29 enum MemberContext {
37 30 MemberName,
38 31 MemberValue
39 32 }
40 33
41 34 #region Parser rules
42 35 struct ParserContext {
43 36 readonly int[,] m_dfa;
44 37 int m_state;
45 38
46 39 readonly JSONElementContext m_elementContext;
47 40
48 41 public ParserContext(int[,] dfa, int state, JSONElementContext context) {
49 42 m_dfa = dfa;
50 43 m_state = state;
51 44 m_elementContext = context;
52 45 }
53 46
54 47 public bool Move(JsonTokenType token) {
55 var next = m_dfa[m_state, token];
48 var next = m_dfa[m_state, (int)token];
56 49 if (next == AutomatonConst.UNREACHABLE_STATE)
57 50 return false;
58 51 m_state = next;
52 return true;
59 53 }
60 54
61 55 public JSONElementContext ElementContext {
62 56 get { return m_elementContext; }
63 57 }
64 58 }
65 59
60 static readonly ParserContext _jsonContext;
61 static readonly ParserContext _objectContext;
62 static readonly ParserContext _arrayContext;
63
66 64 static JSONParser() {
67 65
68
69 var valueExpression = Token(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
70 var memberExpression = Token(JsonTokenType.String).Cat(Token(JsonTokenType.NameSeparator)).Cat(valueExpression);
66 var valueExpression = MakeToken(JsonTokenType.BeginArray, JsonTokenType.BeginObject, JsonTokenType.Literal, JsonTokenType.Number, JsonTokenType.String);
67 var memberExpression = MakeToken(JsonTokenType.String).Cat(MakeToken(JsonTokenType.NameSeparator)).Cat(valueExpression);
71 68
72 69 var objectExpression = memberExpression
73 70 .Cat(
74 Token(JsonTokenType.ValueSeparator)
71 MakeToken(JsonTokenType.ValueSeparator)
75 72 .Cat(memberExpression)
76 73 .EClosure()
77 74 )
78 75 .Optional()
79 .Cat(Token(JsonTokenType.EndObject))
76 .Cat(MakeToken(JsonTokenType.EndObject))
80 77 .End();
81 78
82 79 var arrayExpression = valueExpression
83 80 .Cat(
84 Token(JsonTokenType.ValueSeparator)
81 MakeToken(JsonTokenType.ValueSeparator)
85 82 .Cat(valueExpression)
86 83 .EClosure()
87 84 )
88 85 .Optional()
89 .Cat(Token(JsonTokenType.EndArray))
86 .Cat(MakeToken(JsonTokenType.EndArray))
90 87 .End();
91 88
92 89 var jsonExpression = valueExpression.End();
93 90
94 _jsonDFA = CreateParserContext(jsonExpression, JSONElementContext.None);
95 _objectDFA = CreateParserContext(objectExpression, JSONElementContext.Object);
96 _arrayDFA = CreateParserContext(arrayExpression, JSONElementContext.Array);
91 _jsonContext = CreateParserContext(jsonExpression, JSONElementContext.None);
92 _objectContext = CreateParserContext(objectExpression, JSONElementContext.Object);
93 _arrayContext = CreateParserContext(arrayExpression, JSONElementContext.Array);
97 94 }
98 95
99 static Token Token(params JsonTokenType[] input) {
96 static Token MakeToken(params JsonTokenType[] input) {
100 97 return Token.New( input.Select(t => (int)t).ToArray() );
101 98 }
102 99
103 100 static ParserContext CreateParserContext(Token expr, JSONElementContext context) {
104 101
105 102 var dfa = new DFATable();
106 103 var builder = new RegularExpressionVisitor(dfa);
107 104 expr.Accept(builder);
108 105 builder.BuildDFA();
109 106
110 107 return new ParserContext(dfa.CreateTransitionTable(), dfa.InitialState, context);
111 108 }
112 109
113 110 #endregion
114 111
115 JSONScanner m_scanner;
112 readonly JSONScanner m_scanner;
116 113 MemberContext m_memberContext;
117 114
118 115 JSONElementType m_elementType;
119 116 object m_elementValue;
117 string m_memberName = String.Empty;
118
119 Stack<ParserContext> m_stack = new Stack<ParserContext>();
120 ParserContext m_context = _jsonContext;
120 121
121 122 /// <summary>
122 123 /// Создает новый парсер на основе строки, содержащей JSON
123 124 /// </summary>
124 125 /// <param name="text"></param>
125 public JSONParser(string text)
126 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) {
126 public JSONParser(string text) {
127 127 Safe.ArgumentNotEmpty(text, "text");
128 m_scanner = new JSONScanner();
129 m_scanner.Feed(text.ToCharArray());
128 m_scanner = new JSONScanner(text);
130 129 }
131 130
132 131 /// <summary>
133 132 /// Создает новый экземпляр парсера, на основе текстового потока.
134 133 /// </summary>
135 134 /// <param name="reader">Текстовый поток.</param>
136 public JSONParser(TextReader reader)
137 : base(_jsonDFA, INITIAL_STATE, new JSONParserContext { elementContext = JSONElementContext.None, memberName = String.Empty }) {
135 public JSONParser(TextReader reader) {
138 136 Safe.ArgumentNotNull(reader, "reader");
139 m_scanner = new JSONScanner();
140 m_scanner.Feed(reader, dispose);
137 m_scanner = new JSONScanner(reader);
138 }
139
140 public int Level {
141 get { return m_stack.Count; }
141 142 }
142 143
143 144 /// <summary>
144 145 /// Тип текущего элемента на котором стоит парсер.
145 146 /// </summary>
146 147 public JSONElementType ElementType {
147 148 get { return m_elementType; }
148 149 }
149 150
150 151 /// <summary>
151 152 /// Имя элемента - имя свойства родительского контейнера. Для элементов массивов и корневого всегда
152 153 /// пустая строка.
153 154 /// </summary>
154 155 public string ElementName {
155 get { return m_context.info.memberName; }
156 get { return m_memberName; }
156 157 }
157 158
158 159 /// <summary>
159 160 /// Значение элемента. Только для элементов типа <see cref="JSONElementType.Value"/>, для остальных <c>null</c>
160 161 /// </summary>
161 162 public object ElementValue {
162 163 get { return m_elementValue; }
163 164 }
164 165
165 166 /// <summary>
166 167 /// Читает слеюудущий объект из потока
167 168 /// </summary>
168 169 /// <returns><c>true</c> - операция чтения прошла успешно, <c>false</c> - конец данных</returns>
169 170 public bool Read() {
170 if (m_context.current == UNREACHEBLE_STATE)
171 throw new InvalidOperationException("The parser is in invalid state");
172 171 object tokenValue;
173 172 JsonTokenType tokenType;
174 m_context.info.memberName = String.Empty;
173
174 m_memberName = String.Empty;
175
175 176 while (m_scanner.ReadToken(out tokenValue, out tokenType)) {
176 Move((int)tokenType);
177 if (m_context.current == UNREACHEBLE_STATE)
177 if(!m_context.Move(tokenType))
178 178 UnexpectedToken(tokenValue, tokenType);
179
179 180 switch (tokenType) {
180 181 case JsonTokenType.BeginObject:
181 Switch(
182 _objectDFA,
183 INITIAL_STATE,
184 new JSONParserContext {
185 memberName = m_context.info.memberName,
186 elementContext = JSONElementContext.Object
187 }
188 );
182 m_stack.Push(m_context);
183 m_context = _objectContext;
184
189 185 m_elementValue = null;
190 186 m_memberContext = MemberContext.MemberName;
191 187 m_elementType = JSONElementType.BeginObject;
192 188 return true;
193 189 case JsonTokenType.EndObject:
194 Restore();
190 if (m_stack.Count == 0)
191 UnexpectedToken(tokenValue, tokenType);
192 m_context = m_stack.Pop();
193
195 194 m_elementValue = null;
196 195 m_elementType = JSONElementType.EndObject;
197 196 return true;
198 197 case JsonTokenType.BeginArray:
199 Switch(
200 _arrayDFA,
201 INITIAL_STATE,
202 new JSONParserContext {
203 memberName = m_context.info.memberName,
204 elementContext = JSONElementContext.Array
205 }
206 );
198 m_stack.Push(m_context);
199 m_context = _arrayContext;
200
207 201 m_elementValue = null;
208 202 m_memberContext = MemberContext.MemberValue;
209 203 m_elementType = JSONElementType.BeginArray;
210 204 return true;
211 205 case JsonTokenType.EndArray:
212 Restore();
206 if (m_stack.Count == 0)
207 UnexpectedToken(tokenValue, tokenType);
208 m_context = m_stack.Pop();
209
213 210 m_elementValue = null;
214 211 m_elementType = JSONElementType.EndArray;
215 212 return true;
216 213 case JsonTokenType.String:
217 214 if (m_memberContext == MemberContext.MemberName) {
218 m_context.info.memberName = (string)tokenValue;
215 m_memberName = (string)tokenValue;
219 216 break;
220 217 }
221 218 m_elementType = JSONElementType.Value;
222 219 m_elementValue = tokenValue;
223 220 return true;
224 221 case JsonTokenType.Number:
225 222 m_elementType = JSONElementType.Value;
226 223 m_elementValue = tokenValue;
227 224 return true;
228 225 case JsonTokenType.Literal:
229 226 m_elementType = JSONElementType.Value;
230 227 m_elementValue = ParseLiteral((string)tokenValue);
231 228 return true;
232 229 case JsonTokenType.NameSeparator:
233 230 m_memberContext = MemberContext.MemberValue;
234 231 break;
235 232 case JsonTokenType.ValueSeparator:
236 m_memberContext = m_context.info.elementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
233 m_memberContext = m_context.ElementContext == JSONElementContext.Object ? MemberContext.MemberName : MemberContext.MemberValue;
237 234 break;
238 235 default:
239 236 UnexpectedToken(tokenValue, tokenType);
240 237 break;
241 238 }
242 239 }
243 if (m_context.info.elementContext != JSONElementContext.None)
240 if (m_context.ElementContext != JSONElementContext.None)
244 241 throw new ParserException("Unexpedted end of data");
242
243 EOF = true;
244
245 245 return false;
246 246 }
247 247
248 248 object ParseLiteral(string literal) {
249 249 switch (literal) {
250 250 case "null":
251 251 return null;
252 252 case "false":
253 253 return false;
254 254 case "true":
255 255 return true;
256 256 default:
257 257 UnexpectedToken(literal, JsonTokenType.Literal);
258 258 return null; // avoid compliler error
259 259 }
260 260 }
261 261
262 262 void UnexpectedToken(object value, JsonTokenType tokenType) {
263 263 throw new ParserException(String.Format("Unexpected token {0}: '{1}'", tokenType, value));
264 264 }
265 265
266 266
267 267 /// <summary>
268 268 /// Признак конца потока
269 269 /// </summary>
270 270 public bool EOF {
271 get {
272 return m_scanner.EOF;
273 }
271 get;
272 private set;
274 273 }
275 274
276 275 protected override void Dispose(bool disposing) {
277 if (disposing) {
278 m_scanner.Dispose();
279 }
276 if (disposing)
277 Safe.Dispose(m_scanner);
280 278 }
281 279
282 280 /// <summary>
283 281 /// Переходит в конец текущего объекта.
284 282 /// </summary>
285 283 public void SeekElementEnd() {
286 284 var level = Level - 1;
287 285
288 286 Debug.Assert(level >= 0);
289 287
290 288 while (Level != level)
291 289 Read();
292 290 }
293 291 }
294 292
295 293 }
@@ -1,104 +1,107
1 1 using System;
2 2 using System.Globalization;
3 3 using Implab.Automaton;
4 4 using System.Text;
5 5 using Implab.Components;
6 6 using System.IO;
7 7
8 8 namespace Implab.Formats.JSON {
9 9 /// <summary>
10 10 /// Сканнер (лексер), разбивающий поток символов на токены JSON.
11 11 /// </summary>
12 12 public class JSONScanner : Disposable {
13 13 readonly StringBuilder m_builder = new StringBuilder();
14 14
15 15 readonly ScannerContext<JSONGrammar.TokenType> m_jsonContext = JSONGrammar.Instance.JsonExpression;
16 16 readonly ScannerContext<JSONGrammar.TokenType> m_stringContext = JSONGrammar.Instance.JsonStringExpression;
17 17
18 18
19 19 readonly TextScanner m_scanner;
20 20
21 21 /// <summary>
22 22 /// Создает новый экземпляр сканнера
23 23 /// </summary>
24 24 public JSONScanner(string text) {
25 25 Safe.ArgumentNotEmpty(text, "text");
26 26
27 27 m_scanner = new StringScanner(text);
28 28 }
29 29
30 30 public JSONScanner(TextReader reader, int bufferMax, int chunkSize) {
31 31 Safe.ArgumentNotNull(reader, "reader");
32 32
33 33 m_scanner = new ReaderScanner(reader, bufferMax, chunkSize);
34 34 }
35 35
36 public JSONScanner(TextReader reader) : this(reader, 1024*1024, 1024){
37 }
38
36 39 /// <summary>
37 40 /// Читает следующий лексический элемент из входных данных.
38 41 /// </summary>
39 42 /// <param name="tokenValue">Возвращает значение прочитанного токена.</param>
40 43 /// <param name="tokenType">Возвращает тип прочитанного токена.</param>
41 44 /// <returns><c>true</c> - чтение произведено успешно. <c>false</c> - достигнут конец входных данных</returns>
42 45 /// <remarks>В случе если токен не распознается, возникает исключение. Значения токенов обрабатываются, т.е.
43 46 /// в строках обрабатываются экранированные символы, числа становтся типа double.</remarks>
44 47 public bool ReadToken(out object tokenValue, out JsonTokenType tokenType) {
45 48 JSONGrammar.TokenType[] tag;
46 49 if (m_jsonContext.Execute(m_scanner, out tag)) {
47 50 switch (tag[0]) {
48 51 case JSONGrammar.TokenType.StringBound:
49 52 tokenValue = ReadString();
50 53 tokenType = JsonTokenType.String;
51 54 break;
52 55 case JSONGrammar.TokenType.Number:
53 56 tokenValue = Double.Parse(m_scanner.GetTokenValue(), CultureInfo.InvariantCulture);
54 57 tokenType = JsonTokenType.Number;
55 58 break;
56 59 default:
57 60 tokenType = (JsonTokenType)tag[0];
58 61 tokenValue = m_scanner.GetTokenValue();
59 62 break;
60 63 }
61 64 return true;
62 65 }
63 66 tokenValue = null;
64 67 tokenType = JsonTokenType.None;
65 68 return false;
66 69 }
67 70
68 71 string ReadString() {
69 72 int pos = 0;
70 73 var buf = new char[6]; // the buffer for unescaping chars
71 74
72 75 JSONGrammar.TokenType[] tag;
73 76 m_builder.Clear();
74 77
75 78 while (m_stringContext.Execute(m_scanner, out tag)) {
76 79 switch (tag[0]) {
77 80 case JSONGrammar.TokenType.StringBound:
78 81 return m_builder.ToString();
79 82 case JSONGrammar.TokenType.UnescapedChar:
80 83 m_scanner.CopyTokenTo(m_builder);
81 84 break;
82 85 case JSONGrammar.TokenType.EscapedUnicode: // \xXXXX - unicode escape sequence
83 86 m_scanner.CopyTokenTo(buf, 0);
84 87 m_builder.Append(StringTranslator.TranslateHexUnicode(buf, 2));
85 88 pos++;
86 89 break;
87 90 case JSONGrammar.TokenType.EscapedChar: // \t - escape sequence
88 91 m_scanner.CopyTokenTo(buf, 0);
89 92 m_builder.Append(StringTranslator.TranslateEscapedChar(buf[1]));
90 93 break;
91 94 }
92 95
93 96 }
94 97
95 98 throw new ParserException("Unexpected end of data");
96 99 }
97 100
98 101 protected override void Dispose(bool disposing) {
99 102 if (disposing)
100 103 Safe.Dispose(m_scanner);
101 104 base.Dispose(disposing);
102 105 }
103 106 }
104 107 }
@@ -1,319 +1,319
1 1 using System;
2 2 using System.Collections.Generic;
3 3 using System.IO;
4 4 using System.Globalization;
5 5 using System.Diagnostics;
6 6
7 namespace Implab.JSON {
7 namespace Implab.Formats.JSON {
8 8 public class JSONWriter {
9 9 struct Context {
10 10 public bool needComma;
11 11 public JSONElementContext element;
12 12 }
13 13 Stack<Context> m_contextStack = new Stack<Context>();
14 14 Context m_context;
15 15
16 16 const int BUFFER_SIZE = 64;
17 17
18 18 TextWriter m_writer;
19 19 readonly bool m_indent = true;
20 20 readonly int m_indentSize = 4;
21 21 readonly char[] m_buffer = new char[BUFFER_SIZE];
22 22 int m_bufferPos;
23 23
24 24 static readonly char [] _hex = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
25 25 static readonly char [] _escapeBKS,
26 26 _escapeFWD,
27 27 _escapeCR,
28 28 _escapeNL,
29 29 _escapeTAB,
30 30 _escapeBSLASH,
31 31 _escapeQ;
32 32
33 33 static JSONWriter() {
34 34 _escapeBKS = "\\b".ToCharArray();
35 35 _escapeFWD = "\\f".ToCharArray();
36 36 _escapeCR = "\\r".ToCharArray();
37 37 _escapeNL = "\\n".ToCharArray();
38 38 _escapeTAB = "\\t".ToCharArray();
39 39 _escapeBSLASH = "\\\\".ToCharArray();
40 40 _escapeQ = "\\\"".ToCharArray();
41 41 }
42 42
43 43 public JSONWriter(TextWriter writer) {
44 44 Safe.ArgumentNotNull(writer, "writer");
45 45 m_writer = writer;
46 46 }
47 47
48 48 public JSONWriter(TextWriter writer, bool indent) {
49 49 Safe.ArgumentNotNull(writer, "writer");
50 50
51 51 m_writer = writer;
52 52 m_indent = indent;
53 53 }
54 54
55 55 void WriteIndent() {
56 56 if (m_indent) {
57 57 var indent = new char[m_contextStack.Count * m_indentSize + 1];
58 58 indent[0] = '\n';
59 59 for (int i = 1; i < indent.Length; i++)
60 60 indent[i] = ' ';
61 61 m_writer.Write(new String(indent));
62 62 } else {
63 63 m_writer.Write(' ');
64 64 }
65 65 }
66 66
67 67 void WriteMemberName(string name) {
68 68 Safe.ArgumentNotEmpty(name, "name");
69 69 if (m_context.element != JSONElementContext.Object)
70 70 OperationNotApplicable("WriteMember");
71 71 if (m_context.needComma)
72 72 m_writer.Write(",");
73 73
74 74 WriteIndent();
75 75 m_context.needComma = true;
76 76 Write(name);
77 77 m_writer.Write(" : ");
78 78 }
79 79
80 80 public void WriteValue(string name, string value) {
81 81 WriteMemberName(name);
82 82 Write(value);
83 83 }
84 84
85 85 public void WriteValue(string name, bool value) {
86 86 WriteMemberName(name);
87 87 Write(value);
88 88 }
89 89
90 90 public void WriteValue(string name, double value) {
91 91 WriteMemberName(name);
92 92 Write(value);
93 93 }
94 94
95 95 public void WriteValue(string value) {
96 96 if (m_context.element == JSONElementContext.Array) {
97 97
98 98 if (m_context.needComma)
99 99 m_writer.Write(",");
100 100 WriteIndent();
101 101 m_context.needComma = true;
102 102
103 103 Write(value);
104 104 } else if (m_context.element == JSONElementContext.None) {
105 105 Write(value);
106 106 m_context.element = JSONElementContext.Closed;
107 107 } else {
108 108 OperationNotApplicable("WriteValue");
109 109 }
110 110 }
111 111
112 112 public void WriteValue(bool value) {
113 113 if (m_context.element == JSONElementContext.Array) {
114 114
115 115 if (m_context.needComma)
116 116 m_writer.Write(",");
117 117 WriteIndent();
118 118 m_context.needComma = true;
119 119
120 120 Write(value);
121 121 } else if (m_context.element == JSONElementContext.None) {
122 122 Write(value);
123 123 m_context.element = JSONElementContext.Closed;
124 124 } else {
125 125 OperationNotApplicable("WriteValue");
126 126 }
127 127 }
128 128
129 129 public void WriteValue(double value) {
130 130 if (m_context.element == JSONElementContext.Array) {
131 131
132 132 if (m_context.needComma)
133 133 m_writer.Write(",");
134 134 WriteIndent();
135 135 m_context.needComma = true;
136 136
137 137 Write(value);
138 138 } else if (m_context.element == JSONElementContext.None) {
139 139 Write(value);
140 140 m_context.element = JSONElementContext.Closed;
141 141 } else {
142 142 OperationNotApplicable("WriteValue");
143 143 }
144 144 }
145 145
146 146 public void BeginObject() {
147 147 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
148 148 OperationNotApplicable("BeginObject");
149 149 if (m_context.needComma)
150 150 m_writer.Write(",");
151 151
152 152 WriteIndent();
153 153
154 154 m_context.needComma = true;
155 155
156 156 m_contextStack.Push(m_context);
157 157
158 158 m_context = new Context { element = JSONElementContext.Object, needComma = false };
159 159 m_writer.Write("{");
160 160 }
161 161
162 162 public void BeginObject(string name) {
163 163 WriteMemberName(name);
164 164
165 165 m_contextStack.Push(m_context);
166 166
167 167 m_context = new Context { element = JSONElementContext.Object, needComma = false };
168 168 m_writer.Write("{");
169 169 }
170 170
171 171 public void EndObject() {
172 172 if (m_context.element != JSONElementContext.Object)
173 173 OperationNotApplicable("EndObject");
174 174
175 175 m_context = m_contextStack.Pop();
176 176 if (m_contextStack.Count == 0)
177 177 m_context.element = JSONElementContext.Closed;
178 178 WriteIndent();
179 179 m_writer.Write("}");
180 180 }
181 181
182 182 public void BeginArray() {
183 183 if (m_context.element != JSONElementContext.None && m_context.element != JSONElementContext.Array)
184 184 throw new InvalidOperationException();
185 185 if (m_context.needComma) {
186 186 m_writer.Write(",");
187 187
188 188 }
189 189 m_context.needComma = true;
190 190
191 191 WriteIndent();
192 192 m_contextStack.Push(m_context);
193 193 m_context = new Context { element = JSONElementContext.Array, needComma = false };
194 194 m_writer.Write("[");
195 195 }
196 196
197 197 public void BeginArray(string name) {
198 198 WriteMemberName(name);
199 199
200 200 m_contextStack.Push(m_context);
201 201
202 202 m_context = new Context { element = JSONElementContext.Array, needComma = false };
203 203 m_writer.Write("[");
204 204 }
205 205
206 206 public void EndArray() {
207 207 if (m_context.element != JSONElementContext.Array)
208 208 OperationNotApplicable("EndArray");
209 209
210 210 m_context = m_contextStack.Pop();
211 211 if (m_contextStack.Count == 0)
212 212 m_context.element = JSONElementContext.Closed;
213 213 WriteIndent();
214 214 m_writer.Write("]");
215 215 }
216 216
217 217 void Write(bool value) {
218 218 m_writer.Write(value ? "true" : "false");
219 219 }
220 220
221 221 void FlushBuffer() {
222 222 if (m_bufferPos > 0) {
223 223 m_writer.Write(m_buffer, 0, m_bufferPos);
224 224 m_bufferPos = 0;
225 225 }
226 226 }
227 227
228 228 void Write(string value) {
229 229 if (value == null) {
230 230 m_writer.Write("null");
231 231 return;
232 232 }
233 233
234 234 Debug.Assert(m_bufferPos == 0);
235 235
236 236 var chars = value.ToCharArray();
237 237 m_buffer[m_bufferPos++] = '"';
238 238
239 239 // Analysis disable once ForCanBeConvertedToForeach
240 240 for (int i = 0; i < chars.Length; i++) {
241 241 var ch = chars[i];
242 242
243 243 char[] escapeSeq;
244 244
245 245 switch (ch) {
246 246 case '\b':
247 247 escapeSeq = _escapeBKS;
248 248 break;
249 249 case '\f':
250 250 escapeSeq = _escapeFWD;
251 251 break;
252 252 case '\r':
253 253 escapeSeq = _escapeCR;
254 254 break;
255 255 case '\n':
256 256 escapeSeq = _escapeNL;
257 257 break;
258 258 case '\t':
259 259 escapeSeq = _escapeTAB;
260 260 break;
261 261 case '\\':
262 262 escapeSeq = _escapeBSLASH;
263 263 break;
264 264 case '"':
265 265 escapeSeq = _escapeQ;
266 266 break;
267 267 default:
268 268 if (ch < 0x20) {
269 269 if (m_bufferPos + 6 > BUFFER_SIZE)
270 270 FlushBuffer();
271 271
272 272 m_buffer[m_bufferPos++] = '\\';
273 273 m_buffer[m_bufferPos++] = 'u';
274 274 m_buffer[m_bufferPos++] = '0';
275 275 m_buffer[m_bufferPos++] = '0';
276 276 m_buffer[m_bufferPos++] = _hex[ch >> 4 & 0xf];
277 277 m_buffer[m_bufferPos++] = _hex[ch & 0xf];
278 278
279 279 } else {
280 280 if (m_bufferPos >= BUFFER_SIZE)
281 281 FlushBuffer();
282 282 m_buffer[m_bufferPos++] = ch;
283 283 }
284 284 continue;
285 285 }
286 286
287 287 if (m_bufferPos + escapeSeq.Length > BUFFER_SIZE)
288 288 FlushBuffer();
289 289
290 290 Array.Copy(escapeSeq, 0, m_buffer, m_bufferPos, escapeSeq.Length);
291 291 m_bufferPos += escapeSeq.Length;
292 292
293 293 }
294 294
295 295 if (m_bufferPos >= BUFFER_SIZE)
296 296 FlushBuffer();
297 297
298 298 m_buffer[m_bufferPos++] = '"';
299 299
300 300 FlushBuffer();
301 301 }
302 302
303 303 void Write(double value) {
304 304 if (double.IsNaN(value))
305 305 Write("NaN");
306 306 else if (double.IsNegativeInfinity(value))
307 307 Write("-Infinity");
308 308 else if (double.IsPositiveInfinity(value))
309 309 Write("Infinity");
310 310 else
311 311 m_writer.Write(value.ToString(CultureInfo.InvariantCulture));
312 312 }
313 313
314 314 void OperationNotApplicable(string opName) {
315 315 throw new InvalidOperationException(String.Format("The operation '{0}' isn't applicable in the context of '{1}'", opName, m_context.element ));
316 316 }
317 317
318 318 }
319 319 }
@@ -1,343 +1,335
1 1 using Implab;
2 using Implab.Parsing;
3 2 using System;
4 3 using System.Collections.Generic;
5 4 using System.Globalization;
6 5 using System.IO;
7 using System.Linq;
8 using System.Text;
9 using System.Threading.Tasks;
10 6 using System.Xml;
11 7
12 namespace Implab.JSON {
8 namespace Implab.Formats.JSON {
13 9 public class JSONXmlReader : XmlReader {
14 10
15 11 enum ValueContext {
16 12 Undefined,
17 13 ElementStart,
18 14 ElementValue,
19 15 ElementEnd,
20 16 ElementEmpty
21 17 }
22 18
23 19 struct LocalNameContext {
24 20 public string localName;
25 21 public bool isArray;
26 22 }
27 23
28 24 JSONParser m_parser;
29 25 ValueContext m_valueContext;
30 26 ReadState m_state = ReadState.Initial;
31 27 Stack<LocalNameContext> m_localNameStack = new Stack<LocalNameContext>();
32 28 LocalNameContext m_localName;
33 int m_depthCorrection = 0;
29 int m_depthCorrection;
34 30
35 31 readonly string m_rootName;
36 32 readonly string m_prefix;
37 33 readonly string m_namespaceUri;
38 34 readonly bool m_flattenArrays;
39 35 readonly string m_arrayItemName;
40 36 readonly XmlNameTable m_nameTable;
41 37
42 38 JSONXmlReader(JSONParser parser, JSONXmlReaderOptions options) {
43 39 m_parser = parser;
44 40
45 41 if (options != null) {
46 42 m_prefix = options.NodesPrefix ?? String.Empty;
47 43 m_namespaceUri = options.NamespaceURI ?? String.Empty;
48 44 m_rootName = options.RootName ?? "json";
49 45 m_flattenArrays = options.FlattenArrays;
50 46 m_arrayItemName = options.ArrayItemName ?? "item";
51 47 m_nameTable = options.NameTable ?? new NameTable();
52 48 } else {
53 49 m_prefix = String.Empty;
54 50 m_namespaceUri = String.Empty;
55 51 m_rootName = "json";
56 52 m_flattenArrays = false;
57 53 m_arrayItemName = "item";
58 54 m_nameTable = new NameTable();
59 55 }
60 56 }
61 57
62 58 /// <summary>
63 59 /// Always 0, JSON doesn't support attributes
64 60 /// </summary>
65 61 public override int AttributeCount {
66 62 get { return 0; }
67 63 }
68 64
69 65 public override string BaseURI {
70 66 get { return String.Empty; }
71 67 }
72 68
73 69 public override int Depth {
74 70 get {
75 71 return m_localNameStack.Count + m_depthCorrection;
76 72 }
77 73 }
78 74
79 75 public override bool EOF {
80 76 get { return m_parser.EOF; }
81 77 }
82 78
83 79 /// <summary>
84 80 /// Always throws an exception
85 81 /// </summary>
86 82 /// <param name="i"></param>
87 83 /// <returns></returns>
88 84 public override string GetAttribute(int i) {
89 85 throw new ArgumentOutOfRangeException();
90 86 }
91 87
92 88 /// <summary>
93 89 /// Always returns empty string
94 90 /// </summary>
95 91 /// <param name="name"></param>
96 92 /// <param name="namespaceURI"></param>
97 93 /// <returns></returns>
98 94 public override string GetAttribute(string name, string namespaceURI) {
99 95 return String.Empty;
100 96 }
101 97
102 98 /// <summary>
103 99 /// Always returns empty string
104 100 /// </summary>
105 101 /// <param name="name"></param>
106 102 /// <returns></returns>
107 103 public override string GetAttribute(string name) {
108 104 return String.Empty;
109 105 }
110 106
111 107 public override bool IsEmptyElement {
112 108 get { return m_parser.ElementType == JSONElementType.Value && m_valueContext == ValueContext.ElementEmpty; }
113 109 }
114 110
115 111 public override string LocalName {
116 112 get { return m_localName.localName; }
117 113 }
118 114
119 115 public override string LookupNamespace(string prefix) {
120 116 if (String.IsNullOrEmpty(prefix) || prefix == m_prefix)
121 117 return m_namespaceUri;
122 else
118
123 119 return String.Empty;
124 120 }
125 121
126 122 public override bool MoveToAttribute(string name, string ns) {
127 123 return false;
128 124 }
129 125
130 126 public override bool MoveToAttribute(string name) {
131 127 return false;
132 128 }
133 129
134 130 public override bool MoveToElement() {
135 131 return false;
136 132 }
137 133
138 134 public override bool MoveToFirstAttribute() {
139 135 return false;
140 136 }
141 137
142 138 public override bool MoveToNextAttribute() {
143 139 return false;
144 140 }
145 141
146 142 public override XmlNameTable NameTable {
147 143 get { return m_nameTable; }
148 144 }
149 145
150 146 public override string NamespaceURI {
151 147 get { return m_namespaceUri; }
152 148 }
153 149
154 150 public override XmlNodeType NodeType {
155 151 get {
156 152 switch (m_parser.ElementType) {
157 153 case JSONElementType.BeginObject:
158 154 case JSONElementType.BeginArray:
159 155 return XmlNodeType.Element;
160 156 case JSONElementType.EndObject:
161 157 case JSONElementType.EndArray:
162 158 return XmlNodeType.EndElement;
163 159 case JSONElementType.Value:
164 160 switch (m_valueContext) {
165 161 case ValueContext.ElementStart:
166 162 case ValueContext.ElementEmpty:
167 163 return XmlNodeType.Element;
168 164 case ValueContext.ElementValue:
169 165 return XmlNodeType.Text;
170 166 case ValueContext.ElementEnd:
171 167 return XmlNodeType.EndElement;
172 168 default:
173 169 throw new InvalidOperationException();
174 170 }
175 171 default:
176 172 throw new InvalidOperationException();
177 173 }
178 174 }
179 175 }
180 176
181 177 public override string Prefix {
182 178 get { return m_prefix; }
183 179 }
184 180
185 181 public override bool Read() {
186 if (m_state != System.Xml.ReadState.Interactive && m_state != System.Xml.ReadState.Initial)
182 if (m_state != ReadState.Interactive && m_state != ReadState.Initial)
187 183 return false;
188 184
189 185 if (m_state == ReadState.Initial)
190 m_state = System.Xml.ReadState.Interactive;
186 m_state = ReadState.Interactive;
191 187
192 188 try {
193 189 switch (m_parser.ElementType) {
194 190 case JSONElementType.Value:
195 191 switch (m_valueContext) {
196 192 case ValueContext.ElementStart:
197 193 SetLocalName(String.Empty);
198 194 m_valueContext = ValueContext.ElementValue;
199 195 return true;
200 196 case ValueContext.ElementValue:
201 197 RestoreLocalName();
202 198 m_valueContext = ValueContext.ElementEnd;
203 199 return true;
204 200 case ValueContext.ElementEmpty:
205 201 case ValueContext.ElementEnd:
206 202 RestoreLocalName();
207 203 break;
208 204 }
209 205 break;
210 206 case JSONElementType.EndArray:
211 207 case JSONElementType.EndObject:
212 208 RestoreLocalName();
213 209 break;
214 210 }
215 211 string itemName = m_parser.ElementType == JSONElementType.None ? m_rootName : m_flattenArrays ? m_localName.localName : m_arrayItemName;
216 212 while (m_parser.Read()) {
217 213 if (!String.IsNullOrEmpty(m_parser.ElementName))
218 214 itemName = m_parser.ElementName;
219 215
220 216 switch (m_parser.ElementType) {
221 217 case JSONElementType.BeginArray:
222 218 if (m_flattenArrays && !m_localName.isArray) {
223 219 m_depthCorrection--;
224 220 SetLocalName(itemName, true);
225 221 continue;
226 } else {
222 }
227 223 SetLocalName(itemName, true);
228 }
229 224 break;
230 225 case JSONElementType.BeginObject:
231 226 SetLocalName(itemName);
232 227 break;
233 228 case JSONElementType.EndArray:
234 229 if (m_flattenArrays && !m_localNameStack.Peek().isArray) {
235 230 RestoreLocalName();
236 231 m_depthCorrection++;
237 232 continue;
238 233 }
239 234 break;
240 235 case JSONElementType.EndObject:
241 236 break;
242 237 case JSONElementType.Value:
243 238 SetLocalName(itemName);
244 239 m_valueContext = m_parser.ElementValue == null ? ValueContext.ElementEmpty : ValueContext.ElementStart;
245 240 break;
246 default:
247 break;
248 241 }
249 242 return true;
250 243 }
251 244
252 m_state = System.Xml.ReadState.EndOfFile;
245 m_state = ReadState.EndOfFile;
253 246 return false;
254 247 } catch {
255 m_state = System.Xml.ReadState.Error;
248 m_state = ReadState.Error;
256 249 throw;
257 250 }
258 251 }
259 252
260 253 public override bool ReadAttributeValue() {
261 254 return false;
262 255 }
263 256
264 257 public override ReadState ReadState {
265 258 get { return m_state; }
266 259 }
267 260
268 261 public override void ResolveEntity() {
269 262 // do nothing
270 263 }
271 264
272 265 public override string Value {
273 266 get {
274 267 if (m_parser.ElementValue == null)
275 268 return String.Empty;
276 269 if (Convert.GetTypeCode(m_parser.ElementValue) == TypeCode.Double)
277 270 return ((double)m_parser.ElementValue).ToString(CultureInfo.InvariantCulture);
278 else
279 271 return m_parser.ElementValue.ToString();
280 272 }
281 273 }
282 274
283 275 void SetLocalName(string name) {
284 276 m_localNameStack.Push(m_localName);
285 277 m_localName.localName = name;
286 278 m_localName.isArray = false;
287 279 }
288 280
289 281 void SetLocalName(string name, bool isArray) {
290 282 m_localNameStack.Push(m_localName);
291 283 m_localName.localName = name;
292 284 m_localName.isArray = isArray;
293 285 }
294 286
295 287 void RestoreLocalName() {
296 288 m_localName = m_localNameStack.Pop();
297 289 }
298 290
299 291 public override void Close() {
300 292
301 293 }
302 294
303 295 protected override void Dispose(bool disposing) {
304 296 #if MONO
305 297 disposing = true;
306 298 #endif
307 299 if (disposing) {
308 300 m_parser.Dispose();
309 301 }
310 302 base.Dispose(disposing);
311 303 }
312 304
313 305 public static JSONXmlReader Create(string file, JSONXmlReaderOptions options) {
314 306 return Create(File.OpenText(file), options);
315 307 }
316 308
317 309 /// <summary>
318 310 /// Creates the XmlReader for the specified text stream with JSON data.
319 311 /// </summary>
320 312 /// <param name="reader">Text reader.</param>
321 313 /// <param name="options">Options.</param>
322 314 /// <remarks>
323 315 /// The reader will be disposed when the XmlReader is disposed.
324 316 /// </remarks>
325 317 public static JSONXmlReader Create(TextReader reader, JSONXmlReaderOptions options) {
326 return new JSONXmlReader(new JSONParser(reader, true), options);
318 return new JSONXmlReader(new JSONParser(reader), options);
327 319 }
328 320
329 321 /// <summary>
330 322 /// Creates the XmlReader for the specified stream with JSON data.
331 323 /// </summary>
332 324 /// <param name="stream">Stream.</param>
333 325 /// <param name="options">Options.</param>
334 326 /// <remarks>
335 327 /// The stream will be disposed when the XmlReader is disposed.
336 328 /// </remarks>
337 329 public static JSONXmlReader Create(Stream stream, JSONXmlReaderOptions options) {
338 330 Safe.ArgumentNotNull(stream, "stream");
339 331 // HACK don't dispose StreaReader to keep stream opened
340 332 return Create(new StreamReader(stream), options);
341 333 }
342 334 }
343 335 }
@@ -1,65 +1,62
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
1
5 2 using System.Xml;
6 3
7 namespace Implab.JSON {
4 namespace Implab.Formats.JSON {
8 5 /// <summary>
9 6 /// Набор необязательных параметров для <see cref="JSONXmlReader"/>, позволяющий управлять процессом
10 7 /// интерпретации <c>JSON</c> документа.
11 8 /// </summary>
12 9 public class JSONXmlReaderOptions {
13 10 /// <summary>
14 11 /// Пространство имен в котором будут располагаться читаемые элементы документа
15 12 /// </summary>
16 13 public string NamespaceURI {
17 14 get;
18 15 set;
19 16 }
20 17
21 18 /// <summary>
22 19 /// Интерпретировать массивы как множественные элементы (убирает один уровень вложенности), иначе массив
23 20 /// представляется в виде узла, дочерними элементами которого являются элементы массива, имена дочерних элементов
24 21 /// определяются свойством <see cref="ArrayItemName"/>. По умолчанию <c>false</c>.
25 22 /// </summary>
26 23 public bool FlattenArrays {
27 24 get;
28 25 set;
29 26 }
30 27
31 28 /// <summary>
32 29 /// Префикс, для узлов документа
33 30 /// </summary>
34 31 public string NodesPrefix {
35 32 get;
36 33 set;
37 34 }
38 35
39 36 /// <summary>
40 37 /// Имя корневого элемента в xml документе
41 38 /// </summary>
42 39 public string RootName {
43 40 get;
44 41 set;
45 42 }
46 43
47 44 /// <summary>
48 45 /// Имя элемента для массивов, если не включена опция <see cref="FlattenArrays"/>.
49 46 /// По умолчанию <c>item</c>.
50 47 /// </summary>
51 48 public string ArrayItemName {
52 49 get;
53 50 set;
54 51 }
55 52
56 53 /// <summary>
57 54 /// Таблица атомизированных строк для построения документа.
58 55 /// </summary>
59 56 public XmlNameTable NameTable {
60 57 get;
61 58 set;
62 59 }
63 60
64 61 }
65 62 }
@@ -1,95 +1,52
1 1 using Implab;
2 2 using Implab.Formats;
3 3 using System;
4 4 using System.Collections.Generic;
5 5 using System.Diagnostics;
6 6 using System.Linq;
7 7 using System.Text;
8 8 using System.Threading.Tasks;
9 9
10 10 namespace Implab.Formats.JSON {
11 11 /// <summary>
12 12 /// Класс для преобразования экранированной строки JSON
13 13 /// </summary>
14 public class StringTranslator : TextScanner<JSONGrammar.TokenType> {
14 static class StringTranslator {
15 15 static readonly char[] _escMap;
16 16 static readonly int[] _hexMap;
17 17
18 18 static StringTranslator() {
19 19 var chars = new char[] { 'b', 'f', 't', 'r', 'n', '\\', '/' };
20 20 var vals = new char[] { '\b', '\f', '\t', '\r', '\n', '\\', '/' };
21 21
22 22 _escMap = new char[chars.Max() + 1];
23 23
24 24 for (int i = 0; i < chars.Length; i++)
25 25 _escMap[chars[i]] = vals[i];
26 26
27 27 var hexs = new char[] { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'A', 'B', 'C', 'D', 'E', 'F' };
28 28 var ints = new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 10, 11, 12, 13, 14, 15 };
29 29
30 30 _hexMap = new int[hexs.Max() + 1];
31 31
32 32 for (int i = 0; i < hexs.Length; i++)
33 33 _hexMap[hexs[i]] = ints[i];
34 34
35 35 }
36 36
37 public StringTranslator() {
38 }
39
40 public string Translate(string data) {
41 Safe.ArgumentNotNull(data, "data");
42 return Translate(data.ToCharArray());
43 }
44
45 public string Translate(char[] data) {
46 Safe.ArgumentNotNull(data, "data");
47 return Translate(data, data.Length);
48 }
49
50 public string Translate(char[] data, int length) {
51 Safe.ArgumentNotNull(data, "data");
52 Safe.ArgumentInRange(length, 0, data.Length, "length");
53
54 var translated = new char[length];
55
56 Feed(data,length);
57
58 int pos = 0;
59
60 while (ReadTokenInternal()) {
61 switch ((JSONGrammar.TokenType)Tags[0]) {
62 case JSONGrammar.TokenType.UnescapedChar:
63 Array.Copy(m_buffer,m_tokenOffset,translated,pos,m_tokenLen);
64 pos += m_tokenLen;
65 break;
66 case JSONGrammar.TokenType.EscapedChar:
67 translated[pos] = _escMap[m_buffer[m_tokenOffset + 1]];
68 pos++;
69 break;
70 case JSONGrammar.TokenType.EscapedUnicode:
71 translated[pos] = TranslateHexUnicode(m_buffer,m_tokenOffset + 2);
72 pos++;
73 break;
74 }
75 }
76
77 return new String(translated, 0, pos);
78 }
79
80 37 internal static char TranslateEscapedChar(char symbol) {
81 38 return _escMap[symbol];
82 39 }
83 40
84 41 internal static char TranslateHexUnicode(char[] symbols, int offset) {
85 42 Debug.Assert(symbols != null);
86 43 Debug.Assert(symbols.Length - offset >= 4);
87 44
88 45 int value = (_hexMap[symbols[offset]] << 12)
89 46 | (_hexMap[symbols[offset + 1]] << 8)
90 47 | (_hexMap[symbols[offset + 2]] << 4)
91 48 | (_hexMap[symbols[offset + 3]]);
92 49 return (char)value;
93 50 }
94 51 }
95 52 }
@@ -1,150 +1,156
1 1 using System;
2 2 using Implab.Components;
3 3 using System.Diagnostics;
4 4 using Implab.Automaton;
5 5 using System.Text;
6 6
7 7 namespace Implab.Formats {
8 8 public abstract class TextScanner : Disposable {
9 9 readonly int m_bufferMax;
10 10 readonly int m_chunkSize;
11 11
12 12 char[] m_buffer;
13 13 int m_bufferOffset;
14 14 int m_bufferSize;
15 15 int m_tokenOffset;
16 16 int m_tokenLength;
17 17
18 18 /// <summary>
19 19 /// Initializes a new instance of the <see cref="Implab.Formats.TextScanner"/> class.
20 20 /// </summary>
21 21 /// <param name="bufferMax">Buffer max.</param>
22 22 /// <param name="chunkSize">Chunk size.</param>
23 23 protected TextScanner(int bufferMax, int chunkSize) {
24 24 Debug.Assert(m_chunkSize <= m_bufferMax);
25 25
26 26 m_bufferMax = bufferMax;
27 27 m_chunkSize = chunkSize;
28 28 }
29 29
30 30 /// <summary>
31 31 /// Initializes a new instance of the <see cref="Implab.Formats.TextScanner"/> class.
32 32 /// </summary>
33 33 /// <param name="buffer">Buffer.</param>
34 34 protected TextScanner(char[] buffer) {
35 35 if (buffer != null) {
36 36 m_buffer = buffer;
37 37 m_bufferSize = buffer.Length;
38 38 }
39 39 }
40 40
41 41 /// <summary>
42 42 /// (hungry) Reads the next token.
43 43 /// </summary>
44 44 /// <returns><c>true</c>, if token internal was read, <c>false</c> if there is no more tokens in the stream.</returns>
45 45 /// <param name="dfa">The transition map for the automaton</param>
46 46 /// <param name="final">Final states of the automaton.</param>
47 47 /// <param name="tags">Tags.</param>
48 48 /// <param name="state">The initial state for the automaton.</param>
49 49 /// <param name="alphabet"></param>
50 50 /// <param name = "tag"></param>
51 51 internal bool ReadToken<TTag>(int[,] dfa, bool[] final, TTag[][] tags, int state, int[] alphabet, out TTag[] tag) {
52 Safe.ArgumentNotNull();
53 52 m_tokenLength = 0;
53 tag = null;
54 54
55 55 var maxSymbol = alphabet.Length - 1;
56 56
57 57 do {
58 58 // after the next chunk is read the offset in the buffer may change
59 59 int pos = m_bufferOffset + m_tokenLength;
60 60
61 61 while (pos < m_bufferSize) {
62 62 var ch = m_buffer[pos];
63 63
64 64 state = dfa[state, ch > maxSymbol ? AutomatonConst.UNCLASSIFIED_INPUT : alphabet[ch]];
65 65 if (state == AutomatonConst.UNREACHABLE_STATE)
66 66 break;
67 67
68 68 pos++;
69 69 }
70 70
71 71 m_tokenLength = pos - m_bufferOffset;
72 72 } while (state != AutomatonConst.UNREACHABLE_STATE && Feed());
73 73
74 74 m_tokenOffset = m_bufferOffset;
75 75 m_bufferOffset += m_tokenLength;
76 76
77 77 if (final[state]) {
78 78 tag = tags[state];
79 79 return true;
80 80 }
81 81
82 82 if (m_bufferOffset == m_bufferSize) {
83 83 if (m_tokenLength == 0) //EOF
84 84 return false;
85 85
86 86 throw new ParserException();
87 87 }
88 88
89 89 throw new ParserException(String.Format("Unexpected symbol '{0}'", m_buffer[m_bufferOffset]));
90 90
91 91 }
92 92
93 93 protected void Feed(char[] buffer, int offset, int length) {
94 94 m_buffer = buffer;
95 95 m_bufferOffset = offset;
96 96 m_bufferSize = offset + length;
97 97 }
98 98
99 99 protected bool Feed() {
100 100 if (m_chunkSize <= 0)
101 101 return false;
102 102
103 103 if (m_buffer != null) {
104 104 var free = m_buffer.Length - m_bufferSize;
105 105
106 106 if (free < m_chunkSize) {
107 107 free += m_chunkSize;
108 108 var used = m_bufferSize - m_bufferOffset;
109 109 var size = used + free;
110 110
111 111 if (size > m_bufferMax)
112 112 throw new ParserException(String.Format("The buffer limit ({0} Kb) is reached", m_bufferMax/1024));
113 113
114 114 var temp = new char[size];
115 115
116 116 var read = Read(temp, used, m_chunkSize);
117 117 if (read == 0)
118 118 return false;
119 119
120 120 Array.Copy(m_buffer, m_bufferOffset, temp, 0, used);
121 121
122 122 m_bufferOffset = 0;
123 123 m_bufferSize = used + read;
124 124 m_buffer = temp;
125 } else {
126 var read = Read(m_buffer, m_bufferSize, m_chunkSize);
127 if (read == 0)
128 return false;
129 m_bufferSize += m_chunkSize;
125 130 }
131 return true;
126 132 } else {
127 133 Debug.Assert(m_bufferOffset == 0);
128 134 m_buffer = new char[m_chunkSize];
129 135 m_bufferSize = Read(m_buffer, 0, m_chunkSize);
130 136 return (m_bufferSize != 0);
131 137 }
132 138 }
133 139
134 140 protected abstract int Read(char[] buffer, int offset, int size);
135 141
136 142 public string GetTokenValue() {
137 143 return new String(m_buffer, m_tokenOffset, m_tokenLength);
138 144 }
139 145
140 146 public void CopyTokenTo(char[] buffer, int offset) {
141 147 m_buffer.CopyTo(buffer, offset);
142 148 }
143 149
144 150 public void CopyTokenTo(StringBuilder sb) {
145 151 sb.Append(m_buffer, m_tokenOffset, m_tokenLength);
146 152 }
147 153
148 154 }
149 155 }
150 156
@@ -1,276 +1,274
1 1 <?xml version="1.0" encoding="utf-8"?>
2 2 <Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
3 3 <PropertyGroup>
4 4 <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
5 5 <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
6 6 <ProjectGuid>{F550F1F8-8746-4AD0-9614-855F4C4B7F05}</ProjectGuid>
7 7 <OutputType>Library</OutputType>
8 8 <RootNamespace>Implab</RootNamespace>
9 9 <AssemblyName>Implab</AssemblyName>
10 10 <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
11 11 <ReleaseVersion>0.2</ReleaseVersion>
12 12 <ProductVersion>8.0.30703</ProductVersion>
13 13 <SchemaVersion>2.0</SchemaVersion>
14 14 </PropertyGroup>
15 15 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
16 16 <DebugSymbols>true</DebugSymbols>
17 17 <DebugType>full</DebugType>
18 18 <Optimize>false</Optimize>
19 19 <OutputPath>bin\Debug</OutputPath>
20 20 <DefineConstants>TRACE;DEBUG;</DefineConstants>
21 21 <ErrorReport>prompt</ErrorReport>
22 22 <WarningLevel>4</WarningLevel>
23 23 <ConsolePause>false</ConsolePause>
24 24 <RunCodeAnalysis>true</RunCodeAnalysis>
25 25 </PropertyGroup>
26 26 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
27 27 <DebugType>full</DebugType>
28 28 <Optimize>true</Optimize>
29 29 <OutputPath>bin\Release</OutputPath>
30 30 <ErrorReport>prompt</ErrorReport>
31 31 <WarningLevel>4</WarningLevel>
32 32 <ConsolePause>false</ConsolePause>
33 33 </PropertyGroup>
34 34 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug 4.5|AnyCPU' ">
35 35 <DebugSymbols>true</DebugSymbols>
36 36 <DebugType>full</DebugType>
37 37 <Optimize>false</Optimize>
38 38 <OutputPath>bin\Debug</OutputPath>
39 39 <DefineConstants>TRACE;DEBUG;NET_4_5</DefineConstants>
40 40 <ErrorReport>prompt</ErrorReport>
41 41 <WarningLevel>4</WarningLevel>
42 42 <RunCodeAnalysis>true</RunCodeAnalysis>
43 43 <ConsolePause>false</ConsolePause>
44 44 </PropertyGroup>
45 45 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release 4.5|AnyCPU' ">
46 46 <Optimize>true</Optimize>
47 47 <OutputPath>bin\Release</OutputPath>
48 48 <ErrorReport>prompt</ErrorReport>
49 49 <WarningLevel>4</WarningLevel>
50 50 <ConsolePause>false</ConsolePause>
51 51 <DefineConstants>NET_4_5</DefineConstants>
52 52 </PropertyGroup>
53 53 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'DebugMono|AnyCPU' ">
54 54 <DebugSymbols>true</DebugSymbols>
55 55 <DebugType>full</DebugType>
56 56 <Optimize>false</Optimize>
57 57 <OutputPath>bin\Debug</OutputPath>
58 58 <DefineConstants>TRACE;DEBUG;NET_4_5;MONO</DefineConstants>
59 59 <ErrorReport>prompt</ErrorReport>
60 60 <WarningLevel>4</WarningLevel>
61 61 <RunCodeAnalysis>true</RunCodeAnalysis>
62 62 <ConsolePause>false</ConsolePause>
63 63 </PropertyGroup>
64 64 <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'ReleaseMono|AnyCPU' ">
65 65 <Optimize>true</Optimize>
66 66 <OutputPath>bin\Release</OutputPath>
67 67 <DefineConstants>NET_4_5;MONO;</DefineConstants>
68 68 <ErrorReport>prompt</ErrorReport>
69 69 <WarningLevel>4</WarningLevel>
70 70 <ConsolePause>false</ConsolePause>
71 71 </PropertyGroup>
72 72 <ItemGroup>
73 73 <Reference Include="System" />
74 74 <Reference Include="System.Xml" />
75 75 <Reference Include="mscorlib" />
76 76 </ItemGroup>
77 77 <ItemGroup>
78 78 <Compile Include="CustomEqualityComparer.cs" />
79 79 <Compile Include="Diagnostics\ConsoleTraceListener.cs" />
80 80 <Compile Include="Diagnostics\EventText.cs" />
81 81 <Compile Include="Diagnostics\LogChannel.cs" />
82 82 <Compile Include="Diagnostics\LogicalOperation.cs" />
83 83 <Compile Include="Diagnostics\TextFileListener.cs" />
84 84 <Compile Include="Diagnostics\TraceLog.cs" />
85 85 <Compile Include="Diagnostics\TraceEvent.cs" />
86 86 <Compile Include="Diagnostics\TraceEventType.cs" />
87 87 <Compile Include="ICancellable.cs" />
88 88 <Compile Include="IProgressHandler.cs" />
89 89 <Compile Include="IProgressNotifier.cs" />
90 90 <Compile Include="IPromiseT.cs" />
91 91 <Compile Include="IPromise.cs" />
92 92 <Compile Include="IServiceLocator.cs" />
93 93 <Compile Include="ITaskController.cs" />
94 94 <Compile Include="Parallels\DispatchPool.cs" />
95 95 <Compile Include="Parallels\ArrayTraits.cs" />
96 96 <Compile Include="Parallels\MTQueue.cs" />
97 97 <Compile Include="Parallels\WorkerPool.cs" />
98 98 <Compile Include="ProgressInitEventArgs.cs" />
99 99 <Compile Include="Properties\AssemblyInfo.cs" />
100 100 <Compile Include="Parallels\AsyncPool.cs" />
101 101 <Compile Include="Safe.cs" />
102 102 <Compile Include="ValueEventArgs.cs" />
103 103 <Compile Include="PromiseExtensions.cs" />
104 104 <Compile Include="SyncContextPromise.cs" />
105 105 <Compile Include="Diagnostics\OperationContext.cs" />
106 106 <Compile Include="Diagnostics\TraceContext.cs" />
107 107 <Compile Include="Diagnostics\LogEventArgs.cs" />
108 108 <Compile Include="Diagnostics\LogEventArgsT.cs" />
109 109 <Compile Include="Diagnostics\Extensions.cs" />
110 110 <Compile Include="PromiseEventType.cs" />
111 111 <Compile Include="Parallels\AsyncQueue.cs" />
112 112 <Compile Include="PromiseT.cs" />
113 113 <Compile Include="IDeferred.cs" />
114 114 <Compile Include="IDeferredT.cs" />
115 115 <Compile Include="Promise.cs" />
116 116 <Compile Include="PromiseTransientException.cs" />
117 117 <Compile Include="Parallels\Signal.cs" />
118 118 <Compile Include="Parallels\SharedLock.cs" />
119 119 <Compile Include="Diagnostics\ILogWriter.cs" />
120 120 <Compile Include="Diagnostics\ListenerBase.cs" />
121 121 <Compile Include="Parallels\BlockingQueue.cs" />
122 122 <Compile Include="AbstractEvent.cs" />
123 123 <Compile Include="AbstractPromise.cs" />
124 124 <Compile Include="AbstractPromiseT.cs" />
125 125 <Compile Include="FuncTask.cs" />
126 126 <Compile Include="FuncTaskBase.cs" />
127 127 <Compile Include="FuncTaskT.cs" />
128 128 <Compile Include="ActionChainTaskBase.cs" />
129 129 <Compile Include="ActionChainTask.cs" />
130 130 <Compile Include="ActionChainTaskT.cs" />
131 131 <Compile Include="FuncChainTaskBase.cs" />
132 132 <Compile Include="FuncChainTask.cs" />
133 133 <Compile Include="FuncChainTaskT.cs" />
134 134 <Compile Include="ActionTaskBase.cs" />
135 135 <Compile Include="ActionTask.cs" />
136 136 <Compile Include="ActionTaskT.cs" />
137 137 <Compile Include="ICancellationToken.cs" />
138 138 <Compile Include="SuccessPromise.cs" />
139 139 <Compile Include="SuccessPromiseT.cs" />
140 140 <Compile Include="PromiseAwaiterT.cs" />
141 141 <Compile Include="PromiseAwaiter.cs" />
142 142 <Compile Include="Components\ComponentContainer.cs" />
143 143 <Compile Include="Components\Disposable.cs" />
144 144 <Compile Include="Components\DisposablePool.cs" />
145 145 <Compile Include="Components\ObjectPool.cs" />
146 146 <Compile Include="Components\ServiceLocator.cs" />
147 147 <Compile Include="Components\IInitializable.cs" />
148 148 <Compile Include="TaskController.cs" />
149 149 <Compile Include="Components\App.cs" />
150 150 <Compile Include="Components\IRunnable.cs" />
151 151 <Compile Include="Components\ExecutionState.cs" />
152 152 <Compile Include="Components\RunnableComponent.cs" />
153 153 <Compile Include="Components\IFactory.cs" />
154 <Compile Include="Automaton\EnumAlphabet.cs" />
155 154 <Compile Include="Automaton\IAlphabet.cs" />
156 155 <Compile Include="Automaton\ParserException.cs" />
157 156 <Compile Include="Automaton\IndexedAlphabetBase.cs" />
158 157 <Compile Include="Automaton\IAlphabetBuilder.cs" />
159 158 <Compile Include="Automaton\RegularExpressions\AltToken.cs" />
160 159 <Compile Include="Automaton\RegularExpressions\BinaryToken.cs" />
161 160 <Compile Include="Automaton\RegularExpressions\CatToken.cs" />
162 161 <Compile Include="Automaton\RegularExpressions\StarToken.cs" />
163 162 <Compile Include="Automaton\RegularExpressions\SymbolToken.cs" />
164 163 <Compile Include="Automaton\RegularExpressions\EmptyToken.cs" />
165 164 <Compile Include="Automaton\RegularExpressions\Token.cs" />
166 165 <Compile Include="Automaton\RegularExpressions\IVisitor.cs" />
167 166 <Compile Include="Automaton\AutomatonTransition.cs" />
168 167 <Compile Include="Formats\JSON\JSONElementContext.cs" />
169 168 <Compile Include="Formats\JSON\JSONElementType.cs" />
170 169 <Compile Include="Formats\JSON\JSONGrammar.cs" />
171 170 <Compile Include="Formats\JSON\JSONParser.cs" />
172 171 <Compile Include="Formats\JSON\JSONScanner.cs" />
173 172 <Compile Include="Formats\JSON\JsonTokenType.cs" />
174 173 <Compile Include="Formats\JSON\JSONWriter.cs" />
175 174 <Compile Include="Formats\JSON\JSONXmlReader.cs" />
176 175 <Compile Include="Formats\JSON\JSONXmlReaderOptions.cs" />
177 176 <Compile Include="Formats\JSON\StringTranslator.cs" />
178 177 <Compile Include="Automaton\MapAlphabet.cs" />
179 <Compile Include="Automaton\DummyAlphabet.cs" />
180 178 <Compile Include="Formats\CharAlphabet.cs" />
181 179 <Compile Include="Formats\ByteAlphabet.cs" />
182 180 <Compile Include="Automaton\IDFATable.cs" />
183 181 <Compile Include="Automaton\IDFATableBuilder.cs" />
184 182 <Compile Include="Automaton\DFATable.cs" />
185 183 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitor.cs" />
186 184 <Compile Include="Automaton\RegularExpressions\ITaggedDFABuilder.cs" />
187 185 <Compile Include="Formats\TextScanner.cs" />
188 186 <Compile Include="Formats\StringScanner.cs" />
189 187 <Compile Include="Formats\ReaderScanner.cs" />
190 188 <Compile Include="Formats\ScannerContext.cs" />
191 189 <Compile Include="Formats\Grammar.cs" />
192 190 <Compile Include="Automaton\RegularExpressions\EndTokenT.cs" />
193 191 <Compile Include="Automaton\RegularExpressions\EndToken.cs" />
194 192 <Compile Include="Automaton\RegularExpressions\RegularExpressionVisitorT.cs" />
195 193 <Compile Include="Automaton\AutomatonConst.cs" />
196 194 <Compile Include="Automaton\RegularExpressions\RegularDFA.cs" />
197 195 <Compile Include="Components\LazyAndWeak.cs" />
198 196 </ItemGroup>
199 197 <Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
200 198 <ItemGroup />
201 199 <ProjectExtensions>
202 200 <MonoDevelop>
203 201 <Properties>
204 202 <Policies>
205 203 <CSharpFormattingPolicy IndentSwitchBody="True" NamespaceBraceStyle="EndOfLine" ClassBraceStyle="EndOfLine" InterfaceBraceStyle="EndOfLine" StructBraceStyle="EndOfLine" EnumBraceStyle="EndOfLine" MethodBraceStyle="EndOfLine" ConstructorBraceStyle="EndOfLine" DestructorBraceStyle="EndOfLine" BeforeMethodDeclarationParentheses="False" BeforeMethodCallParentheses="False" BeforeConstructorDeclarationParentheses="False" NewLineBeforeConstructorInitializerColon="NewLine" NewLineAfterConstructorInitializerColon="SameLine" BeforeIndexerDeclarationBracket="False" BeforeDelegateDeclarationParentheses="False" NewParentheses="False" SpacesBeforeBrackets="False" inheritsSet="Mono" inheritsScope="text/x-csharp" scope="text/x-csharp" />
206 204 <TextStylePolicy FileWidth="120" EolMarker="Unix" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/x-csharp" />
207 205 <DotNetNamingPolicy DirectoryNamespaceAssociation="PrefixedHierarchical" ResourceNamePolicy="MSBuild" />
208 206 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="application/xml" />
209 207 <XmlFormattingPolicy inheritsSet="Mono" inheritsScope="application/xml" scope="application/xml" />
210 208 <TextStylePolicy FileWidth="120" TabsToSpaces="False" inheritsSet="VisualStudio" inheritsScope="text/plain" scope="text/plain" />
211 209 <NameConventionPolicy>
212 210 <Rules>
213 211 <NamingRule Name="Namespaces" AffectedEntity="Namespace" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
214 212 <NamingRule Name="Types" AffectedEntity="Class, Struct, Enum, Delegate" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
215 213 <NamingRule Name="Interfaces" AffectedEntity="Interface" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
216 214 <RequiredPrefixes>
217 215 <String>I</String>
218 216 </RequiredPrefixes>
219 217 </NamingRule>
220 218 <NamingRule Name="Attributes" AffectedEntity="CustomAttributes" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
221 219 <RequiredSuffixes>
222 220 <String>Attribute</String>
223 221 </RequiredSuffixes>
224 222 </NamingRule>
225 223 <NamingRule Name="Event Arguments" AffectedEntity="CustomEventArgs" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
226 224 <RequiredSuffixes>
227 225 <String>EventArgs</String>
228 226 </RequiredSuffixes>
229 227 </NamingRule>
230 228 <NamingRule Name="Exceptions" AffectedEntity="CustomExceptions" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
231 229 <RequiredSuffixes>
232 230 <String>Exception</String>
233 231 </RequiredSuffixes>
234 232 </NamingRule>
235 233 <NamingRule Name="Methods" AffectedEntity="Methods" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
236 234 <NamingRule Name="Static Readonly Fields" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Protected, Public" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True" />
237 235 <NamingRule Name="Fields (Non Private)" AffectedEntity="Field" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
238 236 <NamingRule Name="ReadOnly Fields (Non Private)" AffectedEntity="ReadonlyField" VisibilityMask="Internal, Public" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False" />
239 237 <NamingRule Name="Fields (Private)" AffectedEntity="Field, ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
240 238 <RequiredPrefixes>
241 239 <String>m_</String>
242 240 </RequiredPrefixes>
243 241 </NamingRule>
244 242 <NamingRule Name="Static Fields (Private)" AffectedEntity="Field" VisibilityMask="Private" NamingStyle="CamelCase" IncludeInstanceMembers="False" IncludeStaticEntities="True">
245 243 <RequiredPrefixes>
246 244 <String>_</String>
247 245 </RequiredPrefixes>
248 246 </NamingRule>
249 247 <NamingRule Name="ReadOnly Fields (Private)" AffectedEntity="ReadonlyField" VisibilityMask="Private, Protected" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="False">
250 248 <RequiredPrefixes>
251 249 <String>m_</String>
252 250 </RequiredPrefixes>
253 251 </NamingRule>
254 252 <NamingRule Name="Constant Fields" AffectedEntity="ConstantField" VisibilityMask="VisibilityMask" NamingStyle="AllUpper" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
255 253 <NamingRule Name="Properties" AffectedEntity="Property" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
256 254 <NamingRule Name="Events" AffectedEntity="Event" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
257 255 <NamingRule Name="Enum Members" AffectedEntity="EnumMember" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
258 256 <NamingRule Name="Parameters" AffectedEntity="Parameter, LocalVariable" VisibilityMask="VisibilityMask" NamingStyle="CamelCase" IncludeInstanceMembers="True" IncludeStaticEntities="True" />
259 257 <NamingRule Name="Type Parameters" AffectedEntity="TypeParameter" VisibilityMask="VisibilityMask" NamingStyle="PascalCase" IncludeInstanceMembers="True" IncludeStaticEntities="True">
260 258 <RequiredPrefixes>
261 259 <String>T</String>
262 260 </RequiredPrefixes>
263 261 </NamingRule>
264 262 </Rules>
265 263 </NameConventionPolicy>
266 264 </Policies>
267 265 </Properties>
268 266 </MonoDevelop>
269 267 </ProjectExtensions>
270 268 <ItemGroup>
271 269 <Folder Include="Components\" />
272 270 <Folder Include="Automaton\RegularExpressions\" />
273 271 <Folder Include="Formats\" />
274 272 <Folder Include="Formats\JSON\" />
275 273 </ItemGroup>
276 274 </Project> No newline at end of file
1 NO CONTENT: file was removed
General Comments 0
You need to be logged in to leave comments. Login now