Skip to main content

Crate zelkova_compiler

Crate zelkova_compiler 

Source
Expand description

The Zelkova compiler

§How to compile a package ?

Note: an interface is built for every module that canonicalizes and kept for whatever imports it within its package; a package that checks also offers its modules’ interfaces to the packages that depend on it. What is still missing is emitting one, so a dependency is compiled from source on every build.

  1. Read the package’s zelkova.toml manifest, and resolve the build: every package reachable through dependencies, plus the root package’s test-dependencies, each ordered after the packages it depends on. Steps 2 to 6 then run once per package — bar the ones only test-dependencies reaches, which a build that did not ask for the tests resolves and leaves uncompiled — over the two source roots: src/ and, for the root package when its tests were asked for, tests/, beside its own manifest. The root’s tests/ is compiled last, after the packages only test-dependencies reach, since one of those may depend on the root’s src/. Before a package’s modules are checked, the whole map of module names it can import is built — its own, plus each direct dependency’s public modules under that package’s namespace or, unwrapped, under their own names — and a name two modules both answer to stops that package there.
  2. Collect all *.zelkova files with their path name relatives to the root.
  3. Create a SourceFiles mapping from ModuleName to parser::Module.
    1. module names are deduced from file name
    2. parsing is done through parser::parse_recovering, which reports every declaration that fails rather than only the first. A file whose header parsed keeps its module, with a record of each declaration that failed; one whose header did not is still a module its importers find, holding nothing
    3. Verify that parser::Module.name match the one from the file system
  4. Build a dependency graphs from the modules import
    1. build it
    2. Verify there is no cyclic relation between modules
  5. Following the deps graph,
    1. canonicalize each modules. A declaration that does not canonicalize costs the module that declaration and nothing else, an import that does not resolve costs it that import and nothing else, and the module publishes its Interface to the modules checked after it, whatever the checks find in it. A not-found error that only restates one of those failures is not reported again (canonical::canonicalize_recovering)
    2. check each module (type check, exhaustiveness, etc…), and build the ir::Module a backend reads out of the canonical module and what the typer solved. The IR is built whether or not a declaration was broken or rejected, and lists each such one as unchecked
    3. Bonus point to parallelize the tree branches which are not dependent on each others
  6. Report. Each phase returns every error it found, check_module_recovering tags those with the module they came from, and check_package accumulates them across modules and hands them back with the file database and every status line, printing nothing. See the PhaseError trait for what a phase error owes the Diagnostic it renders as.

Every step is check_package’s, which writes nothing anywhere. Emitting a build that checked, writing it and printing what the check found are the driver module’s.

Modules§

canonical
The canonical representation of a zelkova programs is a translation of a local source into the broader world.
default_imports
The imports every module gets without writing them.
dependencies
Walk package’s module dependencies
exhaustiveness
This module contains the exhaustiveness checker for pattern matching.
ir
The intermediate representation code generation reads.
manifest
zelkova.toml, the package manifest.
name
Home to the Name and QualName primitives
program
A program’s entry point: the module a manifest’s main names, held to Programs.
resolve
The packages a build is made from, and the module names each of them sees.
scalars
The five type names the compiler knows as scalars, and the one it knows beside them.
source
typer
This module contains the type checker pass of the language

Structs§

CheckedModule
One module the checks built a tree for, in both the forms the compiler still needs it. Whether it passed them is said beside it: by check_module’s Ok, or by the empty error list of check_module_recovering’s Outcome::Module.
CheckedSource
One module of a build the check built a tree for, with the file it was read from and the source root it was read under. Which list of PackageCheck holds it says whether it checked.
Interface
An interface is trim down version of a module.
InvalidPackageName
PackageName::new refused this string; it names the input so a caller can report it.
ModuleName
A module name represent
PackageCheck
What check_package found: everything a build needs to emit, and everything that went wrong, with nothing printed and nothing written.
PackageName
A package name: one flat identifier, ASCII lowercase letters, digits and hyphens, starting with a letter, with every hyphen followed by a letter — docs/spec/packages.md’s whole rule for name. That shape is what keeps a package name and a module name from ever being confused (one is lowercase-with-hyphens, the other uppercase-with-dots), and what makes the namespace a package’s name derives unambiguous.
SourceSpan
A byte span paired with the file it was written in.
SpanLabel
One underlined region of the user’s source, and what to say about it.
Status
One status line of a check, in the order the check reached it: parsed 8 modules, checked modules: [..], or what failed in either.

Enums§

CompilationError
Every way checking a package can fail, tagged with the phase that failed.

Traits§

Checked
What dependencies::ModuleWalker::check_in_order needs of whatever its checker hands back: a name to key the module by, and the interface the modules after it are checked against.
PhaseError
What a compiler phase owes the diagnostic reporter.

Functions§

check_module
Take a parsed module file within the ecosystem and apply all checks to it
check_module_recovering
Apply every check to one parsed module, and hand back the module the checks built beside everything they found wrong with it.
check_package
Check the package rooted at package_dir and every package it depends on, as zelkova::compile_package does, and hand back what was found without printing or writing anything.
check_package_with_tests
check_package, checking the root package’s tests/ as well as its src/, as zelkova::compile_package_with_tests does.
phase_diagnostic
Render the errors one phase produced for one module.
plain_diagnostic
Render an error that is about no place in any source — a path on disk, a program that could not be started — as its message and its notes, with no label.