/**
   * Initializes the CompilationUnit with a CodeSource for controlling security stuff, a class
   * loader for loading classes, and a class loader for loading AST transformations. <b>Note</b> The
   * transform loader must be able to load compiler classes. That means
   * CompilationUnit.class.classLoader must be at last a parent to transformLoader. The other loader
   * has no such constraint.
   *
   * @param transformLoader - the loader for transforms
   * @param loader - loader used to resolve classes against during compilation
   * @param security - security setting for the compilation
   * @param configuration - compilation configuration
   */
  public CompilationUnit(
      CompilerConfiguration configuration,
      CodeSource security,
      GroovyClassLoader loader,
      GroovyClassLoader transformLoader,
      boolean allowTransforms,
      String localTransformsToRunOnReconcile) {
    super(configuration, loader, null);

    // GRECLISE start
    this.allowTransforms = allowTransforms;
    // GRECLISE end
    this.astTransformationsContext = new ASTTransformationsContext(this, transformLoader);
    this.names = new ArrayList<String>();
    this.queuedSources = new LinkedList<SourceUnit>();
    this.sources = new HashMap<String, SourceUnit>();
    this.summariesBySourceName = new HashMap();
    this.summariesByPublicClassName = new HashMap();
    this.classSourcesByPublicClassName = new HashMap();

    this.ast = new CompileUnit(this.classLoader, security, this.configuration);
    this.generatedClasses = new ArrayList<GroovyClass>();

    this.verifier = new Verifier();
    this.resolveVisitor = new ResolveVisitor(this);
    this.staticImportVisitor = new StaticImportVisitor();
    this.optimizer = new OptimizerVisitor(this);
    // GRECLIPSE start
    if (localTransformsToRunOnReconcile == null) {
      this.localTransformsToRunOnReconcile = new ArrayList<String>(); // Collections.emptyList();
      this.localTransformsToRunOnReconcile.add("*");
    } else {
      this.localTransformsToRunOnReconcile = new ArrayList<String>();
      try {
        StringTokenizer st = new StringTokenizer(localTransformsToRunOnReconcile, ",");
        while (st.hasMoreElements()) {
          String classname = st.nextToken();
          this.localTransformsToRunOnReconcile.add(classname);
        }
      } catch (Exception e) {
        // presumed security exception
      }
    }
    // GRECLIPSE end

    phaseOperations = new LinkedList[Phases.ALL + 1];
    newPhaseOperations = new LinkedList[Phases.ALL + 1];
    for (int i = 0; i < phaseOperations.length; i++) {
      phaseOperations[i] = new LinkedList();
      newPhaseOperations[i] = new LinkedList();
    }
    addPhaseOperation(
        new SourceUnitOperation() {
          public void call(SourceUnit source) throws CompilationFailedException {
            source.parse();
          }
        },
        Phases.PARSING);
    addPhaseOperation(convert, Phases.CONVERSION);
    addPhaseOperation(
        new PrimaryClassNodeOperation() {
          public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
              throws CompilationFailedException {
            EnumVisitor ev = new EnumVisitor(CompilationUnit.this, source);
            ev.visitClass(classNode);
          }
        },
        Phases.CONVERSION);
    addPhaseOperation(resolve, Phases.SEMANTIC_ANALYSIS);
    addPhaseOperation(staticImport, Phases.SEMANTIC_ANALYSIS);
    addPhaseOperation(
        new PrimaryClassNodeOperation() {
          @Override
          public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
              throws CompilationFailedException {
            InnerClassVisitor iv = new InnerClassVisitor(CompilationUnit.this, source);
            iv.visitClass(classNode);
          }
        },
        Phases.SEMANTIC_ANALYSIS);
    addPhaseOperation(compileCompleteCheck, Phases.CANONICALIZATION);
    addPhaseOperation(classgen, Phases.CLASS_GENERATION);
    // GRECLIPSE: start: skip output phase
    // addPhaseOperation(output);

    addPhaseOperation(
        new PrimaryClassNodeOperation() {
          @Override
          public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
              throws CompilationFailedException {
            AnnotationCollectorTransform.ClassChanger actt =
                new AnnotationCollectorTransform.ClassChanger();
            actt.transformClass(classNode);
          }
        },
        Phases.SEMANTIC_ANALYSIS);
    ASTTransformationVisitor.addPhaseOperations(this);
    addPhaseOperation(
        new PrimaryClassNodeOperation() {
          @Override
          public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
              throws CompilationFailedException {
            StaticVerifier sv = new StaticVerifier();
            sv.visitClass(classNode, source);
          }
        },
        Phases.SEMANTIC_ANALYSIS);
    addPhaseOperation(
        new PrimaryClassNodeOperation() {
          @Override
          public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
              throws CompilationFailedException {
            InnerClassCompletionVisitor iv =
                new InnerClassCompletionVisitor(CompilationUnit.this, source);
            iv.visitClass(classNode);
          }
        },
        Phases.CANONICALIZATION);
    addPhaseOperation(
        new PrimaryClassNodeOperation() {
          public void call(SourceUnit source, GeneratorContext context, ClassNode classNode)
              throws CompilationFailedException {
            EnumCompletionVisitor ecv = new EnumCompletionVisitor(CompilationUnit.this, source);
            ecv.visitClass(classNode);
          }
        },
        Phases.CANONICALIZATION);

    // apply configuration customizers if any
    if (configuration != null) {
      final List<CompilationCustomizer> customizers = configuration.getCompilationCustomizers();
      for (CompilationCustomizer customizer : customizers) {
        addPhaseOperation(customizer, customizer.getPhase().getPhaseNumber());
      }
    }
    this.classgenCallback = null;
    this.classNodeResolver = new ClassNodeResolver();
  }