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
impl ParsedFile
Sourcepub fn write_formatted<W: Write>(
&self,
sink: &mut W,
options: FormatOptions,
) -> Result<(), FormatError>
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.
Sourcepub fn formatted_bytes(
&self,
options: FormatOptions,
) -> Result<Vec<u8>, FormatError>
pub fn formatted_bytes( &self, options: FormatOptions, ) -> Result<Vec<u8>, FormatError>
Returns source-aware formatted output as bytes.
Source§impl ParsedFile
impl ParsedFile
Sourcepub fn parse(bytes: impl Into<Arc<[u8]>>) -> Result<Self, ParseFileError>
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?
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
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, ®istry)
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(®istry).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(®istry)).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}Sourcepub fn parse_with_limits(
bytes: impl Into<Arc<[u8]>>,
limits: ParseLimits,
) -> Result<Self, ParseFileError>
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.
Sourcepub fn parse_with_registry(
bytes: impl Into<Arc<[u8]>>,
registry: &DialectRegistry,
) -> Result<Self, ParseFileError>
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?
More examples
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}Sourcepub fn parse_with_limits_and_registry(
bytes: impl Into<Arc<[u8]>>,
limits: ParseLimits,
registry: &DialectRegistry,
) -> Result<Self, ParseFileError>
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?
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}pub fn source(&self) -> &Source
pub fn lexer_diagnostics(&self) -> &[LexDiagnostic]
Sourcepub fn syntax(&self) -> &ParsedSyntax
pub fn syntax(&self) -> &ParsedSyntax
Examples found in repository?
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}pub fn max_attribute_depth(&self) -> usize
pub fn max_alias_expansion_depth(&self) -> usize
pub fn original_bytes(&self) -> &[u8] ⓘ
pub fn write_original<W: Write>(&self, sink: &mut W) -> Result<()>
Sourcepub fn apply_text_edits(
&self,
edits: &[TextEdit],
) -> Result<Self, ApplyTextEditsError>
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.
Sourcepub fn apply_text_edits_with_registry(
&self,
edits: &[TextEdit],
registry: &DialectRegistry,
) -> Result<Self, ApplyTextEditsError>
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.