On Jan 30, 2012, at 12:09 PM, Andreas Rossberg wrote:
> (Just a quick reply, because I'm in a bit of a hurry.)
>
> On 30 January 2012 19:17, Allen Wirfs-Brock <[email protected]> wrote:
>>>>
...
>>>>
>
> The analysis is not as straightforward as it might seem. In particular, this:
>
>> The exported name list of a module can be generated while the module is
>> parsed
>
> unfortunately is not true, because of (1) alias bindings, and (2)
> import *. For example, with
>
> module A = B.C
Dave/Sam, it would be nice if we had up to date syntax at
http://wiki.ecmascript.org/doku.php?id=harmony:modules
>
> you won't know what A exports before you haven't analysed B and its
> nested C, which might come later in the program. And those can
> recursively refer to A, which might require you knowing what A
> exports. Here is a more messed up, random example:
>
> 1 module A = B.C
> 2 module D { ... }
> 3 module B {
> 4 let x = B.E.x
> 5 import * from A
> 6 export module B {
> 7 export module E = D
> 8 export module C {
> 9 export module D { ... }
> }
> }
> }
I added line numbers above for reference. I think there is a basic bug in the
above that may just be a typo. "B" reference in line 1 must refer to the
module defined in line 3. Hence "B.C" must refer to an export of "C" from that
module. However, the only export from that module is line 6 which exports "B"
so the "B.C reference in line 1 is invalid. This does require any circular
analysis and line 5 doesn't impact it.
To get around this this issue, I looked at assuming that line 6 wasn't really
intended to be there but that seems to break your example in other ways. What
did you really have in mind?
>
> You couldn't tell which D is aliased by E before processing C and so
> on. In general, it's all recursive, so a simple AST traversal alone,
> in whatever order, won't do. Instead you need to collect and solve
> constraints. In terms of type inference, you infer and unify
> (principal) types.
I agree that * imports complicate matters. I thought there had been discussion
at some point about eliminating them, but I'm not yet convinced that by
themselves they turn this into a constraint solving problems. In stead I think
that we need appropriate static restrictions to ensure that it can never be
such a problem. If it takes solving to understand module compositions then we
have created a too power model of module composition. If the module linkages
aren't pretty damn obvious to both the writer and the reader, then we've done
something wrong.
I'm actually not a bit fan of using nesting to do module wiring, but I don't
think it has result in needing constraint solving to understand the wiring.
>
>
>>>> 2) module instantiation is performed for the block. This instantiates each
>>>> module defined by the top level of the block, instantiating a module
>>>> includes producing the list of identifiers exported by the module. Each
>>>> identifier is associated with a new uninitialized binding. Instantiated
>>>> modules are not initialized (their body is not executed) at this time.
>>>
>>> You need a new uninitialized binding for all identifiers in the
>>> module's local scope, not just the exported ones.
>> The non-exported declarations within a module don't need to be instantiated
>> until module initialization. You probably could instantiate them durning my
>> module instantiation step but I'm trying to only identify what must happen
>> at that step.
I was really thinking about non-module declarations when I wrote the above
statement. Module alias declarations like in these examples do lead to a more
complex traversal. I have to think about is some more.
>
> I'm not so sure. You could export parts of a local module:
>
> module A {
> module B { export module C { ... } }
> export module C = B.C
> }
> module C = A.C
>
>
>>>> 3) An initialized binding for "a" is is created in the top level
>>>> environment
>>>> for the script. (all top level binding are instantiate at this point, if
>>>> there were any others). Note that the binding for a is initialized (it
>>>> reference a module instance object) but the module itself is not yet
>>>> initialized
>>>> 4) initialize module a
>>>> 5) module instantiation is performed for the body of module a. This
>>>> instantiates a module instance for module b with exported identifier "y"
>>>> and
>>>> its binding.
>>>
>>> It's not quite that simple. Recursive initialization does not suffice,
>>> because there can be arbitrary import/export/aliasing cycles (e.g., b
>>> could import from a as well). Consequently, you generally need to
>>> create the instance object for _all_ modules in the program first,
>>> before you can start initializing _any_ of them (or the toplevel, for
>>> that matter).
>>
>> I'm trying to demonstrate an algorithm that takes care of this. Give me a
>> specific example that you don't think works.
>
> If I understand your description correctly, then consider this:
>
> module A { export module C = B.C; export module D { ... } }
> module B { export module C { ... }; export module D = A.D }
Sold, it certainly does look like that modules need to be identified and linked
before evaluation starts.
that feels to me link a distinct pass.
Allen_______________________________________________
es-discuss mailing list
[email protected]
https://mail.mozilla.org/listinfo/es-discuss