compilationunit.java

来自「Groovy动态语言 运行在JVM中的动态语言 可以方便的处理业务逻辑变化大的业」· Java 代码 · 共 1,012 行 · 第 1/3 页

JAVA
1,012
字号
                            ClassNode cn = (ClassNode) suClassesIter.next();
                            if (!first) {
                                message.append(", ");
                            } else {
                                first=false;
                            }
                            message.append(cn.getName());                                
                        }
                    }
                    
                    getErrorCollector().addErrorAndContinue(
                            new SimpleMessage(message.toString(),CompilationUnit.this)
                    );
                    iter.remove();
                } 
            }
        }
    };
    

    /**
     * Runs classgen() on a single ClassNode.
     */
    private PrimaryClassNodeOperation classgen = new PrimaryClassNodeOperation() {
        public boolean needSortedInput() {
            return true;
        }
        public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {

        	//
            // Run the Verifier on the outer class
            //
            try {
                verifier.visitClass(classNode);
            } catch (GroovyRuntimeException rpe) {
                ASTNode node = rpe.getNode();
                getErrorCollector().addError(
                        new SyntaxException(rpe.getMessage(),null,node.getLineNumber(),node.getColumnNumber()),
                        source
                );
            }
            
            LabelVerifier lv = new LabelVerifier(source);
            lv.visitClass(classNode);

            ClassCompletionVerifier completionVerifier = new ClassCompletionVerifier(source);
            completionVerifier.visitClass(classNode);
            
            // because the class may be generated even if a error was found
            // and that class may have an invalid format we fail here if needed
            getErrorCollector().failIfErrors();
            
            //
            // Prep the generator machinery
            //
            ClassVisitor visitor = createClassVisitor();


            String sourceName = (source == null ? classNode.getModule().getDescription() : source.getName());
            // only show the file name and its extension like javac does in its stacktraces rather than the full path
            // also takes care of both \ and / depending on the host compiling environment
            if (sourceName != null)
                sourceName = sourceName.substring(Math.max(sourceName.lastIndexOf('\\'), sourceName.lastIndexOf('/')) + 1);
            ClassGenerator generator = new AsmClassGenerator(context, visitor, classLoader, sourceName);


            //
            // Run the generation and create the class (if required)
            //
            generator.visitClass(classNode);
 

            byte[] bytes = ((ClassWriter) visitor).toByteArray();
            generatedClasses.add(new GroovyClass(classNode.getName(), bytes));


            //
            // Handle any callback that's been set
            //
            if (CompilationUnit.this.classgenCallback != null) {
                classgenCallback.call(visitor, classNode);
            }


            //
            // Recurse for inner classes
            //
            LinkedList innerClasses = generator.getInnerClasses();
            while (!innerClasses.isEmpty()) {
                classgen.call(source, context, (ClassNode) innerClasses.removeFirst());
            }
        }
    };


    protected ClassVisitor createClassVisitor() {
        return new ClassWriter(true);
    }

    //---------------------------------------------------------------------------
    // PHASE HANDLING


    /**
     * Updates the phase marker on all sources.
     */
    protected void mark() throws CompilationFailedException {
        applyToSourceUnits(mark);
    }


    /**
     * Marks a single SourceUnit with the current phase,
     * if it isn't already there yet.
     */
    private SourceUnitOperation mark = new SourceUnitOperation() {
        public void call(SourceUnit source) throws CompilationFailedException {
            if (source.phase < phase) {
                source.gotoPhase(phase);
            }


            if (source.phase == phase && phaseComplete && !source.phaseComplete) {
                source.completePhase();
            }
        }
    };





    //---------------------------------------------------------------------------
    // LOOP SIMPLIFICATION FOR SourceUnit OPERATIONS


    /**
     * An callback interface for use in the applyToSourceUnits loop driver.
     */
    public static abstract class SourceUnitOperation {
        public abstract void call(SourceUnit source) throws CompilationFailedException;
    }
  

    /**
     * A loop driver for applying operations to all SourceUnits.
     * Automatically skips units that have already been processed
     * through the current phase.
     */
    public void applyToSourceUnits(SourceUnitOperation body) throws CompilationFailedException {
        Iterator keys = names.iterator();
        while (keys.hasNext()) {
            String name = (String) keys.next();
            SourceUnit source = (SourceUnit) sources.get(name);
            if ( (source.phase < phase) || (source.phase == phase && !source.phaseComplete)) {
                try {
                    body.call(source);
                } catch (CompilationFailedException e) {
                    throw e;
                } catch (Exception e) {
                    GroovyBugError gbe = new GroovyBugError(e);
                    changeBugText(gbe,source);
                    throw gbe;
                } catch (GroovyBugError e) {
                    changeBugText(e,source);
                    throw e;
                }
            }
        }


        getErrorCollector().failIfErrors();
    }


    //---------------------------------------------------------------------------
    // LOOP SIMPLIFICATION FOR PRIMARY ClassNode OPERATIONS



    /**
     * An callback interface for use in the applyToSourceUnits loop driver.
     */
    public static abstract class PrimaryClassNodeOperation {
        public abstract void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException;
        public boolean needSortedInput(){
            return false;
        }
    }

    public static abstract class GroovyClassOperation {
        public abstract void call(GroovyClass gclass) throws CompilationFailedException;
    }

    private List getPrimaryClassNodes(boolean sort) {
        ArrayList unsorted = new ArrayList();
        Iterator modules = this.ast.getModules().iterator();
        while (modules.hasNext()) {
            ModuleNode module = (ModuleNode) modules.next();

            Iterator classNodes = module.getClasses().iterator();
            while (classNodes.hasNext()) {
                ClassNode classNode = (ClassNode) classNodes.next();
                unsorted.add(classNode);
            }
        }
        
        if(sort==false) return unsorted;
        
        int[] indexClass = new int[unsorted.size()];
        int[] indexInterface = new int[unsorted.size()];
        {            
            int i = 0;
            for (Iterator iter = unsorted.iterator(); iter.hasNext(); i++) {
                ClassNode node = (ClassNode) iter.next();
                int count = 0;
                ClassNode element = node;
                while (element!=null){
                    count++;
                    element = element.getSuperClass();
                }
                if (node.isInterface()) {
                    indexInterface[i] = count;
                    indexClass[i] = -1;
                } else {
                    indexClass[i] = count;
                    indexInterface[i] = -1;
                }
            }
        }
        
        List sorted = getSorted(indexInterface,unsorted);
        sorted.addAll(getSorted(indexClass,unsorted));
        
        return sorted;
    }
    
    private List getSorted(int[] index, List unsorted) {
        ArrayList sorted = new ArrayList(unsorted.size());
        int start = 0;
        for (int i=0; i<unsorted.size(); i++) {           
            int min = -1;
            for (int j=0; j<unsorted.size(); j++) {
                if (index[j]==-1) continue;
                if (min==-1) {
                    min = j;
                } else if (index[j]<index[min]) {
                    min = j;
                }
            }
            if (min==-1) break;
            sorted.add(unsorted.get(min));
            index[min] = -1;
        }
        return sorted;
    }

    /**
     * A loop driver for applying operations to all primary ClassNodes in
     * our AST.  Automatically skips units that have already been processed
     * through the current phase.
     */
    public void applyToPrimaryClassNodes(PrimaryClassNodeOperation body) throws CompilationFailedException {
        Iterator classNodes = getPrimaryClassNodes(body.needSortedInput()).iterator();
        while (classNodes.hasNext()) {
            SourceUnit context=null;
            try {
               ClassNode classNode = (ClassNode) classNodes.next();
               context = classNode.getModule().getContext();
               if (context == null || context.phase <= phase) {
                   body.call(context, new GeneratorContext(this.ast), classNode);
               }
            } catch (CompilationFailedException e) {
                // fall thorugh, getErrorREporter().failIfErrors() will triger
            } catch (NullPointerException npe){
                throw npe;
            } catch (GroovyBugError e) {
                changeBugText(e,context);
                throw e;
            } catch (Exception e) {
                // check the exception for a nested compilation exception
                ErrorCollector nestedCollector = null;
                for (Throwable next = e.getCause(); next!=e && next!=null; next=next.getCause()) {
                    if (!(next instanceof MultipleCompilationErrorsException)) continue;
                    MultipleCompilationErrorsException mcee = (MultipleCompilationErrorsException) next;
                    nestedCollector = mcee.collector;
                    break;
                }

                if (nestedCollector!=null) {
                    getErrorCollector().addCollectorContents(nestedCollector);
                } else {
                    getErrorCollector().addError(new ExceptionMessage(e,configuration.getDebug(),this));
                }
            }
        }

        getErrorCollector().failIfErrors();
    }
    
    public void applyToGeneratedGroovyClasses(GroovyClassOperation body) throws CompilationFailedException {
        if (this.phase != Phases.OUTPUT && !(this.phase == Phases.CLASS_GENERATION && this.phaseComplete)) {
            throw new GroovyBugError("CompilationUnit not ready for output(). Current phase="+getPhaseDescription());
        }

        boolean failures = false;

        Iterator iterator = this.generatedClasses.iterator();
        while (iterator.hasNext()) {
            //
            // Get the class and calculate its filesystem name
            //
            GroovyClass gclass = (GroovyClass) iterator.next();
            try {
                body.call(gclass);
            } catch (CompilationFailedException e) {
                // fall thorugh, getErrorREporter().failIfErrors() will triger
            } catch (NullPointerException npe){
                throw npe;
            } catch (GroovyBugError e) {
                changeBugText(e,null);
                throw e;
            } catch (Exception e) {
                GroovyBugError gbe = new GroovyBugError(e);
                throw gbe;
            }
        }
        
        getErrorCollector().failIfErrors();
    }

    private void changeBugText(GroovyBugError e, SourceUnit context) {
        e.setBugText("exception in phase '"+getPhaseDescription()+"' in source unit '"+((context!=null)?context.getName():"?")+"' "+e.getBugText());
    }
}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?