github.com/aretext/aretext@v1.3.0/syntax/languages/json.go (about) 1 package languages 2 3 import ( 4 "unicode" 5 6 "github.com/aretext/aretext/syntax/parser" 7 ) 8 9 const ( 10 jsonTokenRoleKey = parser.TokenRoleCustom1 11 ) 12 13 // JsonParseFunc returns a parse func for JSON. 14 func JsonParseFunc() parser.Func { 15 return jsonNumberParseFunc(). 16 Or(jsonStringOrKeyParseFunc()). 17 Or(jsonKeywordParseFunc()) 18 } 19 20 func jsonIdentifierRune(r rune) bool { 21 return unicode.IsLetter(r) || (r >= '0' && r <= '9') || r == '.' || r == '_' || r == '-' 22 } 23 24 func jsonNumberParseFunc() parser.Func { 25 consumeDigits := consumeRunesLike(func(r rune) bool { return r >= '0' && r <= '9' }) 26 consumeExponentIndicator := consumeString("e").Or(consumeString("E")) 27 consumePositiveNumber := consumeDigits. 28 ThenMaybe(consumeString(".").Then(consumeDigits)). 29 ThenMaybe( 30 consumeExponentIndicator. 31 ThenMaybe(consumeString("-")). 32 Then(consumeDigits)) 33 consumeNegativeNumber := consumeString("-").Then(consumePositiveNumber) 34 35 return consumeNegativeNumber.Or(consumePositiveNumber). 36 ThenNot(consumeSingleRuneLike(jsonIdentifierRune)). 37 Map(recognizeToken(parser.TokenRoleNumber)) 38 } 39 40 func jsonConsumeToKeyEndParseFunc() parser.Func { 41 // Match pattern /[ \t]*:/ 42 return func(iter parser.TrackingRuneIter, state parser.State) parser.Result { 43 var n uint64 44 for { 45 r, err := iter.NextRune() 46 n++ 47 if err == nil && r == ':' { 48 return parser.Result{ 49 NumConsumed: n, 50 NextState: state, 51 } 52 } 53 54 if err != nil || !(r == ' ' || r == '\t') { 55 return parser.FailedResult 56 } 57 } 58 } 59 } 60 61 func jsonStringOrKeyParseFunc() parser.Func { 62 recognizeKeyToken := recognizeToken(jsonTokenRoleKey) 63 return parseCStyleString('"', false). 64 ThenMaybe(jsonConsumeToKeyEndParseFunc()). 65 Map(func(r parser.Result) parser.Result { 66 if len(r.ComputedTokens) == 1 && r.NumConsumed > r.ComputedTokens[0].Length { 67 // Must have parsed additional characters after the end of the string, 68 // so this is a key. 69 return recognizeKeyToken(r) 70 } else { 71 return r 72 } 73 }) 74 } 75 76 func jsonKeywordParseFunc() parser.Func { 77 keywords := []string{"true", "false", "null"} 78 return consumeRunesLike(jsonIdentifierRune). 79 MapWithInput(recognizeKeywordOrConsume(keywords)) 80 }