Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

VM: Modules. #53

Closed
wants to merge 2 commits into from
Closed

VM: Modules. #53

wants to merge 2 commits into from

Conversation

matthewhammer
Copy link
Contributor

@matthewhammer matthewhammer commented Sep 9, 2022

This PR implements modules for the VM. (WIP)

  1. For each module, combine names defined in the module to create a valid environment. Reusing the same name is an Interruption
  2. combine names in nested modules, and also permit outer names to flow into these internal modules. Unlike inRust, in Motoko, all names in super scopes flow into subscopes.

Unlike other constructs, modules require doing a lot of steps that do not correspond to ordinary execution, but rather, correspond to phases just before or during type checking.

These steps are necessary to resolve identifiers and module projections in real Motoko programs, and involve resolving nested recursive definitions.

Each named module definition introduces a recursive scope that we construct incrementally, in a step-wise manner. When they nest, additional steps propagate the recursion between the nested levels.

Why?

We could eschew a step-based approach, and do the module-level resolution of paths in a batch style, with batch-style errors each time an identifier is used twice. However, that has two drawbacks:

  1. Goes against the rest of the project, where we show internal progress at every possible step and interrupt it immediately when there is an issue. A batch algorithm is not like this, and would introduce another "mode" of interacting with programs that happens before they "run step by step". That would complicate things, including the UX design, potentially.
  2. If we ever want to improvise with other pre-execution steps, this would introduce a place to do them. Such steps may include experimental intensional features, like let box; as with modules, they would step before the program evaluates.

Scoping using nested modules

Consider this nested module declaration:

module {
  module X {
    /* module Y { }; */ // will shadow Y sibling of X
    public module M {
      func f () : Nat { 
           g();h
           N.g();
           M.g();
           /* X.N.g() */
           x
      };
      public func g () { Y.y(); Y.Z.z() };
    };
    module N {
      public func g () { Y.y(); /* Z.z() /* error. */ */ };
    };  
    public let x = 5;
  };

  module Y {
    public module Z { public func z() { Y.y(); y() } };
    public func y() { X.M.g() };
  };
}

Notice:

  • function X.M.g can "see" Y.y and Y.Z.z.
  • function Y.Z.z can "see" function "y" and also see the same function as Y.y.
  • function X.N.g can "see" Y.y but not Z.z (Y.Z.z() works though)

This example could be smaller and simpler. It's something I have been using as I poke at the compiler to test my understanding of the language, and having it be about this large as been helpful.

@matthewhammer
Copy link
Contributor Author

Continued by #70

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant