Import
The import directive allows you to include type definitions and other declarations
from other .zng files into your main specification.
Types, traits, and modules can appear multiple times across the transitive set of imported files,
and their content is merged together.
Syntax
import "./path/to/file.zng";
Path Resolution
Import paths are resolved relative to the directory containing the current .zng file:
import "./types.zng";
At this time, absolute paths are not supported.
Importing paths without a leading specifier (e.g. import "foo/bar.zng";)
is reserved for a possible future extension.
Above, "the current .zng file" refers to the .zng file being parsed,
which is not necessarily the top-level .zng file passed to zngur on the command line.
Behavior
When an import statement is processed:
- The parser reads and parses the imported file
- All declarations from the imported file are merged into the current specification
- Imported content becomes available as if it were defined in the importing file
- Import processing happens recursively - imported files can themselves contain import statements
Merging
Zngur's merge algorithm attempts to compute the union of each set of declarations
which share an identity (e.g. every type crate::Inventory { ... } across all imported files).
Duplicates are ignored, but contradictions will raise a compiler error.
For example, if two different type crate::Inventory { ... } declarations
both specify wellknown_traits(Debug);, parsing will succeed.
However, if they specify different layouts, an error will be reported.
#convert_panic_to_exception constraints
#convert_panic_to_exception may only appear in a top-level .zng file.
This is an application-level decision that should not be determined by dependent libraries.
Example
main.zng:
import "./core_types.zng";
import "./iterators.zng";
// May only appear in the top-level file.
#convert_panic_to_exception
type MyApp {
#layout(size = 8, align = 8);
fn run(&self) -> i32;
}
core_types.zng:
mod ::std {
type option::Option<i32> {
#layout(size = 8, align = 4);
wellknown_traits(Copy);
constructor None;
constructor Some(i32);
fn unwrap(self) -> i32;
}
mod vec {
type Vec<i32> {
#layout(size = 24, align = 8);
fn new() -> Vec<i32>;
fn push(&mut self, i32);
}
}
}
iterators.zng:
mod ::std {
mod vec {
type Vec<i32> {
fn into_iter(self) -> ::std::vec::IntoIter<i32>;
}
}
}
In this example, main.zng imports type definitions from two separate files,
allowing for better organization of the zngur specification.
Notice that iterators.zng is able to "reopen" the ::std::vec::Vec<i32> specification
and extend it with a single function, into_iter.
It does not need to respecify the #layout because that is already declared in core_types.zng.