package me.tomassetti.turin.parser.ast.expressions; import com.google.common.collect.ImmutableList; import me.tomassetti.turin.compiler.errorhandling.ErrorCollector; import me.tomassetti.jvm.JvmMethodDefinition; import me.tomassetti.jvm.JvmType; import me.tomassetti.turin.parser.analysis.exceptions.UnsolvedSymbolException; import me.tomassetti.turin.resolvers.SymbolResolver; import me.tomassetti.turin.parser.ast.invokables.FunctionDefinitionNode; import me.tomassetti.turin.parser.ast.Node; import me.tomassetti.turin.parser.ast.typeusage.TypeUsageNode; import me.tomassetti.turin.symbols.FormalParameter; import me.tomassetti.turin.symbols.Symbol; import me.tomassetti.turin.typesystem.TypeUsage; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; public class ValueReference extends Expression { private String name; private TypeUsageNode precalculatedType; public ValueReference(String name) { this.name = name; } public ValueReference(String name, TypeUsageNode precalculatedType) { this.name = name; this.precalculatedType = precalculatedType; // parent not set on-purpose } @Override public JvmMethodDefinition findMethodFor(List<ActualParam> actualParams, SymbolResolver resolver, boolean staticContext) { List<JvmType> argsTypes = actualParams.stream().map((ap)->ap.getValue().calcType().jvmType()).collect(Collectors.toList()); Optional<Symbol> declaration = resolver.findSymbol(name, this); if (declaration.isPresent()) { if (declaration.get() instanceof Expression) { return ((Expression) declaration.get()).findMethodFor(actualParams, resolver, staticContext); } else if (declaration.get() instanceof FunctionDefinitionNode) { FunctionDefinitionNode functionDefinition = (FunctionDefinitionNode)declaration.get(); if (functionDefinition.match(argsTypes, resolver)) { return functionDefinition.jvmMethodDefinition(resolver); } else { throw new IllegalArgumentException(); } } else { throw new UnsupportedOperationException(declaration.get().getClass().getCanonicalName()); } } else { throw new UnsolvedSymbolException(this); } } @Override public Optional<List<? extends FormalParameter>> findFormalParametersFor(InvokableExpr invokable) { return resolve(symbolResolver()).findFormalParametersFor(invokable); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; ValueReference that = (ValueReference) o; if (!name.equals(that.name)) return false; return true; } public String getName() { return name; } @Override public int hashCode() { return name.hashCode(); } @Override public String toString() { return "ValueReference{" + "name='" + name + '\'' + '}'; } @Override public Symbol getField(String fieldName) { return resolve(symbolResolver()).getField(fieldName); } @Override public TypeUsage calcType() { if (precalculatedType != null) { return precalculatedType; } Optional<Symbol> declaration = symbolResolver().findSymbol(name, this); if (declaration.isPresent()) { return declaration.get().calcType(); } else { throw new UnsolvedSymbolException(this); } } @Override protected boolean specificValidate(SymbolResolver resolver, ErrorCollector errorCollector) { try { resolve(resolver); } catch (UnsolvedSymbolException e) { errorCollector.recordSemanticError(getPosition(), "Symbol not found: " + e.getMessage()); } return super.specificValidate(resolver, errorCollector); } @Override public Iterable<Node> getChildren() { return ImmutableList.of(); } private Symbol cache; public Symbol resolve(SymbolResolver resolver) { if (cache != null) { return cache; } Optional<Symbol> declaration = resolver.findSymbol(name, this); if (declaration.isPresent()) { if (!(declaration.get() instanceof Symbol)) { throw new UnsupportedOperationException(); } cache = (Symbol)declaration.get(); return cache; } else { throw new UnsolvedSymbolException(this); } } }