root/trunk/ProjectFortress/src/com/sun/fortress/Shell.java @ 2399

Revision 2399, 35.5 KB (checked in by nbeckman, 16 months ago)

[typechecker] I have changed the typechecker so that it produces information necessary to Angelina's closure conversion. This is a mapping from Nodes that declare variables to the TypeEnv? objects that were in scope at the location of the declaration. I had to change some other parts of the Shell to pass this map onto her phase of compilation.

Line 
1/*******************************************************************************
2  Copyright 2008 Sun Microsystems, Inc.,
3  4150 Network Circle, Santa Clara, California 95054, U.S.A.
4  All rights reserved.
5
6  U.S. Government Rights - Commercial software.
7  Government users are subject to the Sun Microsystems, Inc. standard
8  license agreement and applicable provisions of the FAR and its supplements.
9
10  Use is subject to license terms.
11
12  This distribution may include materials developed by third parties.
13
14  Sun, Sun Microsystems, the Sun logo and Java are trademarks or registered
15  trademarks of Sun Microsystems, Inc. in the U.S. and other countries.
16  ******************************************************************************/
17
18package com.sun.fortress;
19
20import com.sun.fortress.repository.CacheBasedRepository;
21import com.sun.fortress.repository.FortressRepository;
22import com.sun.fortress.repository.GraphRepository;
23import com.sun.fortress.repository.ProjectProperties;
24import java.io.*;
25import java.util.*;
26import edu.rice.cs.plt.tuple.Option;
27import edu.rice.cs.plt.tuple.OptionUnwrapException;
28import edu.rice.cs.plt.iter.IterUtil;
29import edu.rice.cs.plt.collect.CollectUtil;
30import edu.rice.cs.plt.lambda.Lambda;
31
32import com.sun.fortress.compiler.*;
33import com.sun.fortress.exceptions.shell.UserError;
34import com.sun.fortress.exceptions.StaticError;
35import com.sun.fortress.exceptions.WrappedException;
36import com.sun.fortress.exceptions.MultipleStaticError;
37import com.sun.fortress.exceptions.ProgramError;
38import com.sun.fortress.exceptions.FortressException;
39import com.sun.fortress.exceptions.shell.RepositoryError;
40import com.sun.fortress.compiler.Parser;
41import com.sun.fortress.compiler.environments.TopLevelEnvGen;
42import com.sun.fortress.nodes.Api;
43import com.sun.fortress.nodes.APIName;
44import com.sun.fortress.nodes.CompilationUnit;
45import com.sun.fortress.nodes.Component;
46import com.sun.fortress.nodes_util.NodeFactory;
47import com.sun.fortress.nodes_util.ASTIO;
48import com.sun.fortress.interpreter.Driver;
49import com.sun.fortress.syntax_abstractions.phases.GrammarRewriter;
50import com.sun.fortress.syntax_abstractions.parser.PreParser;
51import com.sun.fortress.useful.Path;
52import com.sun.fortress.useful.Debug;
53import com.sun.fortress.useful.Useful;
54import com.sun.fortress.tools.FortressAstToConcrete;
55
56public final class Shell {
57    static boolean test;
58
59    /* These numbers have no importance, so don't worry about the order or even
60     * their value ( but they must be unique ).
61     * If you feel like changing this to an enum at any point that is fine.
62     */
63    private static final int PHASE_CODEGEN = 0;
64    private static final int PHASE_DESUGAR = 1;
65    private static final int PHASE_TYPECHECK = 2;
66    private static final int PHASE_GRAMMAR = 3;
67    private static final int PHASE_DISAMBIGUATE = 4;
68    private static final int PHASE_EMPTY = 5;
69
70    /* set this statically if you only want to run upto a certain phase */
71    private static int currentPhase = PHASE_CODEGEN;
72
73    private final FortressRepository _repository;
74    private static final CacheBasedRepository defaultRepository =
75        new CacheBasedRepository(ProjectProperties.ANALYZED_CACHE_DIR);
76    public static FortressRepository CURRENT_INTERPRETER_REPOSITORY = null;
77
78    public Shell(FortressRepository repository) { _repository = repository; }
79
80    public FortressRepository getRepository() {
81        return _repository;
82    }
83
84    private static void setPhase( int phase ){
85        currentPhase = phase;
86    }
87
88    /**
89     * This is used to communicate, clumsily, with parsers generated by syntax expansion.
90     * The interface should be improved.
91     */
92    public static void setCurrentInterpreterRepository( FortressRepository g ){
93        CURRENT_INTERPRETER_REPOSITORY = g;
94    }
95
96    private static GraphRepository specificRepository(Path p, CacheBasedRepository cache ){
97        GraphRepository fr = new GraphRepository( p, cache );
98        CURRENT_INTERPRETER_REPOSITORY = fr;
99        return fr;
100    }
101
102    public static GraphRepository specificRepository(Path p) {
103        return specificRepository( p, defaultRepository );
104    }
105
106    /* Helper method to print usage message.*/
107    private static void printUsageMessage() {
108        System.err.println("Usage:");
109        System.err.println(" compile [-out file] [-debug [type]* [#]] somefile.fs{s,i}");
110        System.err.println(" [run] [-test] [-debug [type]* [#]] somefile.fss arg...");
111        System.err.println(" parse [-out file] [-debug [type]* [#]] somefile.fs{s,i}");
112        System.err.println(" unparse [-out file] [-debug [type]* [#]] somefile.tf{s,i}");
113        System.err.println(" disambiguate [-out file] [-debug [type]* [#]] somefile.fs{s,i}");
114        System.err.println(" desugar [-out file] [-debug [type]* [#]] somefile.fs{s,i}");
115        System.err.println(" grammar [-out file] [-debug [type]* [#]] somefile.fs{s,i}");
116        System.err.println(" typecheck [-out file] [-debug [type]* [#]] somefile.fs{s,i}");
117        System.err.println(" help");
118    }
119
120    private static void printHelpMessage() {
121        System.err.println
122        ("Invoked as script: fortress args\n"+
123         "Invoked by java: java ... com.sun.fortress.Shell args\n"+
124         "\n"+
125         "fortress compile [-out file] [-debug [type]* [#]] somefile.fs{s,i}\n"+
126         "  Compile somefile. If compilation succeeds no message will be printed.\n"+
127         "\n"+
128         "fortress [run] [-test] [-debug [type]* [#]] somefile.fss arg ...\n"+
129         "  Runs somefile.fss through the Fortress interpreter, passing arg ... to the\n"+
130         "  run method of somefile.fss.\n"+
131         "\n"+
132         "fortress parse [-out file] [-debug [type]* [#]] somefile.fs{i,s}\n"+
133         "  Parses a file. If parsing succeeds the message \"Ok\" will be printed.\n"+
134         "  If -out file is given, a message about the file being written to will be printed.\n"+
135         "\n"+
136         "fortress unparse [-out file] [-debug [type]* [#]] somefile.tf{i,s}\n"+
137         "  Convert a parsed file back to Fortress source code. The output will be dumped to stdout if -out is not given.\n"+
138         "  If -out file is given, a message about the file being written to will be printed.\n"+
139         "\n"+
140         "fortress disambiguate [-out file] [-debug [type]* [#]] somefile.fs{i,s}\n"+
141         "  Disambiguates a file.\n"+
142         "  If -out file is given, a message about the file being written to will be printed.\n"+
143         "\n"+
144         "fortress desugar [-out file] [-debug [#]] somefile.fs{i,s}\n"+
145         "  Desugars a file.\n"+
146         "  If -out file is given, a message about the file being written to will be printed.\n"+
147         "\n"+
148         "fortress grammar [-out file] [-debug [#]] somefile.fs{i,s}\n"+
149         "  Rewrites syntax grammars in a file.\n"+
150         "  If -out file is given, a message about the file being written to will be printed.\n"+
151         "\n"+
152         "fortress typecheck [-out file] [-debug [#]] somefile.fs{i,s}\n"+
153         "  Typechecks a file. If type checking succeeds no message will be printed.\n"+
154         "\n"+
155         "More details on each flag:\n"+
156         "   -out file : dumps the processed abstract syntax tree to a file.\n"+
157         "   -test : first runs test functions associated with the program.\n"+
158         "   -debug : enables debugging to the maximum level (99) for all \n"+
159         "            debugging types and prints java stack traces.\n"+
160         "   -debug # : sets debugging to the specified level, where # is a number, \n"+
161         "            and sets all debugging types on.\n"+
162         "   -debug types : sets debugging types to the specified types with \n"+
163         "            the maximum debugging level. \n" +
164         "   -debug types # : sets debugging to the specified level, where # is a number, \n"+
165         "            and the debugging types to the specified types. \n" +
166         "   The acceptable debugging types are:\n"+
167         "            " + Debug.typeStrings() + "\n"+
168         "\n"
169        );
170    }
171
172    private static void turnOnTypeChecking(){
173        com.sun.fortress.compiler.StaticChecker.typecheck = true;
174    }
175
176    /* Main entry point for the fortress shell.*/
177    public static void main(String[] tokens) throws InterruptedException, Throwable {
178        if (tokens.length == 0) {
179            printUsageMessage();
180            System.exit(-1);
181        }
182
183        // Now match the assembled string.
184        try {
185            String what = tokens[0];
186            List<String> args = Arrays.asList(tokens).subList(1, tokens.length);
187            if (what.equals("compile")) {
188                compile(args, Option.<String>none());
189            } else if (what.equals("run")) {
190                run(args);
191            } else if ( what.equals("parse" ) ){
192                parse(args, Option.<String>none());
193            } else if ( what.equals("unparse" ) ){
194                unparse(args, Option.<String>none());
195            } else if ( what.equals( "disambiguate" ) ){
196                setPhase( PHASE_DISAMBIGUATE );
197                compile(args, Option.<String>none());
198            } else if ( what.equals( "desugar" ) ){
199                setPhase( PHASE_DESUGAR );
200                compile(args, Option.<String>none());
201            } else if ( what.equals( "grammar" ) ){
202                setPhase( PHASE_GRAMMAR );
203                compile(args, Option.<String>none());
204            } else if (what.equals("typecheck")) {
205                /* TODO: remove the next line once type checking is permanently turned on */
206                turnOnTypeChecking();
207                setPhase( PHASE_TYPECHECK );
208                compile(args, Option.<String>none());
209            } else if (what.contains(ProjectProperties.COMP_SOURCE_SUFFIX)
210                       || (what.startsWith("-") && tokens.length > 1)) {
211                // no "run" command.
212                run(Arrays.asList(tokens));
213            } else if (what.equals("help")) {
214                printHelpMessage();
215
216            } else { printUsageMessage(); }
217        }
218        catch (UserError error) {
219            System.err.println(error.getMessage());
220        }
221        catch (IOException error) {
222            System.err.println(error.getMessage());
223        }
224    }
225
226    /**
227     * Parse a file. If the file parses ok it will say "Ok".
228     * If you want a dump then give -out somefile.
229     */
230    private static void parse(List<String> args, Option<String> out)
231        throws UserError, InterruptedException, IOException {
232        if (args.size() == 0) {
233            throw new UserError("Need a file to parse");
234        }
235        String s = args.get(0);
236        List<String> rest = args.subList(1, args.size());
237
238        if (s.startsWith("-")) {
239            if (s.equals("-debug")){
240                rest = Debug.parseOptions(rest);
241            }
242            if (s.equals("-out") && ! rest.isEmpty() ){
243                out = Option.<String>some(rest.get(0));
244                rest = rest.subList( 1, rest.size() );
245            }
246            if (s.equals("-noPreparse")) ProjectProperties.noPreparse = true;
247
248            parse( rest, out );
249        } else {
250            parse( s, out );
251        }
252    }
253
254    /**
255     * UnParse a file.
256     * If you want a dump then give -out somefile.
257     */
258    private static void unparse(List<String> args, Option<String> out)
259        throws UserError, InterruptedException, IOException {
260        if (args.size() == 0) {
261            throw new UserError("Need a file to unparse");
262        }
263        String s = args.get(0);
264        List<String> rest = args.subList(1, args.size());
265
266        if (s.startsWith("-")) {
267            if (s.equals("-debug")){
268                rest = Debug.parseOptions(rest);
269            }
270            if (s.equals("-out") && ! rest.isEmpty() ){
271                out = Option.<String>some(rest.get(0));
272                rest = rest.subList( 1, rest.size() );
273            }
274            if (s.equals("-noPreparse")) ProjectProperties.noPreparse = true;
275
276            unparse( rest, out );
277        } else {
278            unparse( s, out );
279        }
280    }
281
282    private static void unparse( String file, Option<String> out ){
283        try{
284            String code = ASTIO.readJavaAst( file ).unwrap().accept( new FortressAstToConcrete() );
285            if ( out.isSome() ){
286                try{
287                    BufferedWriter writer = Useful.filenameToBufferedWriter(out.unwrap());
288                    writer.write(code);
289                    writer.close();
290                    System.out.println( "Dumped code to " + out.unwrap() );
291                } catch ( IOException e ){
292                    System.err.println( "Error while writing " + out.unwrap() );
293                }
294            } else {
295                System.out.println( code );
296            }
297        } catch ( IOException i ){
298            i.printStackTrace();
299        } catch ( OptionUnwrapException o ){
300            o.printStackTrace();
301        }
302    }
303
304    private static void parse( String file, Option<String> out){
305        try{
306            CompilationUnit unit = Parser.parseFile(cuName(file), new File(file));
307            System.out.println( "Ok" );
308            if ( out.isSome() ){
309                try{
310                    ASTIO.writeJavaAst(unit, out.unwrap());
311                    System.out.println( "Dumped parse tree to " + out.unwrap() );
312                } catch ( IOException e ){
313                    System.err.println( "Error while writing " + out.unwrap() );
314                }
315            }
316        } catch (ProgramError e) {
317            System.err.println(e.getMessage());
318            e.printInterpreterStackTrace(System.err);
319            if (Debug.isOnMax()) {
320                e.printStackTrace();
321            } else {
322                System.err.println("Turn on -debug for Java-level error dump.");
323            }
324            System.exit(1);
325        } catch ( FileNotFoundException f ){
326            System.err.println( file + " not found" );
327        } catch ( IOException ie ){
328            System.err.println( "Error while reading " + file );
329        } catch ( StaticError s ){
330            System.err.println(s);
331        }
332    }
333
334    private static boolean isApi(String file){
335        return file.endsWith(ProjectProperties.API_SOURCE_SUFFIX);
336    }
337
338    private static boolean isComponent(String file){
339        return file.endsWith(ProjectProperties.COMP_SOURCE_SUFFIX);
340    }
341
342    private static APIName cuName( String file ){
343        if ( file.endsWith( ProjectProperties.COMP_SOURCE_SUFFIX ) ||
344             file.endsWith( ProjectProperties.API_SOURCE_SUFFIX ) ){
345            return NodeFactory.makeAPIName(file.substring( 0, file.lastIndexOf(".") ));
346        }
347        return NodeFactory.makeAPIName(file);
348    }
349
350    public static boolean checkCompilationUnitName(String filename,
351                                                   String cuname) {
352        String file = filename.substring( 0, filename.lastIndexOf(".") );
353        file = file.replace('/','.');
354        file = file.replace('\\','.');
355        String regex = "(.*\\.)?" + cuname.replaceAll("\\.", "\\.") + "$";
356        Debug.debug( Debug.Type.REPOSITORY, 3, "Checking file name " + file + " vs cuname " + regex );
357        return file.matches( regex );
358    }
359
360    /**
361     * Compile a file.
362     * If you want a dump then give -out somefile.
363     */
364    private static void compile(List<String> args, Option<String> out)
365        throws UserError, InterruptedException, IOException {
366        if (args.size() == 0) {
367            throw new UserError("Need a file to compile");
368        }
369        String s = args.get(0);
370        List<String> rest = args.subList(1, args.size());
371
372        if (s.startsWith("-")) {
373            if (s.equals("-debug")){
374                rest = Debug.parseOptions(rest);
375            }
376            if (s.equals("-out") && ! rest.isEmpty() ){
377                out = Option.<String>some(rest.get(0));
378                rest = rest.subList( 1, rest.size() );
379            }
380            if (s.equals("-noPreparse")) ProjectProperties.noPreparse = true;
381            compile(rest, out);
382        } else {
383            try {
384                APIName name = trueApiName( s );
385                Path path = sourcePath( s, name );
386
387                /*
388                Debug.debug( Debug.Type.REPOSITORY, 2, "True api name is " + name );
389                Debug.debug( Debug.Type.REPOSITORY, 2, "Path is " + s );
390                Path path = ProjectProperties.SOURCE_PATH;
391                String source = new File( s ).getCanonicalPath().substring( 0, s.length() - (name.toString().length() + 4) );
392                path = path.prepend( source );
393                Debug.debug( Debug.Type.REPOSITORY, 2, "Source path is " + source );
394                Debug.debug( Debug.Type.REPOSITORY, 2, "Lookup path is " + path );
395                */
396                /*
397                if (s.contains("/")) {
398                    String head = s.substring(0, s.lastIndexOf("/"));
399                    s = s.substring(s.lastIndexOf("/")+1, s.length());
400                    path = path.prepend(head);
401                }
402                */
403                Iterable<? extends StaticError> errors = compile(path, name.toString() + (s.endsWith(".fss") ? ".fss" : ".fsi"), out );
404                if ( errors.iterator().hasNext() ){
405                    for (StaticError error: errors) {
406                        System.err.println(error);
407                    }
408                }
409            } catch (RepositoryError error) {
410                System.err.println(error);
411            }
412        }
413    }
414
415    private static APIName trueApiName( String path ) throws IOException {
416        return PreParser.apiName( NodeFactory.makeAPIName(path), new File(path).getCanonicalFile() );
417    }
418
419    /**
420     * Compile a file.
421     */
422    public static Iterable<? extends StaticError> compile(Path path, String file) {
423        return compile(path, file, Option.<String>none());
424    }
425
426    private static Iterable<? extends StaticError> compile(Path path, String file, Option<String> out) {
427        GraphRepository bcr = specificRepository( path, defaultRepository );
428
429        Debug.debug( Debug.Type.FORTRESS, 2, "Compiling file ", file );
430        APIName name = cuName(file);
431        try {
432            if ( isApi(file) ) {
433                // FIXME: The following line is executed for its side effects
434                Api a = (Api) bcr.getApi(name).ast();
435                if ( out.isSome() )
436                    ASTIO.writeJavaAst(defaultRepository.getApi(name).ast(), out.unwrap());
437            } else if (isComponent(file)) {
438                // FIXME: The following line is executed for its side effects
439                Component c = (Component) bcr.getComponent(name).ast();
440                if ( out.isSome() )
441                    ASTIO.writeJavaAst(defaultRepository.getComponent(name).ast(), out.unwrap());
442            } else {
443                System.out.println( "Don't know what kind of file " + file +
444                                    " is. Append .fsi or .fss." );
445            }
446        } catch (ProgramError pe) {
447            Iterable<? extends StaticError> se = pe.getStaticErrors();
448            if (se == null) {
449                return IterUtil.singleton(new WrappedException(pe, Debug.isOnMax()));
450            }
451            else {
452                return se;
453            }
454        } catch (RepositoryError ex) {
455            throw ex;
456        } catch ( FileNotFoundException ex ){
457            throw new WrappedException(ex);
458        } catch ( IOException e ){
459            throw new WrappedException(e);
460        } catch (StaticError ex) {
461             return IterUtil.singleton(new WrappedException(ex, Debug.isOnMax()));
462        }
463
464        if (bcr.verbose())
465            System.err.println("Compiling done.");
466
467        return IterUtil.empty();
468    }
469
470    /**
471     * Run a file.
472     */
473    private static void run(List<String> args)
474        throws UserError, IOException, Throwable {
475        if (args.size() == 0) {
476            throw new UserError("Need a file to run");
477        }
478        String s = args.get(0);
479        List<String> rest = args.subList(1, args.size());
480
481        if (s.startsWith("-")) {
482            if (s.equals("-debug")){
483                rest = Debug.parseOptions(rest);
484            }
485            if (s.equals("-test")) {
486                test = true;
487            }
488            if (s.equals("-noPreparse")) ProjectProperties.noPreparse = true;
489
490            run(rest);
491        } else {
492            run(s, rest);
493        }
494    }
495
496    private static void run(String fileName, List<String> args)
497        throws UserError, Throwable {
498        try {
499            /*
500            Path path = ProjectProperties.SOURCE_PATH;
501            if (fileName.contains("/")) {
502                String head = fileName.substring(0, fileName.lastIndexOf("/"));
503                fileName = fileName.substring(fileName.lastIndexOf("/")+1, fileName.length());
504                path = path.prepend(head);
505            }
506            APIName componentName = cuName(fileName);
507            */
508
509            APIName name = trueApiName( fileName );
510            Path path = sourcePath(fileName, name);
511           
512            GraphRepository bcr = specificRepository( path, defaultRepository );
513            Iterable<? extends StaticError> errors = IterUtil.empty();
514
515            try {
516                CompilationUnit cu = bcr.getLinkedComponent(name).ast();
517                Driver.runProgram(bcr, cu, test, args);
518            } catch (Throwable th) {
519                // TODO FIXME what is the proper treatment of errors/exceptions etc.?
520                if (th instanceof FortressException) {
521                    FortressException pe = (FortressException) th;
522                    if (pe.getStaticErrors() != null)
523                        errors = pe.getStaticErrors();
524                }
525                if (th instanceof RuntimeException)
526                    throw (RuntimeException) th;
527                if (th instanceof Error)
528                    throw (Error) th;
529                throw new WrappedException(th, Debug.isOnMax());
530            }
531
532            for (StaticError error: errors) {
533                System.err.println(error);
534            }
535            // If there are no errors, all components will have been written to disk by the CacheBasedRepository.
536        } catch ( StaticError e ){
537            System.err.println(e);
538            if ( Debug.isOnMax() ){
539                e.printStackTrace();
540            }
541        } catch (RepositoryError e) {
542            System.err.println(e.getMessage());
543        } catch (FortressException e) {
544            System.err.println(e.getMessage());
545            e.printInterpreterStackTrace(System.err);
546            if (Debug.isOnMax()) {
547                e.printStackTrace();
548            } else {
549                System.err.println("Turn on -debug for Java-level error dump.");
550            }
551            System.exit(1);
552        }
553    }
554
555    /* find the api name for a file and chop it off the source path.
556     * what remains from the source path is the directory that contains
557     * the file( including sub-directories )
558     */
559    private static Path sourcePath( String file, APIName name ) throws IOException {
560        Debug.debug( Debug.Type.REPOSITORY, 2, "True api name is " + name );
561        String fullPath = new File(file).getCanonicalPath();
562        Debug.debug( Debug.Type.REPOSITORY, 2, "Path is " + fullPath );
563        Path path = ProjectProperties.SOURCE_PATH;
564        /* the path to the file is /absolute/path/a/b/c/foo.fss and the apiname is
565         * a.b.c.foo, so we need to take off the apiname plus four more characters,
566         * ".fss" or ".fsi"
567         */
568        String source = fullPath.substring( 0, fullPath.length() - (name.toString().length() + 4) );
569        path = path.prepend( source );
570        Debug.debug( Debug.Type.REPOSITORY, 2, "Source path is " + source );
571        Debug.debug( Debug.Type.REPOSITORY, 2, "Lookup path is " + path );
572        return path;
573    }
574
575    public static AnalyzeResult disambiguate(FortressRepository repository,
576                                             GlobalEnvironment env,
577                                             AnalyzeResult previousPhase,
578                                             long lastModified) throws StaticError {
579
580        // Build a new GlobalEnvironment consisting of all APIs in a global
581        // repository combined with all APIs that have been processed in the previous
582        // step.  For now, we are implementing pure static linking, so there is
583        // no global repository.
584        GlobalEnvironment rawApiEnv =
585            new GlobalEnvironment.FromMap(CollectUtil.union(repository.apis(),
586                                                            previousPhase.apis()));
587
588        // Rewrite all API ASTs so they include only fully qualified names, relying
589        // on the rawApiEnv constructed in the previous step. Note that, after this
590        // step, the rawApiEnv is stale and needs to be rebuilt with the new API ASTs.
591        Disambiguator.ApiResult apiDR =
592            Disambiguator.disambiguateApis(previousPhase.apiIterator(), rawApiEnv, repository.apis());
593        if (!apiDR.isSuccessful()) {
594            throw new MultipleStaticError(apiDR.errors());
595        }
596
597        // Rebuild ApiIndices.
598        IndexBuilder.ApiResult apiIR =
599            IndexBuilder.buildApis(apiDR.apis(), lastModified);
600        if (!apiIR.isSuccessful()) {
601            throw new MultipleStaticError(apiIR.errors());
602        }
603
604        // Rebuild GlobalEnvironment.
605        GlobalEnvironment apiEnv =
606            new GlobalEnvironment.FromMap(CollectUtil.union(repository.apis(),
607                                                            apiIR.apis()));
608
609        Disambiguator.ComponentResult componentDR =
610            Disambiguator.disambiguateComponents(previousPhase.componentIterator(), apiEnv,
611                                                 previousPhase.components());
612        if (!componentDR.isSuccessful()) {
613            throw new MultipleStaticError(componentDR.errors());
614        }
615
616        // Rebuild ComponentIndices.
617        IndexBuilder.ComponentResult componentsDone =
618            IndexBuilder.buildComponents(componentDR.components(), lastModified);
619        if (!componentsDone.isSuccessful()) {
620            throw new MultipleStaticError(componentsDone.errors());
621        }
622
623        return new AnalyzeResult(previousPhase, apiIR.apis(),
624                        componentsDone.components(), IterUtil.<StaticError>empty());
625    }
626
627    public static AnalyzeResult rewriteGrammar(FortressRepository repository,
628                                               GlobalEnvironment env,
629                                               AnalyzeResult previousPhase,
630                                               long lastModified) throws StaticError {
631        GlobalEnvironment apiEnv =
632            new GlobalEnvironment.FromMap(CollectUtil.union(repository.apis(),
633                                                            previousPhase.apis()));
634
635        GrammarRewriter.ApiResult apiID = GrammarRewriter.rewriteApis(previousPhase.apis(), apiEnv);
636        if (!apiID.isSuccessful()) {
637            throw new MultipleStaticError(apiID.errors());
638        }
639
640        IndexBuilder.ApiResult apiDone = IndexBuilder.buildApis(apiID.apis(), lastModified);
641        if (!apiDone.isSuccessful()) {
642            throw new MultipleStaticError(apiDone.errors());
643        }
644
645        return new AnalyzeResult(previousPhase, apiDone.apis(),
646                        previousPhase.components(), IterUtil.<StaticError>empty());
647    }
648
649    public static AnalyzeResult typecheck(FortressRepository _repository,
650                                          GlobalEnvironment env,
651                                          AnalyzeResult previousPhase,
652                                          long lastModified) throws StaticError {
653        IndexBuilder.ApiResult apiIndex = IndexBuilder.buildApis(previousPhase.apiIterator(), lastModified);
654        IndexBuilder.ComponentResult componentIndex = IndexBuilder.buildComponents(previousPhase.componentIterator(), lastModified);
655        GlobalEnvironment apiEnv = new GlobalEnvironment.FromMap(CollectUtil.union(_repository.apis(),
656                                                                                   apiIndex.apis()));
657
658        StaticChecker.ApiResult apiSR = StaticChecker.checkApis( apiIndex.apis(), apiEnv );
659
660        if ( !apiSR.isSuccessful() ){
661            throw new MultipleStaticError(apiSR.errors());
662        }
663
664        StaticChecker.ComponentResult componentSR =
665            StaticChecker.checkComponents( componentIndex.components(), env);
666
667        if ( !componentSR.isSuccessful() ){
668            throw new MultipleStaticError(componentSR.errors());
669        }
670
671        return new AnalyzeResult(apiSR.apis(), componentSR.components(),
672                        IterUtil.<StaticError>empty(), componentSR.typeEnvAtNode());
673    }
674
675    public static AnalyzeResult desugar(FortressRepository _repository,
676                                        GlobalEnvironment env,
677                                        AnalyzeResult previousPhase,
678                                        long lastModified) throws StaticError {
679        GlobalEnvironment apiEnv = new GlobalEnvironment.FromMap(CollectUtil.union(_repository.apis(),
680                                                                                   previousPhase.apis()));
681
682        Desugarer.ApiResult apiDSR = Desugarer.desugarApis(previousPhase.apis(), apiEnv);
683
684        if ( ! apiDSR.isSuccessful() ){
685            throw new MultipleStaticError(apiDSR.errors());
686        }
687
688        Desugarer.ComponentResult componentDSR = Desugarer.desugarComponents(previousPhase.components(), apiEnv);
689
690        if ( ! componentDSR.isSuccessful() ){
691            throw new MultipleStaticError(componentDSR.errors());
692        }
693
694        return new AnalyzeResult(previousPhase, apiDSR.apis(),
695                        componentDSR.components(), IterUtil.<StaticError>empty());
696    }
697
698    public static AnalyzeResult codeGeneration(FortressRepository _repository,
699                                               GlobalEnvironment env,
700                                               AnalyzeResult previousPhase,
701                                               long lastModified) throws StaticError {
702        TopLevelEnvGen.CompilationUnitResult apiGR =
703            TopLevelEnvGen.generateApiEnvs(previousPhase.apis());
704
705        if ( !apiGR.isSuccessful() ){
706            throw new MultipleStaticError(apiGR.errors());
707        }
708
709        // Generate top-level byte code environments for components
710        TopLevelEnvGen.CompilationUnitResult componentGR =
711            TopLevelEnvGen.generateComponentEnvs(previousPhase.components());
712
713        if ( !componentGR.isSuccessful() ){
714            throw new MultipleStaticError(componentGR.errors());
715        }
716
717        return new AnalyzeResult(previousPhase, previousPhase.apis(),
718                        previousPhase.components(), IterUtil.<StaticError>empty());
719    }
720
721    private static abstract class Phase{
722        Phase parent;
723        public Phase( Phase parent ){
724            this.parent = parent;
725        }
726
727        public abstract AnalyzeResult execute( AnalyzeResult previousPhase) throws StaticError ;
728
729        public AnalyzeResult run() throws StaticError {
730            AnalyzeResult result = parent.run();
731            return execute( result );
732        }
733    }
734
735    private static Phase getPhase(final FortressRepository repository,
736                                  final GlobalEnvironment env,
737                                  final Iterable<Api> apis,
738                                  final Iterable<Component> components,
739                                  final long lastModified,
740                                  final int phase){
741        class EmptyPhase extends Phase{
742            public EmptyPhase(){
743                super(null);
744            }
745
746            public AnalyzeResult execute( AnalyzeResult previousPhase ) throws StaticError {
747                return null;
748            }
749
750            public AnalyzeResult run() throws StaticError {
751                Debug.debug( Debug.Type.FORTRESS, 1, "Start phase Empty" );
752                IndexBuilder.ApiResult apiIndex = IndexBuilder.buildApis(apis, lastModified);
753                IndexBuilder.ComponentResult componentIndex = IndexBuilder.buildComponents(components, lastModified);
754                return new AnalyzeResult(apiIndex.apis(), componentIndex.components(), IterUtil.<StaticError>empty());
755            }
756        }
757
758        class DisambiguatePhase extends Phase {
759            public DisambiguatePhase( Phase parent ){
760                super(parent);
761            }
762
763            public AnalyzeResult execute( AnalyzeResult previousPhase ) throws StaticError {
764                Debug.debug( Debug.Type.FORTRESS, 1, "Start phase Disambiguate" );
765                return disambiguate(repository, env, previousPhase, lastModified);
766            }
767        }
768
769        class TypecheckPhase extends Phase {
770            public TypecheckPhase( Phase parent ){
771                super(parent);
772            }
773
774            public AnalyzeResult execute( AnalyzeResult previousPhase ) throws StaticError {
775                Debug.debug( Debug.Type.FORTRESS, 1, "Start phase TypeCheck" );
776                return typecheck(repository, env, previousPhase, lastModified);
777            }
778        }
779
780        class DesugarPhase extends Phase {
781            public DesugarPhase( Phase parent ){
782                super(parent);
783            }
784
785            public AnalyzeResult execute( AnalyzeResult previousPhase ) throws StaticError {
786                Debug.debug( Debug.Type.FORTRESS, 1, "Start phase Desugar" );
787                return desugar(repository, env, previousPhase, lastModified);
788            }
789        }
790
791        class CodeGenerationPhase extends Phase {
792            public CodeGenerationPhase( Phase parent ){
793                super(parent);
794            }
795
796            public AnalyzeResult execute( AnalyzeResult previousPhase ) throws StaticError {
797                Debug.debug( Debug.Type.FORTRESS, 1, "Start phase TopLevelEnvironment" );
798                return codeGeneration(repository, env, previousPhase, lastModified);
799            }
800        }
801
802        class GrammarPhase extends Phase {
803            public GrammarPhase( Phase parent ){
804                super(parent);
805            }
806
807            public AnalyzeResult execute( AnalyzeResult previousPhase ) throws StaticError {
808                Debug.debug( Debug.Type.FORTRESS, 1, "Start phase GrammarPhase" );
809                return rewriteGrammar(repository, env, previousPhase, lastModified);
810            }
811        }
812
813        Lambda<Integer,Phase> nextPhase = new Lambda<Integer,Phase>(){
814            public Phase value(Integer phase){
815                return getPhase(repository, env, apis, components, lastModified, phase );
816            }
817        };
818
819        /* Phases are listed in the order they occur, top to bottom. If new phases are added please
820         * respect this ordering. This is simply to make it easy to look at.
821         */
822        switch (phase){
823            case PHASE_EMPTY : return new EmptyPhase();
824            case PHASE_DISAMBIGUATE : return new DisambiguatePhase(nextPhase.value(PHASE_EMPTY));
825            case PHASE_GRAMMAR : return new GrammarPhase(nextPhase.value(PHASE_DISAMBIGUATE));
826            case PHASE_TYPECHECK : return new TypecheckPhase(nextPhase.value(PHASE_GRAMMAR));
827            case PHASE_DESUGAR : return new DesugarPhase(nextPhase.value(PHASE_TYPECHECK));
828            case PHASE_CODEGEN : return new CodeGenerationPhase(nextPhase.value(PHASE_DESUGAR));
829            default : throw new RuntimeException( "Invalid phase number: " + phase );
830        }
831    }
832
833    /* run all the analysis available */
834    public static AnalyzeResult analyze(final FortressRepository repository,
835                                        final GlobalEnvironment env,
836                                        final Iterable<Api> apis,
837                                        final Iterable<Component> components,
838                                        final long lastModified) throws StaticError {
839        return getPhase(repository, env, apis, components, lastModified, currentPhase).run();
840    }
841
842
843}
Note: See TracBrowser for help on using the browser.