sunjay / brain

A high level programming language that compiles into the brainfuck esoteric programming language

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Modules

sunjay opened this issue · comments

Must be implemented in tandem with: #59

Support the following syntax.

For declaring modules within a package.

// private module
mod motion;

// inline module
mod foo {
    // code for this module goes here
    // can refer to scope above using super
    use super::*;
    //pub blah = ...
}
// foo::blah can be used in this module

// Exposed as just modules since these are less often used and more sensible to access this way
pub mod screen;
pub mod shapes;
pub mod pen;

pub use motion::*;

For linking an external library:

// use package is a compound keyword specially used for linking
// It is only valid to use this statement in the root module for a package
use package something;

use something;
use something::foo;
use something as bar;
use something::foo as bar;
use something::{foo as bar, spam};
use something::{self, foo as bar, spam};
use something::*;
  • support spans across files (implement a code map like rust)
  • local module resolution
  • being able to use functions from other files/directories
  • using external libraries (depends on #38)
  • every module has its own scope/namespace
  • able to access module public items using paths
  • make prelude modules actual modules instead of just abusing scopes
    • namespace prelude modules under std:: and use std::<modname>::* for each of them in prelude's root

Implementation Notes

  • Scopes/modules really only need to contain type definitions and size definitions. The definitions should all be compiled once into a reasonable intermediate form and then reused during code generation whenever that function is called in another module.

  • A module is really just a synonym for a single isolated level of scope.

  • The use keyword is a type of declaration which declares a name in the current scope that maps to a module definition

  • When as is used in use to rename a module in the current scope, it's really just changing the name that the module is being declared as

  • Any path can be included with the use keyword because it simply declares things in the current scope

  • To avoid unnecessary copying, it may be prudent to optimize for when an entire module is included in a scope (using *). Rather than copying the declarations of the entire module into the current scope, we should implement "linked scopes". With linked scopes, each scope level in the scope stack also maintains a vector of references (ids or otherwise) to other scopes. These are used as backups for lookups that aren't found in that scope level before traversing down to other scope levels. This could be implementing by upgrading the Scope type to an actual struct rather than just a type alias. Since modules are just single scopes, they can work well with this idiom. Each scope would have to have an ID and modules would have to be declared elsewhere in order to avoid re-evaluating the same module over and over again.

    • If this is too complicated, it may be sufficient in the short term to just do the long copy
    • something like this is also necessary to avoid accidentally overwriting things from other modules. We still want all of those options to match. The linked modules should be added in order so that the correct definitions take precedence over others. Test this.