@precedence { logic @left }
@top Program { Query }
@skip { space }

Query {
    Name ( WhereClause | LimitClause | OrderClause | SelectClause | RenderClause )*
}

commaSep<content> { content ("," content)* }

WhereClause { Where LogicalExpr }
LimitClause { Limit Number }
OrderClause { Order Name OrderDirection? }
SelectClause { Select commaSep<Name> }
RenderClause { Render (PageRef | String) }

OrderDirection {
  "desc" | "asc"
}

Value { Number | String | Bool | Regex | Null | List }

LogicalExpr { FilterExpr (And FilterExpr)* }

FilterExpr {
  Name "<" Value
| Name "<=" Value
| Name "=" Value
| Name "!=" Value
| Name ">=" Value
| Name ">" Value
| Name "=~" Value
| Name "!=~" Value
| Name "in" Value
}

List { "[" commaSep<Value> "]" }


Bool {
  "true" | "false"
}


@tokens {
  space { std.whitespace+ }
  Name { (std.asciiLetter | "-" | "_")+ }

  Where { "where" }
  Order { "order by" }
  Select { "select" }
  Render { "render" }
  Limit { "limit" }
  And { "and" }
  Null { "null" }

  String {
    ("\"" | "“" | "”") ![\"”“]* ("\"" | "“" | "”")
  }
  PageRef {
    "[" "[" ![\]]* "]" "]"
  }
  Regex { "/" ( ![/\\\n\r] | "\\" _ )* "/"? }

  Number { std.digit+ }

  // @precedence { Where, Sort, Select, Render, Limit, And, Null, Name }
}
