All Downloads are FREE. Search and download functionalities are using the official Maven repository.

ai.vespa.schemals.schemadocument.resolvers.StructFieldDefinitionResolver Maven / Gradle / Ivy

There is a newer version: 8.441.21
Show newest version
package ai.vespa.schemals.schemadocument.resolvers;

import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import org.eclipse.lsp4j.Diagnostic;

import ai.vespa.schemals.context.ParseContext;
import ai.vespa.schemals.index.Symbol;
import ai.vespa.schemals.index.Symbol.SymbolStatus;
import ai.vespa.schemals.index.Symbol.SymbolType;
import ai.vespa.schemals.parser.ast.STRUCT_FIELD;
import ai.vespa.schemals.parser.ast.fieldBodyElm;
import ai.vespa.schemals.parser.ast.identifierStr;
import ai.vespa.schemals.parser.ast.structFieldBodyElm;
import ai.vespa.schemals.parser.ast.structFieldElm;
import ai.vespa.schemals.tree.Node;
import ai.vespa.schemals.tree.SchemaNode;

/**
 * StructFieldDefinitionResolver
 * Finds struct-field declarations and turns them into definitions of fields
 */
public class StructFieldDefinitionResolver {
    public static List resolve(ParseContext context, SchemaNode CST) {
        List diagnostics = new ArrayList<>();
        traverse(context, CST, diagnostics);
        return diagnostics;
    }

    private static void traverse(ParseContext context, SchemaNode node, List diagnostics) {
        if (node.getParent() != null && node.isASTInstance(identifierStr.class) && node.getParent().getASTClass() == structFieldElm.class) {
            handleStructField(context, node, diagnostics);
        }
        for (Node child : node) {
            traverse(context, child.getSchemaNode(), diagnostics);
        }
    }

    private static void handleStructField(ParseContext context, SchemaNode node, List diagnostics) {
        Node prev = node.getPreviousSibling();
        if (prev.getASTClass() == STRUCT_FIELD.class) {
            Node enclosingBodyNode = node.getParent().getParent();

            if (enclosingBodyNode.getASTClass() == fieldBodyElm.class) {
                // struct-field declared inside field
                Node fieldIdentifierNode = enclosingBodyNode.getParent().get(1);

                if (!fieldIdentifierNode.hasSymbol() || fieldIdentifierNode.getSymbol().getStatus() != SymbolStatus.DEFINITION) return;
                Optional subfieldInParent = SymbolReferenceResolver.resolveSubFieldReference(node, fieldIdentifierNode.getSymbol(), context, diagnostics);

                if (subfieldInParent.isEmpty()) return;

                Symbol scope = fieldIdentifierNode.getSymbol();
                createStructFieldDefinition(context, scope, node, subfieldInParent.get());
            } else if (enclosingBodyNode.getASTClass() == structFieldBodyElm.class) {
                // nested struct-field
                // the referred field definition is the last component in the struct-field identifier
                Node lastStructFieldIdentifier = enclosingBodyNode.getParent().get(1);
                while (lastStructFieldIdentifier.getNextSibling() != null && lastStructFieldIdentifier.getNextSibling().getASTClass() == identifierStr.class) {
                    lastStructFieldIdentifier = lastStructFieldIdentifier.getNextSibling();
                }
                if (!lastStructFieldIdentifier.hasSymbol() || lastStructFieldIdentifier.getSymbol().getStatus() != SymbolStatus.DEFINITION) return;

                Optional referredParentFieldDefinition = context.schemaIndex().getFirstSymbolDefinition(lastStructFieldIdentifier.getSymbol());

                if (referredParentFieldDefinition.isEmpty()) return;

                Optional subfieldInParent = SymbolReferenceResolver.resolveSubFieldReference(node, referredParentFieldDefinition.get(), context, diagnostics);

                if (subfieldInParent.isEmpty()) return;

                Symbol scope = lastStructFieldIdentifier.getSymbol();
                createStructFieldDefinition(context, scope, node, subfieldInParent.get());

            }
        } else if (prev.hasSymbol() && prev.getSymbol().getStatus() == SymbolStatus.DEFINITION) {
            // Assume we are in a struct-field statement
            Optional referredParentFieldDefinition = context.schemaIndex().getFirstSymbolDefinition(prev.getSymbol());

            if (referredParentFieldDefinition.isEmpty()) return;

            Optional subfieldInParent = SymbolReferenceResolver.resolveSubFieldReference(node, referredParentFieldDefinition.get(), context, diagnostics);

            if (subfieldInParent.isEmpty()) return;

            Symbol scope = prev.getSymbol();
            createStructFieldDefinition(context, scope, node, subfieldInParent.get());
        }
    }

    private static void createStructFieldDefinition(ParseContext context, Symbol scope, SchemaNode node, Symbol referenceToField) {
        node.setSymbolStatus(SymbolStatus.DEFINITION);
        node.setSymbolType(SymbolType.FIELD);
        node.setSymbolScope(scope);
        context.schemaIndex().insertSymbolDefinition(node.getSymbol());
        context.schemaIndex().insertSymbolReference(referenceToField, node.getSymbol());
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy