compilationunit.java

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

JAVA
1,012
字号
    public SourceUnit addSource(URL url) {
        return addSource(new SourceUnit(url, configuration, classLoader,getErrorCollector()));
    }


    /**
     * Adds a InputStream source to the unit.
     */
    public SourceUnit addSource(String name, InputStream stream) {
        ReaderSource source = new InputStreamReaderSource(stream, configuration);
        return addSource(new SourceUnit(name, source, configuration, classLoader, getErrorCollector()));
    }


    /**
     * Adds a SourceUnit to the unit.
     */
    public SourceUnit addSource(SourceUnit source) {
        String name = source.getName();
        source.setClassLoader(this.classLoader);
        for (Iterator iter = queuedSources.iterator(); iter.hasNext();) {
			SourceUnit su = (SourceUnit) iter.next();
			if (name.equals(su.getName())) return su;
		}
        queuedSources.add(source);
        return source;
    }


    /**
     * Returns an iterator on the unit's SourceUnits.
     */
    public Iterator iterator() {
        return new Iterator() {
            Iterator nameIterator = names.iterator();


            public boolean hasNext() {
                return nameIterator.hasNext();
            }


            public Object next() {
                String name = (String) nameIterator.next();
                return sources.get(name);
            }


            public void remove() {
                throw new UnsupportedOperationException();
            }
        };
    }


    /**
     * Adds a ClassNode directly to the unit (ie. without source).
     * WARNING: the source is needed for error reporting, using
     *          this method without setting a SourceUnit will cause
     *          NullPinterExceptions
     */
    public void addClassNode(ClassNode node) {
        ModuleNode module = new ModuleNode(this.ast);
        this.ast.addModule(module);
        module.addClass(node);
    }


    //---------------------------------------------------------------------------
    // EXTERNAL CALLBACKS


    /**
     * A callback interface you can use to "accompany" the classgen()
     * code as it traverses the ClassNode tree.  You will be called-back
     * for each primary and inner class.  Use setClassgenCallback() before
     * running compile() to set your callback.
     */
    public static abstract class ClassgenCallback {
        public abstract void call(ClassVisitor writer, ClassNode node) throws CompilationFailedException;
    }


    /**
     * Sets a ClassgenCallback.  You can have only one, and setting
     * it to null removes any existing setting.
     */
    public void setClassgenCallback(ClassgenCallback visitor) {
        this.classgenCallback = visitor;
    }


    /**
     * A callback interface you can use to get a callback after every
     * unit of the compile process.  You will be called-back with a
     * ProcessingUnit and a phase indicator.  Use setProgressCallback()
     * before running compile() to set your callback.
     */
    public static abstract class ProgressCallback {

        public abstract void call(ProcessingUnit context, int phase) throws CompilationFailedException;
    }

    /**
     * Sets a ProgressCallback.  You can have only one, and setting
     * it to null removes any existing setting.
     */
    public void setProgressCallback(ProgressCallback callback) {
        this.progressCallback = callback;
    }


    //---------------------------------------------------------------------------
    // ACTIONS


    /**
     * Synonym for compile(Phases.ALL).
     */
    public void compile() throws CompilationFailedException {
        compile(Phases.ALL);
    }

    /**
     * Compiles the compilation unit from sources.
     */
    public void compile(int throughPhase) throws CompilationFailedException {
        //
        // To support delta compilations, we always restart
        // the compiler.  The individual passes are responsible
        // for not reprocessing old code.
        gotoPhase(Phases.INITIALIZATION);
        throughPhase = Math.min(throughPhase,Phases.ALL);

        while (throughPhase >= phase && phase <= Phases.ALL) {
            
            for (Iterator it = phaseOperations[phase].iterator(); it.hasNext();) {
                Object operation = it.next();
                if (operation instanceof PrimaryClassNodeOperation) {
                    applyToPrimaryClassNodes((PrimaryClassNodeOperation) operation);
                } else if (operation instanceof SourceUnitOperation) {
                    applyToSourceUnits((SourceUnitOperation)operation);
                } else {
                    applyToGeneratedGroovyClasses((GroovyClassOperation)operation);
                }
            }
            
            if (dequeued()) continue;
           
            if (progressCallback != null) progressCallback.call(this, phase);
            completePhase();
            applyToSourceUnits(mark);
            
            gotoPhase(phase+1);
            
            if (phase==Phases.CLASS_GENERATION) {
                sortClasses();
            }
        }
            
        errorCollector.failIfErrors();
    }
    
    private void sortClasses() throws CompilationFailedException {
        Iterator modules = this.ast.getModules().iterator();
        while (modules.hasNext()) {
            ModuleNode module = (ModuleNode) modules.next();
            
            // before we actually do the sorting we should check
            // for cyclic references
            List classes = module.getClasses();
            for (Iterator iter = classes.iterator(); iter.hasNext();) {
                ClassNode start = (ClassNode) iter.next();
                ClassNode cn = start;
                HashSet parents = new HashSet();
                do {
                    if (parents.contains(cn.getName())) {
                        getErrorCollector().addErrorAndContinue(
                                new SimpleMessage("cyclic inheritance involving "+cn.getName()+" in class "+start.getName(),this)
                        );
                        cn=null;
                    } else {
                        parents.add(cn.getName());
                        cn = cn.getSuperClass();
                    }
                } while (cn!=null);
            }
            errorCollector.failIfErrors();
            module.sortClasses();
            
        }
    }
    
    
    /**
     * Dequeues any source units add through addSource and resets the compiler phase
     * to initialization. 
     * 
     * Note: this does not mean a file is recompiled. If a SoucreUnit has already passed
     * a phase it is skipped until a higher phase is reached. 
     * @return TODO
     * 
     * @throws CompilationFailedException
     */    
    protected boolean dequeued() throws CompilationFailedException {
        boolean dequeue = !queuedSources.isEmpty();
        while (!queuedSources.isEmpty()) {
            SourceUnit su = (SourceUnit) queuedSources.removeFirst();
            String name = su.getName();
            names.add(name);
            sources.put(name,su);
        }
        if (dequeue) {
            gotoPhase(Phases.INITIALIZATION);
        }
        return dequeue;
    }


    /**
     * Adds summary of each class to maps
     */
    private SourceUnitOperation summarize = new SourceUnitOperation() {
        public void call(SourceUnit source) throws CompilationFailedException {
            SourceSummary sourceSummary = source.getSourceSummary();
            if (sourceSummary != null) {
                summariesBySourceName.put(source.getName(),sourceSummary);
                List publicClassSources = sourceSummary.getPublicClassSources();
                if (publicClassSources == null || publicClassSources.size() == 0) {
                    //todo - is this the best way to handle scripts?
                    summariesByPublicClassName.put("*NoName*",sourceSummary);
                    // nothing to put into classSourcesByClassName as no ClassSource
                } else {
                    Iterator itr = publicClassSources.iterator();
                    while (itr.hasNext()) {
                        ClassSource classSource = (ClassSource)itr.next();
                        summariesByPublicClassName.put(classSource.getName(),sourceSummary);
                        classSourcesByPublicClassName.put(classSource.getName(),classSource);
                    }
                }
            }
        }
    };
    
    /**
     * Resolves all types
     */
    private SourceUnitOperation resolve = new SourceUnitOperation() {
        public void call(SourceUnit source) throws CompilationFailedException {
            List classes = source.ast.getClasses();
            for (Iterator it = classes.iterator(); it.hasNext();) {
                ClassNode node = (ClassNode) it.next();
                
                VariableScopeVisitor scopeVisitor = new VariableScopeVisitor(source);
                scopeVisitor.visitClass(node);
                
                resolveVisitor.startResolving(node,source);
            }
            
        }
    };
    
    /**
     * Runs convert() on a single SourceUnit.
     */
    private SourceUnitOperation convert = new SourceUnitOperation() {
        public void call(SourceUnit source) throws CompilationFailedException {
            source.convert();
            CompilationUnit.this.ast.addModule(source.getAST());


            if (CompilationUnit.this.progressCallback != null) {
                CompilationUnit.this.progressCallback.call(source, CompilationUnit.this.phase);
            }
        }
    };
    
    private GroovyClassOperation output = new GroovyClassOperation() {
        public void call(GroovyClass gclass) throws CompilationFailedException {
            boolean failures = false;
            String name = gclass.getName().replace('.', File.separatorChar) + ".class";
            File path = new File(configuration.getTargetDirectory(), name);
            
            //
            // Ensure the path is ready for the file
            //
            File directory = path.getParentFile();
            if (directory != null && !directory.exists()) {
                directory.mkdirs();
            }
            
            //
            // Create the file and write out the data
            //
            byte[] bytes = gclass.getBytes();
            
            FileOutputStream stream = null;
            try {
                stream = new FileOutputStream(path);
                stream.write(bytes, 0, bytes.length);
            } catch (IOException e) {
                getErrorCollector().addError(Message.create(e.getMessage(),CompilationUnit.this));
                failures = true;
            } finally {
                if (stream != null) {
                    try {
                        stream.close();
                    } catch (Exception e) {
                    }
                }
            }            
        }
    };
    
    /* checks if all needed classes are compiled before generating the bytecode */
    private SourceUnitOperation compileCompleteCheck = new SourceUnitOperation() {
        public void call(SourceUnit source) throws CompilationFailedException {
            List classes = source.ast.getClasses();
            for (Iterator it = classes.iterator(); it.hasNext();) {
                ClassNode node = (ClassNode) it.next();
                CompileUnit cu = node.getCompileUnit();
                for (Iterator iter = cu.iterateClassNodeToCompile(); iter.hasNext();) {
                    String name = (String) iter.next();
                    SourceUnit su = ast.getScriptSourceLocation(name);
                    List classesInSourceUnit = su.ast.getClasses();
                    StringBuffer message = new StringBuffer();
                    message
                    .append ("Compilation incomplete: expected to find the class ")
                    .append (name)
                    .append (" in ")
                    .append (su.getName());
                    if (classesInSourceUnit.size()==0) {
                        message.append(", but the file seems not to contain any classes");
                    } else {
                        message.append(", but the file contains the classes: ");
                        boolean first = true;
                        for (Iterator suClassesIter = classesInSourceUnit
                                .iterator(); suClassesIter.hasNext();) {

⌨️ 快捷键说明

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