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

Code before:
  StringLiteral { string_literal: StringLiteral<'src> },
  /// `variable`
  Variable { name: Name<'src> },
}

impl<'src> Expression<'src> {
  pub(crate) fn variables<'expression>(&'expression self) -> Variables<'expression, 'src> {
    Variables::new(self)
  }

  pub(crate) fn empty_string_literal() -> Self {
    Expression::StringLiteral {
      string_literal: StringLiteral {
        kind: StringKind::new(string_kind::StringDelimiter::QuoteDouble, false),
        raw: "",
        cooked: "".to_string(),
      },
    }
  }
}

impl<'src> Display for Expression<'src> {
  fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
    match self {
      Expression::Backtick { token, .. } => write!(f, "{}", token.lexeme()),
      Expression::Join { lhs, rhs } => write!(
        f,
        "{} / {}",
        lhs
          .as_ref()
          .unwrap_or(&Box::new(Expression::empty_string_literal())),
        rhs
      ),
      Expression::Concatenation { lhs, rhs } => write!(f, "{} + {}", lhs, rhs),
      Expression::Conditional {
        lhs,
        rhs,
        then,
        otherwise,
        operator,
      } => write!(
        f,
        "if {} {} {} {{ {} }} else {{ {} }}",
        lhs, operator, rhs, then, otherwise
      ),
      Expression::StringLiteral { string_literal } => write!(f, "{}", string_literal),
      Expression::Variable { name } => write!(f, "{}", name.lexeme()),
      Expression::Call { thunk } => write!(f, "{}", thunk),
      Expression::Group { contents } => write!(f, "({})", contents),
    }
  }

Review comment (suggestion):
How about:

```
Expression::Join { None, rhs } => write!(
  f,
  "/ {}",
  rhs
),
Expression::Join { Some(lhs), rhs } => write!(
  f,
  "{} / {}",
  lhs,
  rhs
),
```

Code after:
  StringLiteral { string_literal: StringLiteral<'src> },
  /// `variable`
  Variable { name: Name<'src> },
}

impl<'src> Expression<'src> {
  pub(crate) fn variables<'expression>(&'expression self) -> Variables<'expression, 'src> {
    Variables::new(self)
  }
}

impl<'src> Display for Expression<'src> {
  fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
    match self {
      Expression::Backtick { token, .. } => write!(f, "{}", token.lexeme()),
      Expression::Join { lhs: None, rhs } => write!(f, "/ {}", rhs),
      Expression::Join {
        lhs: Some(lhs),
        rhs,
      } => write!(f, "{} / {}", lhs, rhs),
      Expression::Concatenation { lhs, rhs } => write!(f, "{} + {}", lhs, rhs),
      Expression::Conditional {
        lhs,
        rhs,
        then,
        otherwise,
        operator,
      } => write!(
        f,
        "if {} {} {} {{ {} }} else {{ {} }}",
        lhs, operator, rhs, then, otherwise
      ),
      Expression::StringLiteral { string_literal } => write!(f, "{}", string_literal),
      Expression::Variable { name } => write!(f, "{}", name.lexeme()),
      Expression::Call { thunk } => write!(f, "{}", thunk),
      Expression::Group { contents } => write!(f, "({})", contents),
    }
  }
}

impl<'src> Serialize for Expression<'src> {
  fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
  where
    S: Serializer,
  {
    match self {
      Self::Backtick { contents, .. } => {
        let mut seq = serializer.serialize_seq(None)?;
        seq.serialize_element("evaluate")?;
        seq.serialize_element(contents)?;
        seq.end()