Skip to main content

ModuleGraph

Struct ModuleGraph 

Source
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>

Source

pub const fn new() -> Self

Creates an empty graph.

§Examples
use module_lang::ModuleGraph;

let graph: ModuleGraph<()> = ModuleGraph::new();
assert!(graph.is_empty());
Source

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());
Source

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));
Source

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 { .. }),
));
Source

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());
Source

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.
  • UnknownModulemodule is 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 { .. })));
Source

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);
Source

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());
Source

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));
Source

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>

Source§

fn clone(&self) -> ModuleGraph<T>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<T: Debug> Debug for ModuleGraph<T>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<T> Default for ModuleGraph<T>

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<T> Freeze for ModuleGraph<T>

§

impl<T> RefUnwindSafe for ModuleGraph<T>
where T: RefUnwindSafe,

§

impl<T> Send for ModuleGraph<T>
where T: Send,

§

impl<T> Sync for ModuleGraph<T>
where T: Sync,

§

impl<T> Unpin for ModuleGraph<T>

§

impl<T> UnsafeUnpin for ModuleGraph<T>

§

impl<T> UnwindSafe for ModuleGraph<T>
where T: RefUnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.