Skip to main content

ParsedFile

Struct ParsedFile 

Source
pub struct ParsedFile { /* private fields */ }
Expand description

An immutable, owning parse result.

This value keeps the input bytes, lexer diagnostics, parser diagnostics, and compact CST together. Syntax errors do not make construction fail.

Implementations§

Source§

impl ParsedFile

Source

pub fn write_formatted<W: Write>( &self, sink: &mut W, options: FormatOptions, ) -> Result<(), FormatError>

Formats the retained assembly spelling while normalizing layout.

This method does not lower the file. Operation names, SSA names, aliases, comments, and custom assembly forms therefore remain source-derived.

Source

pub fn formatted_bytes( &self, options: FormatOptions, ) -> Result<Vec<u8>, FormatError>

Returns source-aware formatted output as bytes.

Source§

impl ParsedFile

Source

pub fn parse(bytes: impl Into<Arc<[u8]>>) -> Result<Self, ParseFileError>

Parses and owns bytes using default limits and generic operation syntax.

The result remains available for malformed MLIR; inspect Self::lexer_diagnostics and ParsedSyntax::diagnostics.

§Errors

Returns an error when the source exceeds the file-size limit, cannot use compact offsets, or cannot be represented as a compact syntax tree.

Examples found in repository?
examples/large_data_retention_benchmark.rs (line 60)
57fn measure(elements: usize, profile: RetentionProfile) -> Measurement {
58    let bytes = source(elements);
59    let source_len = bytes.len();
60    let parsed = ParsedFile::parse(bytes).expect("benchmark input parses");
61    let started = Instant::now();
62    let result = lower_with_dialect_registry_and_retention(
63        &parsed,
64        LoweringMode::Strict,
65        profile,
66        &DialectRegistry::EMPTY,
67    );
68    assert!(result.diagnostics.is_empty(), "{:?}", result.diagnostics);
69    let document = result.document.expect("benchmark input lowers");
70    document.validate().expect("benchmark document validates");
71    let stats = document.statistics();
72    assert_eq!(document.retention_profile(), profile);
73    assert_eq!(
74        stats.retained_source_bytes,
75        match profile {
76            RetentionProfile::SemanticOnly => 0,
77            RetentionProfile::SyntaxOnly | RetentionProfile::Hybrid => source_len,
78        }
79    );
80    assert_eq!(
81        stats.retained_cst_nodes > 0,
82        profile != RetentionProfile::SemanticOnly
83    );
84    assert_eq!(
85        stats.retained_mapping_entries,
86        match profile {
87            RetentionProfile::Hybrid => 1,
88            RetentionProfile::SyntaxOnly | RetentionProfile::SemanticOnly => 0,
89        }
90    );
91    Measurement {
92        source_bytes: source_len,
93        semantic_attributes: stats.local_attributes,
94        payload_bytes: stats.payload_blob_bytes,
95        payload_blobs: stats.payload_blobs,
96        cst_nodes: stats.retained_cst_nodes,
97        mappings: stats.retained_mapping_entries,
98        direct_owned_bytes: stats.direct_owned_bytes,
99        document_index_bytes: stats.document_index_bytes,
100        retained_cst_bytes: stats.retained_cst_bytes,
101        source_shared: stats.source_storage_shared,
102        cst_shared: stats.cst_storage_shared,
103        lower_us: started.elapsed().as_micros(),
104    }
105}
More examples
Hide additional examples
examples/semantic_compaction_benchmark.rs (line 123)
121fn measure(iterations: u32) -> Measurement {
122    let registry = DialectRegistry::EMPTY;
123    let parsed = ParsedFile::parse(br#"%0 = "anchor"() : () -> i32"#.as_slice()).unwrap();
124    let mut document = lower_with_dialect_registry(&parsed, LoweringMode::Strict, &registry)
125        .document
126        .unwrap();
127    let operation = document.root_operations()[0];
128    let baseline = document.statistics();
129    let allocator_baseline = LIVE_BYTES.load(Ordering::Relaxed);
130    PEAK_BYTES.store(allocator_baseline, Ordering::Relaxed);
131    let edit_start = Instant::now();
132    let mut editor = document.edit(&registry).unwrap();
133    for index in 0..iterations {
134        let width = 33 + index;
135        editor
136            .replace_result_types(
137                operation,
138                &[TypeSpec {
139                    spelling: format!("i{width}"),
140                    value: TypeValue::Integer {
141                        width,
142                        signedness: None,
143                    },
144                }],
145            )
146            .unwrap();
147        let name = format!("temporary_{index}");
148        editor
149            .set_attribute(
150                operation,
151                AttributeSpec::string(name.clone(), format!("value_{index}")),
152            )
153            .unwrap();
154        editor.remove_attribute(operation, &name).unwrap();
155    }
156    editor
157        .replace_result_types(
158            operation,
159            &[TypeSpec {
160                spelling: "i32".into(),
161                value: TypeValue::Integer {
162                    width: 32,
163                    signedness: None,
164                },
165            }],
166        )
167        .unwrap();
168    let pooled_before = editor.document().statistics().pooled_list_entries;
169    let reclaimed_list_entries = editor.compact_pools();
170    editor.commit().unwrap();
171    let edit_ns = edit_start.elapsed().as_nanos();
172    let verify_start = Instant::now();
173    black_box(document.verify_semantics(&registry)).unwrap();
174    let verify_ns = verify_start.elapsed().as_nanos();
175    let stats = document.statistics();
176    assert_eq!(stats.live_attributes, 0);
177    assert!(stats.retained_types > stats.live_types);
178    assert!(stats.retained_attributes > stats.live_attributes);
179    assert!(reclaimed_list_entries > 0 && stats.pooled_list_entries < pooled_before);
180    Measurement {
181        edit_ns,
182        verify_ns,
183        peak_allocated_bytes: PEAK_BYTES
184            .load(Ordering::Relaxed)
185            .saturating_sub(allocator_baseline) as usize,
186        baseline_owned_bytes: baseline.direct_owned_bytes,
187        stats,
188        reclaimed_list_entries,
189    }
190}
Source

pub fn parse_with_limits( bytes: impl Into<Arc<[u8]>>, limits: ParseLimits, ) -> Result<Self, ParseFileError>

Parses bytes with caller-supplied resource limits and generic syntax.

The same limits are retained for Self::apply_text_edits and semantic lowering. Recoverable lexer and syntax problems appear as diagnostics.

§Errors

Returns the fatal errors described by Self::parse.

Source

pub fn parse_with_registry( bytes: impl Into<Arc<[u8]>>, registry: &DialectRegistry, ) -> Result<Self, ParseFileError>

Parses bytes with default limits and registered custom operation syntax.

See the registry contract.

Pass the same registry to semantic lowering, verification, and custom printing so every stage uses the same dialect contract.

§Errors

Returns the fatal errors described by Self::parse.

Examples found in repository?
examples/diff_benchmark.rs (line 12)
10fn lower(source: &str) -> Document {
11    let registry = DialectRegistry::baseline();
12    let parsed = ParsedFile::parse_with_registry(source.as_bytes(), registry).unwrap();
13    lower_with_dialect_registry(&parsed, LoweringMode::Strict, registry)
14        .document
15        .expect("generated workload must lower strictly")
16}
More examples
Hide additional examples
examples/indexing_editing_benchmark.rs (lines 25-28)
11fn main() {
12    let constants = OPERATIONS / 2;
13    let mut source = String::from("builtin.module { func.func @bench() -> i32 {\n");
14    for index in 0..constants {
15        source.push_str(&format!("%v{index} = arith.constant {index} : i32\n"));
16    }
17    for index in constants..OPERATIONS {
18        source.push_str(&format!(
19            "%v{index} = arith.addi %v{}, %v0 : i32\n",
20            index - 1
21        ));
22    }
23    source.push_str(&format!("func.return %v{} : i32\n}} }}", OPERATIONS - 1));
24    let start = Instant::now();
25    let parsed = ParsedFile::parse_with_registry(
26        Arc::<[u8]>::from(source.into_bytes()),
27        DialectRegistry::baseline(),
28    )
29    .unwrap();
30    let parse_ns = start.elapsed().as_nanos();
31    let start = Instant::now();
32    let mut document =
33        lower_with_dialect_registry(&parsed, LoweringMode::Strict, DialectRegistry::baseline())
34            .document
35            .unwrap();
36    let lower_ns = start.elapsed().as_nanos();
37    let parse_only = document.statistics();
38
39    let operations = document.operations().collect::<Vec<_>>();
40    let first = operations
41        .iter()
42        .copied()
43        .find(|operation| document.operation_name(*operation) == Some("arith.constant"))
44        .unwrap();
45    let first_value = document.operation(first).unwrap().result(first, 0).unwrap();
46    let start = Instant::now();
47    black_box(document.uses(first_value));
48    let use_index_ns = start.elapsed().as_nanos();
49    let start = Instant::now();
50    black_box(document.symbol_index_diagnostics(DialectRegistry::baseline()));
51    let symbol_index_ns = start.elapsed().as_nanos();
52    let last = operations
53        .iter()
54        .copied()
55        .rev()
56        .find(|operation| document.operation_name(*operation) == Some("arith.addi"))
57        .unwrap();
58    let start = Instant::now();
59    black_box(document.dominates(first_value, last, DialectRegistry::baseline()));
60    let dominance_index_ns = start.elapsed().as_nanos();
61    let indexed = document.statistics();
62    let second = operations
63        .iter()
64        .copied()
65        .filter(|operation| document.operation_name(*operation) == Some("arith.constant"))
66        .nth(1)
67        .unwrap();
68    let mut editor = document.edit(DialectRegistry::baseline()).unwrap();
69    let second_value = editor
70        .document()
71        .operation(second)
72        .unwrap()
73        .result(second, 0)
74        .unwrap();
75    for value in [second_value, first_value].into_iter().cycle().take(20) {
76        editor.rewire_operand(last, 1, value).unwrap();
77    }
78    let before = editor.document().statistics().pooled_list_entries;
79    let start = Instant::now();
80    let reclaimed = editor.compact_pools();
81    let compaction_ns = start.elapsed().as_nanos();
82    editor.commit().unwrap();
83
84    println!(
85        "operations={OPERATIONS} parse_ns={parse_ns} lower_ns={lower_ns} parse_only_index_entries={} use_index_ns={use_index_ns} symbol_index_ns={symbol_index_ns} dominance_index_ns={dominance_index_ns} indexed_entries={} pooled_before={before} pooled_reclaimed={reclaimed} compaction_ns={compaction_ns}",
86        parse_only.use_index_entries
87            + parse_only.symbol_index_entries
88            + parse_only.dominance_index_entries,
89        indexed.use_index_entries + indexed.symbol_index_entries + indexed.dominance_index_entries,
90    );
91}
Source

pub fn parse_with_limits_and_registry( bytes: impl Into<Arc<[u8]>>, limits: ParseLimits, registry: &DialectRegistry, ) -> Result<Self, ParseFileError>

Parses bytes with explicit limits and a dialect registry.

A successful result is lossless even when it contains diagnostics. Registered parse callbacks may add syntax errors but do not replace the generic recovery model.

§Errors

Returns ParseFileError::ResourceLimit when max_file_bytes is exceeded, ParseFileError::Source when compact source offsets cannot represent the input, or ParseFileError::Syntax when CST compaction rejects the event stream.

Examples found in repository?
examples/processing_benchmark.rs (lines 244-248)
232fn measure(stage: Stage, shape: Shape, depth: Option<usize>, path: &PathBuf) -> Measurement {
233    let registry = DialectRegistry::baseline();
234    let mut limits = ParseLimits::default();
235    if let Some(depth) = depth {
236        limits.max_delimiter_depth = limits.max_delimiter_depth.max(depth.saturating_add(8));
237    }
238    let mut bytes = Vec::new();
239    File::open(path).unwrap().read_to_end(&mut bytes).unwrap();
240    let mut parsed = if stage == Stage::Parse {
241        None
242    } else {
243        Some(
244            ParsedFile::parse_with_limits_and_registry(
245                Arc::<[u8]>::from(bytes.clone()),
246                limits,
247                registry,
248            )
249            .unwrap(),
250        )
251    };
252    let retention = if shape == Shape::Primary
253        && matches!(
254            stage,
255            Stage::Lower | Stage::Preserving | Stage::DirtyPreserving
256        ) {
257        RetentionProfile::Hybrid
258    } else {
259        RetentionProfile::SemanticOnly
260    };
261    let mut document = if matches!(
262        stage,
263        Stage::Lower
264            | Stage::Parse
265            | Stage::Traverse
266            | Stage::SyntaxPayload
267            | Stage::SyntaxOperationPayload
268            | Stage::SyntaxOperationTraverse
269    ) {
270        None
271    } else {
272        Some(
273            lower_with_dialect_registry_and_retention(
274                parsed.as_ref().unwrap(),
275                LoweringMode::Strict,
276                retention,
277                registry,
278            )
279            .document
280            .expect("strict lowering"),
281        )
282    };
283    if stage == Stage::DirtyPreserving {
284        let document = document.as_mut().unwrap();
285        let operations = document
286            .operations()
287            .filter(|operation| {
288                document
289                    .operation_regions(*operation)
290                    .unwrap_or(&[])
291                    .is_empty()
292            })
293            .collect::<Vec<_>>();
294        let mut editor = document.edit(registry).unwrap();
295        for operation in operations {
296            editor
297                .set_attribute(
298                    operation,
299                    AttributeSpec {
300                        name: "bench_dirty".into(),
301                        spelling: "\"yes\"".into(),
302                        value: AttributeValue::String("\"yes\"".into()),
303                    },
304                )
305                .unwrap();
306        }
307        editor.commit().unwrap();
308    }
309    let baseline = LIVE.load(Ordering::Relaxed);
310    PEAK.store(baseline, Ordering::Relaxed);
311    let started = Instant::now();
312    let mut output = 0;
313    let mut checksum = 0_u64;
314    match stage {
315        Stage::Parse => {
316            parsed = Some(
317                ParsedFile::parse_with_limits_and_registry(
318                    Arc::<[u8]>::from(bytes),
319                    limits,
320                    registry,
321                )
322                .unwrap(),
323            )
324        }
325        Stage::Traverse => {
326            for node in parsed
327                .as_ref()
328                .unwrap()
329                .syntax()
330                .tree()
331                .subtree(parsed.as_ref().unwrap().syntax().tree().root())
332                .unwrap()
333            {
334                let tree = parsed.as_ref().unwrap().syntax().tree();
335                checksum = checksum
336                    .wrapping_mul(0x100000001b3)
337                    .wrapping_add(tree.kind(node).unwrap() as u64)
338                    .wrapping_add(tree.token_indices(node).unwrap().len() as u64);
339            }
340        }
341        Stage::SyntaxPayload => {
342            let tree = parsed.as_ref().unwrap().syntax().tree();
343            let mut node_kind = Vec::with_capacity(tree.node_count() * 2);
344            let mut node_start = Vec::with_capacity(tree.node_count() * 4);
345            let mut node_end = Vec::with_capacity(tree.node_count() * 4);
346            let mut node_subtree_end = Vec::with_capacity(tree.node_count() * 4);
347            let mut node_flags = Vec::with_capacity(tree.node_count());
348            for index in 0..tree.node_count() {
349                let id = tree.node(index).unwrap();
350                node_kind.extend_from_slice(&(tree.kind(id).unwrap() as u16).to_ne_bytes());
351                node_start.extend_from_slice(
352                    &tree
353                        .text_range(id)
354                        .map_or(u32::MAX, |r| r.start())
355                        .to_ne_bytes(),
356                );
357                node_end.extend_from_slice(
358                    &tree
359                        .text_range(id)
360                        .map_or(u32::MAX, |r| r.end())
361                        .to_ne_bytes(),
362                );
363                node_subtree_end
364                    .extend_from_slice(&(tree.subtree_end(id).unwrap() as u32).to_ne_bytes());
365                node_flags.push(u8::from(tree.has_error(id).unwrap()));
366            }
367            let mut token_kind = Vec::with_capacity(tree.token_count() * 2);
368            let mut token_start = Vec::with_capacity(tree.token_count() * 4);
369            let mut token_end = Vec::with_capacity(tree.token_count() * 4);
370            for index in 0..tree.token_count() {
371                let token = tree.token(index).unwrap();
372                token_kind.extend_from_slice(&(token.kind() as u16).to_ne_bytes());
373                token_start.extend_from_slice(&token.range().start().to_ne_bytes());
374                token_end.extend_from_slice(&token.range().end().to_ne_bytes());
375            }
376            output = node_kind.len()
377                + node_start.len()
378                + node_end.len()
379                + node_subtree_end.len()
380                + node_flags.len()
381                + token_kind.len()
382                + token_start.len()
383                + token_end.len();
384            checksum = node_kind
385                .iter()
386                .chain(&token_kind)
387                .fold(0_u64, |sum, byte| sum.wrapping_add(*byte as u64));
388            black_box((
389                node_kind,
390                node_start,
391                node_end,
392                node_subtree_end,
393                node_flags,
394                token_kind,
395                token_start,
396                token_end,
397            ));
398        }
399        Stage::SyntaxOperationTraverse => {
400            for operation in parsed.as_ref().unwrap().syntax().file().operations() {
401                checksum = checksum
402                    .wrapping_add(operation.id().index() as u64)
403                    .wrapping_add(operation.results().count() as u64)
404                    .wrapping_add(operation.operands().count() as u64)
405                    .wrapping_add(operation.successors().count() as u64)
406                    .wrapping_add(operation.regions().count() as u64);
407            }
408        }
409        Stage::SyntaxOperationPayload => {
410            let operations = parsed
411                .as_ref()
412                .unwrap()
413                .syntax()
414                .file()
415                .operations()
416                .collect::<Vec<_>>();
417            let result_count = operations.iter().map(|op| op.results().count()).sum();
418            let operand_count = operations.iter().map(|op| op.operands().count()).sum();
419            let successor_count = operations.iter().map(|op| op.successors().count()).sum();
420            let region_count = operations.iter().map(|op| op.regions().count()).sum();
421            let mut columns = [
422                Vec::with_capacity(operations.len()),
423                Vec::with_capacity(operations.len() + 1),
424                Vec::with_capacity(result_count),
425                Vec::with_capacity(operations.len() + 1),
426                Vec::with_capacity(operand_count),
427                Vec::with_capacity(operations.len() + 1),
428                Vec::with_capacity(successor_count),
429                Vec::with_capacity(operations.len() + 1),
430                Vec::with_capacity(region_count),
431            ];
432            for index in [1, 3, 5, 7] {
433                columns[index].push(0);
434            }
435            for operation in operations {
436                columns[0].push(operation.id().index() as u32);
437                columns[2].extend(operation.results().map(|node| node.id().index() as u32));
438                let end = columns[2].len() as u32;
439                columns[1].push(end);
440                columns[4].extend(operation.operands().map(|node| node.id().index() as u32));
441                let end = columns[4].len() as u32;
442                columns[3].push(end);
443                columns[6].extend(operation.successors().map(|node| node.id().index() as u32));
444                let end = columns[6].len() as u32;
445                columns[5].push(end);
446                columns[8].extend(operation.regions().map(|node| node.id().index() as u32));
447                let end = columns[8].len() as u32;
448                columns[7].push(end);
449            }
450            checksum = columns
451                .iter()
452                .flatten()
453                .fold(0_u64, |sum, value| sum.wrapping_add(*value as u64));
454            output = columns
455                .iter()
456                .map(|column| column.len() * size_of::<u32>())
457                .sum();
458            black_box(columns);
459        }
460        Stage::Lower => {
461            document = Some(
462                lower_with_dialect_registry_and_retention(
463                    parsed.as_ref().unwrap(),
464                    LoweringMode::Strict,
465                    retention,
466                    registry,
467                )
468                .document
469                .expect("strict lowering"),
470            )
471        }
472        Stage::OperationPayload => {
473            let doc = document.as_ref().unwrap();
474            let mut names = std::collections::HashMap::<u32, u32>::new();
475            let mut distinct = Vec::new();
476            let mut columns = Vec::<u32>::new();
477            for id in doc.operations() {
478                let stored = doc.operation_name_index(id).unwrap();
479                let next = distinct.len() as u32;
480                let code = *names.entry(stored).or_insert_with(|| {
481                    distinct.push(stored);
482                    next
483                });
484                let range = doc.operation_source_range(id).unwrap();
485                columns.extend([code, range.start(), range.end()]);
486                checksum = checksum.wrapping_add(code as u64);
487            }
488            let name_bytes: usize = distinct
489                .iter()
490                .map(|&index| doc.string_at(index).unwrap().len())
491                .sum();
492            output = columns.len() * std::mem::size_of::<u32>()
493                + doc.operations().count()
494                + (distinct.len() + 1) * std::mem::size_of::<u32>()
495                + name_bytes;
496            black_box(columns);
497        }
498        Stage::OperationTraverse => {
499            let doc = document.as_ref().unwrap();
500            for id in doc.operations() {
501                checksum = checksum
502                    .wrapping_add(doc.operation_name_index(id).unwrap() as u64)
503                    .wrapping_add(doc.operation_source_range(id).unwrap().start() as u64);
504            }
505        }
506        Stage::Verify => document
507            .as_ref()
508            .unwrap()
509            .verify_semantics(registry)
510            .unwrap(),
511        Stage::Canonical => {
512            let mut sink = ByteCounter::default();
513            document
514                .as_ref()
515                .unwrap()
516                .write_canonical(&mut sink, PrintLayout::Compact)
517                .unwrap();
518            output = sink.0;
519        }
520        Stage::UseIndex => {
521            let doc = document.as_ref().unwrap();
522            if let Some((_op, value)) = doc.operations().find_map(|op| {
523                doc.operation(op)
524                    .unwrap()
525                    .result(op, 0)
526                    .map(|value| (op, value))
527            }) {
528                black_box(doc.uses(value));
529            }
530        }
531        Stage::SymbolIndex => {
532            black_box(
533                document
534                    .as_ref()
535                    .unwrap()
536                    .symbol_index_diagnostics(registry),
537            );
538        }
539        Stage::DominanceIndex => {
540            let doc = document.as_ref().unwrap();
541            let ops = doc.operations().collect::<Vec<_>>();
542            if let (Some((_, value)), Some(last)) = (
543                ops.iter().find_map(|op| {
544                    doc.operation(*op)
545                        .unwrap()
546                        .result(*op, 0)
547                        .map(|value| (*op, value))
548                }),
549                ops.last(),
550            ) {
551                black_box(doc.dominates(value, *last, registry));
552            }
553        }
554        Stage::Editor => {
555            let doc = document.as_mut().unwrap();
556            let mut editor = doc.edit(registry).unwrap();
557            if shape == Shape::BlockRich {
558                black_box(editor.compact_pools());
559            } else {
560                let leaf = editor
561                    .document()
562                    .operations()
563                    .find(|op| editor.document().operation_name(*op) == Some("bench.op"))
564                    .expect("editable leaf");
565                editor.erase(leaf).unwrap();
566            }
567            editor.commit().unwrap();
568        }
569        Stage::Preserving | Stage::DirtyPreserving => {
570            let doc = document.as_ref().unwrap();
571            let mut sink = ByteCounter::default();
572            doc.write_preserving(&mut sink, PrintLayout::Compact)
573                .unwrap();
574            output = sink.0;
575        }
576    }
577    let elapsed = started.elapsed();
578    let peak = PEAK.load(Ordering::Relaxed).saturating_sub(baseline) as usize;
579    let stats = document.as_ref().map(|doc| { let s=doc.statistics(); format!("operations={} regions={} blocks={} pooled_entries={} direct_owned_bytes={} document_index_bytes={} retained_source_bytes={} retained_cst_nodes={} retained_cst_bytes={} source_storage_shared={} cst_storage_shared={} retained_mapping_entries={} payload_blob_bytes={} use_index_entries={} symbol_index_entries={} dominance_index_entries={}",s.operations,s.regions,s.blocks,s.pooled_list_entries,s.direct_owned_bytes,s.document_index_bytes,s.retained_source_bytes,s.retained_cst_nodes,s.retained_cst_bytes,s.source_storage_shared,s.cst_storage_shared,s.retained_mapping_entries,s.payload_blob_bytes,s.use_index_entries,s.symbol_index_entries,s.dominance_index_entries) }).unwrap_or_else(|| { let tree=parsed.as_ref().map(|p|p.syntax().tree()); format!("cst_nodes={} cst_tokens={} exact_cst_retained_bytes={}",tree.map_or(0,|t|t.node_count()),tree.map_or(0,|t|t.token_count()),tree.map_or(0,|t|t.exact_retained_bytes())) });
580    black_box(checksum);
581    Measurement {
582        ns: elapsed.as_nanos(),
583        peak,
584        output,
585        checksum,
586        stats,
587    }
588}
Source

pub fn source(&self) -> &Source

Source

pub fn lexer_diagnostics(&self) -> &[LexDiagnostic]

Source

pub fn syntax(&self) -> &ParsedSyntax

Examples found in repository?
examples/processing_benchmark.rs (line 329)
232fn measure(stage: Stage, shape: Shape, depth: Option<usize>, path: &PathBuf) -> Measurement {
233    let registry = DialectRegistry::baseline();
234    let mut limits = ParseLimits::default();
235    if let Some(depth) = depth {
236        limits.max_delimiter_depth = limits.max_delimiter_depth.max(depth.saturating_add(8));
237    }
238    let mut bytes = Vec::new();
239    File::open(path).unwrap().read_to_end(&mut bytes).unwrap();
240    let mut parsed = if stage == Stage::Parse {
241        None
242    } else {
243        Some(
244            ParsedFile::parse_with_limits_and_registry(
245                Arc::<[u8]>::from(bytes.clone()),
246                limits,
247                registry,
248            )
249            .unwrap(),
250        )
251    };
252    let retention = if shape == Shape::Primary
253        && matches!(
254            stage,
255            Stage::Lower | Stage::Preserving | Stage::DirtyPreserving
256        ) {
257        RetentionProfile::Hybrid
258    } else {
259        RetentionProfile::SemanticOnly
260    };
261    let mut document = if matches!(
262        stage,
263        Stage::Lower
264            | Stage::Parse
265            | Stage::Traverse
266            | Stage::SyntaxPayload
267            | Stage::SyntaxOperationPayload
268            | Stage::SyntaxOperationTraverse
269    ) {
270        None
271    } else {
272        Some(
273            lower_with_dialect_registry_and_retention(
274                parsed.as_ref().unwrap(),
275                LoweringMode::Strict,
276                retention,
277                registry,
278            )
279            .document
280            .expect("strict lowering"),
281        )
282    };
283    if stage == Stage::DirtyPreserving {
284        let document = document.as_mut().unwrap();
285        let operations = document
286            .operations()
287            .filter(|operation| {
288                document
289                    .operation_regions(*operation)
290                    .unwrap_or(&[])
291                    .is_empty()
292            })
293            .collect::<Vec<_>>();
294        let mut editor = document.edit(registry).unwrap();
295        for operation in operations {
296            editor
297                .set_attribute(
298                    operation,
299                    AttributeSpec {
300                        name: "bench_dirty".into(),
301                        spelling: "\"yes\"".into(),
302                        value: AttributeValue::String("\"yes\"".into()),
303                    },
304                )
305                .unwrap();
306        }
307        editor.commit().unwrap();
308    }
309    let baseline = LIVE.load(Ordering::Relaxed);
310    PEAK.store(baseline, Ordering::Relaxed);
311    let started = Instant::now();
312    let mut output = 0;
313    let mut checksum = 0_u64;
314    match stage {
315        Stage::Parse => {
316            parsed = Some(
317                ParsedFile::parse_with_limits_and_registry(
318                    Arc::<[u8]>::from(bytes),
319                    limits,
320                    registry,
321                )
322                .unwrap(),
323            )
324        }
325        Stage::Traverse => {
326            for node in parsed
327                .as_ref()
328                .unwrap()
329                .syntax()
330                .tree()
331                .subtree(parsed.as_ref().unwrap().syntax().tree().root())
332                .unwrap()
333            {
334                let tree = parsed.as_ref().unwrap().syntax().tree();
335                checksum = checksum
336                    .wrapping_mul(0x100000001b3)
337                    .wrapping_add(tree.kind(node).unwrap() as u64)
338                    .wrapping_add(tree.token_indices(node).unwrap().len() as u64);
339            }
340        }
341        Stage::SyntaxPayload => {
342            let tree = parsed.as_ref().unwrap().syntax().tree();
343            let mut node_kind = Vec::with_capacity(tree.node_count() * 2);
344            let mut node_start = Vec::with_capacity(tree.node_count() * 4);
345            let mut node_end = Vec::with_capacity(tree.node_count() * 4);
346            let mut node_subtree_end = Vec::with_capacity(tree.node_count() * 4);
347            let mut node_flags = Vec::with_capacity(tree.node_count());
348            for index in 0..tree.node_count() {
349                let id = tree.node(index).unwrap();
350                node_kind.extend_from_slice(&(tree.kind(id).unwrap() as u16).to_ne_bytes());
351                node_start.extend_from_slice(
352                    &tree
353                        .text_range(id)
354                        .map_or(u32::MAX, |r| r.start())
355                        .to_ne_bytes(),
356                );
357                node_end.extend_from_slice(
358                    &tree
359                        .text_range(id)
360                        .map_or(u32::MAX, |r| r.end())
361                        .to_ne_bytes(),
362                );
363                node_subtree_end
364                    .extend_from_slice(&(tree.subtree_end(id).unwrap() as u32).to_ne_bytes());
365                node_flags.push(u8::from(tree.has_error(id).unwrap()));
366            }
367            let mut token_kind = Vec::with_capacity(tree.token_count() * 2);
368            let mut token_start = Vec::with_capacity(tree.token_count() * 4);
369            let mut token_end = Vec::with_capacity(tree.token_count() * 4);
370            for index in 0..tree.token_count() {
371                let token = tree.token(index).unwrap();
372                token_kind.extend_from_slice(&(token.kind() as u16).to_ne_bytes());
373                token_start.extend_from_slice(&token.range().start().to_ne_bytes());
374                token_end.extend_from_slice(&token.range().end().to_ne_bytes());
375            }
376            output = node_kind.len()
377                + node_start.len()
378                + node_end.len()
379                + node_subtree_end.len()
380                + node_flags.len()
381                + token_kind.len()
382                + token_start.len()
383                + token_end.len();
384            checksum = node_kind
385                .iter()
386                .chain(&token_kind)
387                .fold(0_u64, |sum, byte| sum.wrapping_add(*byte as u64));
388            black_box((
389                node_kind,
390                node_start,
391                node_end,
392                node_subtree_end,
393                node_flags,
394                token_kind,
395                token_start,
396                token_end,
397            ));
398        }
399        Stage::SyntaxOperationTraverse => {
400            for operation in parsed.as_ref().unwrap().syntax().file().operations() {
401                checksum = checksum
402                    .wrapping_add(operation.id().index() as u64)
403                    .wrapping_add(operation.results().count() as u64)
404                    .wrapping_add(operation.operands().count() as u64)
405                    .wrapping_add(operation.successors().count() as u64)
406                    .wrapping_add(operation.regions().count() as u64);
407            }
408        }
409        Stage::SyntaxOperationPayload => {
410            let operations = parsed
411                .as_ref()
412                .unwrap()
413                .syntax()
414                .file()
415                .operations()
416                .collect::<Vec<_>>();
417            let result_count = operations.iter().map(|op| op.results().count()).sum();
418            let operand_count = operations.iter().map(|op| op.operands().count()).sum();
419            let successor_count = operations.iter().map(|op| op.successors().count()).sum();
420            let region_count = operations.iter().map(|op| op.regions().count()).sum();
421            let mut columns = [
422                Vec::with_capacity(operations.len()),
423                Vec::with_capacity(operations.len() + 1),
424                Vec::with_capacity(result_count),
425                Vec::with_capacity(operations.len() + 1),
426                Vec::with_capacity(operand_count),
427                Vec::with_capacity(operations.len() + 1),
428                Vec::with_capacity(successor_count),
429                Vec::with_capacity(operations.len() + 1),
430                Vec::with_capacity(region_count),
431            ];
432            for index in [1, 3, 5, 7] {
433                columns[index].push(0);
434            }
435            for operation in operations {
436                columns[0].push(operation.id().index() as u32);
437                columns[2].extend(operation.results().map(|node| node.id().index() as u32));
438                let end = columns[2].len() as u32;
439                columns[1].push(end);
440                columns[4].extend(operation.operands().map(|node| node.id().index() as u32));
441                let end = columns[4].len() as u32;
442                columns[3].push(end);
443                columns[6].extend(operation.successors().map(|node| node.id().index() as u32));
444                let end = columns[6].len() as u32;
445                columns[5].push(end);
446                columns[8].extend(operation.regions().map(|node| node.id().index() as u32));
447                let end = columns[8].len() as u32;
448                columns[7].push(end);
449            }
450            checksum = columns
451                .iter()
452                .flatten()
453                .fold(0_u64, |sum, value| sum.wrapping_add(*value as u64));
454            output = columns
455                .iter()
456                .map(|column| column.len() * size_of::<u32>())
457                .sum();
458            black_box(columns);
459        }
460        Stage::Lower => {
461            document = Some(
462                lower_with_dialect_registry_and_retention(
463                    parsed.as_ref().unwrap(),
464                    LoweringMode::Strict,
465                    retention,
466                    registry,
467                )
468                .document
469                .expect("strict lowering"),
470            )
471        }
472        Stage::OperationPayload => {
473            let doc = document.as_ref().unwrap();
474            let mut names = std::collections::HashMap::<u32, u32>::new();
475            let mut distinct = Vec::new();
476            let mut columns = Vec::<u32>::new();
477            for id in doc.operations() {
478                let stored = doc.operation_name_index(id).unwrap();
479                let next = distinct.len() as u32;
480                let code = *names.entry(stored).or_insert_with(|| {
481                    distinct.push(stored);
482                    next
483                });
484                let range = doc.operation_source_range(id).unwrap();
485                columns.extend([code, range.start(), range.end()]);
486                checksum = checksum.wrapping_add(code as u64);
487            }
488            let name_bytes: usize = distinct
489                .iter()
490                .map(|&index| doc.string_at(index).unwrap().len())
491                .sum();
492            output = columns.len() * std::mem::size_of::<u32>()
493                + doc.operations().count()
494                + (distinct.len() + 1) * std::mem::size_of::<u32>()
495                + name_bytes;
496            black_box(columns);
497        }
498        Stage::OperationTraverse => {
499            let doc = document.as_ref().unwrap();
500            for id in doc.operations() {
501                checksum = checksum
502                    .wrapping_add(doc.operation_name_index(id).unwrap() as u64)
503                    .wrapping_add(doc.operation_source_range(id).unwrap().start() as u64);
504            }
505        }
506        Stage::Verify => document
507            .as_ref()
508            .unwrap()
509            .verify_semantics(registry)
510            .unwrap(),
511        Stage::Canonical => {
512            let mut sink = ByteCounter::default();
513            document
514                .as_ref()
515                .unwrap()
516                .write_canonical(&mut sink, PrintLayout::Compact)
517                .unwrap();
518            output = sink.0;
519        }
520        Stage::UseIndex => {
521            let doc = document.as_ref().unwrap();
522            if let Some((_op, value)) = doc.operations().find_map(|op| {
523                doc.operation(op)
524                    .unwrap()
525                    .result(op, 0)
526                    .map(|value| (op, value))
527            }) {
528                black_box(doc.uses(value));
529            }
530        }
531        Stage::SymbolIndex => {
532            black_box(
533                document
534                    .as_ref()
535                    .unwrap()
536                    .symbol_index_diagnostics(registry),
537            );
538        }
539        Stage::DominanceIndex => {
540            let doc = document.as_ref().unwrap();
541            let ops = doc.operations().collect::<Vec<_>>();
542            if let (Some((_, value)), Some(last)) = (
543                ops.iter().find_map(|op| {
544                    doc.operation(*op)
545                        .unwrap()
546                        .result(*op, 0)
547                        .map(|value| (*op, value))
548                }),
549                ops.last(),
550            ) {
551                black_box(doc.dominates(value, *last, registry));
552            }
553        }
554        Stage::Editor => {
555            let doc = document.as_mut().unwrap();
556            let mut editor = doc.edit(registry).unwrap();
557            if shape == Shape::BlockRich {
558                black_box(editor.compact_pools());
559            } else {
560                let leaf = editor
561                    .document()
562                    .operations()
563                    .find(|op| editor.document().operation_name(*op) == Some("bench.op"))
564                    .expect("editable leaf");
565                editor.erase(leaf).unwrap();
566            }
567            editor.commit().unwrap();
568        }
569        Stage::Preserving | Stage::DirtyPreserving => {
570            let doc = document.as_ref().unwrap();
571            let mut sink = ByteCounter::default();
572            doc.write_preserving(&mut sink, PrintLayout::Compact)
573                .unwrap();
574            output = sink.0;
575        }
576    }
577    let elapsed = started.elapsed();
578    let peak = PEAK.load(Ordering::Relaxed).saturating_sub(baseline) as usize;
579    let stats = document.as_ref().map(|doc| { let s=doc.statistics(); format!("operations={} regions={} blocks={} pooled_entries={} direct_owned_bytes={} document_index_bytes={} retained_source_bytes={} retained_cst_nodes={} retained_cst_bytes={} source_storage_shared={} cst_storage_shared={} retained_mapping_entries={} payload_blob_bytes={} use_index_entries={} symbol_index_entries={} dominance_index_entries={}",s.operations,s.regions,s.blocks,s.pooled_list_entries,s.direct_owned_bytes,s.document_index_bytes,s.retained_source_bytes,s.retained_cst_nodes,s.retained_cst_bytes,s.source_storage_shared,s.cst_storage_shared,s.retained_mapping_entries,s.payload_blob_bytes,s.use_index_entries,s.symbol_index_entries,s.dominance_index_entries) }).unwrap_or_else(|| { let tree=parsed.as_ref().map(|p|p.syntax().tree()); format!("cst_nodes={} cst_tokens={} exact_cst_retained_bytes={}",tree.map_or(0,|t|t.node_count()),tree.map_or(0,|t|t.token_count()),tree.map_or(0,|t|t.exact_retained_bytes())) });
580    black_box(checksum);
581    Measurement {
582        ns: elapsed.as_nanos(),
583        peak,
584        output,
585        checksum,
586        stats,
587    }
588}
Source

pub fn max_attribute_depth(&self) -> usize

Source

pub fn max_alias_expansion_depth(&self) -> usize

Source

pub fn original_bytes(&self) -> &[u8] ⓘ

Source

pub fn write_original<W: Write>(&self, sink: &mut W) -> Result<()>

Source

pub fn apply_text_edits( &self, edits: &[TextEdit], ) -> Result<Self, ApplyTextEditsError>

Applies non-overlapping byte-range edits and reparses the complete result.

Ranges refer to this file’s original bytes. The returned file preserves this file’s complete ParseLimits. This method reparses with the empty registry. For registered custom syntax, use Self::apply_text_edits_with_registry with the original registry.

§Errors

Returns an error for an out-of-bounds or overlapping range, an unrepresentable output length, or a fatal error while reparsing.

Source

pub fn apply_text_edits_with_registry( &self, edits: &[TextEdit], registry: &DialectRegistry, ) -> Result<Self, ApplyTextEditsError>

Applies text edits and reparses with explicit custom syntax.

See the registry contract.

§Errors

Returns the same errors as Self::apply_text_edits.

Trait Implementations§

Source§

impl Debug for ParsedFile

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

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> 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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

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

fn try_from(value: U) -> Result<T, !>

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.