root/trunk/ProjectFortress/src/com/sun/fortress/interpreter/Driver.java @ 3291

Revision 3291, 24.2 KB (checked in by dr2chase, 11 months ago)

[repository, ffi] Generated APIs now use proper import syntax, seem to pass static checking

Line 
1/*******************************************************************************
2    Copyright 2009 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.interpreter;
19
20import static com.sun.fortress.exceptions.InterpreterBug.bug;
21import static com.sun.fortress.exceptions.ProgramError.error;
22import static com.sun.fortress.exceptions.ProgramError.errorMsg;
23
24import com.sun.fortress.interpreter.env.APIWrapper;
25import com.sun.fortress.interpreter.env.CUWrapper;
26import com.sun.fortress.interpreter.env.ComponentWrapper;
27
28import java.io.IOException;
29import java.util.ArrayList;
30import java.util.Collection;
31import java.util.Collections;
32import java.util.HashMap;
33import java.util.HashSet;
34import java.util.Hashtable;
35import java.util.Iterator;
36import java.util.List;
37import java.util.Set;
38import java.util.Stack;
39
40import com.sun.fortress.repository.DerivedFiles;
41import com.sun.fortress.repository.FortressRepository;
42import com.sun.fortress.repository.IOAst;
43import com.sun.fortress.compiler.index.ApiIndex;
44import com.sun.fortress.compiler.index.ComponentIndex;
45import com.sun.fortress.exceptions.RedefinitionError;
46import com.sun.fortress.interpreter.evaluator.CollectTests;
47import com.sun.fortress.interpreter.evaluator.Environment;
48import com.sun.fortress.interpreter.evaluator.EvaluatorBase;
49import com.sun.fortress.interpreter.evaluator.Init;
50import com.sun.fortress.interpreter.evaluator.tasks.EvaluatorTask;
51import com.sun.fortress.interpreter.evaluator.tasks.FortressTaskRunnerGroup;
52import com.sun.fortress.interpreter.evaluator.types.FTraitOrObject;
53import com.sun.fortress.interpreter.evaluator.types.FTraitOrObjectOrGeneric;
54import com.sun.fortress.interpreter.evaluator.types.FType;
55import com.sun.fortress.interpreter.evaluator.values.FunctionClosure;
56import com.sun.fortress.interpreter.evaluator.values.FString;
57import com.sun.fortress.interpreter.evaluator.values.FValue;
58import com.sun.fortress.interpreter.evaluator.values.OverloadedFunction;
59import com.sun.fortress.interpreter.glue.WellKnownNames;
60import com.sun.fortress.nodes.APIName;
61import com.sun.fortress.nodes.AliasedAPIName;
62import com.sun.fortress.nodes.AliasedSimpleName;
63import com.sun.fortress.nodes.Api;
64import com.sun.fortress.nodes.CompilationUnit;
65import com.sun.fortress.nodes.Component;
66import com.sun.fortress.nodes.Decl;
67import com.sun.fortress.nodes.GrammarDecl;
68import com.sun.fortress.nodes.Id;
69import com.sun.fortress.nodes.IdOrOpOrAnonymousName;
70import com.sun.fortress.nodes.Import;
71import com.sun.fortress.nodes.ImportApi;
72import com.sun.fortress.nodes.ImportNames;
73import com.sun.fortress.nodes.ImportStar;
74import com.sun.fortress.nodes.ImportedNames;
75import com.sun.fortress.nodes.NodeAbstractVisitor_void;
76import com.sun.fortress.nodes.NodeVisitor_void;
77import com.sun.fortress.nodes.ObjectDecl;
78import com.sun.fortress.nodes.SyntaxDecl;
79import com.sun.fortress.nodes.SyntaxDef;
80import com.sun.fortress.nodes.TestDecl;
81import com.sun.fortress.nodes.TraitDecl;
82import com.sun.fortress.nodes_util.NodeFactory;
83import com.sun.fortress.nodes_util.NodeUtil;
84import com.sun.fortress.useful.BASet;
85import com.sun.fortress.useful.CheckedNullPointerException;
86import com.sun.fortress.useful.Fn;
87import com.sun.fortress.useful.HasAt;
88import com.sun.fortress.useful.NI;
89import com.sun.fortress.useful.StringComparer;
90import com.sun.fortress.useful.Useful;
91import com.sun.fortress.useful.Visitor1;
92import com.sun.fortress.useful.Visitor2;
93import edu.rice.cs.plt.tuple.Option;
94
95import static com.sun.fortress.interpreter.glue.WellKnownNames.*;
96
97public class Driver {
98
99    private static boolean _libraryTest = false;
100
101    private Driver() {};
102
103    static public void runTests() {
104    }
105
106    /**
107     * Native code sometimes needs access to the library component wrapper.
108     */
109    static ComponentWrapper libraryComponentWrapper = null;
110    public static Environment getFortressLibrary() {
111        return libraryComponentWrapper.getEnvironment();
112    }
113
114    public static ArrayList<ComponentWrapper> components;
115
116    public static void reset() {
117        components = null;
118        libraryComponentWrapper = null;
119    }
120
121    public static Environment evalComponent(ComponentIndex p,
122                                            FortressRepository fr)
123        throws IOException {
124
125        Init.initializeEverything();
126
127        /*
128         * Begin "linker" -- to be replaced with the real thing, when more
129         * infrastructure is present.
130         */
131
132        HashMap<String, ComponentWrapper> linker = new HashMap<String, ComponentWrapper>();
133
134        Stack<ComponentWrapper> pile = new Stack<ComponentWrapper>();
135        // ArrayList<ComponentWrapper>
136        components = new ArrayList<ComponentWrapper>();
137
138        /*
139         * This looks like gratuitous and useless error checking that
140         * interferes with the "test" flag.
141         *
142        for(String defaultLib : WellKnownNames.defaultLibrary()) {
143            APIName libAPI = NodeFactory.makeAPIName(defaultLib);
144            if (p.getName().equals(libAPI)) {
145                error("Fortress built-in library " + defaultLib + " does not export executable.");
146            }
147        }
148        */
149
150        ComponentWrapper comp = commandLineComponent(fr, linker, pile, p);
151
152        /*
153         * This "linker" implements a one-to-one, same-name correspondence
154         * between APIs and components.
155         *
156         * phase 0.5: starting with the main component, identify other
157         * components that will be needed (the fortress will contain the map
158         * from component C's imported APIs to their implementing components).
159         * Each component will be paired with its top level environment (TLE).
160         *
161         * phase 1: for each component, prepare its TLE by creating all name
162         * slots (nothing in the slots will is initialized AT ALL -- it's all
163         * thunks, empty mutables, and uninitialized types).
164         *
165         * phase 1.5: for each component C, add to C's TLE all the names that C
166         * imports (using the API->component map from the fortress to figure out
167         * the values/types associated with each of those names).
168         *
169         */
170        comp.touchExports(false);
171        // linker.put("Executable", comp);
172        // Don't ever use the string "Executable" directly!
173        // Instead look in WellKnownNames.fss
174        //pile.push(comp);
175
176
177        /*
178         * This is a patch; eventually, it will all be done explicitly.
179         */
180
181        /*
182         * Notice that builtins is used ONLY to satisfy the interface of the
183         * importer for purposes of injecting primitives &c into other components.
184         */
185        ComponentWrapper builtins = new ComponentWrapper(readTreeOrSourceComponent(anyTypeLibrary(), anyTypeLibrary(), fr), linker, WellKnownNames.defaultLibrary());
186        builtins.getEnvironment().installPrimitives();
187        linker.put(anyTypeLibrary(), builtins);
188
189        APIWrapper lib = null;
190
191        libraryComponentWrapper = ensureApiImplemented(fr, linker, pile,
192                                                       NodeFactory.makeAPIName(NodeFactory.interpreterSpan,
193                                                                               fortressLibrary()));
194        lib = libraryComponentWrapper.getExportedCW(fortressLibrary());
195
196        ComponentWrapper nativescomp =
197            ensureApiImplemented(fr, linker, pile,
198                                 NodeFactory.makeAPIName(NodeFactory.interpreterSpan,
199                                                         fortressBuiltin()));
200        APIWrapper natives = nativescomp.getExportedCW(fortressBuiltin());
201
202        /*
203         * This performs closure over APIs and components, ensuring that all are
204         * initialized through phase one of building environments.
205         */
206        while (!pile.isEmpty()) {
207
208            ComponentWrapper cw = pile.pop();
209            components.add(cw);
210
211            CompilationUnit c = cw.getCompilationUnit();
212            List<Import> imports = c.getImports();
213
214            ensureImportsImplemented(fr, linker, pile, imports);
215        }
216
217        // Desugarer needs to know about trait members.
218        for (CUWrapper cw : components) {
219            cw.preloadTopLevel();
220        }
221
222        // Iterate to a fixed point, pushing trait info as far as necessary.
223        // This is not the same as pushing information into environments, which
224        // occurs below the call(s) to populateOne.
225        boolean change = true;
226        while (change) {
227            change = false;
228            for (ComponentWrapper cw : components) {
229                change |= injectTraitMembersForDesugaring(linker, cw);
230            }
231
232            change |= injectLibraryTraits(components, lib);
233            change |= injectLibraryTraits(components, natives);
234        }
235
236        /*
237         * After all apis etc have been imported, populate their environments.
238         * First the component is populated, then (recursively, inside that
239         * call to populate) the exported apis are populated.
240         */
241        for (int i = components.size() - 1; i >= 0; i--) {
242            ComponentWrapper cw = components.get(i);
243            // System.err.println("populating " + cw);
244            cw.populateOne();
245        }
246
247        for (CUWrapper cw : components) {
248            cw.initTypes();
249        }
250        for (CUWrapper cw : components) {
251            scanAllFunctionalMethods(cw.getEnvironment());
252        }
253        for (CUWrapper cw : components) {
254            cw.initFuncs();
255        }
256
257        for (CUWrapper cw : components) {
258            finishAllFunctionalMethods(cw.getEnvironment());
259        }
260
261        for (CUWrapper cw : components) {
262            cw.reset();
263        }
264
265         for (CUWrapper cw : components) {
266            cw.initVars();
267        }
268
269        return comp.getEnvironment();
270    }
271
272
273    /**
274     * Copies rewriting information (traits, what members they define) from apis into
275     * components.  This scaffolding is necessary to get the simplification right
276     * for member (field, method) references.
277     *
278     * @param linker
279     * @param cw
280     */
281    private static boolean injectTraitMembersForDesugaring(
282            HashMap<String, ComponentWrapper> linker, ComponentWrapper cw) {
283        CompilationUnit c = cw.getCompilationUnit();
284        List<Import> imports = c.getImports();
285        boolean change = false;
286
287        for (Import i : imports) {
288            if (i instanceof ImportApi) {
289
290                    /*
291                     * Not-yet-implemented because of issues with selectors.
292                     */
293                bug(errorMsg("NYI 'Import api APIName'; ",
294                             "try 'import APIName.{...}' instead."));
295            } else if (i instanceof ImportedNames) {
296                ImportedNames ix = (ImportedNames) i;
297                APIName source = ix.getApiName();
298                String from_apiname = NodeUtil.nameString(source);
299
300                ComponentWrapper from_cw = linker.get(from_apiname);
301                APIWrapper api_cw = from_cw.getExportedCW(from_apiname);
302
303                /* Pull in names, UNqualified */
304
305                if (ix instanceof ImportNames) {
306                    /* A set of names */
307                    List<AliasedSimpleName> names = ((ImportNames) ix).getAliasedNames();
308                    for (AliasedSimpleName an : names) {
309                        IdOrOpOrAnonymousName name = an.getName();
310                        Option<IdOrOpOrAnonymousName> alias = an.getAlias();
311                        /*
312                         * If alias exists, associate the binding from
313                         * component_wrapper with alias, otherwise associate
314                         * it with plain old name.
315                         */
316                        /* probable bug: need to insert into ownNonFunction names */
317                        change |= cw.injectAtTopLevel(alias.unwrap(name).stringName(),
318                                                                name.stringName(),
319                                                                api_cw,
320                                                                cw.excludedImportNames);
321                    }
322
323                } else if (ix instanceof ImportStar) {
324                    /* All names BUT excepts, as they are listed. */
325                    final List<IdOrOpOrAnonymousName> excepts = ((ImportStar) ix)
326                            .getExceptNames();
327                    final Set<String> except_names = Useful.applyToAllInserting(
328                            excepts,
329                            new Fn<IdOrOpOrAnonymousName, String>() {
330                                public String apply(IdOrOpOrAnonymousName n) {
331                                    return NodeUtil.nameString(n);
332                                }
333                            },
334                            new HashSet<String>());
335
336                    for (String s : api_cw.getTopLevelRewriteNames()) {
337                        if (! except_names.contains(s) &&
338                                !cw.isOwnName(s) &&
339                                !cw.excludedImportNames.contains(s)) {
340                            change |= cw.injectAtTopLevel(s, s, api_cw, cw.excludedImportNames);
341                        }
342                    }
343                    for (String s : api_cw.getFunctionals()) {
344                        if (! except_names.contains(s) &&
345                                !cw.excludedImportNames.contains(s)) {
346                            change |= cw.injectAtTopLevel(s, s, api_cw, cw.excludedImportNames);
347                        }
348                    }
349                }
350            } else {
351                bug(errorMsg("NYI Import " + i));
352            }
353        }
354
355
356        return change;
357    }
358
359    private static boolean injectLibraryTraits(List<ComponentWrapper> components,
360            APIWrapper lib) {
361        boolean change = false;
362        for (ComponentWrapper cw : components) {
363            for (String s : lib.getTopLevelRewriteNames()) {
364                if (cw.isOwnName(s)) {
365                    continue;
366                }
367                change |= cw.injectAtTopLevel(s, s, lib, cw.excludedImportNames);
368            }
369            for (String s : lib.getFunctionals()) {
370                change |= cw.injectAtTopLevel(s, s, lib, cw.excludedImportNames);
371            }
372        }
373        return change;
374    }
375
376    private static void scanAllFunctionalMethods(final Environment e) {
377        Visitor2<String, FType> vt = new Visitor2<String, FType>() {
378            public void visit(String s, FType o) {
379                if (o instanceof FTraitOrObjectOrGeneric) {
380                    FTraitOrObjectOrGeneric tooog = (FTraitOrObjectOrGeneric) o;
381                    tooog.initializeFunctionalMethods(e);
382                    if (tooog instanceof FTraitOrObject) {
383                        for (FType t : ((FTraitOrObject)tooog).getProperTransitiveExtends())
384                            if (t instanceof FTraitOrObjectOrGeneric)
385                                ((FTraitOrObject)t).initializeFunctionalMethods(e);
386                    } else {
387
388                    }
389                }
390            }
391        };
392        e.visit(vt, null, null, null, null);
393    }
394
395    private static void finishAllFunctionalMethods(final Environment e) {
396        Visitor2<String, FType> vt = new Visitor2<String, FType>() {
397            public void visit(String s, FType o) {
398                if (o instanceof FTraitOrObjectOrGeneric) {
399                    FTraitOrObjectOrGeneric tooog = (FTraitOrObjectOrGeneric) o;
400                    tooog.finishFunctionalMethods(e);
401                    if (tooog instanceof FTraitOrObject) {
402                        for (FType t : ((FTraitOrObject)tooog).getProperTransitiveExtends())
403                            if (t instanceof FTraitOrObjectOrGeneric)
404                                ((FTraitOrObject)t).finishFunctionalMethods(e);
405                    }
406                }
407            }
408        };
409        e.visit(vt, null, null, null, null);
410    }
411
412    /**
413     * For each imported API, checks to see if it is already "linked". If not,
414     * "finds" it (looks for apiname.fss/apiname.tfs) and reads it in and sticks
415     * it in the "pile".
416     *
417     * For each component, also reads in the corresponding APIs so that we know
418     * what to export.
419     *
420     * @param linker
421     * @param pile
422     * @param imports
423     */
424    private static void ensureImportsImplemented (
425            FortressRepository fr,
426            HashMap<String, ComponentWrapper> linker,
427            Stack<ComponentWrapper> pile,
428            List<Import> imports
429        )
430        throws IOException
431    {
432
433        for (Import i : imports) {
434            if (i instanceof ImportApi) {
435                ImportApi ix = (ImportApi) i;
436                List<AliasedAPIName> apis = ix.getApis();
437                for (AliasedAPIName adi : apis) {
438                    APIName id = adi.getApiName();
439                    ensureApiImplemented(fr, linker, pile, id);
440                }
441            }
442            else if (i instanceof ImportedNames) {
443                ImportedNames ix = (ImportedNames) i;
444                APIName source = ix.getApiName();
445                ensureApiImplemented(fr, linker, pile, source);
446            }
447            else {
448                bug(i, "Unrecognized import");
449            }
450        }
451    }
452
453    /**
454     * Returns the component wrapper (for the component) that exports this API.
455     * Needs to generalize to sets of APIs in the future, perhaps.
456     *
457     * @param linker
458     * @param pile
459     * @param id
460     */
461    private static ComponentWrapper ensureApiImplemented(
462            FortressRepository fr,
463            HashMap<String, ComponentWrapper> linker,
464            Stack<ComponentWrapper> pile, APIName name) throws IOException {
465        String apiname = NodeUtil.nameString(name);
466        ComponentWrapper newwrapper = linker.get(apiname);
467        if (newwrapper == null) {
468            /*
469             * Here, the linker prototype takes the extreme shortcut of assuming
470             * that Api Foo is implemented by Component Foo, dots and all.
471             *
472             * These few lines are what needs to be replaced by a real linker.
473             */
474            Api newapi = readTreeOrSourceApi(apiname, apiname, fr);
475            ComponentIndex newcomp = readTreeOrSourceComponent(apiname, apiname, fr) ;
476
477            APIWrapper apicw = new APIWrapper(newapi, linker, WellKnownNames.defaultLibrary());
478            newwrapper = new ComponentWrapper(newcomp, apicw, linker, WellKnownNames.defaultLibrary());
479            newwrapper.touchExports(true);
480            linker.put(apiname, newwrapper);
481            pile.push(newwrapper);
482
483            List<Import> imports = newapi.getImports();
484            ensureImportsImplemented(fr, linker, pile, imports);
485        }
486        return newwrapper;
487    }
488
489    private static ComponentWrapper commandLineComponent(FortressRepository fr,
490            HashMap<String, ComponentWrapper> linker,
491            Stack<ComponentWrapper> pile, ComponentIndex comp_index) throws IOException {
492
493            Component comp = (Component) (comp_index.ast());
494            APIName name = comp.getName();
495            String apiname = NodeUtil.nameString(name);
496            ComponentWrapper comp_wrapper;
497
498            List<APIWrapper> exports_list = new ArrayList<APIWrapper>(1);
499            for (APIName ex_apiname : comp.getExports()) {
500                String ex_name = NodeUtil.nameString(ex_apiname);
501                Api newapi = readTreeOrSourceApi(ex_name, ex_name, fr);
502                exports_list.add( new APIWrapper(newapi, linker, WellKnownNames.defaultLibrary()) );
503            }
504
505            comp_wrapper = new ComponentWrapper(comp_index, exports_list, linker, WellKnownNames.defaultLibrary());
506            fr.forgetComponent(name);
507            comp_wrapper.touchExports(true);
508            linker.put(apiname, comp_wrapper);
509            pile.push(comp_wrapper);
510
511            for (CUWrapper apicw : exports_list) {
512                List<Import> imports  = apicw.getImports();
513                linker.put(apicw.name(), comp_wrapper);
514                ensureImportsImplemented(fr, linker, pile, imports);
515            }
516        return comp_wrapper;
517    }
518
519    // This runs the program from inside a task.
520    public static FValue
521        runProgramTask(ComponentIndex p,
522                       List<String> args, String toBeRun,
523                       FortressRepository fr)
524        throws IOException
525    {
526
527        Environment e = evalComponent(p, fr);
528
529        FunctionClosure run_fn = e.getClosure(toBeRun);
530        Toplevel toplevel = new Toplevel();
531        ArrayList<FValue> fvalueArgs = new ArrayList<FValue>();
532        for (String s : args) {
533            fvalueArgs.add(FString.make(s));
534        }
535        FValue ret = run_fn.functionInvocation(fvalueArgs, toplevel);
536        // try {
537        // e.dump(System.out);
538        // } catch (IOException ioe) {
539        // System.out.println("io exception" + ioe);
540        // }
541       return ret;
542    }
543
544    static FortressTaskRunnerGroup group;
545
546    static int getNumThreads() {
547        int numThreads;
548
549        String numThreadsString = System.getenv("FORTRESS_THREADS");
550        if (numThreadsString != null)
551            numThreads = Integer.parseInt(numThreadsString);
552        else {
553            int availThreads = Runtime.getRuntime().availableProcessors();
554            if (availThreads <= 2)
555                numThreads = availThreads;
556            else
557                numThreads = (int) Math.floor((double) availThreads/2.0);
558        }
559        return numThreads;
560    }
561
562
563    public static void runTests(FortressRepository fr, ComponentIndex p, boolean verbose)
564        throws Throwable {
565
566        CollectTests bte = new CollectTests ();
567        bte.visit(p.ast());
568        List<String> tests = CollectTests.getTests();
569
570        if (group == null)
571            group = new FortressTaskRunnerGroup(getNumThreads());
572
573        for (String s : tests) {
574            List<String> args = new ArrayList<String>();
575            if ( verbose )
576                System.err.print("starting " + s + "... ");
577            EvaluatorTask evTask = new EvaluatorTask(fr, p, s, args);
578            group.invoke(evTask);
579            if (evTask.causedException()) {
580                throw evTask.taskException();
581            }
582            if ( verbose )
583                System.err.println("finishing " + s);
584        }
585    }
586
587    // This creates the parallel context
588    public static FValue runProgram(FortressRepository fr, ComponentIndex p,
589                                    List<String> args)
590        throws Throwable {
591
592        if (group == null)
593            group = new FortressTaskRunnerGroup(getNumThreads());
594
595        EvaluatorTask evTask = new EvaluatorTask(fr, p, "run", args);
596        try {
597            group.invoke(evTask);
598            if (evTask.causedException()) {
599                throw evTask.taskException();
600            }
601            return evTask.result();
602        }
603        finally {
604            // group.interruptAll();
605        }
606    }
607
608
609    private static class Toplevel implements HasAt {
610        public String at() {
611            return "toplevel";
612        }
613
614        public String stringName() {
615            return "driver";
616        }
617    }
618
619    private static ComponentIndex readTreeOrSourceComponent(String key, String basename, FortressRepository p) throws IOException {
620
621        String name  = key;
622        APIName apiname = NodeFactory.makeAPIName(NodeFactory.interpreterSpan, name);
623
624        ComponentIndex ci = p.getComponent(apiname);
625        return ci;
626
627    }
628
629
630    private static Api readTreeOrSourceApi(String key, String basename, FortressRepository p) throws IOException {
631        String name  = key;
632        APIName apiname = NodeFactory.makeAPIName(NodeFactory.interpreterSpan, name);
633        ApiIndex ci = p.getApi(apiname);
634        CompilationUnit c = ci.ast();
635        return (Api) c;
636
637    }
638
639    static Hashtable<String, CompilationUnit> libraryCache = new Hashtable<String, CompilationUnit>();
640
641}
Note: See TracBrowser for help on using the browser.