JSONGrammar.cs
        
        
            
                    121 lines
            
             | 4.8 KiB
            
                | text/x-csharp
            
             |
                CSharpLexer
            
          
        |  | r163 | using System.Linq; | ||
| using Implab.Automaton.RegularExpressions; | ||||
|  | r165 | using System; | ||
|  | r172 | using Implab.Automaton; | ||
|  | r180 | using Implab.Components; | ||
|  | r163 | |||
| namespace Implab.Formats.JSON { | ||||
|  | r178 | class JSONGrammar : Grammar<char> { | ||
|  | r163 | public enum TokenType { | ||
| None, | ||||
| BeginObject, | ||||
| EndObject, | ||||
| BeginArray, | ||||
| EndArray, | ||||
| String, | ||||
| Number, | ||||
| Literal, | ||||
| NameSeparator, | ||||
| ValueSeparator, | ||||
|  | r183 | Whitespace, | ||
|  | r163 | |||
| StringBound, | ||||
| EscapedChar, | ||||
| UnescapedChar, | ||||
|  | r176 | EscapedUnicode | ||
|  | r163 | } | ||
|  | r180 | static LazyAndWeak<JSONGrammar> _instance = new LazyAndWeak<JSONGrammar>(() => new JSONGrammar()); | ||
|  | r165 | |||
| public static JSONGrammar Instance { | ||||
| get { return _instance.Value; } | ||||
| } | ||||
|  | r178 | readonly ScannerContext<TokenType> m_jsonExpression; | ||
| readonly ScannerContext<TokenType> m_stringExpression; | ||||
|  | r180 | readonly CharAlphabet m_defaultAlphabet = new CharAlphabet(); | ||
|  | r163 | |||
| public JSONGrammar() { | ||||
| DefineAlphabet(Enumerable.Range(0, 0x20).Select(x => (char)x)); | ||||
| var hexDigit = SymbolRangeToken('a','f').Or(SymbolRangeToken('A','F')).Or(SymbolRangeToken('0','9')); | ||||
| var digit9 = SymbolRangeToken('1', '9'); | ||||
| var zero = SymbolToken('0'); | ||||
| var digit = zero.Or(digit9); | ||||
| var dot = SymbolToken('.'); | ||||
| var minus = SymbolToken('-'); | ||||
| var sign = SymbolSetToken('-', '+'); | ||||
| var expSign = SymbolSetToken('e', 'E'); | ||||
| var letters = SymbolRangeToken('a', 'z'); | ||||
| var integer = zero.Or(digit9.Cat(digit.EClosure())); | ||||
| var frac = dot.Cat(digit.Closure()); | ||||
| var exp = expSign.Cat(sign.Optional()).Cat(digit.Closure()); | ||||
| var quote = SymbolToken('"'); | ||||
| var backSlash = SymbolToken('\\'); | ||||
| var specialEscapeChars = SymbolSetToken('\\', '"', '/', 'b', 'f', 't', 'n', 'r'); | ||||
| var unicodeEspace = SymbolToken('u').Cat(hexDigit.Repeat(4)); | ||||
| var whitespace = SymbolSetToken('\n', '\r', '\t', ' ').EClosure(); | ||||
| var beginObject = whitespace.Cat(SymbolToken('{')).Cat(whitespace); | ||||
| var endObject = whitespace.Cat(SymbolToken('}')).Cat(whitespace); | ||||
| var beginArray = whitespace.Cat(SymbolToken('[')).Cat(whitespace); | ||||
| var endArray = whitespace.Cat(SymbolToken(']')).Cat(whitespace); | ||||
| var nameSep = whitespace.Cat(SymbolToken(':')).Cat(whitespace); | ||||
| var valueSep = whitespace.Cat(SymbolToken(',')).Cat(whitespace); | ||||
| var number = minus.Optional().Cat(integer).Cat(frac.Optional()).Cat(exp.Optional()); | ||||
| var literal = letters.Closure(); | ||||
| var unescaped = SymbolTokenExcept(Enumerable.Range(0, 0x20).Union(new int[] { '\\', '"' }).Select(x => (char)x)); | ||||
| var jsonExpression = | ||||
| number.Tag(TokenType.Number) | ||||
| .Or(literal.Tag(TokenType.Literal)) | ||||
| .Or(quote.Tag(TokenType.StringBound)) | ||||
| .Or(beginObject.Tag(TokenType.BeginObject)) | ||||
| .Or(endObject.Tag(TokenType.EndObject)) | ||||
| .Or(beginArray.Tag(TokenType.BeginArray)) | ||||
| .Or(endArray.Tag(TokenType.EndArray)) | ||||
| .Or(nameSep.Tag(TokenType.NameSeparator)) | ||||
|  | r183 | .Or(valueSep.Tag(TokenType.ValueSeparator)) | ||
| .Or(SymbolSetToken('\n', '\r', '\t', ' ').Closure().Tag(TokenType.Whitespace)); | ||||
|  | r163 | |||
| var jsonStringExpression = | ||||
| quote.Tag(TokenType.StringBound) | ||||
| .Or(backSlash.Cat(specialEscapeChars).Tag(TokenType.EscapedChar)) | ||||
| .Or(backSlash.Cat(unicodeEspace).Tag(TokenType.EscapedUnicode)) | ||||
| .Or(unescaped.Closure().Tag(TokenType.UnescapedChar)); | ||||
|  | r178 | m_jsonExpression = BuildScannerContext<TokenType>(jsonExpression); | ||
| m_stringExpression = BuildScannerContext<TokenType>(jsonStringExpression); | ||||
|  | r163 | } | ||
|  | r180 | protected override IAlphabetBuilder<char> AlphabetBuilder { | ||
| get { | ||||
| return m_defaultAlphabet; | ||||
| } | ||||
| } | ||||
|  | r178 | public ScannerContext<TokenType> JsonExpression { | ||
|  | r163 | get { | ||
|  | r178 | return m_jsonExpression; | ||
|  | r163 | } | ||
| } | ||||
|  | r178 | public ScannerContext<TokenType> JsonStringExpression { | ||
|  | r163 | get { | ||
|  | r178 | return m_stringExpression; | ||
|  | r163 | } | ||
| } | ||||
|  | r165 | |||
|  | r178 | Token SymbolRangeToken(char start, char stop) { | ||
|  | r182 | return SymbolToken(Enumerable.Range(start, stop - start + 1).Select(x => (char)x)); | ||
|  | r165 | } | ||
|  | r172 | |||
|  | r180 | protected override IndexedAlphabetBase<char> CreateAlphabet() { | ||
|  | r172 | return new CharAlphabet(); | ||
| } | ||||
|  | r165 | |||
|  | r163 | } | ||
| } | ||||
