package me.tomassetti.turin.parser.ast; import com.google.common.collect.ImmutableList; import me.tomassetti.turin.compiler.errorhandling.ErrorCollector; import me.tomassetti.turin.definitions.TypeDefinition; import me.tomassetti.turin.parser.ast.context.ContextDefinitionNode; import me.tomassetti.turin.resolvers.SymbolResolver; import me.tomassetti.turin.parser.ast.imports.ImportDeclaration; import me.tomassetti.turin.parser.ast.invokables.FunctionDefinitionNode; import me.tomassetti.turin.parser.ast.properties.PropertyDefinition; import me.tomassetti.turin.parser.ast.relations.RelationDefinition; import me.tomassetti.turin.symbols.Symbol; import java.util.*; import java.util.stream.Collectors; public class TurinFile extends Node { private NamespaceDefinition namespaceDefinition; private List<Node> topNodes = new ArrayList<>(); private List<ImportDeclaration> imports = new ArrayList<>(); private ContextDefinitionNode[] topLevelContextDefinitions; public void add(PropertyDefinition propertyDefinition) { topNodes.add(propertyDefinition); propertyDefinition.parent = this; } @Override protected boolean specificValidate(SymbolResolver resolver, ErrorCollector errorCollector) { boolean valid = true; Map<String, List<Position>> positions = new HashMap<>(); for (Node topNode : topNodes) { if (topNode instanceof Named) { Named named = (Named)topNode; if (positions.containsKey(named.getName())) { positions.get(named.getName()).add(topNode.getPosition()); List<String> positionsAsStrings = positions.get(named.getName()).stream().map((p)->p.toString()).collect(Collectors.toList()); errorCollector.recordSemanticError(topNode.getPosition(), "Duplicate name \"" + named.getName() + "\" appearing at " + String.join(", ", positionsAsStrings)); valid = false; } else { List<Position> ps = new ArrayList<>(); ps.add(topNode.getPosition()); positions.put(named.getName(), ps); } } } return valid && super.specificValidate(resolver, errorCollector); } public void add(ImportDeclaration importDeclaration) { imports.add(importDeclaration); importDeclaration.parent = this; } public NamespaceDefinition getNamespaceDefinition() { return namespaceDefinition; } public void add(TurinTypeDefinition typeDefinition) { topNodes.add(typeDefinition); typeDefinition.parent = this; } @Override public String toString() { return "TurinFile{" + "namespaceDefinition=" + namespaceDefinition + ", topNodes=" + topNodes + '}'; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TurinFile turinFile = (TurinFile) o; if (!namespaceDefinition.equals(turinFile.namespaceDefinition)) return false; if (!topNodes.equals(turinFile.topNodes)) return false; return true; } @Override public int hashCode() { int result = namespaceDefinition.hashCode(); result = 31 * result + topNodes.hashCode(); return result; } public ImmutableList<Node> getNodes() { return ImmutableList.copyOf(topNodes); } public void setNameSpace(NamespaceDefinition namespaceDefinition) { if (this.namespaceDefinition != null) { this.namespaceDefinition.parent = null; } this.namespaceDefinition = namespaceDefinition; this.namespaceDefinition.parent = this; } @Override public Iterable<Node> getChildren() { return ImmutableList.<Node>builder().add(namespaceDefinition).addAll(topNodes).addAll(imports).build(); } public Optional<TurinTypeDefinition> getTopTypeDefinition(String name) { Optional<Node> res = topNodes.stream().filter((n)-> (n instanceof TurinTypeDefinition) && ((TurinTypeDefinition)n).getName().equals(name)).findFirst(); if (res.isPresent()) { return Optional.of((TurinTypeDefinition)res.get()); } else { return Optional.empty(); } } public void add(Program program) { topNodes.add(program); program.parent = this; } public List<TurinTypeDefinition> getTopLevelTypeDefinitions() { return topNodes.stream().filter((n)-> (n instanceof TurinTypeDefinition)).map((n) -> (TurinTypeDefinition)n).collect(Collectors.toList()); } public List<FunctionDefinitionNode> getTopLevelFunctionDefinitions() { return topNodes.stream().filter((n)-> (n instanceof FunctionDefinitionNode)).map((n) -> (FunctionDefinitionNode)n).collect(Collectors.toList()); } public List<PropertyDefinition> getTopLevelPropertyDefinitions() { return topNodes.stream().filter((n)-> (n instanceof PropertyDefinition)).map((n) -> (PropertyDefinition)n).collect(Collectors.toList()); } public List<Program> getTopLevelPrograms() { return topNodes.stream().filter((n)-> (n instanceof Program)).map((n) -> (Program)n).collect(Collectors.toList()); } @Override public Optional<Symbol> findSymbol(String name, SymbolResolver resolver) { for (ImportDeclaration importDeclaration : imports) { Optional<Symbol> imported = importDeclaration.findAmongImported(name, resolver); if (imported.isPresent()) { return Optional.of(imported.get()); } } for (FunctionDefinitionNode functionDefinition : getTopLevelFunctionDefinitions()) { if (functionDefinition.getName().equals(name)) { return Optional.of(functionDefinition); } } for (PropertyDefinition propertyDefinition : getTopLevelPropertyDefinitions()) { if (propertyDefinition.getName().equals(name)) { return Optional.of(propertyDefinition); } } for (Program program : getTopLevelPrograms()) { if (program.getName().equals(name)) { return Optional.of(program); } } for (TypeDefinition typeDefinition : getTopLevelTypeDefinitions()) { if (typeDefinition.getName().equals(name)) { return Optional.of(typeDefinition); } } String qName = namespaceDefinition.getName() + "." + name; return resolver.getRoot().findSymbol(qName, null); } public void add(FunctionDefinitionNode functionDefinition) { topNodes.add(functionDefinition); functionDefinition.parent = this; } public void add(RelationDefinition relationDefinition) { topNodes.add(relationDefinition); relationDefinition.parent = this; } public void add(ContextDefinitionNode contextDefinition) { topNodes.add(contextDefinition); contextDefinition.parent = this; } public List<ContextDefinitionNode> getTopLevelContextDefinitions() { return topNodes.stream().filter((n)-> (n instanceof ContextDefinitionNode)).map((n) -> (ContextDefinitionNode)n).collect(Collectors.toList()); } }