Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- https://www.youtube.com/watch?v=A49Xn1gsyPU&t=2415s&ab_channel=RawCoding
- NOTE: THIS CODE IS NOT PATREON!
- I MANUALLY TYPED IT WHILE FOLLOWING THE TUTORIAL
- using System.Collections.Immutable;
- using System.Text;
- using System.Text.Json.Nodes;
- using Json = System.ReadOnlyMemory<char>;
- namespace RawCoding.JsonParserDemo;
- public delegate (ImmutableArray<T> value, Json rest)? Parse<T>(Json json);
- public class JaySonFun
- {
- private static Parse<char> IsDigit => json => json.Length > 0 && char.IsDigit(json.Span[0])
- ? (Result(json.Span[0]), json[1..])
- : null;
- private static Parse<char> Escaped => json => json.Length > 0 && json.Span[0] == '\\'
- ? (Result(json.Span[1]), json[2..])
- : null;
- private static Parse<char> NotDoubleQuote => json => json.Length > 0 && json.Span[0] != '"'
- ? (Result(json.Span[0]), json[1..])
- : null;
- public static JsonValue? Parse(string str) => ParseValue(str.AsMemory())?.value.FirstOrDefault();
- private static readonly Parse<JsonValue> ParseNull = WhiteSpaced(Require("null", new JsonNull()));
- private static readonly Parse<JsonValue> ParseTrue = WhiteSpaced(Require("true", new JsonTrue()));
- private static readonly Parse<JsonValue> ParseFalse = WhiteSpaced(Require("false", new JsonFalse()));
- private static readonly Parse<JsonValue> ParseNumber =
- WhiteSpaced(
- Capture(
- v => new JsonNumber(int.Parse(v)),
- IsDigit
- )
- );
- private static readonly Parse<JsonValue> ParseString =
- WhiteSpaced(
- Parser(
- Require("\""),
- Capture(
- v => new JsonString(v),
- Escaped,
- NotDoubleQuote
- ),
- Require("\"")
- )
- );
- private static readonly Parse<JsonValue> ParseArray =
- Remap(
- Parser(
- WhiteSpaced((Require("["))),
- Multiple(
- ParseValue,
- WhiteSpaced(Require(","))
- ),
- WhiteSpaced((Require("]")))
- ),
- r => new JsonArray(r)
- );
- private static readonly Parse<JsonValue> ParseObject =
- Remap(
- Parser(
- WhiteSpaced((Require("{"))),
- Multiple(
- Parser(
- ParseString,
- WhiteSpaced((Require(":"))),
- ParseValue
- ),
- WhiteSpaced(Require(","))
- ),
- WhiteSpaced((Require("}")))
- ),
- r => new JsonArray(r)
- );
- private static readonly Parse<JsonValue> ParseValue = str =>
- ParseNull(str)
- ?? ParseTrue(str)
- ?? ParseFalse(str)
- ?? ParseNumber(str)
- ?? ParseString(str)
- ?? ParseArray(str)
- ?? ParseObject(str);
- private static Parse<JsonValue> Remap<T>(Parse<T> parser, Func<ImmutableArray<T>, JsonValue> map) =>
- json => parser(json) switch
- {
- var (v, rest) => (Result(map(v)), rest),
- null => null
- };
- private static Parse<JsonValue> WhiteSpaced(Parse<JsonValue> parse) =>
- Parser(Ignore(' ', '\n'), parse, Ignore(' ', '\n'));
- private static Parse<JsonValue> Require(string sequence, JsonValue? v = null) =>
- json => json.Span.StartsWith(sequence)
- ? (Result(v), json[sequence.Length..])
- : null;
- // ignore method
- private static Parse<JsonValue> Ignore(params char[] optionalChar)
- {
- (ImmutableArray<JsonValue> result, Json rest)? IgnoreChar(Json json) =>
- json.Length > 0 && optionalChar.Contains(json.Span[0])
- ? IgnoreChar(json[1..])
- : (ImmutableArray<JsonValue>.Empty, json);
- return IgnoreChar;
- }
- /// <summary>
- /// Capture and advance next
- /// </summary>
- /// <param name="fn"></param>
- /// <param name="parsers"></param>
- /// <returns></returns>
- private static Parse<JsonValue> Capture(Func<string, JsonValue> fn, params Parse<char>[] parsers)
- {
- (string result, Json rest)? AggregateChar(StringBuilder sb, Json json)
- {
- var aggregateChar = parsers.Select(p => p(json)).FirstOrDefault(r => r != null) switch
- {
- var (r, rest) => AggregateChar(sb.Append(r[0]), rest),
- _ => (sb.ToString(), json)
- };
- return aggregateChar;
- }
- return json => AggregateChar(new StringBuilder(), json) switch
- {
- ({ Length: > 0 } str, var rest) => (Result(fn(str)), rest),
- // ({ } str, var res) => (Result(str), rest), // todo: complete
- _ => null,
- };
- }
- public static Parse<JsonValue> Parser(params Parse<JsonValue>[] parser)
- {
- (ImmutableArray<JsonValue> result, Json rest)? AggregateParse(
- ImmutableArray<JsonValue> result,
- Parse<JsonValue>[] remainingParser,
- Json json
- ) => remainingParser.Length > 0
- ? remainingParser[0](json) switch
- {
- var (r, rest) => AggregateParse(result.AddRange(r), remainingParser[1..], rest),
- null => null
- }
- : (result, json);
- return json => AggregateParse(ImmutableArray<JsonValue>.Empty, parser, json);
- }
- private static Parse<JsonValue> Multiple(Parse<JsonValue> element, Parse<JsonValue> separator)
- {
- var nextEl = Parser(separator, element);
- return json => element(json) switch
- {
- ({ Length: > 0 } v, var rest) => AggregateElements(v, rest),
- // ({ Length: 0 } v, var rest) => (v, rest),
- _ => (ImmutableArray<JsonValue>.Empty, json),
- };
- (ImmutableArray<JsonValue>, Json rest)? AggregateElements(ImmutableArray<JsonValue> result, Json json) =>
- nextEl(json) switch
- {
- var (v, rest) => AggregateElements(result.AddRange(v), rest),
- null => (result, json)
- };
- }
- public static JsonObject ToObject(ImmutableArray<JsonValue> values)
- {
- static ImmutableDictionary<string, JsonValue> GetDic(
- ImmutableDictionary<string, JsonValue> result,
- ImmutableArray<JsonValue> values) => values switch
- {
- [JsonString a, var b, ..] => GetDic(result.Add(a.Value, b), values[2..]),
- _ => result,
- };
- return new JsonObject(GetDic(ImmutableDictionary<string, JsonValue>.Empty, values));
- }
- public static ImmutableArray<T> Result<T>(T v) => ImmutableArray<T>.Empty.Add(v);
- public abstract record JsonValue;
- public record JsonNull : JsonValue;
- public record JsonFalse : JsonValue;
- public record JsonTrue : JsonValue;
- public record JsonNumber(int Value) : JsonValue;
- public record JsonString(string Value) : JsonValue;
- public record JsonArray(ImmutableArray<JsonValue> Value) : JsonValue;
- public record JsonObject(ImmutableDictionary<string, JsonValue> Value) : JsonValue;
- }
Advertisement
Comments
-
- NOTE: THIS CODE IS NOT PATREON!
- I MANUALLY TYPED IT WHILE FOLLOWING THE TUTORIAL
Add Comment
Please, Sign In to add comment
Advertisement