@top Query { Expr }

@skip { space+ }
@tokens {
  space { $[ \t\r\n]+ }

  LParen { "(" }
  RParen { ")" }
  At { "@" }
  Colon  { ":" }
  Not  { "-" | "NOT" }

  // Keywords (case-insensitive)
  And    { "AND" }
  Or     { "OR" }

  // "quoted phrase" with simple escapes: \" and \\
  Phrase { '"' (!["\\] | "\\" _)* '"' }

  // Bare words run until filter syntax or whitespace. Leading '-' remains unary
  // negation, but '-' may appear after the first character.
  Word { ![ \t\r\n():"@-] ![ \t\r\n():"@]* }
  FieldValueWord { ![ \t\r\n"] ![ \t\r\n]* }

  @precedence { Not, And, Or, Word }
}

@detectDelim

// Precedence: NOT (highest) > AND > OR (lowest)
// We also allow implicit AND in your parser/evaluator, but for highlighting,
// this grammar parses explicit AND/OR/NOT + adjacency as a sequence (Seq).
Expr {
  OrExpr
}

OrExpr {
  AndExpr (Or AndExpr)*
}

AndExpr {
  Unary (And Unary | Unary)*  // allow implicit AND by adjacency: Unary Unary
}

Unary {
  Not Unary
| Primary
}

Primary {
  Group
| Field
| Phrase
| Term
}

Group {
  LParen Expr RParen
}

Field {
  FieldName Colon FieldValue
}

FieldName {
  At? Word
}

FieldValue {
  Phrase
| FieldValueWord
}

Term {
  Word
}

@external propSource highlight from "./highlight"
