Advertisement
ivandrofly

Json Parser in Functional C# EXPANDS the mind

Aug 24th, 2023 (edited)
1,428
0
Never
1
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 7.26 KB | None | 0 0
  1. https://www.youtube.com/watch?v=A49Xn1gsyPU&t=2415s&ab_channel=RawCoding
  2.  
  3. NOTE: THIS CODE IS NOT PATREON!
  4. I MANUALLY TYPED IT WHILE FOLLOWING THE TUTORIAL
  5.  
  6. using System.Collections.Immutable;
  7. using System.Text;
  8. using System.Text.Json.Nodes;
  9. using Json = System.ReadOnlyMemory<char>;
  10.  
  11. namespace RawCoding.JsonParserDemo;
  12.  
  13. public delegate (ImmutableArray<T> value, Json rest)? Parse<T>(Json json);
  14.  
  15. public class JaySonFun
  16. {
  17.     private static Parse<char> IsDigit => json => json.Length > 0 && char.IsDigit(json.Span[0])
  18.         ? (Result(json.Span[0]), json[1..])
  19.         : null;
  20.  
  21.     private static Parse<char> Escaped => json => json.Length > 0 && json.Span[0] == '\\'
  22.         ? (Result(json.Span[1]), json[2..])
  23.         : null;
  24.  
  25.     private static Parse<char> NotDoubleQuote => json => json.Length > 0 && json.Span[0] != '"'
  26.         ? (Result(json.Span[0]), json[1..])
  27.         : null;
  28.  
  29.     public static JsonValue? Parse(string str) => ParseValue(str.AsMemory())?.value.FirstOrDefault();
  30.  
  31.     private static readonly Parse<JsonValue> ParseNull = WhiteSpaced(Require("null", new JsonNull()));
  32.     private static readonly Parse<JsonValue> ParseTrue = WhiteSpaced(Require("true", new JsonTrue()));
  33.     private static readonly Parse<JsonValue> ParseFalse = WhiteSpaced(Require("false", new JsonFalse()));
  34.  
  35.     private static readonly Parse<JsonValue> ParseNumber =
  36.         WhiteSpaced(
  37.             Capture(
  38.                 v => new JsonNumber(int.Parse(v)),
  39.                 IsDigit
  40.             )
  41.         );
  42.  
  43.     private static readonly Parse<JsonValue> ParseString =
  44.         WhiteSpaced(
  45.             Parser(
  46.                 Require("\""),
  47.                 Capture(
  48.                     v => new JsonString(v),
  49.                     Escaped,
  50.                     NotDoubleQuote
  51.                 ),
  52.                 Require("\"")
  53.             )
  54.         );
  55.  
  56.     private static readonly Parse<JsonValue> ParseArray =
  57.         Remap(
  58.             Parser(
  59.                 WhiteSpaced((Require("["))),
  60.                 Multiple(
  61.                     ParseValue,
  62.                     WhiteSpaced(Require(","))
  63.                 ),
  64.                 WhiteSpaced((Require("]")))
  65.             ),
  66.             r => new JsonArray(r)
  67.         );
  68.  
  69.     private static readonly Parse<JsonValue> ParseObject =
  70.         Remap(
  71.             Parser(
  72.                 WhiteSpaced((Require("{"))),
  73.                 Multiple(
  74.                     Parser(
  75.                         ParseString,
  76.                         WhiteSpaced((Require(":"))),
  77.                         ParseValue
  78.                     ),
  79.                     WhiteSpaced(Require(","))
  80.                 ),
  81.                 WhiteSpaced((Require("}")))
  82.             ),
  83.             r => new JsonArray(r)
  84.         );
  85.  
  86.     private static readonly Parse<JsonValue> ParseValue = str =>
  87.         ParseNull(str)
  88.         ?? ParseTrue(str)
  89.         ?? ParseFalse(str)
  90.         ?? ParseNumber(str)
  91.         ?? ParseString(str)
  92.         ?? ParseArray(str)
  93.         ?? ParseObject(str);
  94.  
  95.     private static Parse<JsonValue> Remap<T>(Parse<T> parser, Func<ImmutableArray<T>, JsonValue> map) =>
  96.         json => parser(json) switch
  97.         {
  98.             var (v, rest) => (Result(map(v)), rest),
  99.             null => null
  100.         };
  101.  
  102.     private static Parse<JsonValue> WhiteSpaced(Parse<JsonValue> parse) =>
  103.         Parser(Ignore(' ', '\n'), parse, Ignore(' ', '\n'));
  104.  
  105.     private static Parse<JsonValue> Require(string sequence, JsonValue? v = null) =>
  106.         json => json.Span.StartsWith(sequence)
  107.             ? (Result(v), json[sequence.Length..])
  108.             : null;
  109.  
  110.     // ignore method
  111.     private static Parse<JsonValue> Ignore(params char[] optionalChar)
  112.     {
  113.         (ImmutableArray<JsonValue> result, Json rest)? IgnoreChar(Json json) =>
  114.             json.Length > 0 && optionalChar.Contains(json.Span[0])
  115.                 ? IgnoreChar(json[1..])
  116.                 : (ImmutableArray<JsonValue>.Empty, json);
  117.  
  118.         return IgnoreChar;
  119.     }
  120.  
  121.     /// <summary>
  122.     /// Capture and advance next
  123.     /// </summary>
  124.     /// <param name="fn"></param>
  125.     /// <param name="parsers"></param>
  126.     /// <returns></returns>
  127.     private static Parse<JsonValue> Capture(Func<string, JsonValue> fn, params Parse<char>[] parsers)
  128.     {
  129.         (string result, Json rest)? AggregateChar(StringBuilder sb, Json json)
  130.         {
  131.             var aggregateChar = parsers.Select(p => p(json)).FirstOrDefault(r => r != null) switch
  132.             {
  133.                 var (r, rest) => AggregateChar(sb.Append(r[0]), rest),
  134.                 _ => (sb.ToString(), json)
  135.             };
  136.             return aggregateChar;
  137.         }
  138.  
  139.         return json => AggregateChar(new StringBuilder(), json) switch
  140.         {
  141.             ({ Length: > 0 } str, var rest) => (Result(fn(str)), rest),
  142.             // ({ } str, var res) => (Result(str), rest),  // todo: complete
  143.             _ => null,
  144.         };
  145.     }
  146.  
  147.     public static Parse<JsonValue> Parser(params Parse<JsonValue>[] parser)
  148.     {
  149.         (ImmutableArray<JsonValue> result, Json rest)? AggregateParse(
  150.             ImmutableArray<JsonValue> result,
  151.             Parse<JsonValue>[] remainingParser,
  152.             Json json
  153.         ) => remainingParser.Length > 0
  154.             ? remainingParser[0](json) switch
  155.             {
  156.                 var (r, rest) => AggregateParse(result.AddRange(r), remainingParser[1..], rest),
  157.                 null => null
  158.             }
  159.             : (result, json);
  160.  
  161.         return json => AggregateParse(ImmutableArray<JsonValue>.Empty, parser, json);
  162.     }
  163.  
  164.     private static Parse<JsonValue> Multiple(Parse<JsonValue> element, Parse<JsonValue> separator)
  165.     {
  166.         var nextEl = Parser(separator, element);
  167.  
  168.         return json => element(json) switch
  169.         {
  170.             ({ Length: > 0 } v, var rest) => AggregateElements(v, rest),
  171.             // ({ Length: 0 } v, var rest) => (v, rest),
  172.             _ => (ImmutableArray<JsonValue>.Empty, json),
  173.         };
  174.  
  175.         (ImmutableArray<JsonValue>, Json rest)? AggregateElements(ImmutableArray<JsonValue> result, Json json) =>
  176.             nextEl(json) switch
  177.             {
  178.                 var (v, rest) => AggregateElements(result.AddRange(v), rest),
  179.                 null => (result, json)
  180.             };
  181.     }
  182.  
  183.     public static JsonObject ToObject(ImmutableArray<JsonValue> values)
  184.     {
  185.         static ImmutableDictionary<string, JsonValue> GetDic(
  186.             ImmutableDictionary<string, JsonValue> result,
  187.             ImmutableArray<JsonValue> values) => values switch
  188.         {
  189.             [JsonString a, var b, ..] => GetDic(result.Add(a.Value, b), values[2..]),
  190.             _ => result,
  191.         };
  192.  
  193.         return new JsonObject(GetDic(ImmutableDictionary<string, JsonValue>.Empty, values));
  194.     }
  195.  
  196.     public static ImmutableArray<T> Result<T>(T v) => ImmutableArray<T>.Empty.Add(v);
  197.  
  198.     public abstract record JsonValue;
  199.  
  200.     public record JsonNull : JsonValue;
  201.  
  202.     public record JsonFalse : JsonValue;
  203.  
  204.     public record JsonTrue : JsonValue;
  205.  
  206.     public record JsonNumber(int Value) : JsonValue;
  207.  
  208.     public record JsonString(string Value) : JsonValue;
  209.  
  210.     public record JsonArray(ImmutableArray<JsonValue> Value) : JsonValue;
  211.  
  212.     public record JsonObject(ImmutableDictionary<string, JsonValue> Value) : JsonValue;
  213. }
Advertisement
Comments
Add Comment
Please, Sign In to add comment
Advertisement