ptx_parser/parser/
function.rs

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            // Check if it's a directive
191            let saved_pos = stream.position();
192            stream.consume()?; // consume dot
193            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(&current_tokens, &current_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(&current_tokens, &current_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    // Parse instruction with label and predicate
475    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}