vrtbl/passerine

Records and Modules

slightknack opened this issue · 1 comments

Passerine's module system is pretty simple. At it's core, a module is defined as:

my_module = mod {
    x = 0
    y = n -> x + 1
    double = a -> 2 * a
    -- ...
}

my_module::double 4
-- is 8

Basically a module turns a scope into a struct, where all top-level variables become fields on that struct. As seen in the above example, we use mod to do this.

All files are modules, and are imported using the use keyword.

-- my_module.pn
x = 0
y = n -> x + 1
double = a -> 2 * a
-- ...

-- main.pn
use my_module
my_module::double 3
-- is 2

A folder with a file named mod.pn in it is also a module. This is similar to how Rust behaves:

-- my_module/mod.pn
-- ...

-- main.pn
use nest::my_module
-- ...

Modules are resolved at compile time. Upon using use, Passerine:

  1. Looks for the file X.pn or X/mod.pn in the current scope of the file being compiled
  2. If the file has already been compiled, use the cached version
  3. Insert the compiled file into the current file, wrapping it all in a mod operation.

All modules must form a tree hierarchy. i.e, there should be only one path from the root ,nest, to any other module. Modules can be mutually recursive, but in this case the full path must be specified:

-- a.pn
use nest::b
print b::x
y = "Hello, "

-- b.pn
use nest::a
print a::y
x = "World!"

-- main.pn
use nest::a
use nest::b

Modules are only executed once, upon first load. Hello, World would be printed to the terminal in the above example. Here's the big ol' todo list. If you'd like to help, I'll mentor anyone through any one of these steps:

  • Implement a Record variant on Data in src/common/data.rs, including methods for displaying it.
  • TODO: This will require some discussion, but we basically need to add support for paths.
  • Implement lexing/parsing for the index (::), mod <block>, use <path>, and nest keywords.
  • Implement lexing/parsing for record types, e.g. { foo: "Bar", baz: 27.5 }
  • Implement destructuring on record types, e.g. { thing: banana } = { thing: "Hello" }
  • Add support for compiling mod blocks to bytecode, converting them to records
  • Add support for indexing on records, and the nest keyword.
  • Add support for loading modules from other files. TODO: We might have to loop in Aspen to resolve these files.
  • Add support for loading modules from other folders. TODO: Aspen, see above step.
  • Polish and make sure everything works together.

The dev branch is a bit of a mess right now as I'm doing some big refactoring, so please make a feature branch off of master and implement any changes there. This will be a 0.9.X feature.

A language currently with the best module system is OCaml. These is a lot this can be borrowed from it.