package compiler.language.translator.conceptual;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.util.List;

import compiler.language.ast.topLevel.CompilationUnitAST;
import compiler.language.conceptual.ConceptualException;
import compiler.language.conceptual.NameConflictException;
import compiler.language.conceptual.QName;
import compiler.language.conceptual.Resolvable;
import compiler.language.conceptual.UnresolvableException;
import compiler.language.conceptual.topLevel.ConceptualFile;
import compiler.language.conceptual.topLevel.ConceptualPackage;
import compiler.language.parser.LanguageParser;
import compiler.language.parser.LanguageTokenizer;

/*
 * Created on 14 Nov 2010
 */

/**
 * @author Anthony Bryant
 */
public class ConceptualTranslator
{

  private LanguageParser parser;
  private ConceptualPackage rootPackage;
  private ASTConverter astConverter;
  private NameResolver nameResolver;

  /**
   * Creates a new ConceptualTranslator to parse and convert files to the conceptual hierarchy.
   * @param parser - the LanguageParser to use to parse files
   * @param classpath - the classpath for this translator
   */
  public ConceptualTranslator(LanguageParser parser, List<File> classpath)
  {
    this.parser = parser;
    rootPackage = new ConceptualPackage(this, classpath);
    astConverter = new ASTConverter(rootPackage);
    nameResolver = new NameResolver(astConverter.getConceptualASTNodes());
    nameResolver.initialize(rootPackage);
  }

  /**
   * Translates the files which have been parsed into the conceptual representation.
   * @throws NameConflictException - if a name conflict was detected
   * @throws ConceptualException - if a conceptual problem was detected during the translation
   */
  public void translate() throws NameConflictException, ConceptualException
  {
    nameResolver.resolveParents();
  }

  /**
   * Resolves the specified QName on the root package
   * @param name - the name to resolve
   * @return the Resolvable resolved
   * @throws NameConflictException - if a name conflict was detected
   * @throws UnresolvableException - if the name is not resolvable without more information
   */
  public Resolvable translate(QName name) throws NameConflictException, UnresolvableException
  {
    return rootPackage.resolve(name, false);
  }

  /**
   * Attempts to parse the specified file into a conceptual file. If something fails in the process, an error is printed before returning null.
   * If a file is correctly parsed and converted into a ConceptualFile, it is also added to the NameResolver.
   * @param file - the file to parse
   * @param expectedPackage - the package that the file is expected to be in, which should be checked against the package declaration inside it
   * @return the ConceptualFile parsed, or null if an error occurred
   */
  public ConceptualFile parseFile(File file, ConceptualPackage expectedPackage)
  {
    CompilationUnitAST ast;
    try
    {
      FileReader reader = new FileReader(file);
      LanguageTokenizer tokenizer = new LanguageTokenizer(reader);
      ast = parser.parse(tokenizer);
    }
    catch (FileNotFoundException e)
    {
      e.printStackTrace();
      return null;
    }

    try
    {
      ConceptualFile conceptualFile = astConverter.convert(file, ast, expectedPackage);
      nameResolver.addFile(conceptualFile);
      return conceptualFile;
    }
    catch (ConceptualException e)
    {
      e.printStackTrace();
      return null;
    }
    catch (NameConflictException e)
    {
      e.printStackTrace();
      return null;
    }
  }

}

@@ -153,16 +153,56 @@
 .List;%0A%0A
+import compiler.language.ast.ParseInfo;%0A
 import c
@@ -3513,34 +3513,73 @@
 %7B%0A      
-e.
 print
-StackTrace(
+ConceptualException(e.getMessage(), e.getParseInfo()
 );%0A     
@@ -3650,46 +3650,1461 @@
     
-e.printStackTrace();%0A      return null
+printConceptualException(e.getMessage() == null ? %22Name conflict detected%22 : e.getMessage(), e.getParseInfo());%0A      return null;%0A    %7D%0A  %7D%0A%0A  private static void printConceptualException(String message, ParseInfo... parseInfos)%0A  %7B%0A    if (parseInfos == null %7C%7C parseInfos.length %3C 1)%0A    %7B%0A      System.err.println(message);%0A      return;%0A    %7D%0A    // make a String representation of the ParseInfos' character ranges%0A    StringBuffer buffer = new StringBuffer();%0A    for (int i = 0; i %3C parseInfos.length; i++)%0A    %7B%0A      String characterRange;%0A      int startLine = parseInfos%5Bi%5D.getStartLine();%0A      int endLine = parseInfos%5Bi%5D.getEndLine();%0A      if (startLine == endLine)%0A      %7B%0A        // line:start-end if it is all on one line%0A        characterRange = startLine + %22:%22;%0A        int startPos = parseInfos%5Bi%5D.getStartPos();%0A        int endPos = parseInfos%5Bi%5D.getEndPos();%0A        characterRange += startPos;%0A        if (startPos %3C endPos - 1)%0A        %7B%0A          characterRange += %22-%22 + (endPos - 1);%0A        %7D%0A      %7D%0A      else%0A      %7B%0A        // startLine-endLine if it spans multiple lines%0A        characterRange = startLine + %22-%22 + endLine;%0A      %7D%0A      buffer.append(characterRange);%0A      if (i != parseInfos.length - 1)%0A      %7B%0A        buffer.append(%22, %22);%0A      %7D%0A    %7D%0A    if (parseInfos.length == 1)%0A    %7B%0A      System.err.println(message + %22: %22 + buffer);%0A    %7D%0A    else%0A    %7B%0A      System.err.println(message + %22%5CnAt: %22 + buffer)
 ;%0A  

Improve conceptual exception reporting