Repository: casey/just
File: src/parser.rs (Rust)

Code before:
      export,
      name,
      value,
    })
  }

  /// Parse an expression, e.g. `1 + 2`
  fn parse_expression(&mut self) -> CompileResult<'src, Expression<'src>> {
    if self.depth == if cfg!(windows) { 48 } else { 256 } {
      return Err(CompileError {
        token: self.next()?,
        kind: CompileErrorKind::ParsingRecursionDepthExceeded,
      });
    }

    self.depth += 1;

    let expression = if self.accepted_keyword(Keyword::If)? {
      self.parse_conditional()?
    } else {
      let value = self.parse_value();
      if self.accepted(Slash)? {
        // Enables Slash operator to build absolute paths, like `/ "Users"`, by
        // setting a default empty string on the lhs if the resulting expression
        // is not Ok.
        let value = value.unwrap_or(Expression::StringLiteral {
          string_literal: StringLiteral {
            kind: StringKind::new(string_kind::StringDelimiter::QuoteDouble, false),
            raw: "",
            cooked: "".to_string(),
          },
        });
        let lhs = Box::new(value);
        let rhs = Box::new(self.parse_expression()?);
        Expression::Join { lhs, rhs }
      } else if self.accepted(Plus)? {
        let lhs = Box::new(value?);
        let rhs = Box::new(self.parse_expression()?);
        Expression::Concatenation { lhs, rhs }
      } else {
        value?
      }
    };

    self.depth -= 1;

    Ok(expression)
  }

  /// Parse a conditional, e.g. `if a == b { "foo" } else { "bar" }`
  fn parse_conditional(&mut self) -> CompileResult<'src, Expression<'src>> {

Review comment (suggestion):
I think this `unwrap_or` will swallow errors. What if `self.parse_value()` returns an error after skipping over some tokens?

Maybe something like this instead?

```rust
    let expression = if self.accepted_keyword(Keyword::If)? {
      self.parse_conditional()?
    } else if self.accepted(Slash)? {
        let lhs = None;
        let rhs = Box::new(self.parse_expression()?);
        Expression::Join { lhs, rhs }
    } else {
      let value = self.parse_value()?;
      
      if self.accepted(Slash)? {
        let lhs = Some(Box::new(value));
        let rhs = Box::new(self.parse_expression()?);
        Expression::Join { lhs, rhs }
      } else if self.accepted(Plus)? {
        let lhs = Box::new(value);
        let rhs = Box::new(self.parse_expression()?);
        Expression::Concatenation { lhs, rhs }
      } else {
        value
      }
    };
```

Code after:
    self.expect_eol()?;
    Ok(Assignment {
      export,
      name,
      value,
    })
  }

  /// Parse an expression, e.g. `1 + 2`
  fn parse_expression(&mut self) -> CompileResult<'src, Expression<'src>> {
    if self.depth == if cfg!(windows) { 48 } else { 256 } {
      return Err(CompileError {
        token: self.next()?,
        kind: CompileErrorKind::ParsingRecursionDepthExceeded,
      });
    }

    self.depth += 1;

    let expression = if self.accepted_keyword(Keyword::If)? {
      self.parse_conditional()?
    } else if self.accepted(Slash)? {
      let lhs = None;
      let rhs = Box::new(self.parse_expression()?);
      Expression::Join { lhs, rhs }
    } else {
      let value = self.parse_value()?;

      if self.accepted(Slash)? {
        let lhs = Some(Box::new(value));
        let rhs = Box::new(self.parse_expression()?);
        Expression::Join { lhs, rhs }
      } else if self.accepted(Plus)? {
        let lhs = Box::new(value);
        let rhs = Box::new(self.parse_expression()?);
        Expression::Concatenation { lhs, rhs }
      } else {
        value
      }
    };

    self.depth -= 1;

    Ok(expression)
  }

  /// Parse a conditional, e.g. `if a == b { "foo" } else { "bar" }`
  fn parse_conditional(&mut self) -> CompileResult<'src, Expression<'src>> {
    let lhs = self.parse_expression()?;

    let operator = if self.accepted(BangEquals)? {