pub struct Program {
pub schema_version: u32,
pub blocks: Vec<Block>,
pub main: Block,
}Expand description
A lowered pattern: comparison blocks plus the observation-tier block.
Fields§
§schema_version: u32Serialized schema version; see SCHEMA_VERSION.
blocks: Vec<Block>The comparison blocks, in lowering order.
main: BlockThe observation-tier block.
Implementations§
Source§impl Program
impl Program
Sourcepub fn to_listing(&self) -> String
pub fn to_listing(&self) -> String
Render this program as a human-readable listing.
Comparison-block results are named t0, t1, … across all blocks in
order; main-block results are named o0, o1, … . These names are
display ordinals, not InstrId values.
Source§impl Program
impl Program
Sourcepub fn span_of(&self, block: BlockId, instr: InstrId) -> Option<Span>
pub fn span_of(&self, block: BlockId, instr: InstrId) -> Option<Span>
The source extent of an instruction: its own span when it has one, otherwise the union of its operands’ extents.
The boolean combinators carry no span of their own — their extent is exactly the span of the text their operands cover — so this computes it on demand rather than storing redundant state that structural edits would have to keep consistent.
Returns None when neither the instruction nor anything it references has
a span, and when block or instr names nothing in this program.
Observe normally answers from its own span, which is the extent of the
whole [...]; only when that is missing does this descend into the
comparison block it names.
This is safe to call on a program that has not been validated. Descent is iterative, so depth costs heap rather than stack, and it visits each instruction at most once, so it terminates on cyclic or shared input and does work linear in the size of the program.
§Example
use stix_pattern::{ir, parse};
let src = "[file:size > 1] AND [file:name = 'a']";
let program = ir::lower(&parse(src).unwrap());
// The `and` in `main` has no span of its own.
let and = program.main.instructions[2].id;
let span = program.span_of(program.main.id, and).unwrap();
assert_eq!(&src[span.start..span.end], src);Source§impl Program
impl Program
Sourcepub fn validate(&self) -> Result<(), IrError>
pub fn validate(&self) -> Result<(), IrError>
Check that this program is well-formed.
Lowered programs always pass. Run this on any program that was built by hand or deserialized, since deserialization does not check invariants.
Unreferenced (“dead”) instructions are allowed — only dangling and
forward references are errors. A value may have at most one consumer,
however, and a comparison block at most one Observe: see
IrError::MultipleUses and IrError::BlockObservedTwice.
Nesting depth is not limited: validation, render
and Program::span_of are all iterative, so a deeply nested program
cannot overflow the stack.