| 163 | 1 using System.Linq; | 
|  | 2 using Implab.Automaton.RegularExpressions; | 
| 165 | 3 using System; | 
| 172 | 4 using Implab.Automaton; | 
| 180 | 5 using Implab.Components; | 
| 163 | 6 | 
|  | 7 namespace Implab.Formats.JSON { | 
| 178 | 8     class JSONGrammar : Grammar<char> { | 
| 163 | 9         public enum TokenType { | 
|  | 10             None, | 
|  | 11             BeginObject, | 
|  | 12             EndObject, | 
|  | 13             BeginArray, | 
|  | 14             EndArray, | 
|  | 15             String, | 
|  | 16             Number, | 
|  | 17             Literal, | 
|  | 18             NameSeparator, | 
|  | 19             ValueSeparator, | 
|  | 20 | 
|  | 21             StringBound, | 
|  | 22             EscapedChar, | 
|  | 23             UnescapedChar, | 
| 176 | 24             EscapedUnicode | 
| 163 | 25         } | 
|  | 26 | 
| 180 | 27         static LazyAndWeak<JSONGrammar> _instance = new LazyAndWeak<JSONGrammar>(() => new JSONGrammar()); | 
| 165 | 28 | 
|  | 29         public static JSONGrammar Instance { | 
|  | 30             get { return _instance.Value; } | 
|  | 31         } | 
|  | 32 | 
| 178 | 33         readonly ScannerContext<TokenType> m_jsonExpression; | 
|  | 34         readonly ScannerContext<TokenType> m_stringExpression; | 
| 180 | 35         readonly CharAlphabet m_defaultAlphabet = new CharAlphabet(); | 
| 163 | 36 | 
|  | 37         public JSONGrammar() { | 
|  | 38             DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x)); | 
|  | 39             var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9')); | 
|  | 40             var digit9 = SymbolRangeToken('1', '9'); | 
|  | 41             var zero = SymbolToken('0'); | 
|  | 42             var digit = zero.Or(digit9); | 
|  | 43             var dot = SymbolToken('.'); | 
|  | 44             var minus = SymbolToken('-'); | 
|  | 45             var sign = SymbolSetToken('-', '+'); | 
|  | 46             var expSign = SymbolSetToken('e', 'E'); | 
|  | 47             var letters = SymbolRangeToken('a', 'z'); | 
|  | 48             var integer = zero.Or(digit9.Cat(digit.EClosure())); | 
|  | 49             var frac = dot.Cat(digit.Closure()); | 
|  | 50             var exp = expSign.Cat(sign.Optional()).Cat(digit.Closure()); | 
|  | 51             var quote = SymbolToken('"'); | 
|  | 52             var backSlash = SymbolToken('\\'); | 
|  | 53             var specialEscapeChars = SymbolSetToken('\\', '"', '/', 'b', 'f', 't', 'n', 'r'); | 
|  | 54             var unicodeEspace = SymbolToken('u').Cat(hexDigit.Repeat(4)); | 
|  | 55             var whitespace = SymbolSetToken('\n', '\r', '\t', ' ').EClosure(); | 
|  | 56             var beginObject = whitespace.Cat(SymbolToken('{')).Cat(whitespace); | 
|  | 57             var endObject = whitespace.Cat(SymbolToken('}')).Cat(whitespace); | 
|  | 58             var beginArray = whitespace.Cat(SymbolToken('[')).Cat(whitespace); | 
|  | 59             var endArray = whitespace.Cat(SymbolToken(']')).Cat(whitespace); | 
|  | 60             var nameSep = whitespace.Cat(SymbolToken(':')).Cat(whitespace); | 
|  | 61             var valueSep = whitespace.Cat(SymbolToken(',')).Cat(whitespace); | 
|  | 62 | 
|  | 63             var number = minus.Optional().Cat(integer).Cat(frac.Optional()).Cat(exp.Optional()); | 
|  | 64             var literal = letters.Closure(); | 
|  | 65             var unescaped = SymbolTokenExcept(Enumerable.Range(0, 0x20).Union(new int[] { '\\', '"' }).Select(x => (char)x)); | 
|  | 66 | 
|  | 67             var jsonExpression = | 
|  | 68                 number.Tag(TokenType.Number) | 
|  | 69                 .Or(literal.Tag(TokenType.Literal)) | 
|  | 70                 .Or(quote.Tag(TokenType.StringBound)) | 
|  | 71                 .Or(beginObject.Tag(TokenType.BeginObject)) | 
|  | 72                 .Or(endObject.Tag(TokenType.EndObject)) | 
|  | 73                 .Or(beginArray.Tag(TokenType.BeginArray)) | 
|  | 74                 .Or(endArray.Tag(TokenType.EndArray)) | 
|  | 75                 .Or(nameSep.Tag(TokenType.NameSeparator)) | 
|  | 76                 .Or(valueSep.Tag(TokenType.ValueSeparator)); | 
|  | 77 | 
|  | 78 | 
|  | 79             var jsonStringExpression = | 
|  | 80                 quote.Tag(TokenType.StringBound) | 
|  | 81                 .Or(backSlash.Cat(specialEscapeChars).Tag(TokenType.EscapedChar)) | 
|  | 82                 .Or(backSlash.Cat(unicodeEspace).Tag(TokenType.EscapedUnicode)) | 
|  | 83                 .Or(unescaped.Closure().Tag(TokenType.UnescapedChar)); | 
|  | 84 | 
|  | 85 | 
| 178 | 86             m_jsonExpression = BuildScannerContext<TokenType>(jsonExpression); | 
|  | 87             m_stringExpression = BuildScannerContext<TokenType>(jsonStringExpression); | 
|  | 88 | 
|  | 89 | 
| 163 | 90         } | 
|  | 91 | 
| 180 | 92         protected override IAlphabetBuilder<char> AlphabetBuilder { | 
|  | 93             get { | 
|  | 94                 return m_defaultAlphabet; | 
|  | 95             } | 
|  | 96         } | 
|  | 97 | 
| 178 | 98         public ScannerContext<TokenType> JsonExpression { | 
| 163 | 99             get { | 
| 178 | 100                 return m_jsonExpression; | 
| 163 | 101             } | 
|  | 102         } | 
|  | 103 | 
| 178 | 104         public ScannerContext<TokenType> JsonStringExpression { | 
| 163 | 105             get { | 
| 178 | 106                 return m_stringExpression; | 
| 163 | 107             } | 
|  | 108         } | 
| 165 | 109 | 
| 178 | 110         Token SymbolRangeToken(char start, char stop) { | 
| 182 | 111             return SymbolToken(Enumerable.Range(start, stop - start + 1).Select(x => (char)x)); | 
| 165 | 112         } | 
| 172 | 113 | 
| 180 | 114         protected override IndexedAlphabetBase<char> CreateAlphabet() { | 
| 172 | 115             return new CharAlphabet(); | 
|  | 116         } | 
| 165 | 117 | 
| 163 | 118     } | 
|  | 119 } |