pub struct ParamList {
pub params: Vec<Param>,
pub ignore_extra: bool,
}Expand description
The dynamic-call signature of a function or an import: what lets a
dcall or dcall_shape pass named, spread, extra, missing, and
by-reference arguments (specs/LSB.md §5.15).
The list describes the signature’s parameters in order. When any
parameter has a default, the signature has one more parameter, an
i64 presence mask: bit i is set when parameter i received an
argument, so the callee computes the defaults of the others itself
(PHP’s and Python’s defaults are expressions). A callee without a list
binds as if it had one positional-only parameter per signature
parameter: exact arity, positional arguments only.
§Examples
use bytecode_lang::{Param, ParamKind, ParamList, StrId};
// PHP: function f($a, &$b = null, ...$rest)
let list = ParamList::new(vec![
Param::normal(StrId(0)),
Param::normal(StrId(1)).by_ref().with_default(),
Param::new(ParamKind::RestMap, Some(StrId(2))),
]);
assert!(list.validate().is_ok());
assert!(list.has_defaults());
assert_eq!(list.signature_len(), 4); // three parameters and the presence mask
assert!(list.positional_by_ref(1));
assert!(!list.positional_by_ref(7)); // a rest argument, by valueFields§
§params: Vec<Param>The parameters, in signature order.
ignore_extra: boolExtra positional arguments with no rest parameter to take them are
dropped instead of raising ArgumentError (PHP user functions,
which see them only through func_get_args).
Implementations§
Source§impl ParamList
impl ParamList
Sourcepub fn new(params: Vec<Param>) -> Self
pub fn new(params: Vec<Param>) -> Self
A list of these parameters that raises on extra arguments.
§Examples
use bytecode_lang::{Param, ParamList, StrId};
let list = ParamList::new(vec![Param::normal(StrId(0))]);
assert!(!list.ignore_extra);Sourcepub fn ignoring_extra(self) -> Self
pub fn ignoring_extra(self) -> Self
This list, dropping extra positional arguments (PHP user functions).
§Examples
use bytecode_lang::ParamList;
assert!(ParamList::new(vec![]).ignoring_extra().ignore_extra);Sourcepub fn has_defaults(&self) -> bool
pub fn has_defaults(&self) -> bool
Whether any parameter has a default, so the signature ends with the presence mask.
§Examples
use bytecode_lang::{Param, ParamList, StrId};
assert!(!ParamList::new(vec![Param::normal(StrId(0))]).has_defaults());Sourcepub fn signature_len(&self) -> usize
pub fn signature_len(&self) -> usize
The number of signature parameters the list describes: one per entry, plus the presence mask when a parameter has a default.
§Examples
use bytecode_lang::{Param, ParamList, StrId};
let list = ParamList::new(vec![Param::normal(StrId(0)).with_default()]);
assert_eq!(list.signature_len(), 2);Sourcepub fn validate(&self) -> Result<(), ParamError>
pub fn validate(&self) -> Result<(), ParamError>
Checks the list’s own rules: at most 255 parameters (64 with defaults); kinds in order (positional-only, normal, one rest, named-only, one named rest); normal and named-only parameters named; names unique; no default on a rest parameter.
§Errors
The first rule broken, as a ParamError.
§Examples
use bytecode_lang::{Param, ParamError, ParamKind, ParamList, StrId};
let rest_first = ParamList::new(vec![
Param::new(ParamKind::Rest, None),
Param::normal(StrId(0)),
]);
assert_eq!(rest_first.validate(), Err(ParamError::OutOfOrder { index: 1 }));Sourcepub fn fits(&self, sig_params: &[ValType]) -> Result<(), ParamError>
pub fn fits(&self, sig_params: &[ValType]) -> Result<(), ParamError>
Checks that the list fits a signature with parameter types
sig_params: one parameter per entry plus a trailing i64 presence
mask when an entry has a default; rest parameters dyn; by-reference
parameters dyn or ref (the verifier checks that the ref is a
cell dyn).
§Errors
ParamError::Signature naming the first parameter that does not
fit.
§Examples
use bytecode_lang::{Param, ParamError, ParamKind, ParamList, StrId, ValType};
let list = ParamList::new(vec![Param::new(ParamKind::Rest, None)]);
assert!(list.fits(&[ValType::Dyn]).is_ok());
assert_eq!(list.fits(&[ValType::I64]), Err(ParamError::Signature { index: 0 }));Sourcepub fn positional_by_ref(&self, pos: u64) -> bool
pub fn positional_by_ref(&self, pos: u64) -> bool
Whether a positional argument at 0-based position pos would be
taken by reference: the semantics of dparam_ref (PHP decides
before evaluating each argument of a dynamic call whether to send a
reference). Positions past the positional parameters belong to the
rest parameter, if any; with none, false.
§Examples
use bytecode_lang::{Param, ParamKind, ParamList, StrId};
let list = ParamList::new(vec![
Param::normal(StrId(0)),
Param::new(ParamKind::RestMap, None).by_ref(),
]);
assert!(!list.positional_by_ref(0));
assert!(list.positional_by_ref(5));Sourcepub fn named_by_ref(&self, module: &Module, name: &[u8]) -> bool
pub fn named_by_ref(&self, module: &Module, name: &[u8]) -> bool
Whether a named argument name would be taken by reference: the
semantics of dparam_ref_named. Parameter names are strings of
module, the callee’s module.
§Examples
use bytecode_lang::{ModuleBuilder, Param, ParamList};
let mut m = ModuleBuilder::new();
let x = m.string("x");
let module = m.finish().unwrap();
let list = ParamList::new(vec![Param::normal(x).by_ref()]);
assert!(list.named_by_ref(&module, b"x"));
assert!(!list.named_by_ref(&module, b"y"));Sourcepub fn bind(
&self,
module: &Module,
items: &[ArgItem<'_>],
) -> Result<Binding, BindError>
pub fn bind( &self, module: &Module, items: &[ArgItem<'_>], ) -> Result<Binding, BindError>
Binds a dynamic call’s arguments to this list: the rule of
specs/LSB.md §5.15, written once so every tier applies it alike.
items are the call’s arguments in order, after spreads were
expanded (a spread array contributes positional items; a spread
map’s integer keys positional items and its string keys named ones).
Parameter names are strings of module, the callee’s module.
- Positional items fill the positional-only and normal parameters
in order; extra ones go to the rest parameter, else are dropped
under
ignore_extra, elseBindError::TooMany. A positional item after a named one isBindError::PositionalAfterNamed. - A named item fills the normal or named-only parameter of that
name (
BindError::Duplicateif it is already filled); with none, it goes to the named rest, else to aRestMap(a repeated name there isDuplicate), elseBindError::UnknownName. - A parameter left empty takes its default (its presence bit is
clear), or is
BindError::Missing; a rest parameter is an empty collection.
The first violation in item order is reported, then the first missing
parameter. Runs in O(items × params) with params ≤ 255, plus
O(n log n) for duplicate names in a rest collection.
§Errors
A BindError; a VM raises ArgumentError (E0114) for every one.
§Examples
use bytecode_lang::{ArgItem, Bound, ModuleBuilder, Param, ParamKind, ParamList};
let mut m = ModuleBuilder::new();
let (a, b) = (m.string("a"), m.string("b"));
let module = m.finish().unwrap();
// function f($a, $b = 2, ...$rest)
let list = ParamList::new(vec![
Param::normal(a),
Param::normal(b).with_default(),
Param::new(ParamKind::RestMap, None),
]);
// f(1, 2, 3, x: 4)
let items = [ArgItem::Positional, ArgItem::Positional, ArgItem::Positional, ArgItem::Named(b"x")];
let bound = list.bind(&module, &items).unwrap();
assert_eq!(bound.slots(), &[Bound::Arg(0), Bound::Arg(1), Bound::Collected(vec![2, 3])]);
assert_eq!(bound.presence(), 0b111);
// f(b: 5, a: 6)
let bound = list.bind(&module, &[ArgItem::Named(b"b"), ArgItem::Named(b"a")]).unwrap();
assert_eq!(bound.slots(), &[Bound::Arg(1), Bound::Arg(0), Bound::Collected(vec![])]);Trait Implementations§
Source§impl Display for ParamList
params (s0, &s1 = ?, ...s2) ignore_extra-style rendering for listings:
each parameter as its kind marker, & when by reference, its name, and
= ? when it has a default.
impl Display for ParamList
params (s0, &s1 = ?, ...s2) ignore_extra-style rendering for listings:
each parameter as its kind marker, & when by reference, its name, and
= ? when it has a default.