Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Stack overflow before parsing #1736

Open
spoutn1k opened this issue Mar 27, 2024 · 1 comment
Open

Stack overflow before parsing #1736

spoutn1k opened this issue Mar 27, 2024 · 1 comment

Comments

@spoutn1k
Copy link

spoutn1k commented Mar 27, 2024

Hello, getting a stack overflow when trying to parse a recursive type using nom. The leaves of the AST tree were reduced to make the example simpler.

Maybe I am not using nom the proper way ?

Prerequisites

Here are a few things you should provide to help me understand the issue:

  • Rust version : rustc 1.74.1 (a28077b28 2023-12-04)
  • nom version : nom = "7.1.3"
  • nom compilation features used: default from cargo add nom

Test case

Example test case:

use nom::branch::alt;
use nom::bytes::complete::tag;
use nom::combinator::map;
use nom::sequence::separated_pair;
use nom::IResult;

mod ast {
    use std::rc::Rc;

    #[derive(Debug, Clone, PartialEq)]
    pub enum Test {
        AccessMin(i32),
    }

    #[derive(Debug, Clone, PartialEq)]
    pub enum Operator {
        And(Expression, Expression),
    }

    #[derive(Debug, Clone, PartialEq)]
    pub enum Expression {
        Operator(Rc<Operator>),
        Test(Test),
    }
}

fn parse_operator(input: &str) -> IResult<&str, ast::Operator> {
    alt((map(
        separated_pair(parse_expression, tag(" -and "), parse_expression),
        |(lhs, rhs)| ast::Operator::And(lhs, rhs),
    ),))(input)
}

pub fn parse_expression(input: &str) -> IResult<&str, ast::Expression> {
    alt((map(parse_operator, |val| {
        let val = std::rc::Rc::new(val);
        ast::Expression::Operator(val)
    }),))(input)
}

fn main() {
    let _ = parse_expression("");
}

Interestingly, using the not operator works with a recursive type. I had the following before:

fn parse_operator(input: &str) -> IResult<&str, ast::Operator> {
    log::info!("Parsing operator !");
    alt((
        map(
            delimited(
                terminated(tag("("), character::complete::space0),
                parse_expression,
                preceded(character::complete::space0, tag(")")),
            ),
            ast::Operator::Precedence,
        ),
        map(
            separated_pair(
                alt((tag("!"), tag("-not"))),
                character::complete::space0,
                parse_expression,
            ),
            |(_, e)| ast::Operator::Not(e),
        ),
    ))(input)
}

So it would seem calling the parse_expression twice creates the issue.
And this worked fine. Am running on arm macOS.

@spoutn1k spoutn1k changed the title Stack overflow Stack overflow before parsing Mar 27, 2024
@spoutn1k
Copy link
Author

Found https://github.com/dalance/nom-recursive. Worth putting on the README.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant