title: PEG: What is wrong wrong with my grammar for if statement?
body: <p>I'm implementing an OCaml-like language using <a href="https://docs.rs/peg/0.6.3/peg/" rel="nofollow noreferrer">rust-peg</a> and my parser has a bug.
  I defined if-statement grammar, but it doesn't work.</p>
  <p>I'm guessing the test-case input is parsed as <code>Apply(Apply(Apply(Apply(f, then), 2) else), 4)</code>. I mean <code>&quot;then&quot;</code> is parsed as Ident, not keyword.</p>
  <p>I have no idea for fixing this apply-expression grammar. Do you have any ideas?</p>
  <pre class="lang-rust prettyprint-override"><code>#[derive(Clone, PartialEq, Eq, Debug)]
  pub enum Expression {
      Number(i64),
      If {
          cond: Box&lt;Expression&gt;,
          conseq: Box&lt;Expression&gt;,
          alt: Box&lt;Expression&gt;,
      },
      Ident(String),
      Apply(Box&lt;Expression&gt;, Box&lt;Expression&gt;),
  }
  
  use peg::parser;
  use toplevel::expression;
  use Expression::*;
  
  parser! {
  pub grammar toplevel() for str {
  
      rule _() = [' ' | '\n']*
  
      pub rule expression() -&gt; Expression
          = expr()
  
      rule expr() -&gt; Expression
          = if_expr()
          / apply_expr()
  
      rule if_expr() -&gt; Expression
          = &quot;if&quot; _ cond:expr() _ &quot;then&quot; _ conseq:expr() _ &quot;else&quot; _ alt:expr() {
              Expression::If {
                  cond: Box::new(cond),
                  conseq: Box::new(conseq),
                  alt: Box::new(alt)
              }
          }
  
      rule apply_expr() -&gt; Expression
          = e1:atom() _ e2:atom() { Apply(Box::new(e1), Box::new(e2)) }
          / atom()
  
      rule atom() -&gt; Expression
          = number()
          / id:ident() { Ident(id) }
  
      rule number() -&gt; Expression
          = n:$(['0'..='9']+) { Expression::Number(n.parse().unwrap()) }
  
      rule ident() -&gt; String
          = id:$(['a'..='z' | 'A'..='Z']['a'..='z' | 'A'..='Z' | '0'..='9']*) { id.to_string() }
  }}
  
  fn main() {
      assert_eq!(expression(&quot;1&quot;), Ok(Number(1)));
      assert_eq!(
          expression(&quot;myFunc 10&quot;),
          Ok(Apply(
              Box::new(Ident(&quot;myFunc&quot;.to_string())),
              Box::new(Number(10))
          ))
      );
  
      // failed
      assert_eq!(
          expression(&quot;if f then 2 else 3&quot;),
          Ok(If {
              cond: Box::new(Ident(&quot;f&quot;.to_string())),
              conseq: Box::new(Number(2)),
              alt: Box::new(Number(3))
          })
      );
  }
  </code></pre>
  <pre><code>thread 'main' panicked at 'assertion failed: `(left == right)`
    left: `Err(ParseError { location: LineCol { line: 1, column: 11, offset: 10 }, expected: ExpectedSet { expected: {&quot;\&quot;then\&quot;&quot;, &quot;\' \' | \'\\n\'&quot;} } })`,
   right: `Ok(If { cond: Ident(&quot;f&quot;), conseq: Number(2), alt: Number(3) })`', src/main.rs:64:5
  </code></pre>