From ef98c1e0bab18ed38762e432f360d151357979d9 Mon Sep 17 00:00:00 2001 From: Violet Date: Thu, 7 Aug 2025 11:51:56 -0700 Subject: [PATCH] Add tracing to custom parsers (#469) --- ptx_parser/src/lib.rs | 634 +++++++++++++++++++++++------------------- 1 file changed, 343 insertions(+), 291 deletions(-) diff --git a/ptx_parser/src/lib.rs b/ptx_parser/src/lib.rs index a413a35..fabb16e 100644 --- a/ptx_parser/src/lib.rs +++ b/ptx_parser/src/lib.rs @@ -396,18 +396,21 @@ pub fn parse_module_checked<'input>( } fn module<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult> { - ( - version, - target, - opt(address_size), - repeat_without_none(directive), - eof, - ) - .map(|(version, _, _, directives, _)| ast::Module { + trace( + "module", + ( version, - directives, - }) - .parse_next(stream) + target, + opt(address_size), + repeat_without_none(directive), + eof, + ) + .map(|(version, _, _, directives, _)| ast::Module { + version, + directives, + }), + ) + .parse_next(stream) } fn address_size<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> { @@ -440,18 +443,20 @@ fn shader_model<'a>(stream: &mut &str) -> PResult<(u32, Option)> { fn directive<'a, 'input>( stream: &mut PtxParser<'a, 'input>, ) -> PResult>>> { - with_recovery( - alt(( - // When adding a new variant here remember to add its first token into recovery parser down below - function.map(|(linking, func)| Some(ast::Directive::Method(linking, func))), - file.map(|_| None), - section.map(|_| None), - (module_variable, Token::Semicolon) - .map(|((linking, var), _)| Some(ast::Directive::Variable(linking, var))), - )), - ( - any, - take_till(1.., |(token, _)| match token { + trace( + "directive", + with_recovery( + alt(( + // When adding a new variant here remember to add its first token into recovery parser down below + function.map(|(linking, func)| Some(ast::Directive::Method(linking, func))), + file.map(|_| None), + section.map(|_| None), + (module_variable, Token::Semicolon) + .map(|((linking, var), _)| Some(ast::Directive::Variable(linking, var))), + )), + ( + any, + take_till(1.., |(token, _)| match token { // visibility Token::DotExtern | Token::DotVisible | Token::DotWeak // methods @@ -462,11 +467,12 @@ fn directive<'a, 'input>( | Token::DotFile | Token::DotSection => true, _ => false, }), + ) + .map(|(_, x)| x), + |text| PtxError::UnrecognizedDirective(text.unwrap_or("")), ) - .map(|(_, x)| x), - |text| PtxError::UnrecognizedDirective(text.unwrap_or("")), + .map(Option::flatten), ) - .map(Option::flatten) .parse_next(stream) } @@ -483,26 +489,32 @@ fn module_variable<'a, 'input>( } fn file<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> { - ( - Token::DotFile, - u32, - Token::String, - opt((Token::Comma, u32, Token::Comma, u32)), + trace( + "file", + ( + Token::DotFile, + u32, + Token::String, + opt((Token::Comma, u32, Token::Comma, u32)), + ) + .void(), ) - .void() - .parse_next(stream) + .parse_next(stream) } fn section<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> { - ( - Token::DotSection.void(), - dot_ident.void(), - Token::LBrace.void(), - repeat::<_, _, (), _, _>(0.., section_dwarf_line), - Token::RBrace.void(), + trace( + "section", + ( + Token::DotSection.void(), + dot_ident.void(), + Token::LBrace.void(), + repeat::<_, _, (), _, _>(0.., section_dwarf_line), + Token::RBrace.void(), + ) + .void(), ) - .void() - .parse_next(stream) + .parse_next(stream) } fn section_dwarf_line<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> { @@ -535,23 +547,26 @@ fn function<'a, 'input>( ast::LinkingDirective, ast::Function<'input, &'input str, ast::Statement>>, )> { - let (linking, function) = ( - linking_directives, - method_declaration, - repeat(0.., tuning_directive), - function_body, + let (linking, function) = trace( + "function", + ( + linking_directives, + method_declaration, + repeat(0.., tuning_directive), + function_body, + ) + .map(|(linking, func_directive, tuning, body)| { + ( + linking, + ast::Function { + func_directive, + tuning, + body, + }, + ) + }), ) - .map(|(linking, func_directive, tuning, body)| { - ( - linking, - ast::Function { - func_directive, - tuning, - body, - }, - ) - }) - .parse_next(stream)?; + .parse_next(stream)?; stream.state.record_function(&function.func_directive); Ok((linking, function)) } @@ -559,16 +574,19 @@ fn function<'a, 'input>( fn linking_directives<'a, 'input>( stream: &mut PtxParser<'a, 'input>, ) -> PResult { - repeat( - 0.., - dispatch! { any; - (Token::DotExtern, _) => empty.value(ast::LinkingDirective::EXTERN), - (Token::DotVisible, _) => empty.value(ast::LinkingDirective::VISIBLE), - (Token::DotWeak, _) => empty.value(ast::LinkingDirective::WEAK), - _ => fail - }, + trace( + "linking_directives", + repeat( + 0.., + dispatch! { any; + (Token::DotExtern, _) => empty.value(ast::LinkingDirective::EXTERN), + (Token::DotVisible, _) => empty.value(ast::LinkingDirective::VISIBLE), + (Token::DotWeak, _) => empty.value(ast::LinkingDirective::WEAK), + _ => fail + }, + ) + .fold(|| ast::LinkingDirective::NONE, |x, y| x | y), ) - .fold(|| ast::LinkingDirective::NONE, |x, y| x | y) .parse_next(stream) } @@ -680,11 +698,11 @@ fn tuple1to3_u32<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<(u32 fn function_body<'a, 'input>( stream: &mut PtxParser<'a, 'input>, ) -> PResult>>>> { - dispatch! {any; + trace("function_body", dispatch! {any; (Token::LBrace, _) => terminated(repeat_without_none(statement), Token::RBrace).map(Some), (Token::Semicolon, _) => empty.map(|_| None), _ => fail - } + }) .parse_next(stream) } @@ -745,7 +763,7 @@ fn take_till_inclusive>( } Err(ParserError::from_error_kind(input, ErrorKind::Eof)) } - move |stream: &mut I| { + trace("take_till_inclusive", move |stream: &mut I| { let mut should_backtrack = false; let offset = get_offset(stream, &backtrack_token, &end_token, &mut should_backtrack)?; let result = stream.next_slice(offset); @@ -757,7 +775,7 @@ fn take_till_inclusive>( } else { Ok(result) } - } + }) } /* @@ -783,27 +801,30 @@ fn with_recovery<'a, 'input: 'a, T>( mut recovery: impl Parser, &'a [(Token<'input>, logos::Span)], ContextError>, mut error: impl FnMut(Option<&'input str>) -> PtxError<'input>, ) -> impl Parser, Option, ContextError> { - move |stream: &mut PtxParser<'a, 'input>| { - let input_start = stream.input.first().map(|(_, s)| s).cloned(); - let stream_start = stream.checkpoint(); - match parser.parse_next(stream) { - Ok(value) => Ok(Some(value)), - Err(_) => { - stream.reset(&stream_start); - let tokens = recovery.parse_next(stream)?; - let range = match input_start { - Some(start) => { - Some(&stream.state.text[start.start..tokens.last().unwrap().1.end]) - } - // We could handle `(Some(start), None)``, but this whole error recovery is to - // recover from unknown instructions, so we don't care about early end of stream - _ => None, - }; - stream.state.errors.push(error(range)); - Ok(None) + trace( + "with_recovery", + move |stream: &mut PtxParser<'a, 'input>| { + let input_start = stream.input.first().map(|(_, s)| s).cloned(); + let stream_start = stream.checkpoint(); + match parser.parse_next(stream) { + Ok(value) => Ok(Some(value)), + Err(_) => { + stream.reset(&stream_start); + let tokens = recovery.parse_next(stream)?; + let range = match input_start { + Some(start) => { + Some(&stream.state.text[start.start..tokens.last().unwrap().1.end]) + } + // We could handle `(Some(start), None)``, but this whole error recovery is to + // recover from unknown instructions, so we don't care about early end of stream + _ => None, + }; + stream.state.errors.push(error(range)); + Ok(None) + } } - } - } + }, + ) } fn pragma<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> { @@ -815,207 +836,225 @@ fn pragma<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<()> { fn method_parameter<'a, 'input: 'a>( state_space: StateSpace, ) -> impl Parser, Variable<&'input str>, ContextError> { - move |stream: &mut PtxParser<'a, 'input>| { - let (align, vector, type_, name) = variable_declaration.parse_next(stream)?; - let array_dimensions = if state_space != StateSpace::Reg { - opt(array_dimensions).parse_next(stream)? - } else { - None - }; - // TODO: push this check into array_dimensions(...) - if let Some(ref dims) = array_dimensions { - if dims[0] == 0 { - return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); + trace( + "method_parameter", + move |stream: &mut PtxParser<'a, 'input>| { + let (align, vector, type_, name) = variable_declaration.parse_next(stream)?; + let array_dimensions = if state_space != StateSpace::Reg { + opt(array_dimensions).parse_next(stream)? + } else { + None + }; + // TODO: push this check into array_dimensions(...) + if let Some(ref dims) = array_dimensions { + if dims[0] == 0 { + return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); + } } - } - Ok(Variable { - align, - v_type: Type::maybe_array(vector, type_, array_dimensions), - state_space, - name, - array_init: Vec::new(), - }) - } + Ok(Variable { + align, + v_type: Type::maybe_array(vector, type_, array_dimensions), + state_space, + name, + array_init: Vec::new(), + }) + }, + ) } // TODO: split to a separate type fn variable_declaration<'a, 'input>( stream: &mut PtxParser<'a, 'input>, ) -> PResult<(Option, Option, ScalarType, &'input str)> { - ( - opt(align.verify(|x| x.count_ones() == 1)), - vector_prefix, - scalar_type, - ident, + trace( + "variable_declaration", + ( + opt(align.verify(|x| x.count_ones() == 1)), + vector_prefix, + scalar_type, + ident, + ), ) - .parse_next(stream) + .parse_next(stream) } fn multi_variable<'a, 'input: 'a>( extern_: bool, state_space: StateSpace, ) -> impl Parser, MultiVariable<&'input str>, ContextError> { - move |stream: &mut PtxParser<'a, 'input>| { - let ((align, vector, type_, name), count) = ( - variable_declaration, - // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parameterized-variable-names - opt(delimited(Token::Lt, u32.verify(|x| *x != 0), Token::Gt)), - ) - .parse_next(stream)?; - if count.is_some() { - return Ok(MultiVariable { + trace( + "multi_variable", + move |stream: &mut PtxParser<'a, 'input>| { + let ((align, vector, type_, name), count) = ( + variable_declaration, + // https://docs.nvidia.com/cuda/parallel-thread-execution/index.html#parameterized-variable-names + opt(delimited(Token::Lt, u32.verify(|x| *x != 0), Token::Gt)), + ) + .parse_next(stream)?; + if count.is_some() { + return Ok(MultiVariable { + var: Variable { + align, + v_type: Type::maybe_vector_parsed(vector, type_), + state_space, + name, + array_init: Vec::new(), + }, + count, + }); + } + let mut array_dimensions = if state_space != StateSpace::Reg { + opt(array_dimensions).parse_next(stream)? + } else { + None + }; + let initializer = match state_space { + StateSpace::Global | StateSpace::Const => match array_dimensions { + Some(ref mut dimensions) => { + opt(array_initializer(vector, type_, dimensions)).parse_next(stream)? + } + None => opt(value_initializer(vector, type_)).parse_next(stream)?, + }, + _ => None, + }; + if let Some(ref dims) = array_dimensions { + if !extern_ && dims[0] == 0 { + return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); + } + } + Ok(MultiVariable { var: Variable { align, - v_type: Type::maybe_vector_parsed(vector, type_), + v_type: Type::maybe_array(vector, type_, array_dimensions), state_space, name, - array_init: Vec::new(), + array_init: initializer.unwrap_or(Vec::new()), }, count, - }); - } - let mut array_dimensions = if state_space != StateSpace::Reg { - opt(array_dimensions).parse_next(stream)? - } else { - None - }; - let initializer = match state_space { - StateSpace::Global | StateSpace::Const => match array_dimensions { - Some(ref mut dimensions) => { - opt(array_initializer(vector, type_, dimensions)).parse_next(stream)? - } - None => opt(value_initializer(vector, type_)).parse_next(stream)?, - }, - _ => None, - }; - if let Some(ref dims) = array_dimensions { - if !extern_ && dims[0] == 0 { - return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); - } - } - Ok(MultiVariable { - var: Variable { - align, - v_type: Type::maybe_array(vector, type_, array_dimensions), - state_space, - name, - array_init: initializer.unwrap_or(Vec::new()), - }, - count, - }) - } + }) + }, + ) } -fn array_initializer<'a, 'input: 'a>( +fn array_initializer<'b, 'a: 'b, 'input: 'a>( vector: Option, type_: ScalarType, - array_dimensions: &mut Vec, -) -> impl Parser, Vec, ContextError> + '_ { - move |stream: &mut PtxParser<'a, 'input>| { - Token::Eq.parse_next(stream)?; - let mut result = Vec::new(); - // TODO: vector constants and multi dim arrays - if vector.is_some() || array_dimensions[0] == 0 || array_dimensions.len() > 1 { - return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); - } - delimited( - Token::LBrace, - separated::<_, (), (), _, _, _, _>( - 0..=array_dimensions[0] as usize, - single_value_append(&mut result, type_), - Token::Comma, - ), - Token::RBrace, - ) - .parse_next(stream)?; - // pad with zeros - let result_size = type_.size_of() as usize * array_dimensions[0] as usize; - result.extend(iter::repeat(0u8).take(result_size - result.len())); - Ok(result) - } + array_dimensions: &'b mut Vec, +) -> impl Parser, Vec, ContextError> + 'b { + trace( + "array_initializer", + move |stream: &mut PtxParser<'a, 'input>| { + Token::Eq.parse_next(stream)?; + let mut result = Vec::new(); + // TODO: vector constants and multi dim arrays + if vector.is_some() || array_dimensions[0] == 0 || array_dimensions.len() > 1 { + return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); + } + delimited( + Token::LBrace, + separated::<_, (), (), _, _, _, _>( + 0..=array_dimensions[0] as usize, + single_value_append(&mut result, type_), + Token::Comma, + ), + Token::RBrace, + ) + .parse_next(stream)?; + // pad with zeros + let result_size = type_.size_of() as usize * array_dimensions[0] as usize; + result.extend(iter::repeat(0u8).take(result_size - result.len())); + Ok(result) + }, + ) } fn value_initializer<'a, 'input: 'a>( vector: Option, type_: ScalarType, ) -> impl Parser, Vec, ContextError> { - move |stream: &mut PtxParser<'a, 'input>| { - Token::Eq.parse_next(stream)?; - let mut result = Vec::new(); - // TODO: vector constants - if vector.is_some() { - return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); - } - single_value_append(&mut result, type_).parse_next(stream)?; - Ok(result) - } + trace( + "value_initializer", + move |stream: &mut PtxParser<'a, 'input>| { + Token::Eq.parse_next(stream)?; + let mut result = Vec::new(); + // TODO: vector constants + if vector.is_some() { + return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)); + } + single_value_append(&mut result, type_).parse_next(stream)?; + Ok(result) + }, + ) } -fn single_value_append<'a, 'input: 'a>( - accumulator: &mut Vec, +fn single_value_append<'b, 'a: 'b, 'input: 'a>( + accumulator: &'b mut Vec, type_: ScalarType, -) -> impl Parser, (), ContextError> + '_ { - move |stream: &mut PtxParser<'a, 'input>| { - let value = immediate_value.parse_next(stream)?; - match (type_, value) { - (ScalarType::U8 | ScalarType::B8, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as u8).to_le_bytes()) +) -> impl Parser, (), ContextError> + 'b { + trace( + "single_value_append", + move |stream: &mut PtxParser<'a, 'input>| { + let value = immediate_value.parse_next(stream)?; + match (type_, value) { + (ScalarType::U8 | ScalarType::B8, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as u8).to_le_bytes()) + } + (ScalarType::U8 | ScalarType::B8, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as u8).to_le_bytes()) + } + (ScalarType::U16 | ScalarType::B16, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as u16).to_le_bytes()) + } + (ScalarType::U16 | ScalarType::B16, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as u16).to_le_bytes()) + } + (ScalarType::U32 | ScalarType::B32, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as u32).to_le_bytes()) + } + (ScalarType::U32 | ScalarType::B32, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as u32).to_le_bytes()) + } + (ScalarType::U64 | ScalarType::B64, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as u64).to_le_bytes()) + } + (ScalarType::U64 | ScalarType::B64, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as u64).to_le_bytes()) + } + (ScalarType::S8, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as i8).to_le_bytes()) + } + (ScalarType::S8, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as i8).to_le_bytes()) + } + (ScalarType::S16, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as i16).to_le_bytes()) + } + (ScalarType::S16, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as i16).to_le_bytes()) + } + (ScalarType::S32, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as i32).to_le_bytes()) + } + (ScalarType::S32, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as i32).to_le_bytes()) + } + (ScalarType::S64, ImmediateValue::U64(x)) => { + accumulator.extend_from_slice(&(x as i64).to_le_bytes()) + } + (ScalarType::S64, ImmediateValue::S64(x)) => { + accumulator.extend_from_slice(&(x as i64).to_le_bytes()) + } + (ScalarType::F32, ImmediateValue::F32(x)) => { + accumulator.extend_from_slice(&x.to_le_bytes()) + } + (ScalarType::F64, ImmediateValue::F64(x)) => { + accumulator.extend_from_slice(&x.to_le_bytes()) + } + _ => return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)), } - (ScalarType::U8 | ScalarType::B8, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as u8).to_le_bytes()) - } - (ScalarType::U16 | ScalarType::B16, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as u16).to_le_bytes()) - } - (ScalarType::U16 | ScalarType::B16, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as u16).to_le_bytes()) - } - (ScalarType::U32 | ScalarType::B32, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as u32).to_le_bytes()) - } - (ScalarType::U32 | ScalarType::B32, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as u32).to_le_bytes()) - } - (ScalarType::U64 | ScalarType::B64, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as u64).to_le_bytes()) - } - (ScalarType::U64 | ScalarType::B64, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as u64).to_le_bytes()) - } - (ScalarType::S8, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as i8).to_le_bytes()) - } - (ScalarType::S8, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as i8).to_le_bytes()) - } - (ScalarType::S16, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as i16).to_le_bytes()) - } - (ScalarType::S16, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as i16).to_le_bytes()) - } - (ScalarType::S32, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as i32).to_le_bytes()) - } - (ScalarType::S32, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as i32).to_le_bytes()) - } - (ScalarType::S64, ImmediateValue::U64(x)) => { - accumulator.extend_from_slice(&(x as i64).to_le_bytes()) - } - (ScalarType::S64, ImmediateValue::S64(x)) => { - accumulator.extend_from_slice(&(x as i64).to_le_bytes()) - } - (ScalarType::F32, ImmediateValue::F32(x)) => { - accumulator.extend_from_slice(&x.to_le_bytes()) - } - (ScalarType::F64, ImmediateValue::F64(x)) => { - accumulator.extend_from_slice(&x.to_le_bytes()) - } - _ => return Err(ErrMode::from_error_kind(stream, ErrorKind::Verify)), - } - Ok(()) - } + Ok(()) + }, + ) } fn array_dimensions<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult> { @@ -1188,20 +1227,26 @@ fn debug_directive<'a, 'input>(stream: &mut PtxParser<'a, 'input>) -> PResult<() fn block_statement<'a, 'input>( stream: &mut PtxParser<'a, 'input>, ) -> PResult>> { - delimited(Token::LBrace, repeat_without_none(statement), Token::RBrace) - .map(|s| ast::Statement::Block(s)) - .parse_next(stream) + trace( + "block_statement", + delimited(Token::LBrace, repeat_without_none(statement), Token::RBrace) + .map(|s| ast::Statement::Block(s)), + ) + .parse_next(stream) } fn repeat_without_none>( parser: impl Parser, Error>, ) -> impl Parser, Error> { - repeat(0.., parser).fold(Vec::new, |mut acc: Vec<_>, item| { - if let Some(item) = item { - acc.push(item); - } - acc - }) + trace( + "repeat_without_none", + repeat(0.., parser).fold(Vec::new, |mut acc: Vec<_>, item| { + if let Some(item) = item { + acc.push(item); + } + acc + }), + ) } fn ident_literal< @@ -1267,11 +1312,14 @@ impl ast::ParsedOperand { } .parse_next(stream) } - alt(( - ident_operands, - immediate_value.map(ast::ParsedOperand::Imm), - vector_operand.map(ast::ParsedOperand::VecPack), - )) + trace( + "operand", + alt(( + ident_operands, + immediate_value.map(ast::ParsedOperand::Imm), + vector_operand.map(ast::ParsedOperand::VecPack), + )), + ) .parse_next(stream) } } @@ -1445,25 +1493,29 @@ fn bra<'a, 'input>( fn call<'a, 'input>( stream: &mut PtxParser<'a, 'input>, ) -> PResult>> { - let (uni, return_arguments, name, input_arguments) = ( - opt(Token::DotUni), - opt(( - Token::LParen, - separated(1.., ident, Token::Comma).map(|x: Vec<_>| x), - Token::RParen, - Token::Comma, - ) - .map(|(_, arguments, _, _)| arguments)), - ident, - opt(( - Token::Comma.void(), - Token::LParen.void(), - separated(1.., ParsedOperand::<&'input str>::parse, Token::Comma).map(|x: Vec<_>| x), - Token::RParen.void(), - ) - .map(|(_, _, arguments, _)| arguments)), + let (uni, return_arguments, name, input_arguments) = trace( + "call", + ( + opt(Token::DotUni), + opt(( + Token::LParen, + separated(1.., ident, Token::Comma).map(|x: Vec<_>| x), + Token::RParen, + Token::Comma, + ) + .map(|(_, arguments, _, _)| arguments)), + ident, + opt(( + Token::Comma.void(), + Token::LParen.void(), + separated(1.., ParsedOperand::<&'input str>::parse, Token::Comma) + .map(|x: Vec<_>| x), + Token::RParen.void(), + ) + .map(|(_, _, arguments, _)| arguments)), + ), ) - .parse_next(stream)?; + .parse_next(stream)?; let uniform = uni.is_some(); let recorded_fn = match stream.state.function_declarations.get(name) { Some(decl) => decl, @@ -1536,7 +1588,7 @@ where ParseRequired: Parser, Error: ParserError, { - move |input: &mut Input| -> Result<(Option, RequiredOutput), ErrMode> { + trace("first_optional", move |input: &mut Input| -> Result<(Option, RequiredOutput), ErrMode> { let start = input.checkpoint(); let parsed_optional = match optional.parse_next(input) { @@ -1555,7 +1607,7 @@ where }; Ok((None, required.parse_next(input)?)) - } + }) } // This macro is responsible for generating parser code for instruction parser.