Defining Modules
In this section, we’ll talk about modules and other parts of the module system, namely paths that
allow you to name items and the use
keyword that brings a path into scope.
Modules Cheat Sheet
Here we provide a quick reference on how modules, paths, and the use
keyword work in the compiler,
and how most developers organize their code. We’ll be going through examples of each of these rules
throughout this chapter, but this is a great place to refer to as a reminder of how modules work.
- Start from the package root: When compiling a package, the compiler first looks for code to
compile in the package root file, which is
src/lib.pnt
for a library package orsrc/contract.pnt
for a contract package. - Declaring modules: You can declare new modules by creating files for them in the appropriate
directories. Say you want to declare a new
garden
module. You have two options:- You can create the file
src/garden.pnt
if you want thegarden
module to be a single file module. That is, if you don't want the modulegarden
to have submodules. - You can create the file
src/garden/garden.pnt
if you want the module to be a multi-file module. That is, if you want the modulegarden
to have submodules. The submodules ofgarden
would then live in thesrc/garden
directory.
- You can create the file
- Declaring submodules: In any directory other than the package root directory, you can create
new submodules. For example, say you want to declare a submodule of
garden
namedvegetables
. You have two options:- You can create the file
src/garden/vegetables.pnt
if you want thevegetables
submodule to be a single file submodule. That is, if you don't want the submodulevegetables
to have its own submodules. - You can create the file
src/garden/vegetables/vegetables.pnt
if you want thevegetables
submodules to be a multi-file submodule. That is, if you want the submodulevegetables
to have its own submodules.
- You can create the file
- Paths to code in modules: Once a module is part of your package, you can refer to code in that
module from anywhere else in the same package. For example, an enum
Asparagus
in the garden vegetables module would be found at::garden::vegetables::Asparagus
. - The
use
keyword: Within a Pint file, theuse
keyword creates shortcuts to items to reduce repetition of long paths. For example, you can create a shortcut to::garden::vegetables::Asparagus
using the statementuse ::garden::vegetables::Asparagus;
declared at global scope in a Pint file. From then on, you only need to writeAsparagus
to make use of that enum in this file.
Here, we create a contract package named backyard
that illustrates these rules. The package's
directory, also named backyard
, contains these files and directories:
backyard
├── pint.toml
└── src
├── contract.pnt
└── garden
├── garden.pnt
└── vegetables.pnt
The package root file is src/contract.pnt
since this is a contract package. It contains:
use garden::vegetables::Asparagus;
predicate Foo(green_asparagus: Asparagus) {
constraint green_asparagus == Asparagus::Green;
}
The submodule vegetables
which is defined in src/garden/vegetables.pnt
, contains:
union Asparagus = Green | White | Purple;