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

org.snapscript.core.type.TypeTraverser Maven / Gradle / Ivy

package org.snapscript.core.type;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import org.snapscript.core.EntityCache;
import org.snapscript.core.constraint.Constraint;
import org.snapscript.core.error.InternalStateException;
import org.snapscript.core.module.Module;
import org.snapscript.core.scope.Scope;

public class TypeTraverser {
   
   private final EntityCache> types;
   
   public TypeTraverser() {
      this.types = new EntityCache>();
   }   

   public Set findHierarchy(Type type) {
      Set list = types.fetch(type);
      
      if(list == null) {
         list = findHierarchy(type, type);
         types.cache(type, list);
      }
      return list;
   }
   
   private Set findHierarchy(Type root, Type type) {
      Set list = new LinkedHashSet();
      
      if(type != null) {
         findHierarchy(root, type, list);
      }
      return Collections.unmodifiableSet(list);
   }
   
   private Set findHierarchy(Type root, Type type, Set list) {
      List types = type.getTypes();
      Scope scope = type.getScope();
      
      if(list.add(type)) {
         for(Constraint entry : types) {
            Type match = entry.getType(scope);
            
            if(match == root) { 
               throw new InternalStateException("Hierarchy for '" + type + "' contains a cycle");
            }
            findHierarchy(root, match, list);
         }
      }
      return list;
   }
   
   public Type findEnclosing(Type type, String name) {
      Set done = new LinkedHashSet();
      
      if(type != null) {
         return findEnclosing(type, name, done);
      }
      return null;
   }
   
   private Type findEnclosing(Type type, String name, Set done) {
      Module module = type.getModule();
      
      while(type != null){ // search outer classes
         String prefix = type.getName();
         Type result = module.getType(prefix + "$"+name);
         
         if(result == null) {
            result = findHierarchy(type, name, done);
         }
         if(result != null) {
            return result;
         }
         type = type.getOuter();
      }
      return null;
   }
   
   private Type findHierarchy(Type type, String name, Set done) {
      List types = type.getTypes(); // do not use extractor here
      Scope scope = type.getScope();
      
      for(Constraint base : types) {
         Type match = base.getType(scope);
         
         if(done.add(match)) { // avoid loop
            Type result = findEnclosing(match, name, done);
            
            if(result != null) {
               return result;
            }
         }
      }
      return null;
   }
   
   public List findPath(Type constraint, Type require) {
      List path = new ArrayList();

      findPath(constraint, require, path);
      Collections.reverse(path);
      
      return path;
   }
   
   public boolean findPath(Type constraint, Type require, List path) {
      Scope scope = require.getScope();
      
      if(constraint != require) {
         List types = constraint.getTypes();
         
         for(Constraint base : types) {
            Type next = base.getType(scope);
            
            if(findPath(next, require, path)) {
               path.add(base);
               return true;
            }
         }
         return false;
      }
      return true;
   }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy