package me.tomassetti.turin.resolvers;
import me.tomassetti.jvm.JvmMethodDefinition;
import me.tomassetti.turin.definitions.ContextDefinition;
import me.tomassetti.turin.definitions.TypeDefinition;
import me.tomassetti.turin.parser.analysis.exceptions.UnsolvedSymbolException;
import me.tomassetti.turin.parser.ast.Node;
import me.tomassetti.turin.parser.ast.properties.PropertyDefinition;
import me.tomassetti.turin.parser.ast.properties.PropertyReference;
import me.tomassetti.turin.parser.ast.expressions.FunctionCall;
import me.tomassetti.turin.symbols.Symbol;
import me.tomassetti.turin.typesystem.TypeUsage;
import java.util.Optional;
/**
* Resolve symbols potentially consider the local context.
*/
public interface SymbolResolver {
///
/// Hierarchy navigation
///
public SymbolResolver getParent();
public void setParent(SymbolResolver parent);
public default SymbolResolver getRoot() {
if (getParent() == null) {
return this;
} else {
return getParent().getRoot();
}
}
/**
* Given a PropertyReference it finds the corresponding declaration.
*/
Optional<PropertyDefinition> findDefinition(PropertyReference propertyReference);
/**
* Find the TypeDefinition corresponding to the given name in the given context.
*
* @param typeName can be a simple name or a canonical name. Note that is not legal to pass a primitive type name
* because it is not a valid identifier and there are no TypeDefinition associated
*/
default TypeDefinition getTypeDefinitionIn(String typeName, Node context) {
SymbolResolver resolver = ResolverRegistry.INSTANCE.requireResolver(context);
Optional<TypeDefinition> result = findTypeDefinitionIn(typeName, context, resolver.getRoot());
if (result.isPresent()) {
return result.get();
} else {
throw new UnsolvedSymbolException(context, typeName);
}
}
/**
* @param typeName can be a simple name or a canonical name. Note that is not legal to pass a primitive type name
* because it is not a valid identifier and there are no TypeDefinition associated
* @param resolver top level resolver used during compilation. This is needed because this resolver could delegate
* to that one during the resolution process.
*/
Optional<TypeDefinition> findTypeDefinitionIn(String typeName, Node context, SymbolResolver resolver);
/**
* @param typeName can be a simple name or a canonical name. It is legal to pass a primitive type name.
* @param resolver top level resolver used during compilation. This is needed because this resolver could delegate
* to that one during the resolution process.
*/
Optional<TypeUsage> findTypeUsageIn(String typeName, Node context, SymbolResolver resolver);
/**
* Find the JVM method corresponding to this function call.
*/
Optional<JvmMethodDefinition> findJvmDefinition(FunctionCall functionCall);
/**
* Find whatever Node is corresponding to the given name in the given context.
*/
Optional<Symbol> findSymbol(String name, Node context);
boolean existPackage(String packageName);
Optional<ContextDefinition> findContextSymbol(String contextName, Node context);
}