1use crate::parser::common::{invalid_literal, parse_register_name, parse_u64_literal};
2use crate::r#type::common::{CodeLinkage, Instruction};
3use crate::unlexer::PtxUnlexer;
4use crate::{
5 lexer::{PtxToken, tokenize},
6 parser::{
7 ParseErrorKind, PtxParseError, PtxParser, PtxTokenStream, Span, expect_directive_value,
8 peek_directive, unexpected_value,
9 },
10 r#type::{
11 function::{
12 DwarfDirective, EntryFunction, ExternCallBlock, ExternCallSetup, FuncFunction,
13 FunctionAlias, FunctionBody, FunctionDim3, FunctionEntryDirective,
14 FunctionHeaderDirective, FunctionKernelDirective, FunctionStatement, LocationDirective,
15 PragmaDirective, RegisterDirective, StatementDirective, StatementSectionDirective,
16 },
17 instruction::Inst,
18 variable::VariableDirective,
19 },
20};
21
22fn parse_header_directives(
23 stream: &mut PtxTokenStream,
24) -> Result<Vec<FunctionHeaderDirective>, PtxParseError> {
25 let mut directives = Vec::new();
26 loop {
27 let Some((name, span)) = peek_directive(stream)? else {
28 break;
29 };
30 match name.as_str() {
31 "visible" | "extern" | "weak" => {
32 let linkage = CodeLinkage::parse(stream)?;
33 directives.push(FunctionHeaderDirective::Linkage(linkage));
34 }
35 "entry" | "func" | "alias" => break,
36 other => {
37 return Err(unexpected_value(
38 span,
39 &[".visible", ".extern", ".weak", ".entry", ".func", ".alias"],
40 format!(".{other}"),
41 ));
42 }
43 }
44 }
45 Ok(directives)
46}
47
48fn parse_register_range(stream: &mut PtxTokenStream) -> Result<Option<u32>, PtxParseError> {
49 if stream
50 .consume_if(|token| matches!(token, PtxToken::LAngle))
51 .is_none()
52 {
53 return Ok(None);
54 }
55
56 let (value, span) = parse_u64_literal(stream)?;
57 if value > u32::MAX as u64 {
58 return Err(invalid_literal(
59 span.clone(),
60 "register range exceeds u32::MAX",
61 ));
62 }
63 stream.expect(&PtxToken::RAngle)?;
64 Ok(Some(value as u32))
65}
66
67fn tokens_to_string(tokens: &[PtxToken], span: &Span) -> Result<String, PtxParseError> {
68 PtxUnlexer::to_string(tokens)
69 .map_err(|_| invalid_literal(span.clone(), "failed to serialize token sequence"))
70}
71
72fn parse_parameter_tokens(
73 tokens: &[PtxToken],
74 span: &Span,
75) -> Result<VariableDirective, PtxParseError> {
76 let serialized = tokens_to_string(tokens, span)?;
77 let source = format!("{};", serialized);
78 let tokenized = tokenize(&source)
79 .map_err(|_| invalid_literal(span.clone(), "failed to tokenize function parameter"))?;
80 let mut temp_stream = PtxTokenStream::new(&tokenized);
81 let mut directive = VariableDirective::parse(&mut temp_stream)?;
82 directive.raw = serialized;
83 Ok(directive)
84}
85
86fn collect_parameter_tokens(
87 stream: &mut PtxTokenStream,
88) -> Result<(Vec<PtxToken>, Span), PtxParseError> {
89 let (first_token, first_span) = stream.peek()?;
90 if matches!(first_token, PtxToken::Comma | PtxToken::RParen) {
91 return Err(unexpected_value(
92 first_span.clone(),
93 &["function parameter"],
94 format!("{first_token:?}"),
95 ));
96 }
97
98 let mut tokens = Vec::new();
99 let mut paren_depth = 0usize;
100 let mut bracket_depth = 0usize;
101
102 loop {
103 let (next_token, _) = stream.peek()?;
104 if paren_depth == 0 && bracket_depth == 0 {
105 if matches!(next_token, PtxToken::Comma | PtxToken::RParen) {
106 break;
107 }
108 }
109
110 let (token, _) = stream.consume()?;
111 match token {
112 PtxToken::LParen => paren_depth += 1,
113 PtxToken::RParen => paren_depth = paren_depth.saturating_sub(1),
114 PtxToken::LBracket => bracket_depth += 1,
115 PtxToken::RBracket => bracket_depth = bracket_depth.saturating_sub(1),
116 _ => {}
117 }
118 tokens.push(token.clone());
119 }
120
121 Ok((tokens, first_span.clone()))
122}
123
124fn parse_parameter(stream: &mut PtxTokenStream) -> Result<VariableDirective, PtxParseError> {
125 let (tokens, span) = collect_parameter_tokens(stream)?;
126 if tokens.is_empty() {
127 return Err(unexpected_value(
128 span.clone(),
129 &["function parameter"],
130 "".to_string(),
131 ));
132 }
133 parse_parameter_tokens(&tokens, &span)
134}
135
136fn parse_parameter_list(
137 stream: &mut PtxTokenStream,
138) -> Result<Vec<VariableDirective>, PtxParseError> {
139 stream.expect(&PtxToken::LParen)?;
140 if stream
141 .consume_if(|token| matches!(token, PtxToken::RParen))
142 .is_some()
143 {
144 return Ok(Vec::new());
145 }
146
147 let mut params = Vec::new();
148 loop {
149 let param = parse_parameter(stream)?;
150 params.push(param);
151 if stream
152 .consume_if(|token| matches!(token, PtxToken::Comma))
153 .is_none()
154 {
155 break;
156 }
157 }
158 stream.expect(&PtxToken::RParen)?;
159 Ok(params)
160}
161
162fn parse_return_parameter(
163 stream: &mut PtxTokenStream,
164) -> Result<Option<VariableDirective>, PtxParseError> {
165 if stream
166 .consume_if(|token| matches!(token, PtxToken::LParen))
167 .is_none()
168 {
169 return Ok(None);
170 }
171
172 if stream
173 .consume_if(|token| matches!(token, PtxToken::RParen))
174 .is_some()
175 {
176 return Ok(None);
177 }
178
179 let param = parse_parameter(stream)?;
180 stream.expect(&PtxToken::RParen)?;
181 Ok(Some(param))
182}
183
184fn parse_optional_noreturn(
185 stream: &mut PtxTokenStream,
186 directives: &mut Vec<FunctionHeaderDirective>,
187) -> Result<bool, PtxParseError> {
188 if let Some((token, _)) = stream.peek().ok() {
189 if let PtxToken::Dot = token {
190 let saved_pos = stream.position();
192 stream.consume()?; if let Ok((name, _)) = stream.expect_identifier() {
194 if name == "noreturn" {
195 if !directives
196 .iter()
197 .any(|directive| matches!(directive, FunctionHeaderDirective::NoReturn))
198 {
199 directives.push(FunctionHeaderDirective::NoReturn);
200 }
201 if stream
202 .consume_if(|token| matches!(token, PtxToken::Semicolon))
203 .is_some()
204 {
205 return Ok(true);
206 }
207 } else {
208 stream.set_position(saved_pos);
209 }
210 } else {
211 stream.set_position(saved_pos);
212 }
213 }
214 }
215 Ok(false)
216}
217
218fn parse_argument_strings(
219 stream: &mut PtxTokenStream,
220 base_span: &Span,
221 raw_tokens: &mut Vec<PtxToken>,
222) -> Result<Vec<String>, PtxParseError> {
223 let mut arguments = Vec::new();
224 let mut current_tokens: Vec<PtxToken> = Vec::new();
225 let mut current_span = base_span.clone();
226
227 while !stream.check(|token| matches!(token, PtxToken::Semicolon)) {
228 let (token, span) = stream.consume()?;
229 raw_tokens.push(token.clone());
230 if matches!(token, PtxToken::Comma) {
231 if !current_tokens.is_empty() {
232 let text = tokens_to_string(¤t_tokens, ¤t_span)?;
233 arguments.push(text);
234 current_tokens.clear();
235 } else {
236 arguments.push(String::new());
237 }
238 } else {
239 if current_tokens.is_empty() {
240 current_span = span.clone();
241 }
242 current_tokens.push(token.clone());
243 }
244 }
245
246 if !current_tokens.is_empty() {
247 let text = tokens_to_string(¤t_tokens, ¤t_span)?;
248 arguments.push(text);
249 }
250
251 stream.expect(&PtxToken::Semicolon)?;
252 raw_tokens.push(PtxToken::Semicolon);
253 Ok(arguments)
254}
255
256fn parse_statement_directive(
257 name: &str,
258 stream: &mut PtxTokenStream,
259 span: Span,
260) -> Result<StatementDirective, PtxParseError> {
261 let mut raw_tokens = vec![PtxToken::Dot, PtxToken::Identifier(name.to_string())];
262 match name {
263 "loc" => {
264 let (file_token, file_span) = stream.consume()?;
265 raw_tokens.push(file_token.clone());
266 let file_index = match file_token {
267 PtxToken::DecimalInteger(value) => value.parse::<u32>().map_err(|_| {
268 invalid_literal(
269 file_span.clone(),
270 "expected 32-bit unsigned integer literal",
271 )
272 })?,
273 ref other => {
274 return Err(unexpected_value(
275 file_span.clone(),
276 &["decimal literal"],
277 format!("{other:?}"),
278 ));
279 }
280 };
281
282 let (line_token, line_span) = stream.consume()?;
283 raw_tokens.push(line_token.clone());
284 let line = match line_token {
285 PtxToken::DecimalInteger(value) => value.parse::<u32>().map_err(|_| {
286 invalid_literal(
287 line_span.clone(),
288 "expected 32-bit unsigned integer literal",
289 )
290 })?,
291 ref other => {
292 return Err(unexpected_value(
293 line_span.clone(),
294 &["decimal literal"],
295 format!("{other:?}"),
296 ));
297 }
298 };
299
300 let (column_token, column_span) = stream.consume()?;
301 raw_tokens.push(column_token.clone());
302 let column = match column_token {
303 PtxToken::DecimalInteger(value) => value.parse::<u32>().map_err(|_| {
304 invalid_literal(
305 column_span.clone(),
306 "expected 32-bit unsigned integer literal",
307 )
308 })?,
309 ref other => {
310 return Err(unexpected_value(
311 column_span.clone(),
312 &["decimal literal"],
313 format!("{other:?}"),
314 ));
315 }
316 };
317
318 let options = Vec::new();
319 if stream
320 .consume_if(|token| matches!(token, PtxToken::Semicolon))
321 .is_some()
322 {
323 raw_tokens.push(PtxToken::Semicolon);
324 }
325
326 let raw = tokens_to_string(&raw_tokens, &span)?;
327 Ok(StatementDirective::Loc(LocationDirective {
328 file_index,
329 line,
330 column,
331 options,
332 comment: None,
333 raw,
334 }))
335 }
336 "pragma" => {
337 let arguments = parse_argument_strings(stream, &span, &mut raw_tokens)?;
338 let raw = tokens_to_string(&raw_tokens, &span)?;
339 Ok(StatementDirective::Pragma(PragmaDirective {
340 arguments,
341 comment: None,
342 raw,
343 }))
344 }
345 "dwarf" => {
346 let (keyword, keyword_span) = stream.expect_identifier()?;
347 raw_tokens.push(PtxToken::Identifier(keyword.clone()));
348 let arguments = parse_argument_strings(stream, &keyword_span, &mut raw_tokens)?;
349 let raw = tokens_to_string(&raw_tokens, &span)?;
350 Ok(StatementDirective::Dwarf(DwarfDirective {
351 keyword,
352 arguments,
353 comment: None,
354 raw,
355 }))
356 }
357 "section" => {
358 let arguments = parse_argument_strings(stream, &span, &mut raw_tokens)?;
359 let mut iter = arguments.into_iter();
360 let name_str = iter
361 .next()
362 .ok_or_else(|| unexpected_value(span.clone(), &["section name"], "".to_string()))?;
363 let raw = tokens_to_string(&raw_tokens, &span)?;
364 Ok(StatementDirective::Section(StatementSectionDirective {
365 name: name_str,
366 arguments: iter.collect(),
367 comment: None,
368 raw,
369 }))
370 }
371 other => Err(unexpected_value(
372 span,
373 &[".loc", ".pragma", ".dwarf", ".section"],
374 format!(".{other}"),
375 )),
376 }
377}
378
379fn parse_register_directive(
380 stream: &mut PtxTokenStream,
381) -> Result<RegisterDirective, PtxParseError> {
382 expect_directive_value(stream, "reg")?;
383
384 let ty = if stream.check(|token| matches!(token, PtxToken::Dot)) {
385 let (directive, _) = stream.expect_directive()?;
386 Some(directive)
387 } else {
388 None
389 };
390
391 let (name, _) = if stream.check(|token| matches!(token, PtxToken::Register(_))) {
392 parse_register_name(stream)?
393 } else {
394 stream.expect_identifier()?
395 };
396
397 let range = parse_register_range(stream)?;
398 stream.expect(&PtxToken::Semicolon)?;
399
400 Ok(RegisterDirective {
401 name,
402 ty,
403 range,
404 comment: None,
405 raw: String::new(),
406 })
407}
408
409fn parse_variable_entry(
410 stream: &mut PtxTokenStream,
411 kind: &str,
412) -> Result<FunctionEntryDirective, PtxParseError> {
413 let directive = VariableDirective::parse(stream)?;
414 match kind {
415 "local" => Ok(FunctionEntryDirective::Local(directive)),
416 "param" => Ok(FunctionEntryDirective::Param(directive)),
417 "shared" => Ok(FunctionEntryDirective::Shared(directive)),
418 other => Err(unexpected_value(
419 0..0,
420 &[".local", ".param", ".shared"],
421 format!(".{other}"),
422 )),
423 }
424}
425
426fn parse_function_entry_directive_internal(
427 stream: &mut PtxTokenStream,
428) -> Result<FunctionEntryDirective, PtxParseError> {
429 let maybe_directive = peek_directive(stream)?;
430 let (name, span) = if let Some(value) = maybe_directive {
431 value
432 } else {
433 let (token, span) = stream
434 .peek()
435 .map(|(token, span)| (token.clone(), span.clone()))?;
436 return Err(unexpected_value(
437 span,
438 &["function entry directive"],
439 format!("{token:?}"),
440 ));
441 };
442
443 match name.as_str() {
444 "reg" => parse_register_directive(stream).map(FunctionEntryDirective::Reg),
445 "local" => parse_variable_entry(stream, "local"),
446 "shared" => parse_variable_entry(stream, "shared"),
447 "param" => parse_variable_entry(stream, "param"),
448 "pragma" | "loc" | "dwarf" => {
449 let (directive_name, directive_span) = stream.expect_directive()?;
450 let statement =
451 parse_statement_directive(&directive_name, stream, directive_span.clone())?;
452 match statement {
453 StatementDirective::Pragma(pragma) => Ok(FunctionEntryDirective::Pragma(pragma)),
454 StatementDirective::Loc(loc) => Ok(FunctionEntryDirective::Loc(loc)),
455 StatementDirective::Dwarf(dwarf) => Ok(FunctionEntryDirective::Dwarf(dwarf)),
456 _ => Err(unexpected_value(
457 directive_span,
458 &[".pragma", ".loc", ".dwarf"],
459 format!(".{directive_name}"),
460 )),
461 }
462 }
463 other => Err(unexpected_value(
464 span,
465 &[
466 ".reg", ".local", ".shared", ".param", ".pragma", ".loc", ".dwarf",
467 ],
468 format!(".{other}"),
469 )),
470 }
471}
472
473fn parse_instruction_statement(stream: &mut PtxTokenStream) -> Result<Instruction, PtxParseError> {
474 Instruction::parse(stream)
476}
477
478fn parse_extern_call_block(stream: &mut PtxTokenStream) -> Result<ExternCallBlock, PtxParseError> {
479 stream.expect(&PtxToken::LBrace)?;
480
481 let mut declarations = Vec::new();
482 let mut setup = Vec::new();
483 let mut call = None;
484 let mut post_call = Vec::new();
485
486 loop {
487 if stream.check(|token| matches!(token, PtxToken::RBrace)) {
488 let (_, span) = stream.consume()?;
489 if call.is_none() {
490 return Err(unexpected_value(
491 span.clone(),
492 &["call instruction"],
493 "}".to_string(),
494 ));
495 }
496 break;
497 }
498
499 if stream.is_at_end() {
500 return Err(PtxParseError {
501 kind: ParseErrorKind::UnexpectedEof,
502 span: 0..0,
503 });
504 }
505
506 if let Some((name, _)) = peek_directive(stream)? {
507 match name.as_str() {
508 "reg" | "local" | "shared" => {
509 declarations.push(parse_function_entry_directive_internal(stream)?);
510 continue;
511 }
512 "param" => {
513 let directive = VariableDirective::parse(stream)?;
514 setup.push(ExternCallSetup::Param(directive));
515 continue;
516 }
517 _ => {}
518 }
519 }
520
521 let instruction = parse_instruction_statement(stream)?;
522 if call.is_none() {
523 if matches!(
524 instruction.inst,
525 Inst::CallUni(_)
526 | Inst::CallUni1(_)
527 | Inst::CallUni2(_)
528 | Inst::CallUni3(_)
529 | Inst::CallUni4(_)
530 | Inst::CallUni5(_)
531 | Inst::CallUni6(_)
532 | Inst::CallUni7(_)
533 | Inst::CallUni8(_)
534 ) {
535 call = Some(instruction);
536 } else {
537 setup.push(ExternCallSetup::Store(instruction));
538 }
539 } else {
540 post_call.push(instruction);
541 }
542 }
543
544 Ok(ExternCallBlock {
545 declarations,
546 setup,
547 call: call.expect("call instruction validated before break"),
548 post_call,
549 })
550}
551
552fn parse_function_statement(
553 stream: &mut PtxTokenStream,
554) -> Result<FunctionStatement, PtxParseError> {
555 if let Some((name, _)) = peek_directive(stream)? {
556 match name.as_str() {
557 "loc" | "pragma" | "dwarf" | "section" => {
558 let (directive_name, span) = stream.expect_directive()?;
559 let directive = parse_statement_directive(&directive_name, stream, span.clone())?;
560 return Ok(FunctionStatement::Directive(directive));
561 }
562 _ => {}
563 }
564 }
565
566 if stream.check(|token| matches!(token, PtxToken::LBrace)) {
567 let block = parse_extern_call_block(stream)?;
568 return Ok(FunctionStatement::ExternCallBlock(block));
569 }
570
571 let instruction = parse_instruction_statement(stream)?;
572 Ok(FunctionStatement::Instruction(instruction))
573}
574
575fn collect_body_tokens(
576 stream: &mut PtxTokenStream,
577) -> Result<(Vec<PtxToken>, Span), PtxParseError> {
578 let mut tokens = Vec::new();
579 let mut depth = 1usize;
580 let mut first_span: Option<Span> = None;
581
582 while depth > 0 {
583 let (token, span) = stream.consume()?;
584 if first_span.is_none() {
585 first_span = Some(span.clone());
586 }
587 match token {
588 PtxToken::LBrace => {
589 depth += 1;
590 tokens.push(token.clone());
591 }
592 PtxToken::RBrace => {
593 depth -= 1;
594 if depth == 0 {
595 break;
596 }
597 tokens.push(token.clone());
598 }
599 _ => tokens.push(token.clone()),
600 }
601 }
602
603 Ok((tokens, first_span.unwrap_or(0..0)))
604}
605
606fn parse_function_body(stream: &mut PtxTokenStream) -> Result<FunctionBody, PtxParseError> {
607 if let Some((token, _)) = stream.peek().ok() {
608 match token {
609 PtxToken::Semicolon => {
610 stream.consume()?;
611 return Ok(FunctionBody::default());
612 }
613 PtxToken::LBrace => {
614 stream.consume()?;
615 let mut body = FunctionBody::default();
616 let mut parsing_entry_directives = true;
617 loop {
618 if stream.check(|token| matches!(token, PtxToken::RBrace)) {
619 stream.consume()?;
620 break;
621 }
622
623 if stream.is_at_end() {
624 return Err(PtxParseError {
625 kind: ParseErrorKind::UnexpectedEof,
626 span: 0..0,
627 });
628 }
629
630 if parsing_entry_directives {
631 if let Some((name, _)) = peek_directive(stream)? {
632 match name.as_str() {
633 "reg" | "local" | "shared" | "param" | "pragma" | "loc"
634 | "dwarf" => {
635 let directive =
636 parse_function_entry_directive_internal(stream)?;
637 body.entry_directives.push(directive);
638 continue;
639 }
640 _ => parsing_entry_directives = false,
641 }
642 } else {
643 parsing_entry_directives = false;
644 }
645 }
646
647 let position = stream.position();
648 match parse_function_statement(stream) {
649 Ok(statement) => body.statements.push(statement),
650 Err(_err) => {
651 stream.set_position(position);
652 let (tokens, span) = collect_body_tokens(stream)?;
653 if !tokens.is_empty() {
654 let raw = tokens_to_string(&tokens, &span)?;
655 body.statements.push(FunctionStatement::Directive(
656 StatementDirective::Pragma(PragmaDirective {
657 arguments: Vec::new(),
658 comment: None,
659 raw,
660 }),
661 ));
662 }
663 return Ok(body);
664 }
665 }
666 }
667
668 return Ok(body);
669 }
670 _ => {
671 let span = stream.peek()?.1.clone();
672 return Err(unexpected_value(
673 span,
674 &[";", ".noreturn", "{"],
675 format!("{token:?}"),
676 ));
677 }
678 }
679 }
680
681 Err(PtxParseError {
682 kind: ParseErrorKind::UnexpectedEof,
683 span: 0..0,
684 })
685}
686
687impl PtxParser for FunctionBody {
688 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
689 parse_function_body(stream)
690 }
691}
692
693impl PtxParser for EntryFunction {
694 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
695 let mut directives = parse_header_directives(stream)?;
696 expect_directive_value(stream, "entry")?;
697 let (name, _) = stream.expect_identifier()?;
698 let params = parse_parameter_list(stream)?;
699 let body = if parse_optional_noreturn(stream, &mut directives)? {
700 FunctionBody::default()
701 } else {
702 parse_function_body(stream)?
703 };
704 Ok(EntryFunction {
705 name,
706 directives,
707 params,
708 body,
709 })
710 }
711}
712
713impl PtxParser for FuncFunction {
714 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
715 let mut directives = parse_header_directives(stream)?;
716 expect_directive_value(stream, "func")?;
717
718 let return_param = parse_return_parameter(stream)?;
719
720 let (name, _) = stream.expect_identifier()?;
721 let params = parse_parameter_list(stream)?;
722 let body = if parse_optional_noreturn(stream, &mut directives)? {
723 FunctionBody::default()
724 } else {
725 parse_function_body(stream)?
726 };
727 Ok(FuncFunction {
728 name,
729 directives,
730 return_param,
731 params,
732 body,
733 })
734 }
735}
736
737impl PtxParser for FunctionAlias {
738 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
739 let _ = parse_header_directives(stream)?;
740 expect_directive_value(stream, "alias")?;
741 let (alias, _) = stream.expect_identifier()?;
742 stream.expect(&PtxToken::Comma)?;
743 let (target, _) = stream.expect_identifier()?;
744 stream.expect(&PtxToken::Semicolon)?;
745 Ok(FunctionAlias {
746 alias,
747 target,
748 raw: String::new(),
749 })
750 }
751}
752
753impl PtxParser for FunctionKernelDirective {
754 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
755 let position = stream.position();
756 if let Ok(entry) = EntryFunction::parse(stream) {
757 return Ok(FunctionKernelDirective::Entry(entry));
758 }
759 stream.set_position(position);
760 if let Ok(func) = FuncFunction::parse(stream) {
761 return Ok(FunctionKernelDirective::Func(func));
762 }
763 stream.set_position(position);
764 let alias = FunctionAlias::parse(stream)?;
765 Ok(FunctionKernelDirective::Alias(alias))
766 }
767}
768
769impl PtxParser for FunctionEntryDirective {
770 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
771 parse_function_entry_directive_internal(stream)
772 }
773}
774
775impl PtxParser for FunctionStatement {
776 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
777 parse_function_statement(stream)
778 }
779}
780
781impl PtxParser for FunctionDim3 {
782 fn parse(_stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
783 Err(unexpected_value(
784 0..0,
785 &["dimension literal"],
786 "parsing function dimension directives is not supported yet".to_string(),
787 ))
788 }
789}