pub struct Policy { /* private fields */ }Expand description
A language’s complete scoping policy.
Start from a preset (kraken, php,
python) or new (the lexical default, the
same as Kraken), then adjust with the with_* setters. The policy is plain
data, normally read from the language’s sketch.
§Examples
use resolve_lang::{ClassScope, Hoist, ItemClass, Namespace, Policy};
let p = Policy::new()
.with_hoisting(ItemClass::Fn, Hoist::AfterDecl)
.with_class_scope(ClassScope::BodyOnly)
.with_merge(Namespace::Type, Namespace::Value);
assert_eq!(p.hoisting(ItemClass::Fn), Hoist::AfterDecl);
assert_eq!(p.table(Namespace::Type), Namespace::Value);Implementations§
Source§impl Policy
impl Policy
Sourcepub const fn new() -> Self
pub const fn new() -> Self
The lexical default (equal to kraken): every item
hoisted to its scope; separate value, type, and macro tables with
modules sharing the type table and constants sharing the value table;
every table case-sensitive; class members (own and inherited) visible
in methods;
isolated nested modules; Self:: early, parent::/static::
unsupported; visibility enforced with private items visible to child
modules; globs, aliases, and declared re-exports.
§Examples
use resolve_lang::{ItemClass, Namespace, NsSet, Policy};
let p = Policy::new();
assert_eq!(p.occupies(ItemClass::Record), NsSet::of(&[Namespace::Type, Namespace::Value]));
assert!(p.visibility_enforced());Sourcepub const fn php() -> Self
pub const fn php() -> Self
PHP (and Mox): functions, classes, interfaces, enums, and constants are
visible in their whole namespace wherever declared; class members are
reached only through self::/parent::/static:: (late static
binding for static::); use imports are file-local and have no
globs; global $x may name a global that does not exist yet.
Names follow PHP 8’s tables and case rules:
| Table | Holds | Case |
|---|---|---|
Value | functions, methods | ASCII-insensitive |
Type (with Module) | classes, interfaces, traits, enums, namespaces | ASCII-insensitive |
Const | constants, class constants, globals, static properties | sensitive |
So a function and a constant, or a method and a class constant, may
share a name; strlen and STRLEN are one function; and a class
lives in the type table only. A class named where a value goes
(new C, x instanceof C, as the Mox sketch lowers them) still
resolves, through class_values; a class reaches
its interfaces’ constants and methods through
interface_members. HIR paths carry no $ sigil, so a sketch that strips it from static
property names makes a static property and a class constant of the
same name collide; keep the sigil in property names ($count) to
keep them apart.
§Examples
use resolve_lang::{Case, Hoist, ItemClass, Namespace, NsSet, Policy};
let p = Policy::php();
assert_eq!(p.hoisting(ItemClass::Class), Hoist::Module);
assert_eq!(p.occupies(ItemClass::Class), NsSet::single(Namespace::Type));
assert_ne!(p.table(Namespace::Const), p.table(Namespace::Value));
assert_eq!(p.case(Namespace::Type), Case::AsciiInsensitive);
assert!(!p.globs_allowed());
assert!(p.implicit_globals());
assert!(p.class_values() && p.interface_members());Sourcepub const fn python() -> Self
pub const fn python() -> Self
Python (and Mercury): one case-sensitive table for every kind of
name; a name bound anywhere in a scope belongs to the whole scope;
class bodies are not visible to methods; members are inherited in C3
method resolution order (as under every policy; an inconsistent
hierarchy is reported, as Python raises TypeError at class
creation); redefinition rebinds; visibility is convention only;
imports become module attributes.
§Examples
use resolve_lang::{Namespace, Policy};
let p = Policy::python();
assert_eq!(p.table(Namespace::Type), Namespace::Value);
assert_eq!(p.table(Namespace::Module), Namespace::Value);
assert!(!p.visibility_enforced());Sourcepub const fn with_hoisting(self, class: ItemClass, hoist: Hoist) -> Self
pub const fn with_hoisting(self, class: ItemClass, hoist: Hoist) -> Self
Sets when items of class become visible.
§Examples
use resolve_lang::{Hoist, ItemClass, Policy};
let p = Policy::new().with_hoisting(ItemClass::Global, Hoist::AfterDecl);
assert_eq!(p.hoisting(ItemClass::Global), Hoist::AfterDecl);Sourcepub const fn with_occupies(self, class: ItemClass, set: NsSet) -> Self
pub const fn with_occupies(self, class: ItemClass, set: NsSet) -> Self
Sets the namespaces items of class define their name in. Imports
ignore this (an import binds whatever its target defines).
§Examples
use resolve_lang::{ItemClass, Namespace, NsSet, Policy};
// Rust: a braced struct defines no constructor value.
let p = Policy::new().with_occupies(ItemClass::Record, NsSet::single(Namespace::Type));
assert!(!p.occupies(ItemClass::Record).contains(Namespace::Value));Sourcepub const fn with_merge(self, from: Namespace, into: Namespace) -> Self
pub const fn with_merge(self, from: Namespace, into: Namespace) -> Self
Merges namespace from into the table of into: afterwards both (and
everything already merged with either) share one table, so a name
defined in one conflicts with and is found by the other. The merged
table keeps into’s Case.
§Examples
use resolve_lang::{Namespace, Policy};
let p = Policy::new().with_merge(Namespace::Value, Namespace::Type);
// Modules already share the type table, so all three are one table now.
assert_eq!(p.table(Namespace::Value), p.table(Namespace::Module));Sourcepub const fn with_case(self, ns: Namespace, case: Case) -> Self
pub const fn with_case(self, ns: Namespace, case: Case) -> Self
Sets how the table of ns (and every namespace merged with it)
compares names. Merge first, then set the case: a later merge keeps
the target table’s case.
§Examples
use resolve_lang::{Case, Namespace, Policy};
let p = Policy::new().with_case(Namespace::Type, Case::AsciiInsensitive);
// Modules share the type table, so they fold too.
assert_eq!(p.case(Namespace::Module), Case::AsciiInsensitive);
assert_eq!(p.case(Namespace::Value), Case::Sensitive);Sourcepub const fn with_shadowing(self, shadowing: Shadowing) -> Self
pub const fn with_shadowing(self, shadowing: Shadowing) -> Self
Sets the shadowing rule for binders.
§Examples
use resolve_lang::{Policy, Shadowing};
assert_eq!(Policy::new().with_shadowing(Shadowing::DenyLocals).shadowing(), Shadowing::DenyLocals);Sourcepub const fn with_redefinition(self, redefinition: Redefinition) -> Self
pub const fn with_redefinition(self, redefinition: Redefinition) -> Self
Sets what duplicate definitions mean.
§Examples
use resolve_lang::{Policy, Redefinition};
let p = Policy::new().with_redefinition(Redefinition::LastWins);
assert_eq!(p.redefinition(), Redefinition::LastWins);Sourcepub const fn with_class_scope(self, class_scope: ClassScope) -> Self
pub const fn with_class_scope(self, class_scope: ClassScope) -> Self
Sets what code inside a class sees of its members.
§Examples
use resolve_lang::{ClassScope, Policy};
let p = Policy::new().with_class_scope(ClassScope::Qualified);
assert_eq!(p.class_scope(), ClassScope::Qualified);Sourcepub const fn with_module_scope(self, module_scope: ModuleScope) -> Self
pub const fn with_module_scope(self, module_scope: ModuleScope) -> Self
Sets whether nested modules see outer names.
§Examples
use resolve_lang::{ModuleScope, Policy};
let p = Policy::new().with_module_scope(ModuleScope::Lexical);
assert_eq!(p.module_scope(), ModuleScope::Lexical);Sourcepub const fn with_roots(
self,
self_root: RootBinding,
parent_root: RootBinding,
static_root: RootBinding,
) -> Self
pub const fn with_roots( self, self_root: RootBinding, parent_root: RootBinding, static_root: RootBinding, ) -> Self
Sets how self::, parent::, and static:: bind.
§Examples
use resolve_lang::{Policy, RootBinding};
let p = Policy::new().with_roots(RootBinding::Early, RootBinding::Early, RootBinding::Late);
assert_eq!(p.parent_root(), RootBinding::Early);Sourcepub const fn with_visibility(
self,
enforce: bool,
private_to_descendants: bool,
) -> Self
pub const fn with_visibility( self, enforce: bool, private_to_descendants: bool, ) -> Self
Sets whether visibility is enforced, and whether private items of a module are visible to its descendant modules.
§Examples
use resolve_lang::Policy;
let p = Policy::new().with_visibility(true, false);
assert!(p.visibility_enforced());
assert!(!p.private_to_descendants());Sourcepub const fn with_imports(
self,
globs: bool,
aliases: bool,
reexport: Reexport,
) -> Self
pub const fn with_imports( self, globs: bool, aliases: bool, reexport: Reexport, ) -> Self
Sets which import forms the language has, and how imports re-export.
§Examples
use resolve_lang::{Policy, Reexport};
let p = Policy::new().with_imports(false, true, Reexport::Never);
assert!(!p.globs_allowed());
assert!(p.aliases_allowed());Sourcepub const fn with_implicit_globals(self, implicit: bool) -> Self
pub const fn with_implicit_globals(self, implicit: bool) -> Self
Sets whether a global declaration naming no known global binds a host
global (Res::Extern) instead of being reported.
§Examples
use resolve_lang::Policy;
assert!(Policy::new().with_implicit_globals(true).implicit_globals());Sourcepub const fn with_class_values(self, on: bool) -> Self
pub const fn with_class_values(self, on: bool) -> Self
Sets whether a class may be named in value position.
Languages whose classes are not values still write class names where
a value goes: new Foo(1) lowers to a call whose first operand is
Foo, and $x instanceof Foo takes it as its right operand. With
this set, a value path that finds nothing in the value tables falls
back to the type table and resolves to a class (or record) item there,
or to a class the host defines. It applies to unqualified names
(Foo), module-qualified ones (App\Foo, \App\Foo), and imported
ones, folded by the type table’s case rule. A constant or function of
the same name wins, and a path that is the callee of a call does not
fall back (Foo() is not new Foo). Foo::bar, Foo::C, and
Foo::class need no fallback: their first segment is already looked
up as a container.
An interface (or a sum) stays an error in value position: hir-lang refuses a value path that resolves to one, so a lowering names an interface through a type argument.
Off by default; php turns it on.
§Examples
use resolve_lang::Policy;
assert!(Policy::php().class_values());
assert!(!Policy::kraken().class_values());
assert!(Policy::kraken().with_class_values(true).class_values());Sourcepub const fn with_interface_members(self, on: bool) -> Self
pub const fn with_interface_members(self, on: bool) -> Self
Sets whether a class inherits the members of the interfaces it implements.
With this set, Impl::NAME finds a constant (or method) declared on
an interface Impl implements, directly or through a base class or a
super-interface, when neither the class nor its base classes declare
it; PHP’s lookup order. Without it, interfaces contribute no members
to the classes implementing them.
Off by default; php turns it on.
§Examples
use resolve_lang::Policy;
assert!(Policy::php().interface_members());
assert!(!Policy::python().interface_members());Sourcepub const fn hoisting(&self, class: ItemClass) -> Hoist
pub const fn hoisting(&self, class: ItemClass) -> Hoist
When items of class become visible.
§Examples
use resolve_lang::{Hoist, ItemClass, Policy};
assert_eq!(Policy::new().hoisting(ItemClass::Fn), Hoist::Scope);Sourcepub const fn occupies(&self, class: ItemClass) -> NsSet
pub const fn occupies(&self, class: ItemClass) -> NsSet
The namespaces items of class define their name in (before merging).
§Examples
use resolve_lang::{ItemClass, Namespace, Policy};
assert!(Policy::new().occupies(ItemClass::Fn).contains(Namespace::Value));Sourcepub const fn table(&self, ns: Namespace) -> Namespace
pub const fn table(&self, ns: Namespace) -> Namespace
The table namespace ns is stored in after merging.
§Examples
use resolve_lang::{Namespace, Policy};
assert_eq!(Policy::new().table(Namespace::Module), Namespace::Type);
assert_eq!(Policy::new().table(Namespace::Value), Namespace::Value);Sourcepub const fn case(&self, ns: Namespace) -> Case
pub const fn case(&self, ns: Namespace) -> Case
How the table of ns compares names.
§Examples
use resolve_lang::{Case, Namespace, Policy};
assert_eq!(Policy::new().case(Namespace::Value), Case::Sensitive);Sourcepub const fn shadowing(&self) -> Shadowing
pub const fn shadowing(&self) -> Shadowing
The shadowing rule.
§Examples
use resolve_lang::{Policy, Shadowing};
assert_eq!(Policy::new().shadowing(), Shadowing::Allow);Sourcepub const fn redefinition(&self) -> Redefinition
pub const fn redefinition(&self) -> Redefinition
What duplicate definitions mean.
§Examples
use resolve_lang::{Policy, Redefinition};
assert_eq!(Policy::php().redefinition(), Redefinition::Error);Sourcepub const fn class_scope(&self) -> ClassScope
pub const fn class_scope(&self) -> ClassScope
What code inside a class sees of its members.
§Examples
use resolve_lang::{ClassScope, Policy};
assert_eq!(Policy::new().class_scope(), ClassScope::Lexical);Sourcepub const fn module_scope(&self) -> ModuleScope
pub const fn module_scope(&self) -> ModuleScope
Whether nested modules see outer names.
§Examples
use resolve_lang::{ModuleScope, Policy};
assert_eq!(Policy::php().module_scope(), ModuleScope::Lexical);Sourcepub const fn self_root(&self) -> RootBinding
pub const fn self_root(&self) -> RootBinding
How self:: binds.
§Examples
use resolve_lang::{Policy, RootBinding};
assert_eq!(Policy::python().self_root(), RootBinding::Unsupported);Sourcepub const fn parent_root(&self) -> RootBinding
pub const fn parent_root(&self) -> RootBinding
How parent:: binds.
§Examples
use resolve_lang::{Policy, RootBinding};
assert_eq!(Policy::kraken().parent_root(), RootBinding::Unsupported);Sourcepub const fn static_root(&self) -> RootBinding
pub const fn static_root(&self) -> RootBinding
How static:: binds.
§Examples
use resolve_lang::{Policy, RootBinding};
assert_eq!(Policy::php().static_root(), RootBinding::Late);Sourcepub const fn visibility_enforced(&self) -> bool
pub const fn visibility_enforced(&self) -> bool
Whether visibility (Vis) is enforced.
§Examples
use resolve_lang::Policy;
assert!(Policy::php().visibility_enforced());Sourcepub const fn private_to_descendants(&self) -> bool
pub const fn private_to_descendants(&self) -> bool
Whether private items of a module are visible in its descendant modules (Rust’s rule).
§Examples
use resolve_lang::Policy;
assert!(Policy::new().private_to_descendants());Sourcepub const fn globs_allowed(&self) -> bool
pub const fn globs_allowed(&self) -> bool
Whether glob imports are allowed.
§Examples
use resolve_lang::Policy;
assert!(Policy::python().globs_allowed());Sourcepub const fn aliases_allowed(&self) -> bool
pub const fn aliases_allowed(&self) -> bool
Whether aliased imports (use x as y) are allowed.
§Examples
use resolve_lang::Policy;
assert!(Policy::php().aliases_allowed());Sourcepub const fn reexport(&self) -> Reexport
pub const fn reexport(&self) -> Reexport
How imports re-export.
§Examples
use resolve_lang::{Policy, Reexport};
assert_eq!(Policy::php().reexport(), Reexport::Never);Sourcepub const fn implicit_globals(&self) -> bool
pub const fn implicit_globals(&self) -> bool
Whether an unknown global name binds a host global.
§Examples
use resolve_lang::Policy;
assert!(!Policy::kraken().implicit_globals());Sourcepub const fn class_values(&self) -> bool
pub const fn class_values(&self) -> bool
Whether a class-like item may be named in value position
(with_class_values).
§Examples
use resolve_lang::Policy;
assert!(Policy::php().class_values());Sourcepub const fn interface_members(&self) -> bool
pub const fn interface_members(&self) -> bool
Whether classes inherit the members of their interfaces
(with_interface_members).
§Examples
use resolve_lang::Policy;
assert!(Policy::php().interface_members());