3652 lines
145 KiB
C#
3652 lines
145 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using Antlr4.Runtime;
|
|
using Antlr4.Runtime.Misc;
|
|
using Antlr4.Runtime.Tree;
|
|
using MarketAlly.IronJava.Core.AST.Nodes;
|
|
using MarketAlly.IronJava.Core.Grammar;
|
|
|
|
namespace MarketAlly.IronJava.Core.AST.Builders
|
|
{
|
|
/// <summary>
|
|
/// Builds a typed AST from ANTLR parse tree.
|
|
/// </summary>
|
|
public class AstBuilder : Java9ParserBaseVisitor<JavaNode?>
|
|
{
|
|
private readonly ITokenStream _tokens;
|
|
|
|
public AstBuilder(ITokenStream tokens)
|
|
{
|
|
_tokens = tokens;
|
|
}
|
|
|
|
private SourceRange GetSourceRange(ParserRuleContext context)
|
|
{
|
|
var start = new SourceLocation(
|
|
context.Start.Line,
|
|
context.Start.Column,
|
|
context.Start.StartIndex,
|
|
context.Start.Text?.Length ?? 0
|
|
);
|
|
|
|
var stop = context.Stop ?? context.Start;
|
|
var end = new SourceLocation(
|
|
stop.Line,
|
|
stop.Column + (stop.Text?.Length ?? 0),
|
|
stop.StopIndex,
|
|
stop.Text?.Length ?? 0
|
|
);
|
|
|
|
return new SourceRange(start, end);
|
|
}
|
|
|
|
private SourceRange GetSourceRange(ITerminalNode node)
|
|
{
|
|
var token = node.Symbol;
|
|
var location = new SourceLocation(
|
|
token.Line,
|
|
token.Column,
|
|
token.StartIndex,
|
|
token.Text?.Length ?? 0
|
|
);
|
|
return new SourceRange(location, location);
|
|
}
|
|
|
|
private PrimitiveTypeKind ParsePrimitiveTypeKind(string typeName)
|
|
{
|
|
return typeName switch
|
|
{
|
|
"boolean" => PrimitiveTypeKind.Boolean,
|
|
"byte" => PrimitiveTypeKind.Byte,
|
|
"short" => PrimitiveTypeKind.Short,
|
|
"int" => PrimitiveTypeKind.Int,
|
|
"long" => PrimitiveTypeKind.Long,
|
|
"char" => PrimitiveTypeKind.Char,
|
|
"float" => PrimitiveTypeKind.Float,
|
|
"double" => PrimitiveTypeKind.Double,
|
|
"void" => PrimitiveTypeKind.Void,
|
|
_ => PrimitiveTypeKind.Int // Default fallback
|
|
};
|
|
}
|
|
|
|
public override JavaNode? VisitCompilationUnit(Java9Parser.CompilationUnitContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
PackageDeclaration? package = null;
|
|
var imports = new List<ImportDeclaration>();
|
|
var types = new List<TypeDeclaration>();
|
|
|
|
// Check if it's ordinary compilation or modular compilation
|
|
if (context.ordinaryCompilation() != null)
|
|
{
|
|
var ordinaryComp = context.ordinaryCompilation();
|
|
|
|
package = ordinaryComp.packageDeclaration() != null
|
|
? Visit(ordinaryComp.packageDeclaration()) as PackageDeclaration
|
|
: null;
|
|
|
|
imports = ordinaryComp.importDeclaration()
|
|
.Select(i => Visit(i) as ImportDeclaration)
|
|
.Where(i => i != null)
|
|
.Cast<ImportDeclaration>()
|
|
.ToList();
|
|
|
|
types = ordinaryComp.typeDeclaration()
|
|
.Select(t => Visit(t) as TypeDeclaration)
|
|
.Where(t => t != null)
|
|
.Cast<TypeDeclaration>()
|
|
.ToList();
|
|
}
|
|
else if (context.modularCompilation() != null)
|
|
{
|
|
var modularComp = context.modularCompilation();
|
|
|
|
// Handle module declaration if needed
|
|
// For now, we'll just handle imports
|
|
imports = modularComp.importDeclaration()
|
|
.Select(i => Visit(i) as ImportDeclaration)
|
|
.Where(i => i != null)
|
|
.Cast<ImportDeclaration>()
|
|
.ToList();
|
|
}
|
|
|
|
return new CompilationUnit(location, package, imports, types);
|
|
}
|
|
|
|
public override JavaNode? VisitPackageDeclaration(Java9Parser.PackageDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var annotations = BuildAnnotations(context.packageModifier());
|
|
var packageName = context.packageName().GetText();
|
|
|
|
return new PackageDeclaration(location, packageName, annotations);
|
|
}
|
|
|
|
public override JavaNode? VisitImportDeclaration(Java9Parser.ImportDeclarationContext context)
|
|
{
|
|
if (context.singleTypeImportDeclaration() != null)
|
|
{
|
|
return VisitSingleTypeImportDeclaration(context.singleTypeImportDeclaration());
|
|
}
|
|
else if (context.typeImportOnDemandDeclaration() != null)
|
|
{
|
|
return VisitTypeImportOnDemandDeclaration(context.typeImportOnDemandDeclaration());
|
|
}
|
|
else if (context.singleStaticImportDeclaration() != null)
|
|
{
|
|
return VisitSingleStaticImportDeclaration(context.singleStaticImportDeclaration());
|
|
}
|
|
else if (context.staticImportOnDemandDeclaration() != null)
|
|
{
|
|
return VisitStaticImportOnDemandDeclaration(context.staticImportOnDemandDeclaration());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override JavaNode? VisitSingleTypeImportDeclaration(Java9Parser.SingleTypeImportDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var typeName = context.typeName().GetText();
|
|
return new ImportDeclaration(location, typeName, false, false);
|
|
}
|
|
|
|
public override JavaNode? VisitTypeImportOnDemandDeclaration(Java9Parser.TypeImportOnDemandDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var packageOrTypeName = context.packageOrTypeName().GetText();
|
|
return new ImportDeclaration(location, packageOrTypeName, false, true);
|
|
}
|
|
|
|
public override JavaNode? VisitSingleStaticImportDeclaration(Java9Parser.SingleStaticImportDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var typeName = context.typeName().GetText() + "." + context.identifier().GetText();
|
|
return new ImportDeclaration(location, typeName, true, false);
|
|
}
|
|
|
|
public override JavaNode? VisitStaticImportOnDemandDeclaration(Java9Parser.StaticImportOnDemandDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var typeName = context.typeName().GetText();
|
|
return new ImportDeclaration(location, typeName, true, true);
|
|
}
|
|
|
|
public override JavaNode? VisitTypeDeclaration(Java9Parser.TypeDeclarationContext context)
|
|
{
|
|
if (context.classDeclaration() != null)
|
|
{
|
|
return Visit(context.classDeclaration());
|
|
}
|
|
else if (context.interfaceDeclaration() != null)
|
|
{
|
|
return Visit(context.interfaceDeclaration());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
public override JavaNode? VisitNormalClassDeclaration(Java9Parser.NormalClassDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.classModifier());
|
|
var annotations = BuildAnnotations(context.classModifier());
|
|
var name = context.identifier().GetText();
|
|
var typeParameters = BuildTypeParameters(context.typeParameters());
|
|
var superClass = context.superclass() != null ? BuildTypeReference(context.superclass().classType()) : null;
|
|
var interfaces = BuildInterfaces(context.superinterfaces());
|
|
var bodyResult = BuildClassBody(context.classBody());
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new ClassDeclaration(
|
|
location, name, modifiers, annotations, typeParameters,
|
|
superClass, interfaces, bodyResult.Members, bodyResult.NestedTypes, javaDoc, false
|
|
);
|
|
}
|
|
|
|
public override JavaNode? VisitNormalInterfaceDeclaration(Java9Parser.NormalInterfaceDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.interfaceModifier());
|
|
var annotations = BuildAnnotations(context.interfaceModifier());
|
|
var name = context.identifier().GetText();
|
|
var typeParameters = BuildTypeParameters(context.typeParameters());
|
|
var extendedInterfaces = BuildExtendedInterfaces(context.extendsInterfaces());
|
|
var bodyResult = BuildInterfaceBody(context.interfaceBody());
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new InterfaceDeclaration(
|
|
location, name, modifiers, annotations, typeParameters,
|
|
extendedInterfaces, bodyResult.Members, bodyResult.NestedTypes, javaDoc
|
|
);
|
|
}
|
|
|
|
public override JavaNode? VisitEnumDeclaration(Java9Parser.EnumDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.classModifier());
|
|
var annotations = BuildAnnotations(context.classModifier());
|
|
var name = context.identifier().GetText();
|
|
var interfaces = BuildInterfaces(context.superinterfaces());
|
|
var enumBody = context.enumBody();
|
|
var constants = BuildEnumConstants(enumBody.enumConstantList());
|
|
var bodyResult = BuildEnumBody(enumBody.enumBodyDeclarations());
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new EnumDeclaration(
|
|
location, name, modifiers, annotations,
|
|
interfaces, constants,
|
|
bodyResult?.Members ?? new List<MemberDeclaration>(),
|
|
bodyResult?.NestedTypes ?? new List<TypeDeclaration>(),
|
|
javaDoc
|
|
);
|
|
}
|
|
|
|
public override JavaNode? VisitAnnotationTypeDeclaration(Java9Parser.AnnotationTypeDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.interfaceModifier());
|
|
var annotations = BuildAnnotations(context.interfaceModifier());
|
|
var name = context.identifier().GetText();
|
|
var members = BuildAnnotationMembers(context.annotationTypeBody());
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
// Annotations don't support nested types in Java
|
|
return new AnnotationDeclaration(
|
|
location, name, modifiers, annotations, members, new List<TypeDeclaration>(), javaDoc
|
|
);
|
|
}
|
|
|
|
// Helper methods for building AST components
|
|
|
|
private Modifiers BuildModifiers(IEnumerable<IParseTree>? modifierContexts)
|
|
{
|
|
if (modifierContexts == null) return Modifiers.None;
|
|
|
|
var modifiers = Modifiers.None;
|
|
foreach (var modifier in modifierContexts)
|
|
{
|
|
var text = modifier.GetText();
|
|
modifiers |= text switch
|
|
{
|
|
"public" => Modifiers.Public,
|
|
"protected" => Modifiers.Protected,
|
|
"private" => Modifiers.Private,
|
|
"static" => Modifiers.Static,
|
|
"final" => Modifiers.Final,
|
|
"abstract" => Modifiers.Abstract,
|
|
"native" => Modifiers.Native,
|
|
"synchronized" => Modifiers.Synchronized,
|
|
"transient" => Modifiers.Transient,
|
|
"volatile" => Modifiers.Volatile,
|
|
"strictfp" => Modifiers.Strictfp,
|
|
"default" => Modifiers.Default,
|
|
"sealed" => Modifiers.Sealed,
|
|
"non-sealed" => Modifiers.NonSealed,
|
|
_ => Modifiers.None
|
|
};
|
|
}
|
|
return modifiers;
|
|
}
|
|
|
|
private List<Annotation> BuildAnnotations(IEnumerable<IParseTree>? contexts)
|
|
{
|
|
if (contexts == null) return new List<Annotation>();
|
|
|
|
var annotations = new List<Annotation>();
|
|
foreach (var context in contexts)
|
|
{
|
|
// Check if this is directly an annotation context
|
|
if (context is Java9Parser.AnnotationContext annotationContext)
|
|
{
|
|
var annotation = BuildAnnotation(annotationContext);
|
|
if (annotation != null) annotations.Add(annotation);
|
|
}
|
|
// Check if this is a modifier that contains an annotation
|
|
else if (context is ParserRuleContext ruleContext && ruleContext.ChildCount > 0)
|
|
{
|
|
// The first child of a modifier rule that represents an annotation
|
|
// will be an AnnotationContext
|
|
var firstChild = ruleContext.GetChild(0);
|
|
if (firstChild is Java9Parser.AnnotationContext childAnnotation)
|
|
{
|
|
var annotation = BuildAnnotation(childAnnotation);
|
|
if (annotation != null) annotations.Add(annotation);
|
|
}
|
|
}
|
|
}
|
|
return annotations;
|
|
}
|
|
|
|
private Annotation? BuildAnnotation(Java9Parser.AnnotationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
TypeReference? type = null;
|
|
var arguments = new List<AnnotationArgument>();
|
|
|
|
|
|
// Annotations can be NormalAnnotation, MarkerAnnotation, or SingleElementAnnotation
|
|
if (context.normalAnnotation() != null)
|
|
{
|
|
var normalAnn = context.normalAnnotation();
|
|
type = BuildTypeReference(normalAnn.typeName());
|
|
// Don't return early - try to build the type from the name
|
|
if (type == null)
|
|
{
|
|
var typeName = normalAnn.typeName().GetText();
|
|
type = new ClassOrInterfaceType(GetSourceRange(normalAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
|
}
|
|
|
|
if (normalAnn.elementValuePairList() != null)
|
|
{
|
|
foreach (var pair in normalAnn.elementValuePairList().elementValuePair())
|
|
{
|
|
var name = pair.identifier().GetText();
|
|
var value = BuildElementValue(pair.elementValue());
|
|
|
|
// Debug - always add the argument even if value is null
|
|
// If value is null, create a string literal as fallback
|
|
if (value == null)
|
|
{
|
|
var elementText = pair.elementValue().GetText();
|
|
value = new LiteralExpression(GetSourceRange(pair.elementValue()), elementText, LiteralKind.String);
|
|
}
|
|
|
|
arguments.Add(new AnnotationValueArgument(
|
|
GetSourceRange(pair), name, value
|
|
));
|
|
}
|
|
}
|
|
}
|
|
else if (context.markerAnnotation() != null)
|
|
{
|
|
var markerAnn = context.markerAnnotation();
|
|
type = BuildTypeReference(markerAnn.typeName());
|
|
if (type == null)
|
|
{
|
|
var typeName = markerAnn.typeName().GetText();
|
|
type = new ClassOrInterfaceType(GetSourceRange(markerAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
|
}
|
|
// Marker annotations have no arguments
|
|
}
|
|
else if (context.singleElementAnnotation() != null)
|
|
{
|
|
var singleAnn = context.singleElementAnnotation();
|
|
type = BuildTypeReference(singleAnn.typeName());
|
|
if (type == null)
|
|
{
|
|
var typeName = singleAnn.typeName().GetText();
|
|
type = new ClassOrInterfaceType(GetSourceRange(singleAnn.typeName()), typeName, null, new List<TypeArgument>(), new List<Annotation>());
|
|
}
|
|
|
|
if (singleAnn.elementValue() != null)
|
|
{
|
|
var value = BuildElementValue(singleAnn.elementValue());
|
|
|
|
// Fallback if BuildElementValue returns null
|
|
if (value == null)
|
|
{
|
|
var elementText = singleAnn.elementValue().GetText();
|
|
value = new LiteralExpression(GetSourceRange(singleAnn.elementValue()), elementText, LiteralKind.String);
|
|
}
|
|
|
|
arguments.Add(new AnnotationValueArgument(
|
|
location, "value", value
|
|
));
|
|
}
|
|
}
|
|
|
|
return type != null ? new Annotation(location, type, arguments) : null;
|
|
}
|
|
|
|
private Expression? BuildElementValue(Java9Parser.ElementValueContext context)
|
|
{
|
|
if (context.conditionalExpression() != null)
|
|
{
|
|
var expr = BuildExpression(context.conditionalExpression());
|
|
// If BuildExpression returns null, try to parse it as a string literal
|
|
if (expr == null)
|
|
{
|
|
var text = context.conditionalExpression().GetText();
|
|
if (text.StartsWith('"') && text.EndsWith('"'))
|
|
{
|
|
// Remove quotes and create a string literal
|
|
var value = text.Substring(1, text.Length - 2);
|
|
expr = new LiteralExpression(GetSourceRange(context), value, LiteralKind.String);
|
|
}
|
|
}
|
|
return expr;
|
|
}
|
|
else if (context.annotation() != null)
|
|
{
|
|
var annotation = BuildAnnotation(context.annotation());
|
|
if (annotation != null)
|
|
{
|
|
return new AnnotationExpression(GetSourceRange(context), annotation);
|
|
}
|
|
}
|
|
else if (context.elementValueArrayInitializer() != null)
|
|
{
|
|
var arrayInit = context.elementValueArrayInitializer();
|
|
var elements = new List<Expression>();
|
|
|
|
if (arrayInit.elementValueList() != null)
|
|
{
|
|
foreach (var elementValue in arrayInit.elementValueList().elementValue())
|
|
{
|
|
var element = BuildElementValue(elementValue);
|
|
if (element != null) elements.Add(element);
|
|
}
|
|
}
|
|
|
|
return new ArrayInitializer(GetSourceRange(arrayInit), elements);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private List<TypeParameter> BuildTypeParameters(Java9Parser.TypeParametersContext? context)
|
|
{
|
|
if (context == null) return new List<TypeParameter>();
|
|
|
|
return context.typeParameterList().typeParameter()
|
|
.Select(tp => BuildTypeParameter(tp))
|
|
.Where(tp => tp != null)
|
|
.Cast<TypeParameter>()
|
|
.ToList();
|
|
}
|
|
|
|
private TypeParameter? BuildTypeParameter(Java9Parser.TypeParameterContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var name = context.identifier().GetText();
|
|
var bounds = new List<TypeReference>();
|
|
var annotations = BuildAnnotations(context.typeParameterModifier());
|
|
|
|
if (context.typeBound() != null)
|
|
{
|
|
if (context.typeBound().typeVariable() != null)
|
|
{
|
|
var boundType = BuildTypeReference(context.typeBound().typeVariable());
|
|
if (boundType != null) bounds.Add(boundType);
|
|
}
|
|
else if (context.typeBound().classOrInterfaceType() != null)
|
|
{
|
|
var boundType = BuildTypeReference(context.typeBound().classOrInterfaceType());
|
|
if (boundType != null) bounds.Add(boundType);
|
|
|
|
foreach (var additionalBound in context.typeBound().additionalBound())
|
|
{
|
|
var additionalType = BuildTypeReference(additionalBound.interfaceType());
|
|
if (additionalType != null) bounds.Add(additionalType);
|
|
}
|
|
}
|
|
}
|
|
|
|
return new TypeParameter(location, name, bounds, annotations);
|
|
}
|
|
|
|
private TypeReference? BuildTypeReference(IParseTree? context)
|
|
{
|
|
if (context == null) return null;
|
|
|
|
return context switch
|
|
{
|
|
Java9Parser.PrimitiveTypeContext primitive => BuildPrimitiveType(primitive),
|
|
Java9Parser.ClassOrInterfaceTypeContext classOrInterface => BuildClassOrInterfaceType(classOrInterface),
|
|
Java9Parser.ArrayTypeContext array => BuildArrayType(array),
|
|
Java9Parser.TypeVariableContext typeVar => BuildTypeVariable(typeVar),
|
|
Java9Parser.ClassTypeContext classType => BuildClassType(classType),
|
|
Java9Parser.TypeNameContext typeName => BuildTypeName(typeName),
|
|
Java9Parser.InterfaceTypeContext interfaceType => BuildInterfaceType(interfaceType),
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
private PrimitiveType? BuildPrimitiveType(Java9Parser.PrimitiveTypeContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var text = context.GetText();
|
|
|
|
var kind = text switch
|
|
{
|
|
"boolean" => PrimitiveTypeKind.Boolean,
|
|
"byte" => PrimitiveTypeKind.Byte,
|
|
"short" => PrimitiveTypeKind.Short,
|
|
"int" => PrimitiveTypeKind.Int,
|
|
"long" => PrimitiveTypeKind.Long,
|
|
"char" => PrimitiveTypeKind.Char,
|
|
"float" => PrimitiveTypeKind.Float,
|
|
"double" => PrimitiveTypeKind.Double,
|
|
_ => (PrimitiveTypeKind?)null
|
|
};
|
|
|
|
return kind.HasValue ? new PrimitiveType(location, kind.Value) : null;
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildClassOrInterfaceType(Java9Parser.ClassOrInterfaceTypeContext context)
|
|
{
|
|
ClassOrInterfaceType? current = null;
|
|
|
|
if (context.classType_lfno_classOrInterfaceType() != null)
|
|
{
|
|
current = BuildClassType_lfno(context.classType_lfno_classOrInterfaceType());
|
|
}
|
|
else if (context.interfaceType_lfno_classOrInterfaceType() != null)
|
|
{
|
|
current = BuildInterfaceType_lfno(context.interfaceType_lfno_classOrInterfaceType());
|
|
}
|
|
|
|
foreach (var additional in context.classType_lf_classOrInterfaceType())
|
|
{
|
|
var name = additional.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(additional.typeArguments());
|
|
var annotations = BuildAnnotations(additional.annotation());
|
|
var location = GetSourceRange(additional);
|
|
|
|
current = new ClassOrInterfaceType(location, name, current, typeArgs, annotations);
|
|
}
|
|
|
|
foreach (var additional in context.interfaceType_lf_classOrInterfaceType())
|
|
{
|
|
// InterfaceType_lf_classOrInterfaceType delegates to classType_lf_classOrInterfaceType
|
|
var classType = additional.classType_lf_classOrInterfaceType();
|
|
if (classType != null)
|
|
{
|
|
var name = classType.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(classType.typeArguments());
|
|
var annotations = BuildAnnotations(classType.annotation());
|
|
var location = GetSourceRange(additional);
|
|
|
|
current = new ClassOrInterfaceType(location, name, current, typeArgs, annotations);
|
|
}
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildClassType(Java9Parser.ClassTypeContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var annotations = BuildAnnotations(context.annotation());
|
|
|
|
if (context.identifier() != null)
|
|
{
|
|
var name = context.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(context.typeArguments());
|
|
var scope = context.classOrInterfaceType() != null
|
|
? BuildClassOrInterfaceType(context.classOrInterfaceType())
|
|
: null;
|
|
|
|
return new ClassOrInterfaceType(location, name, scope, typeArgs, annotations);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildClassType_lfno(Java9Parser.ClassType_lfno_classOrInterfaceTypeContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var name = context.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(context.typeArguments());
|
|
var annotations = BuildAnnotations(context.annotation());
|
|
|
|
return new ClassOrInterfaceType(location, name, null, typeArgs, annotations);
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildInterfaceType(Java9Parser.InterfaceTypeContext context)
|
|
{
|
|
return BuildClassType(context.classType());
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildInterfaceType_lfno(Java9Parser.InterfaceType_lfno_classOrInterfaceTypeContext context)
|
|
{
|
|
return BuildClassType_lfno(context.classType_lfno_classOrInterfaceType());
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildTypeName(Java9Parser.TypeNameContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
// TypeName has a recursive structure, just use GetText()
|
|
return new ClassOrInterfaceType(
|
|
location,
|
|
context.GetText(),
|
|
null,
|
|
new List<TypeArgument>(),
|
|
new List<Annotation>()
|
|
);
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildTypeVariable(Java9Parser.TypeVariableContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var name = context.identifier().GetText();
|
|
var annotations = BuildAnnotations(context.annotation());
|
|
|
|
return new ClassOrInterfaceType(location, name, null, new List<TypeArgument>(), annotations);
|
|
}
|
|
|
|
private ArrayType? BuildArrayType(Java9Parser.ArrayTypeContext context)
|
|
{
|
|
TypeReference? elementType = null;
|
|
int dimensions = 0;
|
|
|
|
if (context.primitiveType() != null)
|
|
{
|
|
elementType = BuildPrimitiveType(context.primitiveType());
|
|
dimensions = context.dims().GetText().Length / 2; // Each dimension is "[]"
|
|
}
|
|
else if (context.classOrInterfaceType() != null)
|
|
{
|
|
elementType = BuildClassOrInterfaceType(context.classOrInterfaceType());
|
|
dimensions = context.dims().GetText().Length / 2;
|
|
}
|
|
else if (context.typeVariable() != null)
|
|
{
|
|
elementType = BuildTypeVariable(context.typeVariable());
|
|
dimensions = context.dims().GetText().Length / 2;
|
|
}
|
|
|
|
return elementType != null
|
|
? new ArrayType(GetSourceRange(context), elementType, dimensions)
|
|
: null;
|
|
}
|
|
|
|
private List<TypeArgument> BuildTypeArguments(Java9Parser.TypeArgumentsContext? context)
|
|
{
|
|
if (context?.typeArgumentList() == null) return new List<TypeArgument>();
|
|
|
|
return context.typeArgumentList().typeArgument()
|
|
.Select(ta => BuildTypeArgument(ta))
|
|
.Where(ta => ta != null)
|
|
.Cast<TypeArgument>()
|
|
.ToList();
|
|
}
|
|
|
|
private TypeArgument? BuildTypeArgument(Java9Parser.TypeArgumentContext context)
|
|
{
|
|
if (context.referenceType() != null)
|
|
{
|
|
var type = BuildTypeReference(context.referenceType());
|
|
return type != null
|
|
? new TypeArgumentType(GetSourceRange(context), type)
|
|
: null;
|
|
}
|
|
else if (context.wildcard() != null)
|
|
{
|
|
return BuildWildcard(context.wildcard());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private WildcardType? BuildWildcard(Java9Parser.WildcardContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
TypeReference? bound = null;
|
|
var boundKind = WildcardBoundKind.None;
|
|
|
|
if (context.wildcardBounds() != null)
|
|
{
|
|
var boundsContext = context.wildcardBounds();
|
|
if (boundsContext.referenceType() != null)
|
|
{
|
|
bound = BuildTypeReference(boundsContext.referenceType());
|
|
boundKind = boundsContext.GetChild(0).GetText() == "extends"
|
|
? WildcardBoundKind.Extends
|
|
: WildcardBoundKind.Super;
|
|
}
|
|
}
|
|
|
|
return new WildcardType(location, bound, boundKind);
|
|
}
|
|
|
|
private List<TypeReference> BuildInterfaces(Java9Parser.SuperinterfacesContext? context)
|
|
{
|
|
if (context?.interfaceTypeList() == null) return new List<TypeReference>();
|
|
|
|
return context.interfaceTypeList().interfaceType()
|
|
.Select(i => BuildTypeReference(i))
|
|
.Where(i => i != null)
|
|
.Cast<TypeReference>()
|
|
.ToList();
|
|
}
|
|
|
|
private List<TypeReference> BuildExtendedInterfaces(Java9Parser.ExtendsInterfacesContext? context)
|
|
{
|
|
if (context?.interfaceTypeList() == null) return new List<TypeReference>();
|
|
|
|
return context.interfaceTypeList().interfaceType()
|
|
.Select(i => BuildTypeReference(i))
|
|
.Where(i => i != null)
|
|
.Cast<TypeReference>()
|
|
.ToList();
|
|
}
|
|
|
|
private List<MemberDeclaration> BuildClassMembers(Java9Parser.ClassBodyContext context)
|
|
{
|
|
var members = new List<MemberDeclaration>();
|
|
|
|
foreach (var declaration in context.classBodyDeclaration())
|
|
{
|
|
if (declaration.classMemberDeclaration() != null)
|
|
{
|
|
var member = BuildClassMember(declaration.classMemberDeclaration());
|
|
if (member != null) members.Add(member);
|
|
}
|
|
else if (declaration.instanceInitializer() != null)
|
|
{
|
|
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
|
if (initializer != null) members.Add(initializer);
|
|
}
|
|
else if (declaration.staticInitializer() != null)
|
|
{
|
|
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
|
if (initializer != null) members.Add(initializer);
|
|
}
|
|
else if (declaration.constructorDeclaration() != null)
|
|
{
|
|
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
|
if (constructor != null) members.Add(constructor);
|
|
}
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
private ClassBodyResult BuildClassBody(Java9Parser.ClassBodyContext context)
|
|
{
|
|
var result = new ClassBodyResult();
|
|
|
|
foreach (var declaration in context.classBodyDeclaration())
|
|
{
|
|
if (declaration.classMemberDeclaration() != null)
|
|
{
|
|
var classMemberContext = declaration.classMemberDeclaration();
|
|
|
|
// Check if it's a nested type declaration
|
|
if (classMemberContext.classDeclaration() != null)
|
|
{
|
|
var nestedType = Visit(classMemberContext.classDeclaration()) as TypeDeclaration;
|
|
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
|
}
|
|
else if (classMemberContext.interfaceDeclaration() != null)
|
|
{
|
|
var nestedType = Visit(classMemberContext.interfaceDeclaration()) as TypeDeclaration;
|
|
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
|
}
|
|
else
|
|
{
|
|
// It's a regular member (field or method)
|
|
var member = BuildClassMember(classMemberContext);
|
|
if (member != null) result.Members.Add(member);
|
|
}
|
|
}
|
|
else if (declaration.instanceInitializer() != null)
|
|
{
|
|
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
|
if (initializer != null) result.Members.Add(initializer);
|
|
}
|
|
else if (declaration.staticInitializer() != null)
|
|
{
|
|
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
|
if (initializer != null) result.Members.Add(initializer);
|
|
}
|
|
else if (declaration.constructorDeclaration() != null)
|
|
{
|
|
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
|
if (constructor != null) result.Members.Add(constructor);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private MemberDeclaration? BuildClassMember(Java9Parser.ClassMemberDeclarationContext context)
|
|
{
|
|
if (context.fieldDeclaration() != null)
|
|
{
|
|
return BuildFieldDeclaration(context.fieldDeclaration());
|
|
}
|
|
else if (context.methodDeclaration() != null)
|
|
{
|
|
return BuildMethodDeclaration(context.methodDeclaration());
|
|
}
|
|
// Nested types are now handled in BuildClassBody
|
|
|
|
return null;
|
|
}
|
|
|
|
private FieldDeclaration? BuildFieldDeclaration(Java9Parser.FieldDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.fieldModifier());
|
|
var annotations = BuildAnnotations(context.fieldModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var variables = context.variableDeclaratorList().variableDeclarator()
|
|
.Select(v => BuildVariableDeclarator(v))
|
|
.Where(v => v != null)
|
|
.Cast<VariableDeclarator>()
|
|
.ToList();
|
|
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new FieldDeclaration(location, modifiers, annotations, type, variables, javaDoc);
|
|
}
|
|
|
|
private VariableDeclarator? BuildVariableDeclarator(Java9Parser.VariableDeclaratorContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var id = context.variableDeclaratorId();
|
|
var name = id.identifier().GetText();
|
|
var dimensions = id.dims()?.GetText().Length / 2 ?? 0;
|
|
|
|
Expression? initializer = null;
|
|
if (context.variableInitializer() != null)
|
|
{
|
|
initializer = BuildExpression(context.variableInitializer());
|
|
}
|
|
|
|
return new VariableDeclarator(location, name, dimensions, initializer);
|
|
}
|
|
|
|
private MethodDeclaration? BuildMethodDeclaration(Java9Parser.MethodDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.methodModifier());
|
|
var annotations = BuildAnnotations(context.methodModifier());
|
|
var header = context.methodHeader();
|
|
|
|
var typeParameters = BuildTypeParameters(header.typeParameters());
|
|
var returnType = BuildTypeReference(header.result());
|
|
var declarator = header.methodDeclarator();
|
|
var name = declarator.identifier().GetText();
|
|
var parameters = BuildParameters(declarator.formalParameterList());
|
|
var throws_ = BuildThrows(header.throws_());
|
|
var body = context.methodBody().block() != null
|
|
? BuildBlock(context.methodBody().block())
|
|
: null;
|
|
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new MethodDeclaration(
|
|
location, name, modifiers, annotations, returnType,
|
|
typeParameters, parameters, throws_, body, javaDoc
|
|
);
|
|
}
|
|
|
|
private TypeReference? BuildTypeReference(Java9Parser.ResultContext? context)
|
|
{
|
|
if (context == null) return null;
|
|
|
|
if (context.unannType() != null)
|
|
{
|
|
return BuildTypeReference(context.unannType());
|
|
}
|
|
else if (context.GetText() == "void")
|
|
{
|
|
return new PrimitiveType(GetSourceRange(context), PrimitiveTypeKind.Void);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private TypeReference? BuildTypeReference(Java9Parser.UnannTypeContext? context)
|
|
{
|
|
if (context == null) return null;
|
|
|
|
if (context.unannPrimitiveType() != null)
|
|
{
|
|
return BuildPrimitiveType(context.unannPrimitiveType());
|
|
}
|
|
else if (context.unannReferenceType() != null)
|
|
{
|
|
return BuildTypeReference(context.unannReferenceType());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private PrimitiveType? BuildPrimitiveType(Java9Parser.UnannPrimitiveTypeContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var text = context.GetText();
|
|
|
|
var kind = text switch
|
|
{
|
|
"boolean" => PrimitiveTypeKind.Boolean,
|
|
"byte" => PrimitiveTypeKind.Byte,
|
|
"short" => PrimitiveTypeKind.Short,
|
|
"int" => PrimitiveTypeKind.Int,
|
|
"long" => PrimitiveTypeKind.Long,
|
|
"char" => PrimitiveTypeKind.Char,
|
|
"float" => PrimitiveTypeKind.Float,
|
|
"double" => PrimitiveTypeKind.Double,
|
|
_ => (PrimitiveTypeKind?)null
|
|
};
|
|
|
|
return kind.HasValue ? new PrimitiveType(location, kind.Value) : null;
|
|
}
|
|
|
|
private TypeReference? BuildTypeReference(Java9Parser.UnannReferenceTypeContext? context)
|
|
{
|
|
if (context == null) return null;
|
|
|
|
if (context.unannClassOrInterfaceType() != null)
|
|
{
|
|
return BuildClassOrInterfaceType(context.unannClassOrInterfaceType());
|
|
}
|
|
else if (context.unannTypeVariable() != null)
|
|
{
|
|
return BuildTypeVariable(context.unannTypeVariable());
|
|
}
|
|
else if (context.unannArrayType() != null)
|
|
{
|
|
return BuildArrayType(context.unannArrayType());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildClassOrInterfaceType(Java9Parser.UnannClassOrInterfaceTypeContext context)
|
|
{
|
|
ClassOrInterfaceType? current = null;
|
|
|
|
if (context.unannClassType_lfno_unannClassOrInterfaceType() != null)
|
|
{
|
|
var first = context.unannClassType_lfno_unannClassOrInterfaceType();
|
|
var name = first.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(first.typeArguments());
|
|
var location = GetSourceRange(first);
|
|
|
|
current = new ClassOrInterfaceType(location, name, null, typeArgs, new List<Annotation>());
|
|
}
|
|
|
|
foreach (var additional in context.unannClassType_lf_unannClassOrInterfaceType())
|
|
{
|
|
var name = additional.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(additional.typeArguments());
|
|
var location = GetSourceRange(additional);
|
|
|
|
current = new ClassOrInterfaceType(location, name, current, typeArgs, new List<Annotation>());
|
|
}
|
|
|
|
return current;
|
|
}
|
|
|
|
private ClassOrInterfaceType? BuildTypeVariable(Java9Parser.UnannTypeVariableContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var name = context.identifier().GetText();
|
|
|
|
return new ClassOrInterfaceType(location, name, null, new List<TypeArgument>(), new List<Annotation>());
|
|
}
|
|
|
|
private ArrayType? BuildArrayType(Java9Parser.UnannArrayTypeContext context)
|
|
{
|
|
TypeReference? elementType = null;
|
|
int dimensions = 0;
|
|
|
|
if (context.unannPrimitiveType() != null)
|
|
{
|
|
elementType = BuildPrimitiveType(context.unannPrimitiveType());
|
|
dimensions = context.dims().GetText().Length / 2;
|
|
}
|
|
else if (context.unannClassOrInterfaceType() != null)
|
|
{
|
|
elementType = BuildClassOrInterfaceType(context.unannClassOrInterfaceType());
|
|
dimensions = context.dims().GetText().Length / 2;
|
|
}
|
|
else if (context.unannTypeVariable() != null)
|
|
{
|
|
elementType = BuildTypeVariable(context.unannTypeVariable());
|
|
dimensions = context.dims().GetText().Length / 2;
|
|
}
|
|
|
|
return elementType != null
|
|
? new ArrayType(GetSourceRange(context), elementType, dimensions)
|
|
: null;
|
|
}
|
|
|
|
private List<Parameter> BuildParameters(Java9Parser.FormalParameterListContext? context)
|
|
{
|
|
if (context == null) return new List<Parameter>();
|
|
|
|
var parameters = new List<Parameter>();
|
|
|
|
if (context.formalParameters() != null)
|
|
{
|
|
foreach (var param in context.formalParameters().formalParameter())
|
|
{
|
|
var parameter = BuildParameter(param);
|
|
if (parameter != null) parameters.Add(parameter);
|
|
}
|
|
|
|
if (context.formalParameters().receiverParameter() != null)
|
|
{
|
|
// Skip receiver parameter for now
|
|
}
|
|
}
|
|
|
|
if (context.lastFormalParameter() != null)
|
|
{
|
|
var parameter = BuildLastParameter(context.lastFormalParameter());
|
|
if (parameter != null) parameters.Add(parameter);
|
|
}
|
|
|
|
return parameters;
|
|
}
|
|
|
|
private Parameter? BuildParameter(Java9Parser.FormalParameterContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.variableModifier());
|
|
var annotations = BuildAnnotations(context.variableModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var declaratorId = context.variableDeclaratorId();
|
|
var name = declaratorId.identifier().GetText();
|
|
var isFinal = modifiers.HasFlag(Modifiers.Final);
|
|
|
|
// Handle array dimensions on parameter name
|
|
if (declaratorId.dims() != null)
|
|
{
|
|
var dimensions = declaratorId.dims().GetText().Length / 2;
|
|
type = new ArrayType(location, type, dimensions);
|
|
}
|
|
|
|
return new Parameter(location, type, name, false, isFinal, annotations);
|
|
}
|
|
|
|
private Parameter? BuildLastParameter(Java9Parser.LastFormalParameterContext context)
|
|
{
|
|
// Check if this is just a regular parameter (not varargs)
|
|
if (context.formalParameter() != null)
|
|
{
|
|
return BuildParameter(context.formalParameter());
|
|
}
|
|
|
|
// Otherwise, it's a varargs parameter
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.variableModifier());
|
|
var annotations = BuildAnnotations(context.variableModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var declaratorId = context.variableDeclaratorId();
|
|
var name = declaratorId.identifier().GetText();
|
|
var isFinal = modifiers.HasFlag(Modifiers.Final);
|
|
var isVarArgs = true; // This branch is only for varargs
|
|
|
|
return new Parameter(location, type, name, isVarArgs, isFinal, annotations);
|
|
}
|
|
|
|
private List<TypeReference> BuildThrows(Java9Parser.Throws_Context? context)
|
|
{
|
|
if (context?.exceptionTypeList() == null) return new List<TypeReference>();
|
|
|
|
return context.exceptionTypeList().exceptionType()
|
|
.Select(e => BuildTypeReference(e))
|
|
.Where(e => e != null)
|
|
.Cast<TypeReference>()
|
|
.ToList();
|
|
}
|
|
|
|
private TypeReference? BuildTypeReference(Java9Parser.ExceptionTypeContext context)
|
|
{
|
|
if (context.classType() != null)
|
|
{
|
|
return BuildClassType(context.classType());
|
|
}
|
|
else if (context.typeVariable() != null)
|
|
{
|
|
return BuildTypeVariable(context.typeVariable());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private MethodDeclaration? BuildConstructor(Java9Parser.ConstructorDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.constructorModifier());
|
|
var annotations = BuildAnnotations(context.constructorModifier());
|
|
var declarator = context.constructorDeclarator();
|
|
var typeParameters = BuildTypeParameters(declarator.typeParameters());
|
|
var name = declarator.simpleTypeName().identifier().GetText();
|
|
var parameters = BuildParameters(declarator.formalParameterList());
|
|
var throws_ = BuildThrows(context.throws_());
|
|
var body = context.constructorBody().blockStatements() != null
|
|
? BuildBlockFromStatements(context.constructorBody().blockStatements())
|
|
: new BlockStatement(GetSourceRange(context.constructorBody()), new List<Statement>());
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new MethodDeclaration(
|
|
location, name, modifiers, annotations, null,
|
|
typeParameters, parameters, throws_, body, javaDoc, true
|
|
);
|
|
}
|
|
|
|
private InitializerBlock? BuildInstanceInitializer(Java9Parser.InstanceInitializerContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var body = BuildBlock(context.block());
|
|
return body != null ? new InitializerBlock(location, body, false) : null;
|
|
}
|
|
|
|
private InitializerBlock? BuildStaticInitializer(Java9Parser.StaticInitializerContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var body = BuildBlock(context.block());
|
|
return body != null ? new InitializerBlock(location, body, true) : null;
|
|
}
|
|
|
|
private List<MemberDeclaration> BuildInterfaceMembers(Java9Parser.InterfaceBodyContext context)
|
|
{
|
|
var members = new List<MemberDeclaration>();
|
|
|
|
foreach (var declaration in context.interfaceMemberDeclaration())
|
|
{
|
|
if (declaration.constantDeclaration() != null)
|
|
{
|
|
var constant = BuildConstantDeclaration(declaration.constantDeclaration());
|
|
if (constant != null) members.Add(constant);
|
|
}
|
|
else if (declaration.interfaceMethodDeclaration() != null)
|
|
{
|
|
var method = BuildInterfaceMethodDeclaration(declaration.interfaceMethodDeclaration());
|
|
if (method != null) members.Add(method);
|
|
}
|
|
else if (declaration.classDeclaration() != null)
|
|
{
|
|
var classDecl = Visit(declaration.classDeclaration()) as MemberDeclaration;
|
|
if (classDecl != null) members.Add(classDecl);
|
|
}
|
|
else if (declaration.interfaceDeclaration() != null)
|
|
{
|
|
var interfaceDecl = Visit(declaration.interfaceDeclaration()) as MemberDeclaration;
|
|
if (interfaceDecl != null) members.Add(interfaceDecl);
|
|
}
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
private ClassBodyResult BuildInterfaceBody(Java9Parser.InterfaceBodyContext context)
|
|
{
|
|
var result = new ClassBodyResult();
|
|
|
|
foreach (var declaration in context.interfaceMemberDeclaration())
|
|
{
|
|
if (declaration.constantDeclaration() != null)
|
|
{
|
|
var constant = BuildConstantDeclaration(declaration.constantDeclaration());
|
|
if (constant != null) result.Members.Add(constant);
|
|
}
|
|
else if (declaration.interfaceMethodDeclaration() != null)
|
|
{
|
|
var method = BuildInterfaceMethodDeclaration(declaration.interfaceMethodDeclaration());
|
|
if (method != null) result.Members.Add(method);
|
|
}
|
|
else if (declaration.classDeclaration() != null)
|
|
{
|
|
var nestedType = Visit(declaration.classDeclaration()) as TypeDeclaration;
|
|
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
|
}
|
|
else if (declaration.interfaceDeclaration() != null)
|
|
{
|
|
var nestedType = Visit(declaration.interfaceDeclaration()) as TypeDeclaration;
|
|
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private FieldDeclaration? BuildConstantDeclaration(Java9Parser.ConstantDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.constantModifier()) | Modifiers.Public | Modifiers.Static | Modifiers.Final;
|
|
var annotations = BuildAnnotations(context.constantModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var variables = context.variableDeclaratorList().variableDeclarator()
|
|
.Select(v => BuildVariableDeclarator(v))
|
|
.Where(v => v != null)
|
|
.Cast<VariableDeclarator>()
|
|
.ToList();
|
|
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new FieldDeclaration(location, modifiers, annotations, type, variables, javaDoc);
|
|
}
|
|
|
|
private MethodDeclaration? BuildInterfaceMethodDeclaration(Java9Parser.InterfaceMethodDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.interfaceMethodModifier());
|
|
var annotations = BuildAnnotations(context.interfaceMethodModifier());
|
|
var header = context.methodHeader();
|
|
|
|
var typeParameters = BuildTypeParameters(header.typeParameters());
|
|
var returnType = BuildTypeReference(header.result());
|
|
var declarator = header.methodDeclarator();
|
|
var name = declarator.identifier().GetText();
|
|
var parameters = BuildParameters(declarator.formalParameterList());
|
|
var throws_ = BuildThrows(header.throws_());
|
|
var body = context.methodBody().block() != null
|
|
? BuildBlock(context.methodBody().block())
|
|
: null;
|
|
|
|
var javaDoc = ExtractJavaDoc(context);
|
|
|
|
return new MethodDeclaration(
|
|
location, name, modifiers, annotations, returnType,
|
|
typeParameters, parameters, throws_, body, javaDoc
|
|
);
|
|
}
|
|
|
|
private List<EnumConstant> BuildEnumConstants(Java9Parser.EnumConstantListContext? context)
|
|
{
|
|
if (context == null) return new List<EnumConstant>();
|
|
|
|
return context.enumConstant()
|
|
.Select(ec => BuildEnumConstant(ec))
|
|
.Where(ec => ec != null)
|
|
.Cast<EnumConstant>()
|
|
.ToList();
|
|
}
|
|
|
|
private EnumConstant? BuildEnumConstant(Java9Parser.EnumConstantContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var name = context.identifier().GetText();
|
|
var annotations = BuildAnnotations(context.enumConstantModifier());
|
|
var arguments = new List<Expression>();
|
|
|
|
if (context.argumentList() != null)
|
|
{
|
|
arguments = context.argumentList().expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList();
|
|
}
|
|
|
|
ClassDeclaration? body = null;
|
|
if (context.classBody() != null)
|
|
{
|
|
// Build anonymous class body
|
|
var members = BuildClassMembers(context.classBody());
|
|
body = new ClassDeclaration(
|
|
GetSourceRange(context.classBody()),
|
|
"", // Anonymous
|
|
Modifiers.None,
|
|
new List<Annotation>(),
|
|
new List<TypeParameter>(),
|
|
null,
|
|
new List<TypeReference>(),
|
|
members,
|
|
new List<TypeDeclaration>(),
|
|
null,
|
|
false
|
|
);
|
|
}
|
|
|
|
return new EnumConstant(location, name, annotations, arguments, body);
|
|
}
|
|
|
|
private List<MemberDeclaration> BuildEnumMembers(Java9Parser.EnumBodyDeclarationsContext? context)
|
|
{
|
|
if (context == null) return new List<MemberDeclaration>();
|
|
|
|
return BuildClassMembers(context);
|
|
}
|
|
|
|
private List<MemberDeclaration> BuildClassMembers(Java9Parser.EnumBodyDeclarationsContext context)
|
|
{
|
|
var members = new List<MemberDeclaration>();
|
|
|
|
foreach (var declaration in context.classBodyDeclaration())
|
|
{
|
|
if (declaration.classMemberDeclaration() != null)
|
|
{
|
|
var member = BuildClassMember(declaration.classMemberDeclaration());
|
|
if (member != null) members.Add(member);
|
|
}
|
|
else if (declaration.instanceInitializer() != null)
|
|
{
|
|
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
|
if (initializer != null) members.Add(initializer);
|
|
}
|
|
else if (declaration.staticInitializer() != null)
|
|
{
|
|
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
|
if (initializer != null) members.Add(initializer);
|
|
}
|
|
else if (declaration.constructorDeclaration() != null)
|
|
{
|
|
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
|
if (constructor != null) members.Add(constructor);
|
|
}
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
private ClassBodyResult? BuildEnumBody(Java9Parser.EnumBodyDeclarationsContext? context)
|
|
{
|
|
if (context == null) return null;
|
|
|
|
var result = new ClassBodyResult();
|
|
|
|
foreach (var declaration in context.classBodyDeclaration())
|
|
{
|
|
if (declaration.classMemberDeclaration() != null)
|
|
{
|
|
var classMemberContext = declaration.classMemberDeclaration();
|
|
|
|
// Check if it's a nested type declaration
|
|
if (classMemberContext.classDeclaration() != null)
|
|
{
|
|
var nestedType = Visit(classMemberContext.classDeclaration()) as TypeDeclaration;
|
|
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
|
}
|
|
else if (classMemberContext.interfaceDeclaration() != null)
|
|
{
|
|
var nestedType = Visit(classMemberContext.interfaceDeclaration()) as TypeDeclaration;
|
|
if (nestedType != null) result.NestedTypes.Add(nestedType);
|
|
}
|
|
else
|
|
{
|
|
// It's a regular member (field or method)
|
|
var member = BuildClassMember(classMemberContext);
|
|
if (member != null) result.Members.Add(member);
|
|
}
|
|
}
|
|
else if (declaration.instanceInitializer() != null)
|
|
{
|
|
var initializer = BuildInstanceInitializer(declaration.instanceInitializer());
|
|
if (initializer != null) result.Members.Add(initializer);
|
|
}
|
|
else if (declaration.staticInitializer() != null)
|
|
{
|
|
var initializer = BuildStaticInitializer(declaration.staticInitializer());
|
|
if (initializer != null) result.Members.Add(initializer);
|
|
}
|
|
else if (declaration.constructorDeclaration() != null)
|
|
{
|
|
var constructor = BuildConstructor(declaration.constructorDeclaration());
|
|
if (constructor != null) result.Members.Add(constructor);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private List<AnnotationMember> BuildAnnotationMembers(Java9Parser.AnnotationTypeBodyContext context)
|
|
{
|
|
var members = new List<AnnotationMember>();
|
|
|
|
foreach (var declaration in context.annotationTypeMemberDeclaration())
|
|
{
|
|
if (declaration.annotationTypeElementDeclaration() != null)
|
|
{
|
|
var member = BuildAnnotationElement(declaration.annotationTypeElementDeclaration());
|
|
if (member != null) members.Add(member);
|
|
}
|
|
}
|
|
|
|
return members;
|
|
}
|
|
|
|
private AnnotationMember? BuildAnnotationElement(Java9Parser.AnnotationTypeElementDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var name = context.identifier().GetText();
|
|
Expression? defaultValue = null;
|
|
|
|
if (context.defaultValue() != null)
|
|
{
|
|
defaultValue = BuildElementValue(context.defaultValue().elementValue());
|
|
}
|
|
|
|
return new AnnotationMember(location, name, type, defaultValue);
|
|
}
|
|
|
|
// Expression building methods
|
|
|
|
private Expression? BuildExpression(IParseTree? context)
|
|
{
|
|
if (context == null) return null;
|
|
|
|
return context switch
|
|
{
|
|
Java9Parser.ExpressionContext expr => BuildExpression(expr),
|
|
Java9Parser.LiteralContext literal => BuildLiteral(literal),
|
|
Java9Parser.PrimaryContext primary => BuildPrimary(primary),
|
|
Java9Parser.ElementValueContext elementValue => BuildElementValue(elementValue),
|
|
Java9Parser.VariableInitializerContext varInit => BuildVariableInitializer(varInit),
|
|
Java9Parser.ArrayInitializerContext arrayInit => BuildArrayInitializer(arrayInit),
|
|
_ => null
|
|
};
|
|
}
|
|
|
|
private Expression? BuildExpression(Java9Parser.ExpressionContext context)
|
|
{
|
|
if (context.lambdaExpression() != null)
|
|
{
|
|
return BuildLambdaExpression(context.lambdaExpression());
|
|
}
|
|
else if (context.assignmentExpression() != null)
|
|
{
|
|
return BuildAssignmentExpression(context.assignmentExpression());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildAssignmentExpression(Java9Parser.AssignmentExpressionContext context)
|
|
{
|
|
if (context.conditionalExpression() != null)
|
|
{
|
|
return BuildConditionalExpression(context.conditionalExpression());
|
|
}
|
|
else if (context.assignment() != null)
|
|
{
|
|
return BuildAssignment(context.assignment());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildAssignment(Java9Parser.AssignmentContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var left = BuildExpression(context.leftHandSide());
|
|
var right = BuildExpression(context.expression());
|
|
|
|
if (left == null || right == null) return null;
|
|
|
|
var operatorText = context.assignmentOperator().GetText();
|
|
var @operator = operatorText switch
|
|
{
|
|
"=" => BinaryOperator.Assign,
|
|
"+=" => BinaryOperator.AddAssign,
|
|
"-=" => BinaryOperator.SubtractAssign,
|
|
"*=" => BinaryOperator.MultiplyAssign,
|
|
"/=" => BinaryOperator.DivideAssign,
|
|
"%=" => BinaryOperator.ModuloAssign,
|
|
"&=" => BinaryOperator.BitwiseAndAssign,
|
|
"|=" => BinaryOperator.BitwiseOrAssign,
|
|
"^=" => BinaryOperator.BitwiseXorAssign,
|
|
"<<=" => BinaryOperator.LeftShiftAssign,
|
|
">>=" => BinaryOperator.RightShiftAssign,
|
|
">>>=" => BinaryOperator.UnsignedRightShiftAssign,
|
|
_ => BinaryOperator.Assign
|
|
};
|
|
|
|
return new BinaryExpression(location, left, @operator, right);
|
|
}
|
|
|
|
private Expression? BuildExpression(Java9Parser.LeftHandSideContext context)
|
|
{
|
|
if (context.expressionName() != null)
|
|
{
|
|
return BuildExpressionName(context.expressionName());
|
|
}
|
|
else if (context.fieldAccess() != null)
|
|
{
|
|
return BuildFieldAccess(context.fieldAccess());
|
|
}
|
|
else if (context.arrayAccess() != null)
|
|
{
|
|
return BuildArrayAccess(context.arrayAccess());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildConditionalExpression(Java9Parser.ConditionalExpressionContext context)
|
|
{
|
|
if (context.conditionalOrExpression() != null &&
|
|
context.expression() == null)
|
|
{
|
|
return BuildConditionalOrExpression(context.conditionalOrExpression());
|
|
}
|
|
else if (context.conditionalOrExpression() != null &&
|
|
context.expression() != null &&
|
|
context.conditionalExpression() != null)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var condition = BuildConditionalOrExpression(context.conditionalOrExpression());
|
|
var thenExpr = BuildExpression(context.expression());
|
|
var elseExpr = BuildConditionalExpression(context.conditionalExpression());
|
|
|
|
if (condition != null && thenExpr != null && elseExpr != null)
|
|
{
|
|
return new ConditionalExpression(location, condition, thenExpr, elseExpr);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildConditionalOrExpression(Java9Parser.ConditionalOrExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar
|
|
if (context.conditionalAndExpression() != null && context.conditionalOrExpression() == null)
|
|
{
|
|
// Simple case - just one conditional AND expression
|
|
return BuildConditionalAndExpression(context.conditionalAndExpression());
|
|
}
|
|
else if (context.conditionalOrExpression() != null && context.conditionalAndExpression() != null)
|
|
{
|
|
// Binary OR expression
|
|
var left = BuildConditionalOrExpression(context.conditionalOrExpression());
|
|
var right = BuildConditionalAndExpression(context.conditionalAndExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, BinaryOperator.LogicalOr, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildConditionalAndExpression(Java9Parser.ConditionalAndExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar
|
|
if (context.inclusiveOrExpression() != null && context.conditionalAndExpression() == null)
|
|
{
|
|
// Simple case - just one inclusive OR expression
|
|
return BuildInclusiveOrExpression(context.inclusiveOrExpression());
|
|
}
|
|
else if (context.conditionalAndExpression() != null && context.inclusiveOrExpression() != null)
|
|
{
|
|
// Binary AND expression
|
|
var left = BuildConditionalAndExpression(context.conditionalAndExpression());
|
|
var right = BuildInclusiveOrExpression(context.inclusiveOrExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, BinaryOperator.LogicalAnd, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildInclusiveOrExpression(Java9Parser.InclusiveOrExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar
|
|
if (context.exclusiveOrExpression() != null && context.inclusiveOrExpression() == null)
|
|
{
|
|
// Simple case - just one exclusive OR expression
|
|
return BuildExclusiveOrExpression(context.exclusiveOrExpression());
|
|
}
|
|
else if (context.inclusiveOrExpression() != null && context.exclusiveOrExpression() != null)
|
|
{
|
|
// Binary OR expression
|
|
var left = BuildInclusiveOrExpression(context.inclusiveOrExpression());
|
|
var right = BuildExclusiveOrExpression(context.exclusiveOrExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, BinaryOperator.BitwiseOr, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildExclusiveOrExpression(Java9Parser.ExclusiveOrExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar
|
|
if (context.andExpression() != null && context.exclusiveOrExpression() == null)
|
|
{
|
|
// Simple case - just one AND expression
|
|
return BuildAndExpression(context.andExpression());
|
|
}
|
|
else if (context.exclusiveOrExpression() != null && context.andExpression() != null)
|
|
{
|
|
// Binary XOR expression
|
|
var left = BuildExclusiveOrExpression(context.exclusiveOrExpression());
|
|
var right = BuildAndExpression(context.andExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, BinaryOperator.BitwiseXor, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildAndExpression(Java9Parser.AndExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar
|
|
if (context.equalityExpression() != null && context.andExpression() == null)
|
|
{
|
|
// Simple case - just one equality expression
|
|
return BuildEqualityExpression(context.equalityExpression());
|
|
}
|
|
else if (context.andExpression() != null && context.equalityExpression() != null)
|
|
{
|
|
// Binary AND expression
|
|
var left = BuildAndExpression(context.andExpression());
|
|
var right = BuildEqualityExpression(context.equalityExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, BinaryOperator.BitwiseAnd, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildEqualityExpression(Java9Parser.EqualityExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar
|
|
if (context.relationalExpression() != null && context.equalityExpression() == null)
|
|
{
|
|
// Simple case - just one relational expression
|
|
return BuildRelationalExpression(context.relationalExpression());
|
|
}
|
|
else if (context.equalityExpression() != null && context.relationalExpression() != null)
|
|
{
|
|
// Binary equality expression
|
|
var left = BuildEqualityExpression(context.equalityExpression());
|
|
var right = BuildRelationalExpression(context.relationalExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
var @operator = context.EQUAL() != null ? BinaryOperator.Equals : BinaryOperator.NotEquals;
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, @operator, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildRelationalExpression(Java9Parser.RelationalExpressionContext context)
|
|
{
|
|
// Handle instanceof expression
|
|
if (context.referenceType() != null && context.shiftExpression() != null)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var expr = BuildShiftExpression(context.shiftExpression());
|
|
var type = BuildTypeReference(context.referenceType());
|
|
if (expr != null && type != null)
|
|
{
|
|
return new InstanceOfExpression(location, expr, type);
|
|
}
|
|
}
|
|
// Handle left-recursive grammar for relational expressions
|
|
else if (context.shiftExpression() != null && context.relationalExpression() == null)
|
|
{
|
|
// Simple case - just one shift expression
|
|
return BuildShiftExpression(context.shiftExpression());
|
|
}
|
|
else if (context.relationalExpression() != null && context.shiftExpression() != null)
|
|
{
|
|
// Binary relational expression
|
|
var left = BuildRelationalExpression(context.relationalExpression());
|
|
var right = BuildShiftExpression(context.shiftExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
BinaryOperator @operator;
|
|
if (context.LT() != null) @operator = BinaryOperator.LessThan;
|
|
else if (context.GT() != null) @operator = BinaryOperator.GreaterThan;
|
|
else if (context.LE() != null) @operator = BinaryOperator.LessThanOrEqual;
|
|
else if (context.GE() != null) @operator = BinaryOperator.GreaterThanOrEqual;
|
|
else @operator = BinaryOperator.LessThan;
|
|
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, @operator, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildShiftExpression(Java9Parser.ShiftExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar for shift expressions
|
|
if (context.additiveExpression() != null && context.shiftExpression() == null)
|
|
{
|
|
// Simple case - just one additive expression
|
|
return BuildAdditiveExpression(context.additiveExpression());
|
|
}
|
|
else if (context.shiftExpression() != null && context.additiveExpression() != null)
|
|
{
|
|
// Binary shift expression
|
|
var left = BuildShiftExpression(context.shiftExpression());
|
|
var right = BuildAdditiveExpression(context.additiveExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
// Check the operator between the operands
|
|
BinaryOperator @operator;
|
|
var operatorText = "";
|
|
var gtCount = 0;
|
|
var ltCount = 0;
|
|
|
|
// Count consecutive < or > operators
|
|
for (int i = 0; i < context.ChildCount; i++)
|
|
{
|
|
var child = context.GetChild(i);
|
|
var text = child.GetText();
|
|
if (text == "<")
|
|
{
|
|
ltCount++;
|
|
if (ltCount == 2)
|
|
{
|
|
operatorText = "<<";
|
|
break;
|
|
}
|
|
}
|
|
else if (text == ">")
|
|
{
|
|
gtCount++;
|
|
if (gtCount == 3)
|
|
{
|
|
operatorText = ">>>";
|
|
break;
|
|
}
|
|
else if (gtCount == 2 && i + 1 < context.ChildCount && context.GetChild(i + 1).GetText() != ">")
|
|
{
|
|
operatorText = ">>";
|
|
break;
|
|
}
|
|
}
|
|
else if (ltCount > 0 || gtCount > 0)
|
|
{
|
|
// Reset if we hit a non-operator
|
|
break;
|
|
}
|
|
}
|
|
|
|
@operator = operatorText switch
|
|
{
|
|
"<<" => BinaryOperator.LeftShift,
|
|
">>" => BinaryOperator.RightShift,
|
|
">>>" => BinaryOperator.UnsignedRightShift,
|
|
_ => BinaryOperator.LeftShift
|
|
};
|
|
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, @operator, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildAdditiveExpression(Java9Parser.AdditiveExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar for additive expressions
|
|
if (context.multiplicativeExpression() != null && context.additiveExpression() == null)
|
|
{
|
|
// Simple case - just one multiplicative expression
|
|
return BuildMultiplicativeExpression(context.multiplicativeExpression());
|
|
}
|
|
else if (context.additiveExpression() != null && context.multiplicativeExpression() != null)
|
|
{
|
|
// Binary additive expression
|
|
var left = BuildAdditiveExpression(context.additiveExpression());
|
|
var right = BuildMultiplicativeExpression(context.multiplicativeExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
// Check the operator between the operands
|
|
var operatorText = "";
|
|
for (int i = 0; i < context.ChildCount; i++)
|
|
{
|
|
var child = context.GetChild(i);
|
|
if (child.GetText() == "+" || child.GetText() == "-")
|
|
{
|
|
operatorText = child.GetText();
|
|
break;
|
|
}
|
|
}
|
|
|
|
var @operator = operatorText == "+" ? BinaryOperator.Add : BinaryOperator.Subtract;
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, @operator, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildMultiplicativeExpression(Java9Parser.MultiplicativeExpressionContext context)
|
|
{
|
|
// Handle left-recursive grammar for multiplicative expressions
|
|
if (context.unaryExpression() != null && context.multiplicativeExpression() == null)
|
|
{
|
|
// Simple case - just one unary expression
|
|
return BuildUnaryExpression(context.unaryExpression());
|
|
}
|
|
else if (context.multiplicativeExpression() != null && context.unaryExpression() != null)
|
|
{
|
|
// Binary multiplicative expression
|
|
var left = BuildMultiplicativeExpression(context.multiplicativeExpression());
|
|
var right = BuildUnaryExpression(context.unaryExpression());
|
|
|
|
if (left != null && right != null)
|
|
{
|
|
BinaryOperator @operator;
|
|
// Check the operator between the operands
|
|
var operatorText = "";
|
|
for (int i = 0; i < context.ChildCount; i++)
|
|
{
|
|
var child = context.GetChild(i);
|
|
if (child.GetText() == "*" || child.GetText() == "/" || child.GetText() == "%")
|
|
{
|
|
operatorText = child.GetText();
|
|
break;
|
|
}
|
|
}
|
|
|
|
@operator = operatorText switch
|
|
{
|
|
"*" => BinaryOperator.Multiply,
|
|
"/" => BinaryOperator.Divide,
|
|
"%" => BinaryOperator.Modulo,
|
|
_ => BinaryOperator.Multiply
|
|
};
|
|
|
|
var location = new SourceRange(left.Location.Start, right.Location.End);
|
|
return new BinaryExpression(location, left, @operator, right);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildUnaryExpression(Java9Parser.UnaryExpressionContext context)
|
|
{
|
|
if (context.preIncrementExpression() != null)
|
|
{
|
|
return BuildPreIncrementExpression(context.preIncrementExpression());
|
|
}
|
|
else if (context.preDecrementExpression() != null)
|
|
{
|
|
return BuildPreDecrementExpression(context.preDecrementExpression());
|
|
}
|
|
else if (context.unaryExpressionNotPlusMinus() != null)
|
|
{
|
|
return BuildUnaryExpressionNotPlusMinus(context.unaryExpressionNotPlusMinus());
|
|
}
|
|
else if (context.GetChild(0).GetText() == "+" && context.unaryExpression() != null)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildUnaryExpression(context.unaryExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.Plus, operand)
|
|
: null;
|
|
}
|
|
else if (context.GetChild(0).GetText() == "-" && context.unaryExpression() != null)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildUnaryExpression(context.unaryExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.Minus, operand)
|
|
: null;
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildPreIncrementExpression(Java9Parser.PreIncrementExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildUnaryExpression(context.unaryExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.PreIncrement, operand)
|
|
: null;
|
|
}
|
|
|
|
private Expression? BuildPreDecrementExpression(Java9Parser.PreDecrementExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildUnaryExpression(context.unaryExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.PreDecrement, operand)
|
|
: null;
|
|
}
|
|
|
|
private Expression? BuildUnaryExpressionNotPlusMinus(Java9Parser.UnaryExpressionNotPlusMinusContext context)
|
|
{
|
|
if (context.postfixExpression() != null)
|
|
{
|
|
return BuildPostfixExpression(context.postfixExpression());
|
|
}
|
|
else if (context.GetChild(0).GetText() == "~" && context.unaryExpression() != null)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildUnaryExpression(context.unaryExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.BitwiseNot, operand)
|
|
: null;
|
|
}
|
|
else if (context.GetChild(0).GetText() == "!" && context.unaryExpression() != null)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildUnaryExpression(context.unaryExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.LogicalNot, operand)
|
|
: null;
|
|
}
|
|
else if (context.castExpression() != null)
|
|
{
|
|
return BuildCastExpression(context.castExpression());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildPostfixExpression(Java9Parser.PostfixExpressionContext context)
|
|
{
|
|
Expression? expr = null;
|
|
|
|
if (context.primary() != null)
|
|
{
|
|
expr = BuildPrimary(context.primary());
|
|
}
|
|
else if (context.expressionName() != null)
|
|
{
|
|
expr = BuildExpressionName(context.expressionName());
|
|
}
|
|
|
|
if (expr == null) return null;
|
|
|
|
// Handle postfix operators
|
|
foreach (var child in context.children.Skip(1))
|
|
{
|
|
if (child.GetText() == "++")
|
|
{
|
|
var location = new SourceRange(expr.Location.Start, GetSourceRange(context).End);
|
|
expr = new UnaryExpression(location, UnaryOperator.PostIncrement, expr, false);
|
|
}
|
|
else if (child.GetText() == "--")
|
|
{
|
|
var location = new SourceRange(expr.Location.Start, GetSourceRange(context).End);
|
|
expr = new UnaryExpression(location, UnaryOperator.PostDecrement, expr, false);
|
|
}
|
|
}
|
|
|
|
return expr;
|
|
}
|
|
|
|
private Expression? BuildCastExpression(Java9Parser.CastExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
|
|
if (context.primitiveType() != null)
|
|
{
|
|
var type = BuildPrimitiveType(context.primitiveType());
|
|
var expr = BuildUnaryExpression(context.unaryExpression());
|
|
|
|
if (type != null && expr != null)
|
|
{
|
|
return new CastExpression(location, type, expr);
|
|
}
|
|
}
|
|
else if (context.referenceType() != null)
|
|
{
|
|
var type = BuildTypeReference(context.referenceType());
|
|
var expr = context.unaryExpressionNotPlusMinus() != null
|
|
? BuildUnaryExpressionNotPlusMinus(context.unaryExpressionNotPlusMinus())
|
|
: BuildLambdaExpression(context.lambdaExpression());
|
|
|
|
if (type != null && expr != null)
|
|
{
|
|
return new CastExpression(location, type, expr);
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildPrimary(Java9Parser.PrimaryContext context)
|
|
{
|
|
if (context.primaryNoNewArray_lfno_primary() != null)
|
|
{
|
|
return BuildPrimaryNoNewArray(context.primaryNoNewArray_lfno_primary());
|
|
}
|
|
else if (context.arrayCreationExpression() != null)
|
|
{
|
|
return BuildArrayCreationExpression(context.arrayCreationExpression());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildPrimaryNoNewArray(Java9Parser.PrimaryNoNewArray_lfno_primaryContext context)
|
|
{
|
|
if (context.literal() != null)
|
|
{
|
|
return BuildLiteral(context.literal());
|
|
}
|
|
else if (context.CLASS() != null)
|
|
{
|
|
// Handle class literal
|
|
var location = GetSourceRange(context);
|
|
TypeReference? type = null;
|
|
|
|
if (context.typeName() != null)
|
|
{
|
|
type = BuildTypeName(context.typeName());
|
|
// Handle array dimensions
|
|
var dimsCount = context.LBRACK()?.Length ?? 0;
|
|
if (dimsCount > 0 && type != null)
|
|
{
|
|
type = new ArrayType(type.Location, type, dimsCount);
|
|
}
|
|
}
|
|
else if (context.unannPrimitiveType() != null)
|
|
{
|
|
var primitiveType = ParsePrimitiveTypeKind(context.unannPrimitiveType().GetText());
|
|
type = new PrimitiveType(GetSourceRange(context.unannPrimitiveType()), primitiveType);
|
|
// Handle array dimensions
|
|
var dimsCount = context.LBRACK()?.Length ?? 0;
|
|
if (dimsCount > 0)
|
|
{
|
|
type = new ArrayType(type.Location, type, dimsCount);
|
|
}
|
|
}
|
|
else if (context.VOID() != null)
|
|
{
|
|
type = new PrimitiveType(GetSourceRange(context), PrimitiveTypeKind.Void);
|
|
}
|
|
|
|
return type != null ? new ClassLiteralExpression(location, type) : null;
|
|
}
|
|
else if (context.GetText() == "this")
|
|
{
|
|
return new ThisExpression(GetSourceRange(context));
|
|
}
|
|
else if (context.typeName() != null && context.GetChild(context.ChildCount - 1).GetText() == "this")
|
|
{
|
|
var qualifier = BuildExpressionName(context.typeName());
|
|
return new ThisExpression(GetSourceRange(context), qualifier);
|
|
}
|
|
else if (context.expression() != null)
|
|
{
|
|
// Parenthesized expression
|
|
return BuildExpression(context.expression());
|
|
}
|
|
else if (context.classInstanceCreationExpression_lfno_primary() != null)
|
|
{
|
|
return BuildClassInstanceCreationExpression(context.classInstanceCreationExpression_lfno_primary());
|
|
}
|
|
else if (context.fieldAccess_lfno_primary() != null)
|
|
{
|
|
return BuildFieldAccess(context.fieldAccess_lfno_primary());
|
|
}
|
|
else if (context.arrayAccess_lfno_primary() != null)
|
|
{
|
|
return BuildArrayAccess(context.arrayAccess_lfno_primary());
|
|
}
|
|
else if (context.methodInvocation_lfno_primary() != null)
|
|
{
|
|
return BuildMethodInvocation(context.methodInvocation_lfno_primary());
|
|
}
|
|
else if (context.methodReference_lfno_primary() != null)
|
|
{
|
|
return BuildMethodReference(context.methodReference_lfno_primary());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildLiteral(Java9Parser.LiteralContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var text = context.GetText();
|
|
|
|
if (context.IntegerLiteral() != null)
|
|
{
|
|
if (int.TryParse(text.TrimEnd('l', 'L'), out int intValue))
|
|
{
|
|
return new LiteralExpression(location, intValue, LiteralKind.Integer);
|
|
}
|
|
else if (long.TryParse(text.TrimEnd('l', 'L'), out long longValue))
|
|
{
|
|
return new LiteralExpression(location, longValue, LiteralKind.Long);
|
|
}
|
|
}
|
|
else if (context.FloatingPointLiteral() != null)
|
|
{
|
|
if (text.EndsWith('f') || text.EndsWith('F'))
|
|
{
|
|
if (float.TryParse(text.TrimEnd('f', 'F'), out float floatValue))
|
|
{
|
|
return new LiteralExpression(location, floatValue, LiteralKind.Float);
|
|
}
|
|
}
|
|
else if (double.TryParse(text.TrimEnd('d', 'D'), out double doubleValue))
|
|
{
|
|
return new LiteralExpression(location, doubleValue, LiteralKind.Double);
|
|
}
|
|
}
|
|
else if (context.BooleanLiteral() != null)
|
|
{
|
|
var boolValue = text == "true";
|
|
return new LiteralExpression(location, boolValue, LiteralKind.Boolean);
|
|
}
|
|
else if (context.CharacterLiteral() != null)
|
|
{
|
|
var charValue = UnescapeCharacterLiteral(text);
|
|
return new LiteralExpression(location, charValue, LiteralKind.Character);
|
|
}
|
|
else if (context.StringLiteral() != null)
|
|
{
|
|
var stringValue = UnescapeStringLiteral(text);
|
|
return new LiteralExpression(location, stringValue, LiteralKind.String);
|
|
}
|
|
else if (context.NullLiteral() != null)
|
|
{
|
|
return new LiteralExpression(location, null, LiteralKind.Null);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private char UnescapeCharacterLiteral(string literal)
|
|
{
|
|
// Remove quotes
|
|
literal = literal.Substring(1, literal.Length - 2);
|
|
|
|
if (literal.Length == 1) return literal[0];
|
|
|
|
// Handle escape sequences
|
|
return literal[1] switch
|
|
{
|
|
'b' => '\b',
|
|
't' => '\t',
|
|
'n' => '\n',
|
|
'f' => '\f',
|
|
'r' => '\r',
|
|
'\"' => '\"',
|
|
'\'' => '\'',
|
|
'\\' => '\\',
|
|
_ => literal[1]
|
|
};
|
|
}
|
|
|
|
private string UnescapeStringLiteral(string literal)
|
|
{
|
|
// Remove quotes
|
|
literal = literal.Substring(1, literal.Length - 2);
|
|
|
|
// Handle escape sequences
|
|
return literal
|
|
.Replace("\\b", "\b")
|
|
.Replace("\\t", "\t")
|
|
.Replace("\\n", "\n")
|
|
.Replace("\\f", "\f")
|
|
.Replace("\\r", "\r")
|
|
.Replace("\\\"", "\"")
|
|
.Replace("\\'", "'")
|
|
.Replace("\\\\", "\\");
|
|
}
|
|
|
|
private Expression? BuildClassLiteral(Java9Parser.ClassLiteralContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
TypeReference? type = null;
|
|
|
|
if (context.typeName() != null)
|
|
{
|
|
type = BuildTypeName(context.typeName());
|
|
|
|
// Handle array dimensions
|
|
var dimsCount = context.children.Count(c => c.GetText() == "[");
|
|
if (dimsCount > 0 && type != null)
|
|
{
|
|
type = new ArrayType(location, type, dimsCount);
|
|
}
|
|
}
|
|
else if (context.numericType() != null)
|
|
{
|
|
type = BuildNumericType(context.numericType());
|
|
|
|
// Handle array dimensions
|
|
var dimsCount = context.children.Count(c => c.GetText() == "[");
|
|
if (dimsCount > 0 && type != null)
|
|
{
|
|
type = new ArrayType(location, type, dimsCount);
|
|
}
|
|
}
|
|
else if (context.GetText() == "boolean.class")
|
|
{
|
|
type = new PrimitiveType(location, PrimitiveTypeKind.Boolean);
|
|
}
|
|
else if (context.GetText() == "void.class")
|
|
{
|
|
type = new PrimitiveType(location, PrimitiveTypeKind.Void);
|
|
}
|
|
|
|
return type != null ? new ClassLiteralExpression(location, type) : null;
|
|
}
|
|
|
|
private PrimitiveType? BuildNumericType(Java9Parser.NumericTypeContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var text = context.GetText();
|
|
|
|
var kind = text switch
|
|
{
|
|
"byte" => PrimitiveTypeKind.Byte,
|
|
"short" => PrimitiveTypeKind.Short,
|
|
"int" => PrimitiveTypeKind.Int,
|
|
"long" => PrimitiveTypeKind.Long,
|
|
"char" => PrimitiveTypeKind.Char,
|
|
"float" => PrimitiveTypeKind.Float,
|
|
"double" => PrimitiveTypeKind.Double,
|
|
_ => (PrimitiveTypeKind?)null
|
|
};
|
|
|
|
return kind.HasValue ? new PrimitiveType(location, kind.Value) : null;
|
|
}
|
|
|
|
private Expression? BuildExpressionName(IParseTree context)
|
|
{
|
|
if (context is Java9Parser.TypeNameContext typeName)
|
|
{
|
|
// TypeName has a recursive structure
|
|
var location = GetSourceRange(typeName);
|
|
return new IdentifierExpression(location, typeName.GetText());
|
|
}
|
|
else if (context is Java9Parser.ExpressionNameContext exprName)
|
|
{
|
|
// ExpressionName has a recursive structure
|
|
var location = GetSourceRange(exprName);
|
|
return new IdentifierExpression(location, exprName.GetText());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildClassInstanceCreationExpression(Java9Parser.ClassInstanceCreationExpression_lfno_primaryContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var typeArgs = BuildTypeArguments(context.typeArguments());
|
|
var annotations = BuildAnnotations(context.annotation());
|
|
var identifiers = context.identifier();
|
|
|
|
ClassOrInterfaceType? type = null;
|
|
foreach (var id in identifiers)
|
|
{
|
|
var idLocation = GetSourceRange(id);
|
|
type = new ClassOrInterfaceType(idLocation, id.GetText(), type,
|
|
id == identifiers.Last() ? typeArgs : new List<TypeArgument>(),
|
|
annotations);
|
|
}
|
|
|
|
if (type == null) return null;
|
|
|
|
var arguments = context.argumentList() != null
|
|
? context.argumentList().expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList()
|
|
: new List<Expression>();
|
|
|
|
ClassDeclaration? anonymousBody = null;
|
|
if (context.classBody() != null)
|
|
{
|
|
var members = BuildClassMembers(context.classBody());
|
|
anonymousBody = new ClassDeclaration(
|
|
GetSourceRange(context.classBody()),
|
|
"", // Anonymous
|
|
Modifiers.None,
|
|
new List<Annotation>(),
|
|
new List<TypeParameter>(),
|
|
type,
|
|
new List<TypeReference>(),
|
|
members,
|
|
new List<TypeDeclaration>(),
|
|
null,
|
|
false
|
|
);
|
|
}
|
|
|
|
return new NewExpression(location, type, arguments, anonymousBody);
|
|
}
|
|
|
|
private Expression? BuildFieldAccess(Java9Parser.FieldAccess_lfno_primaryContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
Expression? target = null;
|
|
|
|
if (context.GetChild(0).GetText() == "super")
|
|
{
|
|
var childContext = context.GetChild(0) as ParserRuleContext;
|
|
if (childContext != null)
|
|
{
|
|
target = new SuperExpression(GetSourceRange(childContext));
|
|
}
|
|
}
|
|
else if (context.typeName() != null)
|
|
{
|
|
var qualifier = BuildExpressionName(context.typeName());
|
|
target = new SuperExpression(location, qualifier);
|
|
}
|
|
|
|
if (target != null && context.identifier() != null)
|
|
{
|
|
return new FieldAccessExpression(location, target, context.identifier().GetText());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildFieldAccess(Java9Parser.FieldAccessContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var target = BuildPrimary(context.primary());
|
|
|
|
if (target != null && context.identifier() != null)
|
|
{
|
|
return new FieldAccessExpression(location, target, context.identifier().GetText());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildArrayAccess(Java9Parser.ArrayAccess_lfno_primaryContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var array = BuildExpressionName(context.expressionName());
|
|
var indices = context.expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList();
|
|
|
|
if (array == null || indices.Count == 0) return null;
|
|
|
|
Expression result = array;
|
|
foreach (var index in indices)
|
|
{
|
|
result = new ArrayAccessExpression(location, result, index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private Expression? BuildArrayAccess(Java9Parser.ArrayAccessContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
Expression? array = null;
|
|
|
|
if (context.expressionName() != null)
|
|
{
|
|
array = BuildExpressionName(context.expressionName());
|
|
}
|
|
else if (context.primaryNoNewArray_lfno_arrayAccess() != null)
|
|
{
|
|
// Complex array access - simplified for now
|
|
array = BuildExpression(context.primaryNoNewArray_lfno_arrayAccess());
|
|
}
|
|
|
|
if (array == null) return null;
|
|
|
|
var indices = context.expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList();
|
|
|
|
Expression result = array;
|
|
foreach (var index in indices)
|
|
{
|
|
result = new ArrayAccessExpression(location, result, index);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
private Expression? BuildMethodInvocation(Java9Parser.MethodInvocation_lfno_primaryContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
Expression? target = null;
|
|
string? methodName = null;
|
|
List<TypeArgument> typeArgs = new();
|
|
|
|
if (context.methodName() != null)
|
|
{
|
|
// Simple method name
|
|
methodName = context.methodName().identifier().GetText();
|
|
}
|
|
else if (context.typeName() != null)
|
|
{
|
|
// TypeName.method or TypeName.super.method
|
|
target = BuildExpressionName(context.typeName());
|
|
|
|
if (context.identifier() != null)
|
|
{
|
|
methodName = context.identifier().GetText();
|
|
}
|
|
else if (context.GetChild(context.ChildCount - 3)?.GetText() == "super")
|
|
{
|
|
target = new SuperExpression(location, target);
|
|
methodName = context.identifier().GetText();
|
|
}
|
|
}
|
|
else if (context.expressionName() != null)
|
|
{
|
|
// ExpressionName.method or ExpressionName.super.method
|
|
target = BuildExpressionName(context.expressionName());
|
|
|
|
if (context.identifier() != null)
|
|
{
|
|
methodName = context.identifier().GetText();
|
|
}
|
|
else if (context.GetChild(context.ChildCount - 3)?.GetText() == "super")
|
|
{
|
|
target = new SuperExpression(location, target);
|
|
methodName = context.identifier().GetText();
|
|
}
|
|
}
|
|
else if (context.GetChild(0).GetText() == "super")
|
|
{
|
|
// super.method
|
|
var childContext = context.GetChild(0) as ParserRuleContext;
|
|
if (childContext != null)
|
|
{
|
|
target = new SuperExpression(GetSourceRange(childContext));
|
|
}
|
|
methodName = context.identifier().GetText();
|
|
}
|
|
|
|
if (methodName == null) return null;
|
|
|
|
// Type arguments
|
|
if (context.typeArguments() != null)
|
|
{
|
|
typeArgs = BuildTypeArguments(context.typeArguments());
|
|
}
|
|
|
|
// Arguments
|
|
var arguments = context.argumentList() != null
|
|
? context.argumentList().expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList()
|
|
: new List<Expression>();
|
|
|
|
return new MethodCallExpression(location, target, methodName, typeArgs, arguments);
|
|
}
|
|
|
|
private Expression? BuildMethodReference(Java9Parser.MethodReference_lfno_primaryContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
Expression? target = null;
|
|
string? methodName = null;
|
|
List<TypeArgument> typeArgs = new();
|
|
|
|
if (context.expressionName() != null)
|
|
{
|
|
target = BuildExpressionName(context.expressionName());
|
|
}
|
|
else if (context.referenceType() != null)
|
|
{
|
|
var type = BuildTypeReference(context.referenceType());
|
|
if (type != null)
|
|
{
|
|
target = new ClassLiteralExpression(location, type);
|
|
}
|
|
}
|
|
else if (context.GetChild(0).GetText() == "super")
|
|
{
|
|
var childContext = context.GetChild(0) as ParserRuleContext;
|
|
if (childContext != null)
|
|
{
|
|
target = new SuperExpression(GetSourceRange(childContext));
|
|
}
|
|
}
|
|
else if (context.typeName() != null)
|
|
{
|
|
var qualifier = BuildExpressionName(context.typeName());
|
|
target = new SuperExpression(location, qualifier);
|
|
}
|
|
|
|
if (target == null) return null;
|
|
|
|
// Type arguments
|
|
if (context.typeArguments() != null)
|
|
{
|
|
typeArgs = BuildTypeArguments(context.typeArguments());
|
|
}
|
|
|
|
// Method name
|
|
if (context.identifier() != null)
|
|
{
|
|
methodName = context.identifier().GetText();
|
|
}
|
|
else if (context.GetChild(context.ChildCount - 1).GetText() == "new")
|
|
{
|
|
methodName = "new";
|
|
}
|
|
|
|
if (methodName == null) return null;
|
|
|
|
return new MethodReferenceExpression(location, target, methodName, typeArgs);
|
|
}
|
|
|
|
private Expression? BuildArrayCreationExpression(Java9Parser.ArrayCreationExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
TypeReference? elementType = null;
|
|
List<Expression> dimensions = new();
|
|
ArrayInitializer? initializer = null;
|
|
|
|
if (context.primitiveType() != null)
|
|
{
|
|
elementType = BuildPrimitiveType(context.primitiveType());
|
|
}
|
|
else if (context.classOrInterfaceType() != null)
|
|
{
|
|
elementType = BuildClassOrInterfaceType(context.classOrInterfaceType());
|
|
}
|
|
|
|
if (elementType == null) return null;
|
|
|
|
// Dimensions with expressions
|
|
if (context.dimExprs() != null)
|
|
{
|
|
foreach (var dimExpr in context.dimExprs().dimExpr())
|
|
{
|
|
var expr = BuildExpression(dimExpr.expression());
|
|
if (expr != null) dimensions.Add(expr);
|
|
}
|
|
}
|
|
|
|
// Array initializer
|
|
if (context.arrayInitializer() != null)
|
|
{
|
|
initializer = BuildArrayInitializer(context.arrayInitializer());
|
|
}
|
|
|
|
return new NewArrayExpression(location, elementType, dimensions, initializer);
|
|
}
|
|
|
|
private ArrayInitializer? BuildArrayInitializer(Java9Parser.ArrayInitializerContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var elements = new List<Expression>();
|
|
|
|
if (context.variableInitializerList() != null)
|
|
{
|
|
foreach (var init in context.variableInitializerList().variableInitializer())
|
|
{
|
|
var expr = BuildVariableInitializer(init);
|
|
if (expr != null) elements.Add(expr);
|
|
}
|
|
}
|
|
|
|
return new ArrayInitializer(location, elements);
|
|
}
|
|
|
|
private Expression? BuildVariableInitializer(Java9Parser.VariableInitializerContext context)
|
|
{
|
|
if (context.expression() != null)
|
|
{
|
|
return BuildExpression(context.expression());
|
|
}
|
|
else if (context.arrayInitializer() != null)
|
|
{
|
|
return BuildArrayInitializer(context.arrayInitializer());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildLambdaExpression(Java9Parser.LambdaExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var parameters = BuildLambdaParameters(context.lambdaParameters());
|
|
JavaNode? body = null;
|
|
|
|
if (context.lambdaBody().expression() != null)
|
|
{
|
|
body = BuildExpression(context.lambdaBody().expression());
|
|
}
|
|
else if (context.lambdaBody().block() != null)
|
|
{
|
|
body = BuildBlock(context.lambdaBody().block());
|
|
}
|
|
|
|
return body != null ? new LambdaExpression(location, parameters, body) : null;
|
|
}
|
|
|
|
private List<LambdaParameter> BuildLambdaParameters(Java9Parser.LambdaParametersContext context)
|
|
{
|
|
var parameters = new List<LambdaParameter>();
|
|
|
|
if (context.identifier() != null)
|
|
{
|
|
// Single parameter without parentheses
|
|
var location = GetSourceRange(context.identifier());
|
|
parameters.Add(new LambdaParameter(location, context.identifier().GetText()));
|
|
}
|
|
else if (context.formalParameterList() != null)
|
|
{
|
|
// Formal parameters with types
|
|
var formalParams = BuildParameters(context.formalParameterList());
|
|
foreach (var param in formalParams)
|
|
{
|
|
parameters.Add(new LambdaParameter(
|
|
param.Location,
|
|
param.Name,
|
|
param.Type,
|
|
param.IsFinal
|
|
));
|
|
}
|
|
}
|
|
else if (context.inferredFormalParameterList() != null)
|
|
{
|
|
// Inferred parameters without types
|
|
foreach (var id in context.inferredFormalParameterList().identifier())
|
|
{
|
|
var location = GetSourceRange(id);
|
|
parameters.Add(new LambdaParameter(location, id.GetText()));
|
|
}
|
|
}
|
|
|
|
return parameters;
|
|
}
|
|
|
|
|
|
// Statement building methods
|
|
|
|
private BlockStatement BuildBlockFromStatements(Java9Parser.BlockStatementsContext blockStatements)
|
|
{
|
|
var statements = new List<Statement>();
|
|
foreach (var stmt in blockStatements.blockStatement())
|
|
{
|
|
var statement = BuildBlockStatement(stmt);
|
|
if (statement != null) statements.Add(statement);
|
|
}
|
|
|
|
return new BlockStatement(GetSourceRange(blockStatements), statements);
|
|
}
|
|
|
|
private BlockStatement? BuildBlock(Java9Parser.BlockContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var statements = new List<Statement>();
|
|
|
|
if (context.blockStatements() != null)
|
|
{
|
|
foreach (var stmt in context.blockStatements().blockStatement())
|
|
{
|
|
var statement = BuildBlockStatement(stmt);
|
|
if (statement != null) statements.Add(statement);
|
|
}
|
|
}
|
|
|
|
return new BlockStatement(location, statements);
|
|
}
|
|
|
|
private Statement? BuildBlockStatement(Java9Parser.BlockStatementContext context)
|
|
{
|
|
if (context.localVariableDeclarationStatement() != null)
|
|
{
|
|
return BuildLocalVariableDeclarationStatement(context.localVariableDeclarationStatement());
|
|
}
|
|
else if (context.classDeclaration() != null)
|
|
{
|
|
// Local class declaration - we'll skip this for now
|
|
return null;
|
|
}
|
|
else if (context.statement() != null)
|
|
{
|
|
return BuildStatement(context.statement());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Statement? BuildLocalVariableDeclarationStatement(Java9Parser.LocalVariableDeclarationStatementContext context)
|
|
{
|
|
return BuildLocalVariableDeclaration(context.localVariableDeclaration());
|
|
}
|
|
|
|
private LocalVariableStatement? BuildLocalVariableDeclaration(Java9Parser.LocalVariableDeclarationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.variableModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var variables = context.variableDeclaratorList().variableDeclarator()
|
|
.Select(v => BuildVariableDeclarator(v))
|
|
.Where(v => v != null)
|
|
.Cast<VariableDeclarator>()
|
|
.ToList();
|
|
|
|
var isFinal = modifiers.HasFlag(Modifiers.Final);
|
|
|
|
return new LocalVariableStatement(location, type, variables, isFinal);
|
|
}
|
|
|
|
private Statement? BuildStatement(Java9Parser.StatementContext context)
|
|
{
|
|
if (context.statementWithoutTrailingSubstatement() != null)
|
|
{
|
|
return BuildStatementWithoutTrailingSubstatement(context.statementWithoutTrailingSubstatement());
|
|
}
|
|
else if (context.labeledStatement() != null)
|
|
{
|
|
return BuildLabeledStatement(context.labeledStatement());
|
|
}
|
|
else if (context.ifThenStatement() != null)
|
|
{
|
|
return BuildIfStatement(context.ifThenStatement());
|
|
}
|
|
else if (context.ifThenElseStatement() != null)
|
|
{
|
|
return BuildIfElseStatement(context.ifThenElseStatement());
|
|
}
|
|
else if (context.whileStatement() != null)
|
|
{
|
|
return BuildWhileStatement(context.whileStatement());
|
|
}
|
|
else if (context.forStatement() != null)
|
|
{
|
|
return BuildForStatement(context.forStatement());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Statement? BuildStatementWithoutTrailingSubstatement(Java9Parser.StatementWithoutTrailingSubstatementContext context)
|
|
{
|
|
if (context.block() != null)
|
|
{
|
|
return BuildBlock(context.block());
|
|
}
|
|
else if (context.emptyStatement_() != null)
|
|
{
|
|
return new EmptyStatement(GetSourceRange(context.emptyStatement_()));
|
|
}
|
|
else if (context.expressionStatement() != null)
|
|
{
|
|
return BuildExpressionStatement(context.expressionStatement());
|
|
}
|
|
else if (context.assertStatement() != null)
|
|
{
|
|
return BuildAssertStatement(context.assertStatement());
|
|
}
|
|
else if (context.switchStatement() != null)
|
|
{
|
|
return BuildSwitchStatement(context.switchStatement());
|
|
}
|
|
else if (context.doStatement() != null)
|
|
{
|
|
return BuildDoStatement(context.doStatement());
|
|
}
|
|
else if (context.breakStatement() != null)
|
|
{
|
|
return BuildBreakStatement(context.breakStatement());
|
|
}
|
|
else if (context.continueStatement() != null)
|
|
{
|
|
return BuildContinueStatement(context.continueStatement());
|
|
}
|
|
else if (context.returnStatement() != null)
|
|
{
|
|
return BuildReturnStatement(context.returnStatement());
|
|
}
|
|
else if (context.synchronizedStatement() != null)
|
|
{
|
|
return BuildSynchronizedStatement(context.synchronizedStatement());
|
|
}
|
|
else if (context.throwStatement() != null)
|
|
{
|
|
return BuildThrowStatement(context.throwStatement());
|
|
}
|
|
else if (context.tryStatement() != null)
|
|
{
|
|
return BuildTryStatement(context.tryStatement());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private ExpressionStatement? BuildExpressionStatement(Java9Parser.ExpressionStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var expr = BuildExpression(context.statementExpression());
|
|
return expr != null ? new ExpressionStatement(location, expr) : null;
|
|
}
|
|
|
|
private Expression? BuildExpression(Java9Parser.StatementExpressionContext context)
|
|
{
|
|
if (context.assignment() != null)
|
|
{
|
|
return BuildAssignment(context.assignment());
|
|
}
|
|
else if (context.preIncrementExpression() != null)
|
|
{
|
|
return BuildPreIncrementExpression(context.preIncrementExpression());
|
|
}
|
|
else if (context.preDecrementExpression() != null)
|
|
{
|
|
return BuildPreDecrementExpression(context.preDecrementExpression());
|
|
}
|
|
else if (context.postIncrementExpression() != null)
|
|
{
|
|
return BuildPostIncrementExpression(context.postIncrementExpression());
|
|
}
|
|
else if (context.postDecrementExpression() != null)
|
|
{
|
|
return BuildPostDecrementExpression(context.postDecrementExpression());
|
|
}
|
|
else if (context.methodInvocation() != null)
|
|
{
|
|
return BuildMethodInvocation(context.methodInvocation());
|
|
}
|
|
else if (context.classInstanceCreationExpression() != null)
|
|
{
|
|
return BuildClassInstanceCreationExpression(context.classInstanceCreationExpression());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Expression? BuildPostIncrementExpression(Java9Parser.PostIncrementExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildPostfixExpression(context.postfixExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.PostIncrement, operand, false)
|
|
: null;
|
|
}
|
|
|
|
private Expression? BuildPostDecrementExpression(Java9Parser.PostDecrementExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var operand = BuildPostfixExpression(context.postfixExpression());
|
|
return operand != null
|
|
? new UnaryExpression(location, UnaryOperator.PostDecrement, operand, false)
|
|
: null;
|
|
}
|
|
|
|
private Expression? BuildMethodInvocation(Java9Parser.MethodInvocationContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
Expression? target = null;
|
|
string methodName;
|
|
List<TypeArgument> typeArgs = new List<TypeArgument>();
|
|
|
|
// Handle different method invocation patterns
|
|
if (context.methodName() != null)
|
|
{
|
|
// Simple method call
|
|
methodName = context.methodName().GetText();
|
|
}
|
|
else if (context.typeName() != null && context.identifier() != null)
|
|
{
|
|
// Qualified method call
|
|
target = BuildExpressionName(context.typeName());
|
|
methodName = context.identifier().GetText();
|
|
if (context.typeArguments() != null)
|
|
{
|
|
typeArgs = BuildTypeArguments(context.typeArguments());
|
|
}
|
|
}
|
|
else if (context.expressionName() != null && context.identifier() != null)
|
|
{
|
|
// Expression.method() call
|
|
target = BuildExpressionName(context.expressionName());
|
|
methodName = context.identifier().GetText();
|
|
if (context.typeArguments() != null)
|
|
{
|
|
typeArgs = BuildTypeArguments(context.typeArguments());
|
|
}
|
|
}
|
|
else if (context.primary() != null && context.identifier() != null)
|
|
{
|
|
// primary.method() call
|
|
target = BuildPrimary(context.primary());
|
|
methodName = context.identifier().GetText();
|
|
if (context.typeArguments() != null)
|
|
{
|
|
typeArgs = BuildTypeArguments(context.typeArguments());
|
|
}
|
|
}
|
|
else if (context.SUPER() != null && context.identifier() != null)
|
|
{
|
|
// super.method() call
|
|
target = new SuperExpression(GetSourceRange(context));
|
|
methodName = context.identifier().GetText();
|
|
if (context.typeArguments() != null)
|
|
{
|
|
typeArgs = BuildTypeArguments(context.typeArguments());
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Fallback
|
|
methodName = "unknown";
|
|
}
|
|
|
|
// Arguments
|
|
var arguments = context.argumentList() != null
|
|
? context.argumentList().expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList()
|
|
: new List<Expression>();
|
|
|
|
return new MethodCallExpression(location, target, methodName, typeArgs, arguments);
|
|
}
|
|
|
|
private Expression? BuildClassInstanceCreationExpression(Java9Parser.ClassInstanceCreationExpressionContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
|
|
// Build the type being instantiated
|
|
TypeReference? type = null;
|
|
var identifiers = context.identifier();
|
|
if (identifiers != null && identifiers.Length > 0)
|
|
{
|
|
var typeName = string.Join(".", identifiers.Select(id => id.GetText()));
|
|
var typeArgs = context.typeArguments() != null
|
|
? BuildTypeArguments(context.typeArguments())
|
|
: new List<TypeArgument>();
|
|
type = new ClassOrInterfaceType(location, typeName, null, typeArgs, new List<Annotation>());
|
|
}
|
|
|
|
if (type == null) return null;
|
|
|
|
// Build arguments
|
|
var arguments = context.argumentList() != null
|
|
? context.argumentList().expression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList()
|
|
: new List<Expression>();
|
|
|
|
// Handle anonymous class body if present
|
|
ClassDeclaration? anonymousBody = null;
|
|
if (context.classBody() != null)
|
|
{
|
|
var members = BuildClassMembers(context.classBody());
|
|
anonymousBody = new ClassDeclaration(
|
|
location,
|
|
"$Anonymous",
|
|
Modifiers.None,
|
|
new List<Annotation>(),
|
|
new List<TypeParameter>(),
|
|
type,
|
|
new List<TypeReference>(),
|
|
members,
|
|
new List<TypeDeclaration>(),
|
|
null,
|
|
false
|
|
);
|
|
}
|
|
|
|
return new NewExpression(location, type as ClassOrInterfaceType ??
|
|
new ClassOrInterfaceType(location, "Unknown", null, new List<TypeArgument>(), new List<Annotation>()),
|
|
arguments, anonymousBody);
|
|
}
|
|
|
|
private IfStatement? BuildIfStatement(Java9Parser.IfThenStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var condition = BuildExpression(context.expression());
|
|
var thenStmt = BuildStatement(context.statement());
|
|
|
|
if (condition != null && thenStmt != null)
|
|
{
|
|
return new IfStatement(location, condition, thenStmt);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private IfStatement? BuildIfElseStatement(Java9Parser.IfThenElseStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var condition = BuildExpression(context.expression());
|
|
var thenStmt = BuildStatement(context.statementNoShortIf());
|
|
var elseStmt = BuildStatement(context.statement());
|
|
|
|
if (condition != null && thenStmt != null)
|
|
{
|
|
return new IfStatement(location, condition, thenStmt, elseStmt);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Statement? BuildStatement(Java9Parser.StatementNoShortIfContext context)
|
|
{
|
|
if (context.statementWithoutTrailingSubstatement() != null)
|
|
{
|
|
return BuildStatementWithoutTrailingSubstatement(context.statementWithoutTrailingSubstatement());
|
|
}
|
|
else if (context.labeledStatementNoShortIf() != null)
|
|
{
|
|
return BuildLabeledStatementNoShortIf(context.labeledStatementNoShortIf());
|
|
}
|
|
else if (context.ifThenElseStatementNoShortIf() != null)
|
|
{
|
|
return BuildIfElseStatementNoShortIf(context.ifThenElseStatementNoShortIf());
|
|
}
|
|
else if (context.whileStatementNoShortIf() != null)
|
|
{
|
|
return BuildWhileStatementNoShortIf(context.whileStatementNoShortIf());
|
|
}
|
|
else if (context.forStatementNoShortIf() != null)
|
|
{
|
|
return BuildForStatementNoShortIf(context.forStatementNoShortIf());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private IfStatement? BuildIfElseStatementNoShortIf(Java9Parser.IfThenElseStatementNoShortIfContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var condition = BuildExpression(context.expression());
|
|
var thenStmt = BuildStatement(context.statementNoShortIf()[0]);
|
|
var elseStmt = BuildStatement(context.statementNoShortIf()[1]);
|
|
|
|
if (condition != null && thenStmt != null)
|
|
{
|
|
return new IfStatement(location, condition, thenStmt, elseStmt);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private WhileStatement? BuildWhileStatement(Java9Parser.WhileStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var condition = BuildExpression(context.expression());
|
|
var body = BuildStatement(context.statement());
|
|
|
|
if (condition != null && body != null)
|
|
{
|
|
return new WhileStatement(location, condition, body);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private WhileStatement? BuildWhileStatementNoShortIf(Java9Parser.WhileStatementNoShortIfContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var condition = BuildExpression(context.expression());
|
|
var body = BuildStatement(context.statementNoShortIf());
|
|
|
|
if (condition != null && body != null)
|
|
{
|
|
return new WhileStatement(location, condition, body);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private DoWhileStatement? BuildDoStatement(Java9Parser.DoStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var body = BuildStatement(context.statement());
|
|
var condition = BuildExpression(context.expression());
|
|
|
|
if (body != null && condition != null)
|
|
{
|
|
return new DoWhileStatement(location, body, condition);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Statement? BuildForStatement(Java9Parser.ForStatementContext context)
|
|
{
|
|
if (context.basicForStatement() != null)
|
|
{
|
|
return BuildBasicForStatement(context.basicForStatement());
|
|
}
|
|
else if (context.enhancedForStatement() != null)
|
|
{
|
|
return BuildEnhancedForStatement(context.enhancedForStatement());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private Statement? BuildForStatementNoShortIf(Java9Parser.ForStatementNoShortIfContext context)
|
|
{
|
|
if (context.basicForStatementNoShortIf() != null)
|
|
{
|
|
return BuildBasicForStatementNoShortIf(context.basicForStatementNoShortIf());
|
|
}
|
|
else if (context.enhancedForStatementNoShortIf() != null)
|
|
{
|
|
return BuildEnhancedForStatementNoShortIf(context.enhancedForStatementNoShortIf());
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private ForStatement? BuildBasicForStatement(Java9Parser.BasicForStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var initializers = new List<Statement>();
|
|
Expression? condition = null;
|
|
var updates = new List<Expression>();
|
|
|
|
if (context.forInit() != null)
|
|
{
|
|
initializers = BuildForInit(context.forInit());
|
|
}
|
|
|
|
if (context.expression() != null)
|
|
{
|
|
condition = BuildExpression(context.expression());
|
|
}
|
|
|
|
if (context.forUpdate() != null)
|
|
{
|
|
updates = BuildForUpdate(context.forUpdate());
|
|
}
|
|
|
|
var body = BuildStatement(context.statement());
|
|
if (body == null) return null;
|
|
|
|
return new ForStatement(location, initializers, condition, updates, body);
|
|
}
|
|
|
|
private ForStatement? BuildBasicForStatementNoShortIf(Java9Parser.BasicForStatementNoShortIfContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var initializers = new List<Statement>();
|
|
Expression? condition = null;
|
|
var updates = new List<Expression>();
|
|
|
|
if (context.forInit() != null)
|
|
{
|
|
initializers = BuildForInit(context.forInit());
|
|
}
|
|
|
|
if (context.expression() != null)
|
|
{
|
|
condition = BuildExpression(context.expression());
|
|
}
|
|
|
|
if (context.forUpdate() != null)
|
|
{
|
|
updates = BuildForUpdate(context.forUpdate());
|
|
}
|
|
|
|
var body = BuildStatement(context.statementNoShortIf());
|
|
if (body == null) return null;
|
|
|
|
return new ForStatement(location, initializers, condition, updates, body);
|
|
}
|
|
|
|
private List<Statement> BuildForInit(Java9Parser.ForInitContext context)
|
|
{
|
|
var statements = new List<Statement>();
|
|
|
|
if (context.statementExpressionList() != null)
|
|
{
|
|
foreach (var expr in context.statementExpressionList().statementExpression())
|
|
{
|
|
var expression = BuildExpression(expr);
|
|
if (expression != null)
|
|
{
|
|
statements.Add(new ExpressionStatement(expression.Location, expression));
|
|
}
|
|
}
|
|
}
|
|
else if (context.localVariableDeclaration() != null)
|
|
{
|
|
var varDecl = BuildLocalVariableDeclaration(context.localVariableDeclaration());
|
|
if (varDecl != null) statements.Add(varDecl);
|
|
}
|
|
|
|
return statements;
|
|
}
|
|
|
|
private List<Expression> BuildForUpdate(Java9Parser.ForUpdateContext context)
|
|
{
|
|
return context.statementExpressionList().statementExpression()
|
|
.Select(e => BuildExpression(e))
|
|
.Where(e => e != null)
|
|
.Cast<Expression>()
|
|
.ToList();
|
|
}
|
|
|
|
private ForEachStatement? BuildEnhancedForStatement(Java9Parser.EnhancedForStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.variableModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var varId = context.variableDeclaratorId();
|
|
var varName = varId.identifier().GetText();
|
|
|
|
// Handle array dimensions on variable name
|
|
if (varId.dims() != null)
|
|
{
|
|
var dimensions = varId.dims().GetText().Length / 2;
|
|
type = new ArrayType(location, type, dimensions);
|
|
}
|
|
|
|
var iterable = BuildExpression(context.expression());
|
|
var body = BuildStatement(context.statement());
|
|
|
|
if (iterable != null && body != null)
|
|
{
|
|
return new ForEachStatement(location, type, varName, iterable, body, modifiers.HasFlag(Modifiers.Final));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private ForEachStatement? BuildEnhancedForStatementNoShortIf(Java9Parser.EnhancedForStatementNoShortIfContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.variableModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var varId = context.variableDeclaratorId();
|
|
var varName = varId.identifier().GetText();
|
|
|
|
// Handle array dimensions on variable name
|
|
if (varId.dims() != null)
|
|
{
|
|
var dimensions = varId.dims().GetText().Length / 2;
|
|
type = new ArrayType(location, type, dimensions);
|
|
}
|
|
|
|
var iterable = BuildExpression(context.expression());
|
|
var body = BuildStatement(context.statementNoShortIf());
|
|
|
|
if (iterable != null && body != null)
|
|
{
|
|
return new ForEachStatement(location, type, varName, iterable, body, modifiers.HasFlag(Modifiers.Final));
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private LabeledStatement? BuildLabeledStatement(Java9Parser.LabeledStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var label = context.identifier().GetText();
|
|
var statement = BuildStatement(context.statement());
|
|
|
|
return statement != null
|
|
? new LabeledStatement(location, label, statement)
|
|
: null;
|
|
}
|
|
|
|
private LabeledStatement? BuildLabeledStatementNoShortIf(Java9Parser.LabeledStatementNoShortIfContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var label = context.identifier().GetText();
|
|
var statement = BuildStatement(context.statementNoShortIf());
|
|
|
|
return statement != null
|
|
? new LabeledStatement(location, label, statement)
|
|
: null;
|
|
}
|
|
|
|
private BreakStatement BuildBreakStatement(Java9Parser.BreakStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var label = context.identifier()?.GetText();
|
|
return new BreakStatement(location, label);
|
|
}
|
|
|
|
private ContinueStatement BuildContinueStatement(Java9Parser.ContinueStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var label = context.identifier()?.GetText();
|
|
return new ContinueStatement(location, label);
|
|
}
|
|
|
|
private ReturnStatement BuildReturnStatement(Java9Parser.ReturnStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var value = context.expression() != null
|
|
? BuildExpression(context.expression())
|
|
: null;
|
|
return new ReturnStatement(location, value);
|
|
}
|
|
|
|
private ThrowStatement? BuildThrowStatement(Java9Parser.ThrowStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var exception = BuildExpression(context.expression());
|
|
return exception != null
|
|
? new ThrowStatement(location, exception)
|
|
: null;
|
|
}
|
|
|
|
private SynchronizedStatement? BuildSynchronizedStatement(Java9Parser.SynchronizedStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var lockExpr = BuildExpression(context.expression());
|
|
var body = BuildBlock(context.block());
|
|
|
|
if (lockExpr != null && body != null)
|
|
{
|
|
return new SynchronizedStatement(location, lockExpr, body);
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private TryStatement? BuildTryStatement(Java9Parser.TryStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
|
|
if (context.tryWithResourcesStatement() != null)
|
|
{
|
|
return BuildTryWithResourcesStatement(context.tryWithResourcesStatement());
|
|
}
|
|
|
|
var body = BuildBlock(context.block());
|
|
if (body == null) return null;
|
|
|
|
var catchClauses = new List<CatchClause>();
|
|
if (context.catches() != null)
|
|
{
|
|
catchClauses = BuildCatchClauses(context.catches());
|
|
}
|
|
|
|
BlockStatement? finallyBlock = null;
|
|
if (context.finally_() != null)
|
|
{
|
|
finallyBlock = BuildBlock(context.finally_().block());
|
|
}
|
|
|
|
return new TryStatement(location, new List<ResourceDeclaration>(), body, catchClauses, finallyBlock);
|
|
}
|
|
|
|
private TryStatement? BuildTryWithResourcesStatement(Java9Parser.TryWithResourcesStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var resources = BuildResourceList(context.resourceSpecification());
|
|
var body = BuildBlock(context.block());
|
|
if (body == null) return null;
|
|
|
|
var catchClauses = new List<CatchClause>();
|
|
if (context.catches() != null)
|
|
{
|
|
catchClauses = BuildCatchClauses(context.catches());
|
|
}
|
|
|
|
BlockStatement? finallyBlock = null;
|
|
if (context.finally_() != null)
|
|
{
|
|
finallyBlock = BuildBlock(context.finally_().block());
|
|
}
|
|
|
|
return new TryStatement(location, resources, body, catchClauses, finallyBlock);
|
|
}
|
|
|
|
private List<ResourceDeclaration> BuildResourceList(Java9Parser.ResourceSpecificationContext context)
|
|
{
|
|
var resources = new List<ResourceDeclaration>();
|
|
|
|
if (context.resourceList() != null)
|
|
{
|
|
foreach (var resource in context.resourceList().resource())
|
|
{
|
|
var decl = BuildResource(resource);
|
|
if (decl != null) resources.Add(decl);
|
|
}
|
|
}
|
|
|
|
return resources;
|
|
}
|
|
|
|
private ResourceDeclaration? BuildResource(Java9Parser.ResourceContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var modifiers = BuildModifiers(context.variableModifier());
|
|
var type = BuildTypeReference(context.unannType());
|
|
if (type == null) return null;
|
|
|
|
var name = context.variableDeclaratorId().identifier().GetText();
|
|
var initializer = BuildExpression(context.expression());
|
|
if (initializer == null) return null;
|
|
|
|
return new ResourceDeclaration(location, type, name, initializer, modifiers.HasFlag(Modifiers.Final));
|
|
}
|
|
|
|
private List<CatchClause> BuildCatchClauses(Java9Parser.CatchesContext context)
|
|
{
|
|
return context.catchClause()
|
|
.Select(c => BuildCatchClause(c))
|
|
.Where(c => c != null)
|
|
.Cast<CatchClause>()
|
|
.ToList();
|
|
}
|
|
|
|
private CatchClause? BuildCatchClause(Java9Parser.CatchClauseContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var catchParam = context.catchFormalParameter();
|
|
var exceptionTypes = new List<TypeReference>();
|
|
|
|
if (catchParam.catchType().unannClassType() != null)
|
|
{
|
|
var type = BuildTypeReference(catchParam.catchType().unannClassType());
|
|
if (type != null) exceptionTypes.Add(type);
|
|
}
|
|
|
|
foreach (var additional in catchParam.catchType().classType())
|
|
{
|
|
var type = BuildClassType(additional);
|
|
if (type != null) exceptionTypes.Add(type);
|
|
}
|
|
|
|
var varName = catchParam.variableDeclaratorId().identifier().GetText();
|
|
var body = BuildBlock(context.block());
|
|
|
|
return body != null
|
|
? new CatchClause(location, exceptionTypes, varName, body)
|
|
: null;
|
|
}
|
|
|
|
private TypeReference? BuildTypeReference(Java9Parser.UnannClassTypeContext context)
|
|
{
|
|
// Convert unann class type to regular class type handling
|
|
var location = GetSourceRange(context);
|
|
var name = context.identifier().GetText();
|
|
var typeArgs = BuildTypeArguments(context.typeArguments());
|
|
|
|
return new ClassOrInterfaceType(location, name, null, typeArgs, new List<Annotation>());
|
|
}
|
|
|
|
private SwitchStatement? BuildSwitchStatement(Java9Parser.SwitchStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var selector = BuildExpression(context.expression());
|
|
if (selector == null) return null;
|
|
|
|
var cases = BuildSwitchCases(context.switchBlock());
|
|
|
|
return new SwitchStatement(location, selector, cases);
|
|
}
|
|
|
|
private List<SwitchCase> BuildSwitchCases(Java9Parser.SwitchBlockContext context)
|
|
{
|
|
var cases = new List<SwitchCase>();
|
|
|
|
if (context.switchBlockStatementGroup() != null)
|
|
{
|
|
foreach (var group in context.switchBlockStatementGroup())
|
|
{
|
|
var labels = new List<Expression>();
|
|
bool isDefault = false;
|
|
|
|
foreach (var label in group.switchLabels().switchLabel())
|
|
{
|
|
if (label.constantExpression() != null)
|
|
{
|
|
var expr = BuildExpression(label.constantExpression());
|
|
if (expr != null) labels.Add(expr);
|
|
}
|
|
else if (label.enumConstantName() != null)
|
|
{
|
|
var location = GetSourceRange(label.enumConstantName());
|
|
var name = label.enumConstantName().identifier().GetText();
|
|
labels.Add(new IdentifierExpression(location, name));
|
|
}
|
|
else if (label.GetChild(0).GetText() == "default")
|
|
{
|
|
isDefault = true;
|
|
}
|
|
}
|
|
|
|
var statements = new List<Statement>();
|
|
foreach (var stmt in group.blockStatements().blockStatement())
|
|
{
|
|
var statement = BuildBlockStatement(stmt);
|
|
if (statement != null) statements.Add(statement);
|
|
}
|
|
|
|
var caseLocation = GetSourceRange(group);
|
|
cases.Add(new SwitchCase(caseLocation, labels, statements, isDefault));
|
|
}
|
|
}
|
|
|
|
return cases;
|
|
}
|
|
|
|
private Expression? BuildExpression(Java9Parser.ConstantExpressionContext context)
|
|
{
|
|
return BuildExpression(context.expression());
|
|
}
|
|
|
|
private AssertStatement? BuildAssertStatement(Java9Parser.AssertStatementContext context)
|
|
{
|
|
var location = GetSourceRange(context);
|
|
var expressions = context.expression();
|
|
|
|
if (expressions.Length == 0) return null;
|
|
|
|
var condition = BuildExpression(expressions[0]);
|
|
if (condition == null) return null;
|
|
|
|
Expression? message = null;
|
|
if (expressions.Length > 1)
|
|
{
|
|
message = BuildExpression(expressions[1]);
|
|
}
|
|
|
|
return new AssertStatement(location, condition, message);
|
|
}
|
|
|
|
// Helper methods
|
|
|
|
private string GetQualifiedName(IList<ITerminalNode> identifiers)
|
|
{
|
|
return string.Join(".", identifiers.Select(id => id.GetText()));
|
|
}
|
|
|
|
private JavaDoc? ExtractJavaDoc(ParserRuleContext context)
|
|
{
|
|
// Look for JavaDoc comment in the hidden channel before this node
|
|
var tokenIndex = context.Start.TokenIndex;
|
|
if (tokenIndex > 0)
|
|
{
|
|
var bufferedTokens = _tokens as BufferedTokenStream;
|
|
var hiddenTokens = bufferedTokens?.GetHiddenTokensToLeft(tokenIndex, Java9Lexer.COMMENT);
|
|
if (hiddenTokens != null)
|
|
{
|
|
foreach (var token in hiddenTokens)
|
|
{
|
|
if (token.Text.StartsWith("/**", StringComparison.Ordinal))
|
|
{
|
|
return ParseJavaDoc(token);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
private JavaDoc ParseJavaDoc(IToken token)
|
|
{
|
|
var location = new SourceLocation(
|
|
token.Line,
|
|
token.Column,
|
|
token.StartIndex,
|
|
token.Text.Length
|
|
);
|
|
var range = new SourceRange(location, location);
|
|
|
|
var content = token.Text;
|
|
var tags = new List<JavaDocTag>();
|
|
|
|
// Simple JavaDoc parsing - can be enhanced
|
|
var lines = content.Split('\n');
|
|
foreach (var line in lines)
|
|
{
|
|
var trimmed = line.Trim().TrimStart('*').Trim();
|
|
if (trimmed.StartsWith('@'))
|
|
{
|
|
var parts = trimmed.Split(' ', 3);
|
|
if (parts.Length >= 2)
|
|
{
|
|
var tagName = parts[0];
|
|
var parameter = parts.Length > 2 ? parts[1] : null;
|
|
var description = parts.Length > 2 ? parts[2] : (parts.Length > 1 ? parts[1] : "");
|
|
tags.Add(new JavaDocTag(tagName, parameter, description));
|
|
}
|
|
}
|
|
}
|
|
|
|
return new JavaDoc(range, content, tags);
|
|
}
|
|
|
|
// Helper classes for building class bodies with both members and nested types
|
|
private class ClassBodyResult
|
|
{
|
|
public List<MemberDeclaration> Members { get; set; } = new List<MemberDeclaration>();
|
|
public List<TypeDeclaration> NestedTypes { get; set; } = new List<TypeDeclaration>();
|
|
}
|
|
}
|
|
} |