Summarizer.java

package edu.udel.cis.vsl.abc.main;

import java.io.PrintStream;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;

import edu.udel.cis.vsl.abc.ast.IF.AST;
import edu.udel.cis.vsl.abc.ast.entity.IF.Entity;
import edu.udel.cis.vsl.abc.ast.entity.IF.ProgramEntity;
import edu.udel.cis.vsl.abc.ast.node.IF.IdentifierNode;
import edu.udel.cis.vsl.abc.ast.node.IF.SequenceNode;
import edu.udel.cis.vsl.abc.ast.node.IF.declaration.DeclarationNode;
import edu.udel.cis.vsl.abc.ast.node.IF.statement.BlockItemNode;
import edu.udel.cis.vsl.abc.token.IF.CivlcToken;
import edu.udel.cis.vsl.abc.token.IF.Formation;
import edu.udel.cis.vsl.abc.token.IF.Inclusion;
import edu.udel.cis.vsl.abc.token.IF.Source;
import edu.udel.cis.vsl.abc.token.IF.SourceFile;

/**
 * Summarizes the source files and entities defined in an AST.
 * 
 * Iterate over all source files, and for each, the entities declared or defined
 * in that file that are needed.
 * 
 * Iterate over all external defns in the AST. For each, record sourcefile of
 * the decl or defn.
 * 
 * Map: sourceFile -> Set of entity
 * 
 * If A includes B and entity is defined in B...?
 * 
 * Iterate over all tokens and accumulate the last source file (i.e., B, the
 * file immediately containing the token) and the external defn in which that
 * token occurs, if any
 * 
 * Alternative: iterate over leaf AST nodes only, get the source, iterate over
 * tokens
 * 
 * for each token : get file and containing external def
 * 
 * alternative: if A includes B includes C and token occurs in C with source
 * (A->B->C) then add A, B, and C to set
 * 
 * print the map.
 * 
 * Iterate over all external defs. For each: get the Entity it is declaring or
 * defining (if any). Look at source of identifier. process as above
 * 
 * @author siegel
 *
 */
public class Summarizer {

	private Map<SourceFile, Set<Entity>> fileMap = new TreeMap<>();

	private AST ast;

	Set<Entity> allEntities = new HashSet<>();

	public Summarizer(AST ast) {
		this.ast = ast;
		analyze();
	}

	private void getFilesOf(CivlcToken token, Collection<SourceFile> files) {
		Formation formation = token.getFormation();
		SourceFile sourceFile = formation.getLastFile();

		files.add(sourceFile);
		if (formation instanceof Inclusion) {
			CivlcToken includeToken = ((Inclusion) formation).getIncludeToken();

			if (includeToken != null)
				getFilesOf(includeToken, files);
		}
	}

	@SuppressWarnings("unused")
	private Collection<SourceFile> getFilesOf(CivlcToken token) {
		HashSet<SourceFile> sourceFiles = new HashSet<>();

		getFilesOf(token, sourceFiles);
		return sourceFiles;
	}

	private void add(SourceFile sourceFile, Entity entity) {
		Set<Entity> set = fileMap.get(sourceFile);

		if (set == null) {
			set = new HashSet<Entity>();
			fileMap.put(sourceFile, set);
		}
		set.add(entity);
	}

	private void analyze() {
		SequenceNode<BlockItemNode> root = ast.getRootNode();

		for (BlockItemNode itemNode : root) {
			if (itemNode instanceof DeclarationNode) {
				DeclarationNode decl = (DeclarationNode) itemNode;
				Entity entity = decl.getEntity();

				if (entity instanceof ProgramEntity) {
					DeclarationNode defnNode = ((ProgramEntity) entity)
							.getDefinition();

					// don't list declarations that are not defns
					if (defnNode != null && defnNode != itemNode)
						continue;
				}

				IdentifierNode idNode = decl.getIdentifier();

				allEntities.add(entity);
				if (idNode != null) {
					Source source = idNode.getSource();
					CivlcToken token = source.getFirstToken();

					if (token != null) {
						SourceFile sf = token.getSourceFile();

						add(sf, entity);
						/*
						 * Collection<SourceFile> sourceFiles =
						 * getFilesOf(token); for (SourceFile sf : sourceFiles)
						 * { add(sf, entity); }
						 */
					}
				}
			}
		}
	}

	public void print(PrintStream out) {
		out.println("Required source files:");
		for (SourceFile sourceFile : fileMap.keySet()) {
			out.println(
					sourceFile.getIndexName() + "\t: " + sourceFile.getPath());
		}
		for (Entry<SourceFile, Set<Entity>> entry : fileMap.entrySet()) {
			SourceFile sourceFile = entry.getKey();

			out.println();
			out.println("Entities used from " + sourceFile.getIndexName() + ": "
					+ sourceFile.getPath() + " :");
			for (Entity entity : entry.getValue()) {
				out.println("  " + entity.getName());
			}
		}
		out.flush();
	}

}