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.UnsolvedMethodException;
import me.tomassetti.turin.parser.ast.*;
import me.tomassetti.turin.parser.ast.context.ContextDefinitionNode;
import me.tomassetti.turin.parser.ast.expressions.FunctionCall;
import me.tomassetti.turin.parser.ast.invokables.FunctionDefinitionNode;
import me.tomassetti.turin.parser.ast.properties.PropertyDefinition;
import me.tomassetti.turin.parser.ast.properties.PropertyReference;
import me.tomassetti.turin.symbols.Symbol;
import me.tomassetti.turin.typesystem.ReferenceTypeUsage;
import me.tomassetti.turin.typesystem.TypeUsage;
import java.util.*;
/**
* Solve symbols considering TurinFiles.
*/
public class SrcSymbolResolver implements SymbolResolver {
private Set<String> packages = new HashSet<>();
private Map<String, TypeDefinition> typeDefinitions;
private Map<String, PropertyDefinition> propertyDefinitions;
private Map<String, Program> programsDefinitions;
private Map<String, FunctionDefinitionNode> functionDefinitions;
private Map<String, ContextDefinitionNode> contextDefinitions;
private SymbolResolver parent = null;
@Override
public SymbolResolver getParent() {
return parent;
}
@Override
public void setParent(SymbolResolver parent) {
this.parent = parent;
}
public SrcSymbolResolver(List<TurinFile> turinFiles) {
this.typeDefinitions = new HashMap<>();
this.propertyDefinitions = new HashMap<>();
this.programsDefinitions = new HashMap<>();
this.functionDefinitions = new HashMap<>();
this.contextDefinitions = new HashMap<>();
for (TurinFile turinFile : turinFiles) {
for (TypeDefinitionNode typeDefinition : turinFile.getTopLevelTypeDefinitions()) {
packages.add(typeDefinition.contextName());
typeDefinitions.put(typeDefinition.getQualifiedName(), typeDefinition);
}
for (PropertyDefinition propertyDefinition : turinFile.getTopLevelPropertyDefinitions()) {
packages.add(propertyDefinition.contextName());
propertyDefinitions.put(propertyDefinition.getQualifiedName(), propertyDefinition);
}
for (Program program : turinFile.getTopLevelPrograms()) {
packages.add(program.contextName());
programsDefinitions.put(program.getQualifiedName(), program);
}
for (FunctionDefinitionNode functionDefinition : turinFile.getTopLevelFunctionDefinitions()) {
packages.add(functionDefinition.contextName());
functionDefinitions.put(functionDefinition.getQualifiedName(), functionDefinition);
}
for (ContextDefinitionNode contextDefinition : turinFile.getTopLevelContextDefinitions()) {
packages.add(contextDefinition.contextName());
contextDefinitions.put(contextDefinition.getQualifiedName(), contextDefinition);
}
}
}
@Override
public Optional<PropertyDefinition> findDefinition(PropertyReference propertyReference) {
String name = propertyReference.contextName() + "." + propertyReference.getName();
if (propertyDefinitions.containsKey(name)) {
return Optional.of(propertyDefinitions.get(name));
} else {
return Optional.empty();
}
}
@Override
public Optional<TypeDefinition> findTypeDefinitionIn(String typeName, Node context, SymbolResolver resolver) {
if (typeDefinitions.containsKey(typeName)) {
return Optional.of(typeDefinitions.get(typeName));
} else {
return Optional.empty();
}
}
@Override
public Optional<TypeUsage> findTypeUsageIn(String typeName, Node context, SymbolResolver resolver) {
if (typeDefinitions.containsKey(typeName)) {
return Optional.of(new ReferenceTypeUsage(typeDefinitions.get(typeName)));
} else {
return Optional.empty();
}
}
@Override
public Optional<JvmMethodDefinition> findJvmDefinition(FunctionCall functionCall) {
throw new UnsolvedMethodException(functionCall);
}
@Override
public Optional<Symbol> findSymbol(String name, Node context) {
// TODO consider also static fields and methods
if (typeDefinitions.containsKey(name)) {
return Optional.of(typeDefinitions.get(name));
} else if (propertyDefinitions.containsKey(name)) {
return Optional.of(propertyDefinitions.get(name));
} else if (functionDefinitions.containsKey(name)) {
return Optional.of(functionDefinitions.get(name));
} else if (programsDefinitions.containsKey(name)) {
return Optional.of(programsDefinitions.get(name));
} else {
return Optional.empty();
}
}
@Override
public boolean existPackage(String packageName) {
return packages.contains(packageName);
}
@Override
public Optional<ContextDefinition> findContextSymbol(String contextName, Node context) {
if (contextDefinitions.containsKey(contextName)) {
return Optional.of(contextDefinitions.get(contextName));
} else {
return Optional.empty();
}
}
}