jtr/DevDisciples.Json.Parser/JsonParser.cs
mdnapo 82a59eebd2 - Refactored code
- Implemented basic JSON Path interpreter
- Clean up
2024-09-22 16:30:31 +02:00

98 lines
3.4 KiB
C#

using DevDisciples.Json.Parser.Syntax;
using DevDisciples.Parsing;
namespace DevDisciples.Json.Parser;
public static partial class JsonParser
{
public static IJsonSyntax Parse(string file, string source)
{
var tokens = JsonLexer.Default.Lex(file, source).ToArray();
var context = new Context(tokens);
var nodes = Expression(context);
return nodes;
}
private static IJsonSyntax Expression(ParserContext<JsonToken> ctx)
{
if (ctx.Match(JsonToken.LeftBracket))
return ArrayExpression(ctx);
if (ctx.Match(JsonToken.LeftBrace))
return ObjectExpression(ctx);
if (ctx.Match(JsonToken.Minus) || ctx.Match(JsonToken.Number))
return NumberExpression(ctx);
if (ctx.Match(JsonToken.String))
return StringExpression(ctx);
if (ctx.Match(JsonToken.Null))
return NullExpression(ctx);
if (ctx.Match(JsonToken.True) || ctx.Match(JsonToken.False))
return BoolExpression(ctx);
throw Report.Error(ctx.Current, $"Expected a JSON expression, got '{ctx.Current.Lexeme}'");
}
private static IJsonSyntax ArrayExpression(ParserContext<JsonToken> ctx)
{
var previous = ctx.Previous();
List<IJsonSyntax>? elements = null;
if (!ctx.Check(JsonToken.RightBracket))
{
do
{
elements ??= new();
elements.Add(Expression(ctx));
} while (ctx.Match(JsonToken.Comma));
}
ctx.Consume(JsonToken.RightBracket, "Expected ']'");
return new JsonArraySyntax(previous, elements?.ToArray() ?? System.Array.Empty<IJsonSyntax>());
}
private static IJsonSyntax ObjectExpression(ParserContext<JsonToken> ctx)
{
var previous = ctx.Previous();
Dictionary<Lexer<JsonToken>.Token, IJsonSyntax>? properties = null;
if (!ctx.Check(JsonToken.RightBrace))
{
do
{
var key = ctx.Consume(JsonToken.String, "Expected property name");
ctx.Consume(JsonToken.Colon, "Expected ':' after property name");
properties ??= new();
properties[key] = Expression(ctx);
} while (ctx.Match(JsonToken.Comma));
}
ctx.Consume(JsonToken.RightBrace, "Expected '}'");
var propertiesArray = properties?.Select(kv => new JsonPropertySyntax(kv.Key, kv.Value)).ToArray();
return new JsonObjectSyntax(previous, propertiesArray ?? System.Array.Empty<JsonPropertySyntax>());
}
private static IJsonSyntax NumberExpression(ParserContext<JsonToken> ctx)
{
if (ctx.Previous().Type != JsonToken.Minus) return new JsonNumberSyntax(ctx.Previous());
var minus = ctx.Previous();
var number = ctx.Consume(JsonToken.Number, "Expected a number after '-'.");
return new JsonNumberSyntax(
new Lexer<JsonToken>.Token(minus.File, JsonToken.Number, $"-{number.Lexeme}", minus.Line, minus.Column)
);
}
private static IJsonSyntax StringExpression(ParserContext<JsonToken> ctx) => new JsonStringSyntax(ctx.Previous());
private static IJsonSyntax NullExpression(ParserContext<JsonToken> ctx) => new JsonNullSyntax(ctx.Previous());
private static IJsonSyntax BoolExpression(ParserContext<JsonToken> ctx) => new JsonBoolSyntax(ctx.Previous());
}