1use crate::parser::common::{invalid_literal, parse_register_name, parse_u64_literal};
2use crate::r#type::common::CodeLinkage;
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::Instruction,
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 try_parse_label(stream: &mut PtxTokenStream) -> Result<Option<String>, PtxParseError> {
474 if !stream.check(|token| matches!(token, PtxToken::Identifier(_))) {
475 return Ok(None);
476 }
477
478 let position = stream.position();
479 let (name, _) = stream.expect_identifier()?;
480 if stream
481 .consume_if(|token| matches!(token, PtxToken::Colon))
482 .is_some()
483 {
484 Ok(Some(name))
485 } else {
486 stream.set_position(position);
487 Ok(None)
488 }
489}
490
491fn parse_instruction_statement(stream: &mut PtxTokenStream) -> Result<Instruction, PtxParseError> {
492 Instruction::parse(stream)
494}
495
496fn parse_extern_call_block(stream: &mut PtxTokenStream) -> Result<ExternCallBlock, PtxParseError> {
497 stream.expect(&PtxToken::LBrace)?;
498
499 let mut declarations = Vec::new();
500 let mut setup = Vec::new();
501 let mut call = None;
502 let mut post_call = Vec::new();
503
504 loop {
505 if stream.check(|token| matches!(token, PtxToken::RBrace)) {
506 let (_, span) = stream.consume()?;
507 if call.is_none() {
508 return Err(unexpected_value(
509 span.clone(),
510 &["call instruction"],
511 "}".to_string(),
512 ));
513 }
514 break;
515 }
516
517 if stream.is_at_end() {
518 return Err(PtxParseError {
519 kind: ParseErrorKind::UnexpectedEof,
520 span: 0..0,
521 });
522 }
523
524 if let Some((name, _)) = peek_directive(stream)? {
525 match name.as_str() {
526 "reg" | "local" | "shared" => {
527 declarations.push(parse_function_entry_directive_internal(stream)?);
528 continue;
529 }
530 "param" => {
531 let directive = VariableDirective::parse(stream)?;
532 setup.push(ExternCallSetup::Param(directive));
533 continue;
534 }
535 _ => {}
536 }
537 }
538
539 let instruction = parse_instruction_statement(stream)?;
540 if call.is_none() {
541 if matches!(
542 instruction,
543 Instruction::CallUni(_)
544 | Instruction::CallUni1(_)
545 | Instruction::CallUni2(_)
546 | Instruction::CallUni3(_)
547 | Instruction::CallUni4(_)
548 | Instruction::CallUni5(_)
549 | Instruction::CallUni6(_)
550 | Instruction::CallUni7(_)
551 | Instruction::CallUni8(_)
552 ) {
553 call = Some(instruction);
554 } else {
555 setup.push(ExternCallSetup::Store(instruction));
556 }
557 } else {
558 post_call.push(instruction);
559 }
560 }
561
562 Ok(ExternCallBlock {
563 declarations,
564 setup,
565 call: call.expect("call instruction validated before break"),
566 post_call,
567 })
568}
569
570fn parse_function_statement(
571 stream: &mut PtxTokenStream,
572) -> Result<FunctionStatement, PtxParseError> {
573 if let Some(label) = try_parse_label(stream)? {
574 return Ok(FunctionStatement::Label(label));
575 }
576
577 if let Some((name, _)) = peek_directive(stream)? {
578 match name.as_str() {
579 "loc" | "pragma" | "dwarf" | "section" => {
580 let (directive_name, span) = stream.expect_directive()?;
581 let directive = parse_statement_directive(&directive_name, stream, span.clone())?;
582 return Ok(FunctionStatement::Directive(directive));
583 }
584 _ => {}
585 }
586 }
587
588 if stream.check(|token| matches!(token, PtxToken::LBrace)) {
589 let block = parse_extern_call_block(stream)?;
590 return Ok(FunctionStatement::ExternCallBlock(block));
591 }
592
593 let instruction = parse_instruction_statement(stream)?;
594 Ok(FunctionStatement::Instruction(instruction))
595}
596
597fn collect_body_tokens(
598 stream: &mut PtxTokenStream,
599) -> Result<(Vec<PtxToken>, Span), PtxParseError> {
600 let mut tokens = Vec::new();
601 let mut depth = 1usize;
602 let mut first_span: Option<Span> = None;
603
604 while depth > 0 {
605 let (token, span) = stream.consume()?;
606 if first_span.is_none() {
607 first_span = Some(span.clone());
608 }
609 match token {
610 PtxToken::LBrace => {
611 depth += 1;
612 tokens.push(token.clone());
613 }
614 PtxToken::RBrace => {
615 depth -= 1;
616 if depth == 0 {
617 break;
618 }
619 tokens.push(token.clone());
620 }
621 _ => tokens.push(token.clone()),
622 }
623 }
624
625 Ok((tokens, first_span.unwrap_or(0..0)))
626}
627
628fn parse_function_body(stream: &mut PtxTokenStream) -> Result<FunctionBody, PtxParseError> {
629 if let Some((token, _)) = stream.peek().ok() {
630 match token {
631 PtxToken::Semicolon => {
632 stream.consume()?;
633 return Ok(FunctionBody::default());
634 }
635 PtxToken::LBrace => {
636 stream.consume()?;
637 let mut body = FunctionBody::default();
638 let mut parsing_entry_directives = true;
639 loop {
640 if stream.check(|token| matches!(token, PtxToken::RBrace)) {
641 stream.consume()?;
642 break;
643 }
644
645 if stream.is_at_end() {
646 return Err(PtxParseError {
647 kind: ParseErrorKind::UnexpectedEof,
648 span: 0..0,
649 });
650 }
651
652 if parsing_entry_directives {
653 if let Some((name, _)) = peek_directive(stream)? {
654 match name.as_str() {
655 "reg" | "local" | "shared" | "param" | "pragma" | "loc"
656 | "dwarf" => {
657 let directive =
658 parse_function_entry_directive_internal(stream)?;
659 body.entry_directives.push(directive);
660 continue;
661 }
662 _ => parsing_entry_directives = false,
663 }
664 } else {
665 parsing_entry_directives = false;
666 }
667 }
668
669 let position = stream.position();
670 match parse_function_statement(stream) {
671 Ok(statement) => body.statements.push(statement),
672 Err(_err) => {
673 stream.set_position(position);
674 let (tokens, span) = collect_body_tokens(stream)?;
675 if !tokens.is_empty() {
676 let raw = tokens_to_string(&tokens, &span)?;
677 body.statements.push(FunctionStatement::Directive(
678 StatementDirective::Pragma(PragmaDirective {
679 arguments: Vec::new(),
680 comment: None,
681 raw,
682 }),
683 ));
684 }
685 return Ok(body);
686 }
687 }
688 }
689
690 return Ok(body);
691 }
692 _ => {
693 let span = stream.peek()?.1.clone();
694 return Err(unexpected_value(
695 span,
696 &[";", ".noreturn", "{"],
697 format!("{token:?}"),
698 ));
699 }
700 }
701 }
702
703 Err(PtxParseError {
704 kind: ParseErrorKind::UnexpectedEof,
705 span: 0..0,
706 })
707}
708
709impl PtxParser for FunctionBody {
710 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
711 parse_function_body(stream)
712 }
713}
714
715impl PtxParser for EntryFunction {
716 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
717 let mut directives = parse_header_directives(stream)?;
718 expect_directive_value(stream, "entry")?;
719 let (name, _) = stream.expect_identifier()?;
720 let params = parse_parameter_list(stream)?;
721 let body = if parse_optional_noreturn(stream, &mut directives)? {
722 FunctionBody::default()
723 } else {
724 parse_function_body(stream)?
725 };
726 Ok(EntryFunction {
727 name,
728 directives,
729 params,
730 body,
731 })
732 }
733}
734
735impl PtxParser for FuncFunction {
736 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
737 let mut directives = parse_header_directives(stream)?;
738 expect_directive_value(stream, "func")?;
739
740 let return_param = parse_return_parameter(stream)?;
741
742 let (name, _) = stream.expect_identifier()?;
743 let params = parse_parameter_list(stream)?;
744 let body = if parse_optional_noreturn(stream, &mut directives)? {
745 FunctionBody::default()
746 } else {
747 parse_function_body(stream)?
748 };
749 Ok(FuncFunction {
750 name,
751 directives,
752 return_param,
753 params,
754 body,
755 })
756 }
757}
758
759impl PtxParser for FunctionAlias {
760 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
761 let _ = parse_header_directives(stream)?;
762 expect_directive_value(stream, "alias")?;
763 let (alias, _) = stream.expect_identifier()?;
764 stream.expect(&PtxToken::Comma)?;
765 let (target, _) = stream.expect_identifier()?;
766 stream.expect(&PtxToken::Semicolon)?;
767 Ok(FunctionAlias {
768 alias,
769 target,
770 raw: String::new(),
771 })
772 }
773}
774
775impl PtxParser for FunctionKernelDirective {
776 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
777 let position = stream.position();
778 if let Ok(entry) = EntryFunction::parse(stream) {
779 return Ok(FunctionKernelDirective::Entry(entry));
780 }
781 stream.set_position(position);
782 if let Ok(func) = FuncFunction::parse(stream) {
783 return Ok(FunctionKernelDirective::Func(func));
784 }
785 stream.set_position(position);
786 let alias = FunctionAlias::parse(stream)?;
787 Ok(FunctionKernelDirective::Alias(alias))
788 }
789}
790
791impl PtxParser for FunctionEntryDirective {
792 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
793 parse_function_entry_directive_internal(stream)
794 }
795}
796
797impl PtxParser for FunctionStatement {
798 fn parse(stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
799 parse_function_statement(stream)
800 }
801}
802
803impl PtxParser for FunctionDim3 {
804 fn parse(_stream: &mut PtxTokenStream) -> Result<Self, PtxParseError> {
805 Err(unexpected_value(
806 0..0,
807 &["dimension literal"],
808 "parsing function dimension directives is not supported yet".to_string(),
809 ))
810 }
811}