using System; using System.Collections.Generic; using System.Linq; using System.Text.Json; using System.Text.Json.Serialization; using MarketAlly.IronJava.Core.AST; using MarketAlly.IronJava.Core.AST.Nodes; using MarketAlly.IronJava.Core.AST.Visitors; namespace MarketAlly.IronJava.Core.Serialization { /// /// Provides JSON serialization for Java AST nodes. /// public class AstJsonSerializer { private readonly JsonSerializerOptions _options; public AstJsonSerializer(bool indented = true) { _options = new JsonSerializerOptions { WriteIndented = indented, DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull, Converters = { new JsonStringEnumConverter(), new AstNodeConverterFactory() } }; } public string Serialize(JavaNode node) { var visitor = new JsonSerializationVisitor(); var jsonNode = node.Accept(visitor); return JsonSerializer.Serialize(jsonNode, _options); } public T? Deserialize(string json) where T : JavaNode { using var document = JsonDocument.Parse(json); var deserializer = new JsonDeserializationVisitor(); return deserializer.Deserialize(document.RootElement) as T; } } /// /// Custom converter factory for AST nodes. /// internal class AstNodeConverterFactory : JsonConverterFactory { public override bool CanConvert(Type typeToConvert) { return typeof(JavaNode).IsAssignableFrom(typeToConvert); } public override JsonConverter CreateConverter(Type typeToConvert, JsonSerializerOptions options) { return new AstNodeConverter(); } } /// /// Custom converter for AST nodes. /// internal class AstNodeConverter : JsonConverter { public override JavaNode Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { using var document = JsonDocument.ParseValue(ref reader); var deserializer = new JsonDeserializationVisitor(); return deserializer.Deserialize(document.RootElement); } public override void Write(Utf8JsonWriter writer, JavaNode value, JsonSerializerOptions options) { var visitor = new JsonSerializationVisitor(); var jsonNode = value.Accept(visitor); JsonSerializer.Serialize(writer, jsonNode, options); } } /// /// Visitor that converts AST nodes to JSON-serializable dictionaries. /// internal class JsonSerializationVisitor : JavaVisitorBase> { protected override Dictionary DefaultVisit(JavaNode node) { var result = new Dictionary { ["nodeType"] = node.GetType().Name, ["location"] = SerializeLocation(node.Location) }; var children = node.Children.Select(child => child.Accept(this)).ToList(); if (children.Count > 0) { result["children"] = children; } return result; } private Dictionary SerializeLocation(SourceRange location) { return new Dictionary { ["start"] = new Dictionary { ["line"] = location.Start.Line, ["column"] = location.Start.Column, ["position"] = location.Start.Position }, ["end"] = new Dictionary { ["line"] = location.End.Line, ["column"] = location.End.Column, ["position"] = location.End.Position } }; } public override Dictionary VisitCompilationUnit(CompilationUnit node) { var result = CreateBaseNode(node); result["package"] = node.Package?.Accept(this); result["imports"] = node.Imports.Select(i => i.Accept(this)).ToList(); result["types"] = node.Types.Select(t => t.Accept(this)).ToList(); return result; } public override Dictionary VisitPackageDeclaration(PackageDeclaration node) { var result = CreateBaseNode(node); result["packageName"] = node.PackageName; result["annotations"] = SerializeAnnotations(node.Annotations); return result; } public override Dictionary VisitImportDeclaration(ImportDeclaration node) { var result = CreateBaseNode(node); result["importPath"] = node.ImportPath; result["isStatic"] = node.IsStatic; result["isWildcard"] = node.IsWildcard; return result; } public override Dictionary VisitClassDeclaration(ClassDeclaration node) { var result = CreateTypeDeclarationBase(node); result["superClass"] = node.SuperClass?.Accept(this); result["interfaces"] = node.Interfaces.Select(i => i.Accept(this)).ToList(); result["members"] = node.Members.Select(m => m.Accept(this)).ToList(); result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList(); result["isRecord"] = node.IsRecord; return result; } public override Dictionary VisitInterfaceDeclaration(InterfaceDeclaration node) { var result = CreateTypeDeclarationBase(node); result["extendedInterfaces"] = node.ExtendedInterfaces.Select(i => i.Accept(this)).ToList(); result["members"] = node.Members.Select(m => m.Accept(this)).ToList(); result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList(); return result; } public override Dictionary VisitEnumDeclaration(EnumDeclaration node) { var result = CreateTypeDeclarationBase(node); result["interfaces"] = node.Interfaces.Select(i => i.Accept(this)).ToList(); result["constants"] = node.Constants.Select(c => c.Accept(this)).ToList(); result["members"] = node.Members.Select(m => m.Accept(this)).ToList(); result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList(); return result; } public override Dictionary VisitAnnotationDeclaration(AnnotationDeclaration node) { var result = CreateTypeDeclarationBase(node); result["members"] = node.Members.Select(m => m.Accept(this)).ToList(); result["nestedTypes"] = node.NestedTypes.Select(t => t.Accept(this)).ToList(); return result; } public override Dictionary VisitFieldDeclaration(FieldDeclaration node) { var result = CreateMemberDeclarationBase(node); result["type"] = node.Type.Accept(this); result["variables"] = node.Variables.Select(v => v.Accept(this)).ToList(); return result; } public override Dictionary VisitMethodDeclaration(MethodDeclaration node) { var result = CreateMemberDeclarationBase(node); result["name"] = node.Name; result["returnType"] = node.ReturnType?.Accept(this); result["typeParameters"] = SerializeTypeParameters(node.TypeParameters); result["parameters"] = node.Parameters.Select(p => p.Accept(this)).ToList(); result["throws"] = node.Throws.Select(t => t.Accept(this)).ToList(); result["body"] = node.Body?.Accept(this); result["isConstructor"] = node.IsConstructor; return result; } public override Dictionary VisitParameter(Parameter node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); result["name"] = node.Name; result["isVarArgs"] = node.IsVarArgs; result["isFinal"] = node.IsFinal; result["annotations"] = SerializeAnnotations(node.Annotations); return result; } public override Dictionary VisitVariableDeclarator(VariableDeclarator node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["arrayDimensions"] = node.ArrayDimensions; result["initializer"] = node.Initializer?.Accept(this); return result; } public override Dictionary VisitPrimitiveType(PrimitiveType node) { var result = CreateBaseNode(node); result["kind"] = node.Kind.ToString(); return result; } public override Dictionary VisitClassOrInterfaceType(ClassOrInterfaceType node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["scope"] = node.Scope?.Accept(this); result["typeArguments"] = node.TypeArguments.Select(t => t.Accept(this)).ToList(); result["annotations"] = SerializeAnnotations(node.Annotations); result["fullName"] = node.FullName; return result; } public override Dictionary VisitArrayType(ArrayType node) { var result = CreateBaseNode(node); result["elementType"] = node.ElementType.Accept(this); result["dimensions"] = node.Dimensions; return result; } public override Dictionary VisitTypeParameter(TypeParameter node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["bounds"] = node.Bounds.Select(b => b.Accept(this)).ToList(); result["annotations"] = SerializeAnnotations(node.Annotations); return result; } public override Dictionary VisitLiteralExpression(LiteralExpression node) { var result = CreateBaseNode(node); result["value"] = node.Value; result["kind"] = node.Kind.ToString(); return result; } public override Dictionary VisitIdentifierExpression(IdentifierExpression node) { var result = CreateBaseNode(node); result["name"] = node.Name; return result; } public override Dictionary VisitBinaryExpression(BinaryExpression node) { var result = CreateBaseNode(node); result["left"] = node.Left.Accept(this); result["operator"] = node.Operator.ToString(); result["right"] = node.Right.Accept(this); return result; } public override Dictionary VisitUnaryExpression(UnaryExpression node) { var result = CreateBaseNode(node); result["operator"] = node.Operator.ToString(); result["operand"] = node.Operand.Accept(this); result["isPrefix"] = node.IsPrefix; return result; } public override Dictionary VisitMethodCallExpression(MethodCallExpression node) { var result = CreateBaseNode(node); result["target"] = node.Target?.Accept(this); result["methodName"] = node.MethodName; result["typeArguments"] = node.TypeArguments.Select(t => t.Accept(this)).ToList(); result["arguments"] = node.Arguments.Select(a => a.Accept(this)).ToList(); return result; } public override Dictionary VisitFieldAccessExpression(FieldAccessExpression node) { var result = CreateBaseNode(node); result["target"] = node.Target.Accept(this); result["fieldName"] = node.FieldName; return result; } public override Dictionary VisitBlockStatement(BlockStatement node) { var result = CreateBaseNode(node); result["statements"] = node.Statements.Select(s => s.Accept(this)).ToList(); return result; } public override Dictionary VisitIfStatement(IfStatement node) { var result = CreateBaseNode(node); result["condition"] = node.Condition.Accept(this); result["thenStatement"] = node.ThenStatement.Accept(this); result["elseStatement"] = node.ElseStatement?.Accept(this); return result; } public override Dictionary VisitWhileStatement(WhileStatement node) { var result = CreateBaseNode(node); result["condition"] = node.Condition.Accept(this); result["body"] = node.Body.Accept(this); return result; } public override Dictionary VisitForStatement(ForStatement node) { var result = CreateBaseNode(node); result["initializers"] = node.Initializers.Select(i => i.Accept(this)).ToList(); result["condition"] = node.Condition?.Accept(this); result["updates"] = node.Updates.Select(u => u.Accept(this)).ToList(); result["body"] = node.Body.Accept(this); return result; } public override Dictionary VisitReturnStatement(ReturnStatement node) { var result = CreateBaseNode(node); result["value"] = node.Value?.Accept(this); return result; } // Helper methods private Dictionary CreateBaseNode(JavaNode node) { return new Dictionary { ["nodeType"] = node.GetType().Name, ["location"] = SerializeLocation(node.Location) }; } private Dictionary CreateTypeDeclarationBase(TypeDeclaration node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["modifiers"] = SerializeModifiers(node.Modifiers); result["annotations"] = SerializeAnnotations(node.Annotations); result["typeParameters"] = SerializeTypeParameters(node.TypeParameters); result["javaDoc"] = node.JavaDoc?.Accept(this); return result; } private Dictionary CreateMemberDeclarationBase(MemberDeclaration node) { var result = CreateBaseNode(node); result["modifiers"] = SerializeModifiers(node.Modifiers); result["annotations"] = SerializeAnnotations(node.Annotations); result["javaDoc"] = node.JavaDoc?.Accept(this); return result; } private List SerializeModifiers(Modifiers modifiers) { var result = new List(); foreach (Modifiers value in Enum.GetValues()) { if (value != Modifiers.None && modifiers.HasFlag(value)) { result.Add(value.ToString().ToLowerInvariant()); } } return result; } private List> SerializeAnnotations(IReadOnlyList annotations) { return annotations.Select(a => a.Accept(this)).ToList(); } private List> SerializeTypeParameters(IReadOnlyList typeParameters) { return typeParameters.Select(tp => tp.Accept(this)).ToList(); } public override Dictionary VisitAnnotation(Annotation node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); result["arguments"] = node.Arguments.Select(a => a.Accept(this)).ToList(); return result; } public override Dictionary VisitAnnotationValueArgument(AnnotationValueArgument node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["value"] = node.Value.Accept(this); return result; } public override Dictionary VisitAnnotationArrayArgument(AnnotationArrayArgument node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["values"] = node.Values.Select(v => v.Accept(this)).ToList(); return result; } public override Dictionary VisitJavaDoc(JavaDoc node) { var result = CreateBaseNode(node); result["content"] = node.Content; result["tags"] = node.Tags.Select(t => new Dictionary { ["name"] = t.Name, ["parameter"] = t.Parameter, ["description"] = t.Description }).ToList(); return result; } // Implement remaining visit methods... // (For brevity, showing pattern - all other node types follow similar structure) public override Dictionary VisitThisExpression(ThisExpression node) { var result = CreateBaseNode(node); result["qualifier"] = node.Qualifier?.Accept(this); return result; } public override Dictionary VisitNewExpression(NewExpression node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); result["arguments"] = node.Arguments.Select(a => a.Accept(this)).ToList(); result["anonymousClassBody"] = node.AnonymousClassBody?.Accept(this); return result; } public override Dictionary VisitLambdaExpression(LambdaExpression node) { var result = CreateBaseNode(node); result["parameters"] = node.Parameters.Select(p => p.Accept(this)).ToList(); result["body"] = node.Body.Accept(this); return result; } public override Dictionary VisitLambdaParameter(LambdaParameter node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["type"] = node.Type?.Accept(this); result["isFinal"] = node.IsFinal; return result; } public override Dictionary VisitTryStatement(TryStatement node) { var result = CreateBaseNode(node); result["resources"] = node.Resources.Select(r => r.Accept(this)).ToList(); result["body"] = node.Body.Accept(this); result["catchClauses"] = node.CatchClauses.Select(c => c.Accept(this)).ToList(); result["finallyBlock"] = node.FinallyBlock?.Accept(this); return result; } public override Dictionary VisitResourceDeclaration(ResourceDeclaration node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); result["name"] = node.Name; result["initializer"] = node.Initializer.Accept(this); result["isFinal"] = node.IsFinal; return result; } public override Dictionary VisitEnumConstant(EnumConstant node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["arguments"] = node.Arguments.Select(a => a.Accept(this)).ToList(); result["body"] = node.Body?.Accept(this); result["annotations"] = SerializeAnnotations(node.Annotations); return result; } public override Dictionary VisitAnnotationMember(AnnotationMember node) { var result = CreateBaseNode(node); result["name"] = node.Name; result["type"] = node.Type.Accept(this); result["defaultValue"] = node.DefaultValue?.Accept(this); return result; } public override Dictionary VisitSuperExpression(SuperExpression node) { var result = CreateBaseNode(node); result["qualifier"] = node.Qualifier?.Accept(this); return result; } public override Dictionary VisitConditionalExpression(ConditionalExpression node) { var result = CreateBaseNode(node); result["condition"] = node.Condition.Accept(this); result["thenExpression"] = node.ThenExpression.Accept(this); result["elseExpression"] = node.ElseExpression.Accept(this); return result; } public override Dictionary VisitArrayAccessExpression(ArrayAccessExpression node) { var result = CreateBaseNode(node); result["array"] = node.Array.Accept(this); result["index"] = node.Index.Accept(this); return result; } public override Dictionary VisitCastExpression(CastExpression node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); result["expression"] = node.Expression.Accept(this); return result; } public override Dictionary VisitInstanceOfExpression(InstanceOfExpression node) { var result = CreateBaseNode(node); result["expression"] = node.Expression.Accept(this); result["type"] = node.Type.Accept(this); result["patternVariable"] = node.PatternVariable; return result; } public override Dictionary VisitNewArrayExpression(NewArrayExpression node) { var result = CreateBaseNode(node); result["elementType"] = node.ElementType.Accept(this); result["dimensions"] = node.Dimensions.Select(d => d.Accept(this)).ToList(); result["initializer"] = node.Initializer?.Accept(this); return result; } public override Dictionary VisitArrayInitializer(ArrayInitializer node) { var result = CreateBaseNode(node); result["elements"] = node.Elements.Select(e => e.Accept(this)).ToList(); return result; } public override Dictionary VisitAnnotationExpression(AnnotationExpression node) { var result = CreateBaseNode(node); result["annotation"] = node.Annotation.Accept(this); return result; } public override Dictionary VisitMethodReferenceExpression(MethodReferenceExpression node) { var result = CreateBaseNode(node); result["target"] = node.Target.Accept(this); result["methodName"] = node.MethodName; result["typeArguments"] = node.TypeArguments.Select(t => t.Accept(this)).ToList(); return result; } public override Dictionary VisitClassLiteralExpression(ClassLiteralExpression node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); return result; } public override Dictionary VisitLocalVariableStatement(LocalVariableStatement node) { var result = CreateBaseNode(node); result["type"] = node.Type.Accept(this); result["variables"] = node.Variables.Select(v => v.Accept(this)).ToList(); result["isFinal"] = node.IsFinal; return result; } public override Dictionary VisitExpressionStatement(ExpressionStatement node) { var result = CreateBaseNode(node); result["expression"] = node.Expression.Accept(this); return result; } public override Dictionary VisitDoWhileStatement(DoWhileStatement node) { var result = CreateBaseNode(node); result["body"] = node.Body.Accept(this); result["condition"] = node.Condition.Accept(this); return result; } public override Dictionary VisitForEachStatement(ForEachStatement node) { var result = CreateBaseNode(node); result["variableType"] = node.VariableType.Accept(this); result["variableName"] = node.VariableName; result["iterable"] = node.Iterable.Accept(this); result["body"] = node.Body.Accept(this); result["isFinal"] = node.IsFinal; return result; } public override Dictionary VisitSwitchStatement(SwitchStatement node) { var result = CreateBaseNode(node); result["selector"] = node.Selector.Accept(this); result["cases"] = node.Cases.Select(c => c.Accept(this)).ToList(); return result; } public override Dictionary VisitSwitchCase(SwitchCase node) { var result = CreateBaseNode(node); result["labels"] = node.Labels.Select(l => l.Accept(this)).ToList(); result["statements"] = node.Statements.Select(s => s.Accept(this)).ToList(); result["isDefault"] = node.IsDefault; return result; } public override Dictionary VisitBreakStatement(BreakStatement node) { var result = CreateBaseNode(node); result["label"] = node.Label; return result; } public override Dictionary VisitContinueStatement(ContinueStatement node) { var result = CreateBaseNode(node); result["label"] = node.Label; return result; } public override Dictionary VisitThrowStatement(ThrowStatement node) { var result = CreateBaseNode(node); result["exception"] = node.Exception.Accept(this); return result; } public override Dictionary VisitCatchClause(CatchClause node) { var result = CreateBaseNode(node); result["exceptionTypes"] = node.ExceptionTypes.Select(t => t.Accept(this)).ToList(); result["variableName"] = node.VariableName; result["body"] = node.Body.Accept(this); return result; } public override Dictionary VisitSynchronizedStatement(SynchronizedStatement node) { var result = CreateBaseNode(node); result["lock"] = node.Lock.Accept(this); result["body"] = node.Body.Accept(this); return result; } public override Dictionary VisitLabeledStatement(LabeledStatement node) { var result = CreateBaseNode(node); result["label"] = node.Label; result["statement"] = node.Statement.Accept(this); return result; } public override Dictionary VisitEmptyStatement(EmptyStatement node) { return CreateBaseNode(node); } public override Dictionary VisitAssertStatement(AssertStatement node) { var result = CreateBaseNode(node); result["condition"] = node.Condition.Accept(this); result["message"] = node.Message?.Accept(this); return result; } } /// /// Visitor that deserializes JSON to AST nodes. /// internal class JsonDeserializationVisitor { public JavaNode Deserialize(JsonElement element) { if (!element.TryGetProperty("nodeType", out var nodeTypeElement)) { throw new JsonException("Missing nodeType property"); } var nodeType = nodeTypeElement.GetString() ?? throw new JsonException("nodeType is null"); var location = DeserializeLocation(element.GetProperty("location")); return nodeType switch { "CompilationUnit" => DeserializeCompilationUnit(element, location), "PackageDeclaration" => DeserializePackageDeclaration(element, location), "ImportDeclaration" => DeserializeImportDeclaration(element, location), "ClassDeclaration" => DeserializeClassDeclaration(element, location), "InterfaceDeclaration" => DeserializeInterfaceDeclaration(element, location), "EnumDeclaration" => DeserializeEnumDeclaration(element, location), "AnnotationDeclaration" => DeserializeAnnotationDeclaration(element, location), "FieldDeclaration" => DeserializeFieldDeclaration(element, location), "MethodDeclaration" => DeserializeMethodDeclaration(element, location), "Parameter" => DeserializeParameter(element, location), "VariableDeclarator" => DeserializeVariableDeclarator(element, location), "PrimitiveType" => DeserializePrimitiveType(element, location), "ClassOrInterfaceType" => DeserializeClassOrInterfaceType(element, location), "ArrayType" => DeserializeArrayType(element, location), "TypeParameter" => DeserializeTypeParameter(element, location), "LiteralExpression" => DeserializeLiteralExpression(element, location), "IdentifierExpression" => DeserializeIdentifierExpression(element, location), "BinaryExpression" => DeserializeBinaryExpression(element, location), "UnaryExpression" => DeserializeUnaryExpression(element, location), "MethodCallExpression" => DeserializeMethodCallExpression(element, location), "FieldAccessExpression" => DeserializeFieldAccessExpression(element, location), "BlockStatement" => DeserializeBlockStatement(element, location), "IfStatement" => DeserializeIfStatement(element, location), "WhileStatement" => DeserializeWhileStatement(element, location), "ForStatement" => DeserializeForStatement(element, location), "ReturnStatement" => DeserializeReturnStatement(element, location), "ThisExpression" => DeserializeThisExpression(element, location), "NewExpression" => DeserializeNewExpression(element, location), "LambdaExpression" => DeserializeLambdaExpression(element, location), "TryStatement" => DeserializeTryStatement(element, location), "Annotation" => DeserializeAnnotation(element, location), "JavaDoc" => DeserializeJavaDoc(element, location), "EnumConstant" => DeserializeEnumConstant(element, location), "AnnotationMember" => DeserializeAnnotationMember(element, location), "SuperExpression" => DeserializeSuperExpression(element, location), "ConditionalExpression" => DeserializeConditionalExpression(element, location), "ArrayAccessExpression" => DeserializeArrayAccessExpression(element, location), "CastExpression" => DeserializeCastExpression(element, location), "InstanceOfExpression" => DeserializeInstanceOfExpression(element, location), "NewArrayExpression" => DeserializeNewArrayExpression(element, location), "ArrayInitializer" => DeserializeArrayInitializer(element, location), "AnnotationExpression" => DeserializeAnnotationExpression(element, location), "AnnotationValueArgument" => DeserializeAnnotationValueArgument(element, location), "AnnotationArrayArgument" => DeserializeAnnotationArrayArgument(element, location), "MethodReferenceExpression" => DeserializeMethodReferenceExpression(element, location), "ClassLiteralExpression" => DeserializeClassLiteralExpression(element, location), "LocalVariableStatement" => DeserializeLocalVariableStatement(element, location), "ExpressionStatement" => DeserializeExpressionStatement(element, location), "DoWhileStatement" => DeserializeDoWhileStatement(element, location), "ForEachStatement" => DeserializeForEachStatement(element, location), "SwitchStatement" => DeserializeSwitchStatement(element, location), "BreakStatement" => DeserializeBreakStatement(element, location), "ContinueStatement" => DeserializeContinueStatement(element, location), "ThrowStatement" => DeserializeThrowStatement(element, location), "SynchronizedStatement" => DeserializeSynchronizedStatement(element, location), "LabeledStatement" => DeserializeLabeledStatement(element, location), "EmptyStatement" => DeserializeEmptyStatement(element, location), "AssertStatement" => DeserializeAssertStatement(element, location), "CatchClause" => DeserializeCatchClause(element, location), "SwitchCase" => DeserializeSwitchCase(element, location), "ResourceDeclaration" => DeserializeResourceDeclaration(element, location), "LambdaParameter" => DeserializeLambdaParameter(element, location), _ => throw new JsonException($"Unknown node type: {nodeType}") }; } private SourceRange DeserializeLocation(JsonElement element) { var start = element.GetProperty("start"); var end = element.GetProperty("end"); return new SourceRange( new SourceLocation( start.GetProperty("line").GetInt32(), start.GetProperty("column").GetInt32(), start.GetProperty("position").GetInt32(), 0 ), new SourceLocation( end.GetProperty("line").GetInt32(), end.GetProperty("column").GetInt32(), end.GetProperty("position").GetInt32(), 0 ) ); } private CompilationUnit DeserializeCompilationUnit(JsonElement element, SourceRange location) { var package = element.TryGetProperty("package", out var packageEl) && packageEl.ValueKind != JsonValueKind.Null ? Deserialize(packageEl) as PackageDeclaration : null; var imports = DeserializeList(element.GetProperty("imports")); var types = DeserializeList(element.GetProperty("types")); return new CompilationUnit(location, package, imports, types); } private PackageDeclaration DeserializePackageDeclaration(JsonElement element, SourceRange location) { var packageName = element.GetProperty("packageName").GetString() ?? throw new JsonException("packageName is null"); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); return new PackageDeclaration(location, packageName, annotations); } private ImportDeclaration DeserializeImportDeclaration(JsonElement element, SourceRange location) { var importPath = element.GetProperty("importPath").GetString() ?? throw new JsonException("importPath is null"); var isStatic = element.GetProperty("isStatic").GetBoolean(); var isWildcard = element.GetProperty("isWildcard").GetBoolean(); return new ImportDeclaration(location, importPath, isStatic, isWildcard); } private ClassDeclaration DeserializeClassDeclaration(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var modifiers = DeserializeModifiers(element.GetProperty("modifiers")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); var typeParameters = DeserializeList(element.GetProperty("typeParameters")); var javaDoc = element.TryGetProperty("javaDoc", out var javaDocEl) && javaDocEl.ValueKind != JsonValueKind.Null ? Deserialize(javaDocEl) as JavaDoc : null; var superClass = element.TryGetProperty("superClass", out var superClassEl) && superClassEl.ValueKind != JsonValueKind.Null ? Deserialize(superClassEl) as ClassOrInterfaceType : null; var interfaces = DeserializeList(element.GetProperty("interfaces")); var members = DeserializeList(element.GetProperty("members")); var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl) ? DeserializeList(nestedTypesEl) : new List(); var isRecord = element.TryGetProperty("isRecord", out var isRecordEl) ? isRecordEl.GetBoolean() : false; return new ClassDeclaration(location, name, modifiers, annotations, typeParameters, superClass, interfaces, members, nestedTypes, javaDoc, isRecord); } private InterfaceDeclaration DeserializeInterfaceDeclaration(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var modifiers = DeserializeModifiers(element.GetProperty("modifiers")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); var typeParameters = DeserializeList(element.GetProperty("typeParameters")); var javaDoc = element.TryGetProperty("javaDoc", out var javaDocEl) && javaDocEl.ValueKind != JsonValueKind.Null ? Deserialize(javaDocEl) as JavaDoc : null; var extendedInterfaces = DeserializeList(element.GetProperty("extendedInterfaces")); var members = DeserializeList(element.GetProperty("members")); var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl) ? DeserializeList(nestedTypesEl) : new List(); return new InterfaceDeclaration(location, name, modifiers, annotations, typeParameters, extendedInterfaces, members, nestedTypes, javaDoc); } private EnumDeclaration DeserializeEnumDeclaration(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var modifiers = DeserializeModifiers(element.GetProperty("modifiers")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); var javaDoc = element.TryGetProperty("javaDoc", out var javaDocEl) && javaDocEl.ValueKind != JsonValueKind.Null ? Deserialize(javaDocEl) as JavaDoc : null; var interfaces = DeserializeList(element.GetProperty("interfaces")); var constants = DeserializeList(element.GetProperty("constants")); var members = DeserializeList(element.GetProperty("members")); var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl) ? DeserializeList(nestedTypesEl) : new List(); return new EnumDeclaration(location, name, modifiers, annotations, interfaces, constants, members, nestedTypes, javaDoc); } private AnnotationDeclaration DeserializeAnnotationDeclaration(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var modifiers = DeserializeModifiers(element.GetProperty("modifiers")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); var javaDoc = element.TryGetProperty("javaDoc", out var javaDocEl) && javaDocEl.ValueKind != JsonValueKind.Null ? Deserialize(javaDocEl) as JavaDoc : null; var members = DeserializeList(element.GetProperty("members")); var nestedTypes = element.TryGetProperty("nestedTypes", out var nestedTypesEl) ? DeserializeList(nestedTypesEl) : new List(); return new AnnotationDeclaration(location, name, modifiers, annotations, members, nestedTypes, javaDoc); } private FieldDeclaration DeserializeFieldDeclaration(JsonElement element, SourceRange location) { var modifiers = DeserializeModifiers(element.GetProperty("modifiers")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); var javaDoc = element.TryGetProperty("javaDoc", out var javaDocEl) && javaDocEl.ValueKind != JsonValueKind.Null ? Deserialize(javaDocEl) as JavaDoc : null; var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var variables = DeserializeList(element.GetProperty("variables")); return new FieldDeclaration(location, modifiers, annotations, type, variables, javaDoc); } private MethodDeclaration DeserializeMethodDeclaration(JsonElement element, SourceRange location) { var modifiers = DeserializeModifiers(element.GetProperty("modifiers")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); var javaDoc = element.TryGetProperty("javaDoc", out var javaDocEl) && javaDocEl.ValueKind != JsonValueKind.Null ? Deserialize(javaDocEl) as JavaDoc : null; var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var returnType = element.TryGetProperty("returnType", out var returnTypeEl) && returnTypeEl.ValueKind != JsonValueKind.Null ? Deserialize(returnTypeEl) as TypeReference : null; var typeParameters = DeserializeList(element.GetProperty("typeParameters")); var parameters = DeserializeList(element.GetProperty("parameters")); var throws = DeserializeList(element.GetProperty("throws")); var body = element.TryGetProperty("body", out var bodyEl) && bodyEl.ValueKind != JsonValueKind.Null ? Deserialize(bodyEl) as BlockStatement : null; var isConstructor = element.GetProperty("isConstructor").GetBoolean(); return new MethodDeclaration(location, name, modifiers, annotations, returnType, typeParameters, parameters, throws, body, javaDoc, isConstructor); } private Parameter DeserializeParameter(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var isVarArgs = element.GetProperty("isVarArgs").GetBoolean(); var isFinal = element.GetProperty("isFinal").GetBoolean(); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); return new Parameter(location, type, name, isVarArgs, isFinal, annotations); } private VariableDeclarator DeserializeVariableDeclarator(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var arrayDimensions = element.GetProperty("arrayDimensions").GetInt32(); var initializer = element.TryGetProperty("initializer", out var initializerEl) && initializerEl.ValueKind != JsonValueKind.Null ? Deserialize(initializerEl) as Expression : null; return new VariableDeclarator(location, name, arrayDimensions, initializer); } private PrimitiveType DeserializePrimitiveType(JsonElement element, SourceRange location) { var kindStr = element.GetProperty("kind").GetString() ?? throw new JsonException("kind is null"); var kind = Enum.Parse(kindStr); return new PrimitiveType(location, kind); } private ClassOrInterfaceType DeserializeClassOrInterfaceType(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var scope = element.TryGetProperty("scope", out var scopeEl) && scopeEl.ValueKind != JsonValueKind.Null ? Deserialize(scopeEl) as ClassOrInterfaceType : null; var typeArguments = DeserializeList(element.GetProperty("typeArguments")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); return new ClassOrInterfaceType(location, name, scope, typeArguments, annotations); } private ArrayType DeserializeArrayType(JsonElement element, SourceRange location) { var elementType = Deserialize(element.GetProperty("elementType")) as TypeReference ?? throw new JsonException("elementType is not TypeReference"); var dimensions = element.GetProperty("dimensions").GetInt32(); return new ArrayType(location, elementType, dimensions); } private TypeParameter DeserializeTypeParameter(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var bounds = DeserializeList(element.GetProperty("bounds")); var annotations = DeserializeAnnotations(element.GetProperty("annotations")); return new TypeParameter(location, name, bounds, annotations); } private LiteralExpression DeserializeLiteralExpression(JsonElement element, SourceRange location) { var value = element.GetProperty("value"); var kindStr = element.GetProperty("kind").GetString() ?? throw new JsonException("kind is null"); var kind = Enum.Parse(kindStr); object? literalValue = kind switch { LiteralKind.Integer => value.GetInt32(), LiteralKind.Long => value.GetInt64(), LiteralKind.Float => value.GetSingle(), LiteralKind.Double => value.GetDouble(), LiteralKind.Boolean => value.GetBoolean(), LiteralKind.Character => value.GetString()?.FirstOrDefault(), LiteralKind.String => value.GetString(), LiteralKind.Null => null, _ => throw new JsonException($"Unknown literal kind: {kind}") }; return new LiteralExpression(location, literalValue, kind); } private IdentifierExpression DeserializeIdentifierExpression(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); return new IdentifierExpression(location, name); } private BinaryExpression DeserializeBinaryExpression(JsonElement element, SourceRange location) { var left = Deserialize(element.GetProperty("left")) as Expression ?? throw new JsonException("left is not Expression"); var operatorStr = element.GetProperty("operator").GetString() ?? throw new JsonException("operator is null"); var @operator = Enum.Parse(operatorStr); var right = Deserialize(element.GetProperty("right")) as Expression ?? throw new JsonException("right is not Expression"); return new BinaryExpression(location, left, @operator, right); } private UnaryExpression DeserializeUnaryExpression(JsonElement element, SourceRange location) { var operatorStr = element.GetProperty("operator").GetString() ?? throw new JsonException("operator is null"); var @operator = Enum.Parse(operatorStr); var operand = Deserialize(element.GetProperty("operand")) as Expression ?? throw new JsonException("operand is not Expression"); var isPrefix = element.GetProperty("isPrefix").GetBoolean(); return new UnaryExpression(location, @operator, operand, isPrefix); } private MethodCallExpression DeserializeMethodCallExpression(JsonElement element, SourceRange location) { var target = element.TryGetProperty("target", out var targetEl) && targetEl.ValueKind != JsonValueKind.Null ? Deserialize(targetEl) as Expression : null; var methodName = element.GetProperty("methodName").GetString() ?? throw new JsonException("methodName is null"); var typeArguments = DeserializeList(element.GetProperty("typeArguments")); var arguments = DeserializeList(element.GetProperty("arguments")); return new MethodCallExpression(location, target, methodName, typeArguments, arguments); } private FieldAccessExpression DeserializeFieldAccessExpression(JsonElement element, SourceRange location) { var target = Deserialize(element.GetProperty("target")) as Expression ?? throw new JsonException("target is not Expression"); var fieldName = element.GetProperty("fieldName").GetString() ?? throw new JsonException("fieldName is null"); return new FieldAccessExpression(location, target, fieldName); } private BlockStatement DeserializeBlockStatement(JsonElement element, SourceRange location) { var statements = DeserializeList(element.GetProperty("statements")); return new BlockStatement(location, statements); } private IfStatement DeserializeIfStatement(JsonElement element, SourceRange location) { var condition = Deserialize(element.GetProperty("condition")) as Expression ?? throw new JsonException("condition is not Expression"); var thenStatement = Deserialize(element.GetProperty("thenStatement")) as Statement ?? throw new JsonException("thenStatement is not Statement"); var elseStatement = element.TryGetProperty("elseStatement", out var elseEl) && elseEl.ValueKind != JsonValueKind.Null ? Deserialize(elseEl) as Statement : null; return new IfStatement(location, condition, thenStatement, elseStatement); } private WhileStatement DeserializeWhileStatement(JsonElement element, SourceRange location) { var condition = Deserialize(element.GetProperty("condition")) as Expression ?? throw new JsonException("condition is not Expression"); var body = Deserialize(element.GetProperty("body")) as Statement ?? throw new JsonException("body is not Statement"); return new WhileStatement(location, condition, body); } private ForStatement DeserializeForStatement(JsonElement element, SourceRange location) { var initializers = DeserializeList(element.GetProperty("initializers")); var condition = element.TryGetProperty("condition", out var conditionEl) && conditionEl.ValueKind != JsonValueKind.Null ? Deserialize(conditionEl) as Expression : null; var updates = DeserializeList(element.GetProperty("updates")); var body = Deserialize(element.GetProperty("body")) as Statement ?? throw new JsonException("body is not Statement"); return new ForStatement(location, initializers, condition, updates, body); } private ReturnStatement DeserializeReturnStatement(JsonElement element, SourceRange location) { var value = element.TryGetProperty("value", out var valueEl) && valueEl.ValueKind != JsonValueKind.Null ? Deserialize(valueEl) as Expression : null; return new ReturnStatement(location, value); } private ThisExpression DeserializeThisExpression(JsonElement element, SourceRange location) { var qualifier = element.TryGetProperty("qualifier", out var qualifierEl) && qualifierEl.ValueKind != JsonValueKind.Null ? Deserialize(qualifierEl) as Expression : null; return new ThisExpression(location, qualifier); } private NewExpression DeserializeNewExpression(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as ClassOrInterfaceType ?? throw new JsonException("type is not ClassOrInterfaceType"); var arguments = DeserializeList(element.GetProperty("arguments")); var anonymousClassBody = element.TryGetProperty("anonymousClassBody", out var bodyEl) && bodyEl.ValueKind != JsonValueKind.Null ? Deserialize(bodyEl) as ClassDeclaration : null; return new NewExpression(location, type, arguments, anonymousClassBody); } private LambdaExpression DeserializeLambdaExpression(JsonElement element, SourceRange location) { var parameters = DeserializeList(element.GetProperty("parameters")); var body = Deserialize(element.GetProperty("body")) ?? throw new JsonException("body is null"); return new LambdaExpression(location, parameters, body); } private TryStatement DeserializeTryStatement(JsonElement element, SourceRange location) { var resources = DeserializeList(element.GetProperty("resources")); var body = Deserialize(element.GetProperty("body")) as BlockStatement ?? throw new JsonException("body is not BlockStatement"); var catchClauses = DeserializeList(element.GetProperty("catchClauses")); var finallyBlock = element.TryGetProperty("finallyBlock", out var finallyEl) && finallyEl.ValueKind != JsonValueKind.Null ? Deserialize(finallyEl) as BlockStatement : null; return new TryStatement(location, resources, body, catchClauses, finallyBlock); } private Annotation DeserializeAnnotation(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as ClassOrInterfaceType ?? throw new JsonException("type is not ClassOrInterfaceType"); var arguments = DeserializeList(element.GetProperty("arguments")); return new Annotation(location, type, arguments); } private JavaDoc DeserializeJavaDoc(JsonElement element, SourceRange location) { var content = element.GetProperty("content").GetString() ?? throw new JsonException("content is null"); var tags = element.GetProperty("tags").EnumerateArray().Select(tagEl => { var name = tagEl.GetProperty("name").GetString() ?? ""; var parameter = tagEl.TryGetProperty("parameter", out var paramEl) ? paramEl.GetString() : null; var description = tagEl.TryGetProperty("description", out var descEl) ? descEl.GetString() : null; return new JavaDocTag(name, parameter, description ?? ""); }).ToList(); return new JavaDoc(location, content, tags); } private List DeserializeList(JsonElement element) where T : JavaNode { return element.EnumerateArray() .Select(item => Deserialize(item)) .OfType() .ToList(); } private List DeserializeAnnotations(JsonElement element) { return element.EnumerateArray() .Select(item => Deserialize(item) as Annotation) .Where(ann => ann != null) .Cast() .ToList(); } private Modifiers DeserializeModifiers(JsonElement element) { var modifiers = Modifiers.None; foreach (var modifierStr in element.EnumerateArray()) { var str = modifierStr.GetString(); if (str != null && Enum.TryParse(str, true, out var modifier)) { modifiers |= modifier; } } return modifiers; } // Additional node deserializers private EnumConstant DeserializeEnumConstant(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var arguments = DeserializeList(element.GetProperty("arguments")); var body = element.TryGetProperty("body", out var bodyEl) && bodyEl.ValueKind != JsonValueKind.Null ? Deserialize(bodyEl) as ClassDeclaration : null; var annotations = DeserializeAnnotations(element.GetProperty("annotations")); return new EnumConstant(location, name, annotations, arguments, body); } private AnnotationMember DeserializeAnnotationMember(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var defaultValue = element.TryGetProperty("defaultValue", out var defaultEl) && defaultEl.ValueKind != JsonValueKind.Null ? Deserialize(defaultEl) as Expression : null; return new AnnotationMember(location, name, type, defaultValue); } private SuperExpression DeserializeSuperExpression(JsonElement element, SourceRange location) { var qualifier = element.TryGetProperty("qualifier", out var qualifierEl) && qualifierEl.ValueKind != JsonValueKind.Null ? Deserialize(qualifierEl) as Expression : null; return new SuperExpression(location, qualifier); } private ConditionalExpression DeserializeConditionalExpression(JsonElement element, SourceRange location) { var condition = Deserialize(element.GetProperty("condition")) as Expression ?? throw new JsonException("condition is not Expression"); var thenExpression = Deserialize(element.GetProperty("thenExpression")) as Expression ?? throw new JsonException("thenExpression is not Expression"); var elseExpression = Deserialize(element.GetProperty("elseExpression")) as Expression ?? throw new JsonException("elseExpression is not Expression"); return new ConditionalExpression(location, condition, thenExpression, elseExpression); } private ArrayAccessExpression DeserializeArrayAccessExpression(JsonElement element, SourceRange location) { var array = Deserialize(element.GetProperty("array")) as Expression ?? throw new JsonException("array is not Expression"); var index = Deserialize(element.GetProperty("index")) as Expression ?? throw new JsonException("index is not Expression"); return new ArrayAccessExpression(location, array, index); } private CastExpression DeserializeCastExpression(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var expression = Deserialize(element.GetProperty("expression")) as Expression ?? throw new JsonException("expression is not Expression"); return new CastExpression(location, type, expression); } private InstanceOfExpression DeserializeInstanceOfExpression(JsonElement element, SourceRange location) { var expression = Deserialize(element.GetProperty("expression")) as Expression ?? throw new JsonException("expression is not Expression"); var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var patternVariable = element.TryGetProperty("patternVariable", out var patternEl) && patternEl.ValueKind != JsonValueKind.Null ? patternEl.GetString() : null; return new InstanceOfExpression(location, expression, type, patternVariable); } private NewArrayExpression DeserializeNewArrayExpression(JsonElement element, SourceRange location) { var elementType = Deserialize(element.GetProperty("elementType")) as TypeReference ?? throw new JsonException("elementType is not TypeReference"); var dimensions = DeserializeList(element.GetProperty("dimensions")); var initializer = element.TryGetProperty("initializer", out var initEl) && initEl.ValueKind != JsonValueKind.Null ? Deserialize(initEl) as ArrayInitializer : null; return new NewArrayExpression(location, elementType, dimensions, initializer); } private ArrayInitializer DeserializeArrayInitializer(JsonElement element, SourceRange location) { var elements = DeserializeList(element.GetProperty("elements")); return new ArrayInitializer(location, elements); } private AnnotationExpression DeserializeAnnotationExpression(JsonElement element, SourceRange location) { var annotation = Deserialize(element.GetProperty("annotation")) as Annotation ?? throw new JsonException("annotation is not Annotation"); return new AnnotationExpression(location, annotation); } private AnnotationValueArgument DeserializeAnnotationValueArgument(JsonElement element, SourceRange location) { var name = element.TryGetProperty("name", out var nameEl) && nameEl.ValueKind != JsonValueKind.Null ? nameEl.GetString() : null; var value = Deserialize(element.GetProperty("value")) as Expression ?? throw new JsonException("value is not Expression"); return new AnnotationValueArgument(location, name, value); } private AnnotationArrayArgument DeserializeAnnotationArrayArgument(JsonElement element, SourceRange location) { var name = element.TryGetProperty("name", out var nameEl) && nameEl.ValueKind != JsonValueKind.Null ? nameEl.GetString() : null; var values = DeserializeList(element.GetProperty("values")); return new AnnotationArrayArgument(location, name, values); } private MethodReferenceExpression DeserializeMethodReferenceExpression(JsonElement element, SourceRange location) { var target = Deserialize(element.GetProperty("target")) as Expression ?? throw new JsonException("target is not Expression"); var methodName = element.GetProperty("methodName").GetString() ?? throw new JsonException("methodName is null"); var typeArguments = DeserializeList(element.GetProperty("typeArguments")); return new MethodReferenceExpression(location, target, methodName, typeArguments); } private ClassLiteralExpression DeserializeClassLiteralExpression(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); return new ClassLiteralExpression(location, type); } private LocalVariableStatement DeserializeLocalVariableStatement(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var variables = DeserializeList(element.GetProperty("variables")); var isFinal = element.GetProperty("isFinal").GetBoolean(); return new LocalVariableStatement(location, type, variables, isFinal); } private ExpressionStatement DeserializeExpressionStatement(JsonElement element, SourceRange location) { var expression = Deserialize(element.GetProperty("expression")) as Expression ?? throw new JsonException("expression is not Expression"); return new ExpressionStatement(location, expression); } private DoWhileStatement DeserializeDoWhileStatement(JsonElement element, SourceRange location) { var body = Deserialize(element.GetProperty("body")) as Statement ?? throw new JsonException("body is not Statement"); var condition = Deserialize(element.GetProperty("condition")) as Expression ?? throw new JsonException("condition is not Expression"); return new DoWhileStatement(location, body, condition); } private ForEachStatement DeserializeForEachStatement(JsonElement element, SourceRange location) { var variableType = Deserialize(element.GetProperty("variableType")) as TypeReference ?? throw new JsonException("variableType is not TypeReference"); var variableName = element.GetProperty("variableName").GetString() ?? throw new JsonException("variableName is null"); var iterable = Deserialize(element.GetProperty("iterable")) as Expression ?? throw new JsonException("iterable is not Expression"); var body = Deserialize(element.GetProperty("body")) as Statement ?? throw new JsonException("body is not Statement"); var isFinal = element.GetProperty("isFinal").GetBoolean(); return new ForEachStatement(location, variableType, variableName, iterable, body, isFinal); } private SwitchStatement DeserializeSwitchStatement(JsonElement element, SourceRange location) { var expression = Deserialize(element.GetProperty("selector")) as Expression ?? throw new JsonException("selector is not Expression"); var cases = DeserializeList(element.GetProperty("cases")); return new SwitchStatement(location, expression, cases); } private SwitchCase DeserializeSwitchCase(JsonElement element, SourceRange location) { var labels = DeserializeList(element.GetProperty("labels")); var statements = DeserializeList(element.GetProperty("statements")); var isDefault = element.GetProperty("isDefault").GetBoolean(); return new SwitchCase(location, labels, statements, isDefault); } private BreakStatement DeserializeBreakStatement(JsonElement element, SourceRange location) { var label = element.TryGetProperty("label", out var labelEl) ? labelEl.GetString() : null; return new BreakStatement(location, label); } private ContinueStatement DeserializeContinueStatement(JsonElement element, SourceRange location) { var label = element.TryGetProperty("label", out var labelEl) ? labelEl.GetString() : null; return new ContinueStatement(location, label); } private ThrowStatement DeserializeThrowStatement(JsonElement element, SourceRange location) { var expression = Deserialize(element.GetProperty("exception")) as Expression ?? throw new JsonException("exception is not Expression"); return new ThrowStatement(location, expression); } private CatchClause DeserializeCatchClause(JsonElement element, SourceRange location) { var exceptionTypes = DeserializeList(element.GetProperty("exceptionTypes")); var variableName = element.GetProperty("variableName").GetString() ?? throw new JsonException("variableName is null"); var body = Deserialize(element.GetProperty("body")) as BlockStatement ?? throw new JsonException("body is not BlockStatement"); return new CatchClause(location, exceptionTypes, variableName, body); } private SynchronizedStatement DeserializeSynchronizedStatement(JsonElement element, SourceRange location) { var expression = Deserialize(element.GetProperty("lock")) as Expression ?? throw new JsonException("lock is not Expression"); var body = Deserialize(element.GetProperty("body")) as BlockStatement ?? throw new JsonException("body is not BlockStatement"); return new SynchronizedStatement(location, expression, body); } private LabeledStatement DeserializeLabeledStatement(JsonElement element, SourceRange location) { var label = element.GetProperty("label").GetString() ?? throw new JsonException("label is null"); var statement = Deserialize(element.GetProperty("statement")) as Statement ?? throw new JsonException("statement is not Statement"); return new LabeledStatement(location, label, statement); } private EmptyStatement DeserializeEmptyStatement(JsonElement element, SourceRange location) { return new EmptyStatement(location); } private AssertStatement DeserializeAssertStatement(JsonElement element, SourceRange location) { var condition = Deserialize(element.GetProperty("condition")) as Expression ?? throw new JsonException("condition is not Expression"); var message = element.TryGetProperty("message", out var msgEl) && msgEl.ValueKind != JsonValueKind.Null ? Deserialize(msgEl) as Expression : null; return new AssertStatement(location, condition, message); } private ResourceDeclaration DeserializeResourceDeclaration(JsonElement element, SourceRange location) { var type = Deserialize(element.GetProperty("type")) as TypeReference ?? throw new JsonException("type is not TypeReference"); var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var initializer = Deserialize(element.GetProperty("initializer")) as Expression ?? throw new JsonException("initializer is not Expression"); var isFinal = element.GetProperty("isFinal").GetBoolean(); return new ResourceDeclaration(location, type, name, initializer, isFinal); } private LambdaParameter DeserializeLambdaParameter(JsonElement element, SourceRange location) { var name = element.GetProperty("name").GetString() ?? throw new JsonException("name is null"); var type = element.TryGetProperty("type", out var typeEl) && typeEl.ValueKind != JsonValueKind.Null ? Deserialize(typeEl) as TypeReference : null; var isFinal = element.GetProperty("isFinal").GetBoolean(); return new LambdaParameter(location, name, type, isFinal); } } }