1use crate::unparser::common::push_register;
2use crate::{
3 lexer::PtxToken,
4 r#type::{function::*, variable::ParameterDirective},
5 unparser::*,
6};
7
8fn push_register_components(tokens: &mut Vec<PtxToken>, name: &str) {
9 if let Some(stripped) = name.strip_prefix('%') {
10 let mut parts = stripped.split('.');
11 if let Some(first) = parts.next() {
12 let register_name = format!("%{first}");
13 push_register(tokens, ®ister_name);
14 }
15 for part in parts {
16 if part.is_empty() {
17 continue;
18 }
19 push_directive(tokens, part);
20 }
21 } else {
22 push_identifier(tokens, name);
23 }
24}
25
26fn unparse_param(tokens: &mut Vec<PtxToken>, param: &ParameterDirective, spaced: bool) {
27 match param {
28 ParameterDirective::Parameter {
29 align,
30 ty,
31 ptr,
32 space,
33 name,
34 array,
35 ..
36 } => {
37 push_directive(tokens, "param");
38 push_space(tokens, spaced);
39 if let Some(value) = align {
41 push_directive(tokens, "align");
42 push_space(tokens, spaced);
43 push_decimal(tokens, *value);
44 push_space(tokens, spaced);
45 }
46 ty.unparse_tokens_mode(tokens, spaced);
47 if *ptr {
48 push_directive(tokens, "ptr");
49 }
50 if let Some(address_space) = space {
51 address_space.unparse_tokens_mode(tokens, spaced);
52 }
53 push_space(tokens, spaced);
54 push_identifier(tokens, &name.val);
55 for extent in array {
56 tokens.push(PtxToken::LBracket);
57 if let Some(value) = extent {
58 push_decimal(tokens, *value);
59 }
60 tokens.push(PtxToken::RBracket);
61 }
62 }
63 ParameterDirective::Register { ty, name, .. } => {
64 push_directive(tokens, "reg");
65 push_space(tokens, spaced);
66 ty.unparse_tokens_mode(tokens, spaced);
67 push_space(tokens, spaced);
68 push_register_components(tokens, &name.val);
69 }
70 }
71}
72
73fn unparse_param_list(tokens: &mut Vec<PtxToken>, params: &[ParameterDirective], spaced: bool) {
74 for (idx, param) in params.iter().enumerate() {
75 if idx > 0 {
76 tokens.push(PtxToken::Comma);
77 push_space(tokens, spaced);
78 }
79 unparse_param(tokens, param, spaced);
80 }
81}
82
83fn unparse_section_line(
84 tokens: &mut Vec<PtxToken>,
85 line: &StatementSectionDirectiveLine,
86 spaced: bool,
87) {
88 match line {
89 StatementSectionDirectiveLine::B8 { values, .. } => {
90 push_directive(tokens, "b8");
91 for (idx, value) in values.iter().enumerate() {
92 if idx > 0 {
93 tokens.push(PtxToken::Comma);
94 push_space(tokens, spaced);
95 }
96 push_space(tokens, spaced);
97 push_signed_decimal_i64(tokens, *value as i64);
98 }
99 push_newline(tokens, spaced);
100 }
101 StatementSectionDirectiveLine::B16 { values, .. } => {
102 push_directive(tokens, "b16");
103 for (idx, value) in values.iter().enumerate() {
104 if idx > 0 {
105 tokens.push(PtxToken::Comma);
106 push_space(tokens, spaced);
107 }
108 push_space(tokens, spaced);
109 push_signed_decimal_i64(tokens, *value as i64);
110 }
111 push_newline(tokens, spaced);
112 }
113 StatementSectionDirectiveLine::B32Immediate { values, .. } => {
114 push_directive(tokens, "b32");
115 for (idx, value) in values.iter().enumerate() {
116 if idx > 0 {
117 tokens.push(PtxToken::Comma);
118 push_space(tokens, spaced);
119 }
120 push_space(tokens, spaced);
121 push_signed_decimal_i64(tokens, *value);
122 }
123 push_newline(tokens, spaced);
124 }
125 StatementSectionDirectiveLine::B64Immediate { values, .. } => {
126 push_directive(tokens, "b64");
127 for (idx, value) in values.iter().enumerate() {
128 if idx > 0 {
129 tokens.push(PtxToken::Comma);
130 push_space(tokens, spaced);
131 }
132 push_space(tokens, spaced);
133 push_signed_decimal_i128(tokens, *value);
134 }
135 push_newline(tokens, spaced);
136 }
137 StatementSectionDirectiveLine::B32Label { labels, .. } => {
138 push_directive(tokens, "b32");
139 push_space(tokens, spaced);
140 push_identifier(tokens, &labels.val);
141 push_newline(tokens, spaced);
142 }
143 StatementSectionDirectiveLine::B64Label { labels, .. } => {
144 push_directive(tokens, "b64");
145 push_space(tokens, spaced);
146 push_identifier(tokens, &labels.val);
147 push_newline(tokens, spaced);
148 }
149 StatementSectionDirectiveLine::B32LabelPlusImm { entries, .. } => {
150 push_directive(tokens, "b32");
151 let (label, offset) = entries;
152 push_space(tokens, spaced);
153 push_identifier(tokens, &label.val);
154 if *offset >= 0 {
155 tokens.push(PtxToken::Plus);
156 push_decimal(tokens, *offset);
157 } else {
158 tokens.push(PtxToken::Minus);
159 let magnitude = (*offset as i128).abs();
160 push_decimal(tokens, magnitude);
161 }
162 push_newline(tokens, spaced);
163 }
164 StatementSectionDirectiveLine::B64LabelPlusImm { entries, .. } => {
165 push_directive(tokens, "b64");
166 let (label, offset) = entries;
167 push_space(tokens, spaced);
168 push_identifier(tokens, &label.val);
169 if *offset >= 0 {
170 tokens.push(PtxToken::Plus);
171 push_decimal(tokens, *offset);
172 } else {
173 tokens.push(PtxToken::Minus);
174 let magnitude = (*offset as i128).abs();
175 push_decimal(tokens, magnitude);
176 }
177 push_newline(tokens, spaced);
178 }
179 StatementSectionDirectiveLine::B32LabelDiff { entries, .. } => {
180 push_directive(tokens, "b32");
181 let (left, right) = entries;
182 push_space(tokens, spaced);
183 push_identifier(tokens, &left.val);
184 tokens.push(PtxToken::Minus);
185 push_space(tokens, spaced);
186 push_identifier(tokens, &right.val);
187 push_newline(tokens, spaced);
188 }
189 StatementSectionDirectiveLine::B64LabelDiff { entries, .. } => {
190 push_directive(tokens, "b64");
191 let (left, right) = entries;
192 push_space(tokens, spaced);
193 push_identifier(tokens, &left.val);
194 tokens.push(PtxToken::Minus);
195 push_space(tokens, spaced);
196 push_identifier(tokens, &right.val);
197 push_newline(tokens, spaced);
198 }
199 }
200}
201
202fn push_signed_decimal_i64(tokens: &mut Vec<PtxToken>, value: i64) {
203 if value < 0 {
204 tokens.push(PtxToken::Minus);
205 push_decimal(tokens, (-value) as i128);
206 } else {
207 push_decimal(tokens, value);
208 }
209}
210
211fn push_signed_decimal_i128(tokens: &mut Vec<PtxToken>, value: i128) {
212 if value < 0 {
213 tokens.push(PtxToken::Minus);
214 push_decimal(tokens, -value);
215 } else {
216 push_decimal(tokens, value);
217 }
218}
219
220impl PtxUnparser for RegisterDirective {
221 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
222 self.unparse_tokens_mode(tokens, false);
223 }
224
225 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
226 push_directive(tokens, "reg");
227 push_space(tokens, spaced);
228 if let Some(vector) = self.vector {
229 push_directive(
230 tokens,
231 match vector {
232 RegisterVectorWidth::V2 => "v2",
233 RegisterVectorWidth::V4 => "v4",
234 },
235 );
236 push_space(tokens, spaced);
237 }
238 self.ty.unparse_tokens_mode(tokens, spaced);
239 for (idx, target) in self.registers.iter().enumerate() {
240 if idx > 0 {
241 tokens.push(PtxToken::Comma);
242 push_space(tokens, spaced);
243 } else {
244 push_space(tokens, spaced);
245 }
246 push_register_components(tokens, &target.name.val);
247 if let Some(range) = target.range {
248 tokens.push(PtxToken::LAngle);
249 push_decimal(tokens, range);
250 tokens.push(PtxToken::RAngle);
251 }
252 }
253 tokens.push(PtxToken::Semicolon);
254 push_newline(tokens, spaced);
255 }
256}
257
258impl PtxUnparser for StatementDirective {
259 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
260 self.unparse_tokens_mode(tokens, false);
261 }
262
263 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
264 match self {
265 StatementDirective::Reg {
266 directive: register,
267 ..
268 } => register.unparse_tokens_mode(tokens, spaced),
269 StatementDirective::Local {
270 directive: variable,
271 ..
272 } => {
273 push_directive(tokens, "local");
274 push_space(tokens, spaced);
275 variable.unparse_tokens_mode(tokens, spaced);
276 }
277 StatementDirective::Param {
278 directive: variable,
279 ..
280 } => {
281 push_directive(tokens, "param");
282 push_space(tokens, spaced);
283 variable.unparse_tokens_mode(tokens, spaced);
284 }
285 StatementDirective::Shared {
286 directive: variable,
287 ..
288 } => {
289 push_directive(tokens, "shared");
290 push_space(tokens, spaced);
291 variable.unparse_tokens_mode(tokens, spaced);
292 }
293 StatementDirective::Pragma {
294 directive: pragma, ..
295 } => {
296 push_directive(tokens, "pragma");
297 push_space(tokens, spaced);
298 let text = match &pragma.kind {
299 PragmaDirectiveKind::Nounroll => "nounroll".to_string(),
300 PragmaDirectiveKind::EnableSmemSpilling => "enable_smem_spilling".to_string(),
301 PragmaDirectiveKind::UsedBytesMask { mask } => {
302 format!("used_bytes_mask {}", mask)
303 }
304 PragmaDirectiveKind::Frequency { value } => {
305 format!("frequency {}", value)
306 }
307 PragmaDirectiveKind::Raw(text) => text.clone(),
308 };
309 tokens.push(PtxToken::StringLiteral(text));
310 tokens.push(PtxToken::Semicolon);
311 push_newline(tokens, spaced);
312 }
313 StatementDirective::BranchTargets { directive, .. } => {
314 push_directive(tokens, "branchtargets");
315 push_space(tokens, spaced);
316 for (idx, label) in directive.labels.iter().enumerate() {
317 if idx > 0 {
318 tokens.push(PtxToken::Comma);
319 push_space(tokens, spaced);
320 }
321 push_token_from_str(tokens, &label.val);
322 }
323 tokens.push(PtxToken::Semicolon);
324 push_newline(tokens, spaced);
325 }
326 StatementDirective::CallTargets { directive, .. } => {
327 push_directive(tokens, "calltargets");
328 push_space(tokens, spaced);
329 for (idx, target) in directive.targets.iter().enumerate() {
330 if idx > 0 {
331 tokens.push(PtxToken::Comma);
332 push_space(tokens, spaced);
333 }
334 push_token_from_str(tokens, &target.val);
335 }
336 tokens.push(PtxToken::Semicolon);
337 push_newline(tokens, spaced);
338 }
339 StatementDirective::Loc { directive: loc, .. } => {
340 push_directive(tokens, "loc");
341 push_space(tokens, spaced);
342 push_decimal(tokens, loc.file_index);
343 push_space(tokens, spaced);
344 push_decimal(tokens, loc.line);
345 push_space(tokens, spaced);
346 push_decimal(tokens, loc.column);
347 if let Some(function) = &loc.function {
348 tokens.push(PtxToken::Comma);
349 push_space(tokens, spaced);
350 push_identifier(tokens, "function_name");
351 push_space(tokens, spaced);
352 function.label.unparse_tokens_mode(tokens, spaced);
353 if let Some(offset) = function.label_offset {
354 tokens.push(PtxToken::Plus);
355 push_decimal(tokens, offset);
356 }
357 tokens.push(PtxToken::Comma);
358 push_space(tokens, spaced);
359 push_identifier(tokens, "inlined_at");
360 push_space(tokens, spaced);
361 push_decimal(tokens, function.inlined_at.file_index);
362 push_space(tokens, spaced);
363 push_decimal(tokens, function.inlined_at.line);
364 push_space(tokens, spaced);
365 push_decimal(tokens, function.inlined_at.column);
366 }
367 push_newline(tokens, spaced);
368 }
369 StatementDirective::Dwarf {
370 directive: dwarf, ..
371 } => {
372 dwarf.unparse_tokens_mode(tokens, spaced);
373 push_newline(tokens, spaced);
374 }
375 StatementDirective::Section {
376 directive: section, ..
377 } => {
378 section.unparse_tokens_mode(tokens, spaced);
379 }
380 StatementDirective::CallPrototype { directive, .. } => {
381 push_directive(tokens, "callprototype");
382 push_space(tokens, spaced);
383 if let Some(ret) = &directive.return_param {
384 unparse_param(tokens, ret, spaced);
385 } else {
386 push_identifier(tokens, "_");
387 }
388 tokens.push(PtxToken::LParen);
389 unparse_param_list(tokens, &directive.params, spaced);
390 tokens.push(PtxToken::RParen);
391 if directive.noreturn {
392 push_space(tokens, spaced);
393 push_directive(tokens, "noreturn");
394 }
395 if let Some(value) = directive.abi_preserve {
396 push_space(tokens, spaced);
397 push_directive(tokens, "abi_preserve");
398 push_space(tokens, spaced);
399 push_decimal(tokens, value);
400 }
401 if let Some(value) = directive.abi_preserve_control {
402 push_space(tokens, spaced);
403 push_directive(tokens, "abi_preserve_control");
404 push_space(tokens, spaced);
405 push_decimal(tokens, value);
406 }
407 tokens.push(PtxToken::Semicolon);
408 push_newline(tokens, spaced);
409 }
410 }
411 }
412}
413
414impl PtxUnparser for SectionDirective {
415 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
416 self.unparse_tokens_mode(tokens, false);
417 }
418
419 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
420 push_directive(tokens, "section");
421 push_space(tokens, spaced);
422 push_token_from_str(tokens, &self.name);
423 push_space(tokens, spaced);
424 tokens.push(PtxToken::LBrace);
425 push_newline(tokens, spaced);
426 for entry in &self.entries {
427 match entry {
428 SectionEntry::Label { label, .. } => {
429 push_identifier(tokens, &label.val);
430 tokens.push(PtxToken::Colon);
431 push_newline(tokens, spaced);
432 }
433 SectionEntry::Directive(line) => {
434 unparse_section_line(tokens, line, spaced);
435 }
436 }
437 }
438 tokens.push(PtxToken::RBrace);
439 push_newline(tokens, spaced);
440 }
441}
442
443impl PtxUnparser for FunctionStatement {
444 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
445 self.unparse_tokens_mode(tokens, false);
446 }
447
448 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
449 match self {
450 FunctionStatement::Label { label, .. } => {
451 push_identifier(tokens, &label.val);
452 tokens.push(PtxToken::Colon);
453 push_newline(tokens, spaced);
454 }
455 FunctionStatement::Instruction { instruction, .. } => {
456 instruction.unparse_tokens_mode(tokens, spaced)
457 }
458 FunctionStatement::Directive { directive, .. } => {
459 directive.unparse_tokens_mode(tokens, spaced)
460 }
461 FunctionStatement::Block {
462 statements: block, ..
463 } => {
464 tokens.push(PtxToken::LBrace);
465 for statement in block {
466 statement.unparse_tokens_mode(tokens, spaced);
467 }
468 tokens.push(PtxToken::RBrace);
469 push_newline(tokens, spaced);
470 }
471 }
472 }
473}
474
475impl PtxUnparser for FunctionBody {
476 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
477 self.unparse_tokens_mode(tokens, false);
478 }
479
480 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
481 tokens.push(PtxToken::LBrace);
482 push_newline(tokens, spaced);
483 for statement in &self.statements {
484 statement.unparse_tokens_mode(tokens, spaced);
485 }
486 tokens.push(PtxToken::RBrace);
487 push_newline(tokens, spaced);
488 }
489}
490
491impl PtxUnparser for FunctionDim {
492 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
493 self.unparse_tokens_mode(tokens, false);
494 }
495
496 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
497 match self {
498 FunctionDim::X { x, .. } => {
499 push_decimal(tokens, *x);
500 }
501 FunctionDim::XY { x, y, .. } => {
502 push_decimal(tokens, *x);
503 tokens.push(PtxToken::Comma);
504 push_space(tokens, spaced);
505 push_decimal(tokens, *y);
506 }
507 FunctionDim::XYZ { x, y, z, .. } => {
508 push_decimal(tokens, *x);
509 tokens.push(PtxToken::Comma);
510 push_space(tokens, spaced);
511 push_decimal(tokens, *y);
512 tokens.push(PtxToken::Comma);
513 push_space(tokens, spaced);
514 push_decimal(tokens, *z);
515 }
516 }
517 }
518}
519
520impl PtxUnparser for EntryFunctionHeaderDirective {
521 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
522 self.unparse_tokens_mode(tokens, false);
523 }
524
525 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
526 match self {
527 EntryFunctionHeaderDirective::MaxNReg { value, .. } => {
528 push_directive(tokens, "maxnreg");
529 push_space(tokens, spaced);
530 push_decimal(tokens, *value);
531 }
532 EntryFunctionHeaderDirective::MaxNTid { dim, .. } => {
533 push_directive(tokens, "maxntid");
534 push_space(tokens, spaced);
535 dim.unparse_tokens_mode(tokens, spaced);
536 }
537 EntryFunctionHeaderDirective::ReqNTid { dim, .. } => {
538 push_directive(tokens, "reqntid");
539 push_space(tokens, spaced);
540 dim.unparse_tokens_mode(tokens, spaced);
541 }
542 EntryFunctionHeaderDirective::MinNCtaPerSm { value, .. } => {
543 push_directive(tokens, "minnctapersm");
544 push_space(tokens, spaced);
545 push_decimal(tokens, *value);
546 }
547 EntryFunctionHeaderDirective::MaxNCtaPerSm { value, .. } => {
548 push_directive(tokens, "maxnctapersm");
549 push_space(tokens, spaced);
550 push_decimal(tokens, *value);
551 }
552 EntryFunctionHeaderDirective::Pragma {
553 args: arguments, ..
554 } => {
555 push_directive(tokens, "pragma");
556 push_space(tokens, spaced);
557 for argument in arguments {
558 tokens.push(PtxToken::StringLiteral(argument.clone()));
559 push_space(tokens, spaced);
560 }
561 if spaced {
562 if let Some(last) = tokens.last() {
563 if matches!(last, PtxToken::Space) {
564 tokens.pop();
565 }
566 }
567 }
568 }
569 EntryFunctionHeaderDirective::ReqNctaPerCluster { dim, .. } => {
570 push_directive(tokens, "reqnctapercluster");
571 push_space(tokens, spaced);
572 dim.unparse_tokens_mode(tokens, spaced);
573 }
574 EntryFunctionHeaderDirective::ExplicitCluster { .. } => {
575 push_directive(tokens, "explicitcluster");
576 }
577 EntryFunctionHeaderDirective::MaxClusterRank { value, .. } => {
578 push_directive(tokens, "maxclusterrank");
579 push_space(tokens, spaced);
580 push_decimal(tokens, *value);
581 }
582 EntryFunctionHeaderDirective::BlocksAreClusters { .. } => {
583 push_directive(tokens, "blocksareclusters")
584 }
585 }
586 }
587}
588
589impl PtxUnparser for FuncFunctionHeaderDirective {
590 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
591 self.unparse_tokens_mode(tokens, false);
592 }
593
594 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
595 match self {
596 FuncFunctionHeaderDirective::NoReturn { .. } => push_directive(tokens, "noreturn"),
597 FuncFunctionHeaderDirective::Pragma {
598 args: arguments, ..
599 } => {
600 push_directive(tokens, "pragma");
601 push_space(tokens, spaced);
602 for argument in arguments {
603 tokens.push(PtxToken::StringLiteral(argument.clone()));
604 push_space(tokens, spaced);
605 }
606 if spaced {
607 if let Some(PtxToken::Space) = tokens.last() {
608 tokens.pop();
609 }
610 }
611 }
612 FuncFunctionHeaderDirective::AbiPreserve { value, .. } => {
613 push_directive(tokens, "abi_preserve");
614 push_space(tokens, spaced);
615 push_decimal(tokens, *value);
616 }
617 FuncFunctionHeaderDirective::AbiPreserveControl { value, .. } => {
618 push_directive(tokens, "abi_preserve_control");
619 push_space(tokens, spaced);
620 push_decimal(tokens, *value);
621 }
622 }
623 }
624}
625
626impl PtxUnparser for AliasFunctionDirective {
627 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
628 self.unparse_tokens_mode(tokens, false);
629 }
630
631 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
632 push_directive(tokens, "alias");
633 push_space(tokens, spaced);
634 push_identifier(tokens, &self.alias.val);
635 tokens.push(PtxToken::Comma);
636 push_space(tokens, spaced);
637 push_identifier(tokens, &self.target.val);
638 tokens.push(PtxToken::Semicolon);
639 push_newline(tokens, spaced);
640 }
641}
642
643impl PtxUnparser for EntryFunctionDirective {
644 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
645 self.unparse_tokens_mode(tokens, false);
646 }
647
648 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
649 push_directive(tokens, "entry");
650 push_space(tokens, spaced);
651 push_identifier(tokens, &self.name.val);
652 tokens.push(PtxToken::LParen);
653 unparse_param_list(tokens, &self.params, spaced);
654 tokens.push(PtxToken::RParen);
655 for directive in &self.directives {
656 push_newline(tokens, spaced);
657 directive.unparse_tokens_mode(tokens, spaced);
658 }
659 if !self.directives.is_empty() {
660 push_newline(tokens, spaced);
661 }
662 match &self.body {
663 Some(body) => body.unparse_tokens_mode(tokens, spaced),
664 None => {
665 tokens.push(PtxToken::Semicolon);
666 push_newline(tokens, spaced);
667 }
668 }
669 }
670}
671
672impl PtxUnparser for FuncFunctionDirective {
673 fn unparse_tokens(&self, tokens: &mut Vec<PtxToken>) {
674 self.unparse_tokens_mode(tokens, false);
675 }
676
677 fn unparse_tokens_mode(&self, tokens: &mut Vec<PtxToken>, spaced: bool) {
678 push_directive(tokens, "func");
679 for attribute in &self.attributes {
680 push_space(tokens, spaced);
681 attribute.unparse_tokens_mode(tokens, spaced);
682 }
683 if let Some(ret) = &self.return_param {
684 push_space(tokens, spaced);
685 tokens.push(PtxToken::LParen);
686 unparse_param(tokens, ret, spaced);
687 tokens.push(PtxToken::RParen);
688 }
689 push_space(tokens, spaced);
690 push_identifier(tokens, &self.name.val);
691 tokens.push(PtxToken::LParen);
692 unparse_param_list(tokens, &self.params, spaced);
693 tokens.push(PtxToken::RParen);
694 for directive in &self.directives {
698 push_space(tokens, spaced);
699 directive.unparse_tokens_mode(tokens, spaced);
700 }
701 for decl in &self.pre_body_declarations {
703 push_newline(tokens, spaced);
704 decl.unparse_tokens_mode(tokens, spaced);
705 }
706 match &self.body {
707 Some(body) => body.unparse_tokens_mode(tokens, spaced),
708 None => {
709 tokens.push(PtxToken::Semicolon);
710 push_newline(tokens, spaced);
711 }
712 }
713 }
714}