ptx_parser/parser/
function.rs

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            // 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 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    // The generated Instruction parser handles predicates, labels, etc.
493    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}