pub struct ModuleGraph<T> { /* private fields */ }Expand description
A set of modules and the import edges between them, against which names are resolved.
ModuleGraph<T> is the owner of resolution state. Each module is added with a
name and the SourceId of the file it came from, then has names
defined in it and names imported into it
from other modules. resolve answers the question every
use/import asks — which item does this name refer to? — returning the
language-supplied payload T, or a ResolveError for a name that is missing,
private, or part of an import cycle.
T is whatever the language wants a name to resolve to — a definition id, an
AST node handle, a type — and carries no trait bounds. A module’s namespace is
flat: a name is declared at most once per module, whether by definition or
import. Names are keyed in a BTreeMap, so a lookup compares interned-symbol
integers in O(log items) and iteration is deterministic.
§Examples
use intern_lang::Interner;
use module_lang::{ModuleGraph, Visibility};
use source_lang::SourceMap;
// Two files, each a module.
let mut sources = SourceMap::new();
let app_src = sources.add("app.lang", "use util.helper;").expect("fits");
let util_src = sources.add("util.lang", "pub fn helper() {}").expect("fits");
let mut names = Interner::new();
let helper = names.intern("helper");
// A module per file; `util` exports `helper`; `app` imports it.
let mut graph: ModuleGraph<&str> = ModuleGraph::new();
let app = graph.add_module(names.intern("app"), app_src);
let util = graph.add_module(names.intern("util"), util_src);
graph.define(util, helper, Visibility::Public, "fn helper")?;
graph.import(app, util, helper)?;
// `helper` resolves from `app` through the import to its definition in `util`.
assert_eq!(graph.resolve(app, helper), Ok(&"fn helper"));Implementations§
Source§impl<T> ModuleGraph<T>
impl<T> ModuleGraph<T>
Sourcepub const fn new() -> Self
pub const fn new() -> Self
Creates an empty graph.
§Examples
use module_lang::ModuleGraph;
let graph: ModuleGraph<()> = ModuleGraph::new();
assert!(graph.is_empty());Sourcepub fn with_capacity(modules: usize) -> Self
pub fn with_capacity(modules: usize) -> Self
Creates an empty graph with room for modules modules before reallocating.
A hint only: the graph still grows as needed. Useful when the file count is known up front, to add every module without an intermediate reallocation.
§Examples
use module_lang::ModuleGraph;
let graph: ModuleGraph<()> = ModuleGraph::with_capacity(64);
assert!(graph.is_empty());Sourcepub fn add_module(&mut self, name: Symbol, source: SourceId) -> ModuleId
pub fn add_module(&mut self, name: Symbol, source: SourceId) -> ModuleId
Adds a module with a display name and the source it was read from,
returning its stable ModuleId.
The id is the module’s insertion order and never changes; hold it to define
names in the module, import from it, or resolve against it. The name is
for diagnostics and the source records which file the module came from —
neither participates in resolution, which is always by id.
§Examples
use intern_lang::Interner;
use module_lang::ModuleGraph;
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<()> = ModuleGraph::new();
let src = sources.add("m.lang", "").expect("fits");
let m = graph.add_module(names.intern("m"), src);
assert_eq!(graph.len(), 1);
assert_eq!(graph.module_source(m), Some(src));Sourcepub fn define(
&mut self,
module: ModuleId,
name: Symbol,
visibility: Visibility,
value: T,
) -> Result<(), ResolveError>
pub fn define( &mut self, module: ModuleId, name: Symbol, visibility: Visibility, value: T, ) -> Result<(), ResolveError>
Defines name in module with a visibility and a payload.
Returns ResolveError::DuplicateName if the module already declares the
name (by an earlier definition or an import), and
ResolveError::UnknownModule if module was not minted by this graph. On
success the name resolves to value from within the module immediately, and
from other modules that import it when it is Visibility::Public.
§Examples
use intern_lang::Interner;
use module_lang::{ModuleGraph, ResolveError, Visibility};
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<i32> = ModuleGraph::new();
let m = graph.add_module(names.intern("m"), sources.add("m", "").expect("fits"));
let x = names.intern("x");
graph.define(m, x, Visibility::Public, 42)?;
assert_eq!(graph.resolve(m, x), Ok(&42));
// A second definition of the same name in the same module is rejected.
assert!(matches!(
graph.define(m, x, Visibility::Private, 7),
Err(ResolveError::DuplicateName { .. }),
));Sourcepub fn import(
&mut self,
into: ModuleId,
from: ModuleId,
name: Symbol,
) -> Result<(), ResolveError>
pub fn import( &mut self, into: ModuleId, from: ModuleId, name: Symbol, ) -> Result<(), ResolveError>
Imports name into into from the from module, keeping its spelling.
This records an import edge; it does not require name to be defined in
from yet, so a graph can be built in any order. Whether the import
actually reaches a public definition is determined when the name is
resolved.
Returns ResolveError::DuplicateName if into already declares name,
and ResolveError::UnknownModule if either id was not minted by this
graph.
§Examples
use intern_lang::Interner;
use module_lang::{ModuleGraph, Visibility};
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<()> = ModuleGraph::new();
let lib = graph.add_module(names.intern("lib"), sources.add("lib", "").expect("fits"));
let app = graph.add_module(names.intern("app"), sources.add("app", "").expect("fits"));
let item = names.intern("item");
graph.define(lib, item, Visibility::Public, ())?;
graph.import(app, lib, item)?;
assert!(graph.resolve(app, item).is_ok());Sourcepub fn resolve(
&self,
module: ModuleId,
name: Symbol,
) -> Result<&T, ResolveError>
pub fn resolve( &self, module: ModuleId, name: Symbol, ) -> Result<&T, ResolveError>
Resolves name as seen from within module, returning the payload it
refers to.
A name defined in the module wins, public or private. A name imported into
the module is followed to its source module — and onward along any chain of
re-imports — to the public definition it names. The failure modes are all
defined ResolveErrors:
Unresolved— the name is declared nowhere on the path.Private— an import reached a name private to another module.ImportCycle— the import chain loops.UnknownModule—moduleis not from this graph.
§Examples
use intern_lang::Interner;
use module_lang::{ModuleGraph, ResolveError, Visibility};
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<&str> = ModuleGraph::new();
let m = graph.add_module(names.intern("m"), sources.add("m", "").expect("fits"));
let here = names.intern("here");
let gone = names.intern("gone");
graph.define(m, here, Visibility::Public, "local")?;
assert_eq!(graph.resolve(m, here), Ok(&"local"));
assert!(matches!(graph.resolve(m, gone), Err(ResolveError::Unresolved { .. })));Sourcepub fn len(&self) -> usize
pub fn len(&self) -> usize
Number of modules in the graph.
§Examples
use intern_lang::Interner;
use module_lang::ModuleGraph;
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<()> = ModuleGraph::new();
assert_eq!(graph.len(), 0);
graph.add_module(names.intern("m"), sources.add("m", "").expect("fits"));
assert_eq!(graph.len(), 1);Sourcepub fn is_empty(&self) -> bool
pub fn is_empty(&self) -> bool
Whether the graph holds no modules.
§Examples
use module_lang::ModuleGraph;
let graph: ModuleGraph<()> = ModuleGraph::new();
assert!(graph.is_empty());Sourcepub fn module_name(&self, module: ModuleId) -> Option<Symbol>
pub fn module_name(&self, module: ModuleId) -> Option<Symbol>
The display name a module was added with, or None if module is not from
this graph.
§Examples
use intern_lang::Interner;
use module_lang::ModuleGraph;
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<()> = ModuleGraph::new();
let name = names.intern("m");
let m = graph.add_module(name, sources.add("m", "").expect("fits"));
assert_eq!(graph.module_name(m), Some(name));Sourcepub fn module_source(&self, module: ModuleId) -> Option<SourceId>
pub fn module_source(&self, module: ModuleId) -> Option<SourceId>
The SourceId a module was added with, or None if module is not from
this graph.
§Examples
use intern_lang::Interner;
use module_lang::ModuleGraph;
use source_lang::SourceMap;
let mut sources = SourceMap::new();
let mut names = Interner::new();
let mut graph: ModuleGraph<()> = ModuleGraph::new();
let src = sources.add("m", "").expect("fits");
let m = graph.add_module(names.intern("m"), src);
assert_eq!(graph.module_source(m), Some(src));Trait Implementations§
Source§impl<T: Clone> Clone for ModuleGraph<T>
impl<T: Clone> Clone for ModuleGraph<T>
Source§fn clone(&self) -> ModuleGraph<T>
fn clone(&self) -> ModuleGraph<T>
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read more