WHITESPACE = _{ " " | "\n" }
COMMENT = _{ "--" ~ ANY* ~ "\n"}
value = { null
| boolean
| text
| set_of_texts
}
null = { "null" }
boolean = { "true" | "false" }
text = @{ "'" ~ (!"'" ~ ANY )* ~ "'" }
set_of_texts = { "(" ~ (text ~ ",")* ~ text? ~ ")" }
// https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-PRECEDENCE
not = { "not" }
operand_0 = { identifier
| nested
| value
}
identifier = { todo_field }
nested = { "(" ~ expression ~ ")" }
operand_1 = { function
| operand_0
}
// for now ARGs are just [String]
// TODO: size(identifier) / count(identifier)
function = ${ function_name ~ function_argument_list }
function_argument_list_empty = { "(" ~ ")"}
// FIXME: why do i have to do this whitespace crap here?
function_argument_list_nonempty = { "(" ~ WHITE_SPACE*
~ (value ~ WHITE_SPACE* ~ "," ~ WHITE_SPACE*)*
~ WHITE_SPACE* ~ value ~ WHITE_SPACE* ~ ")" }
function_argument_list = { function_argument_list_empty | function_argument_list_nonempty }
function_name = { ASCII_ALPHA+ }
operand_2 = { between
| in_set
| operand_1
}
between = { operand_1 ~ not? ~ "between" ~ operand_1 ~ "and" ~ operand_1 }
in_set = { operand_1 ~ not? ~ "in" ~ set_of_texts }
operand_3 = { comparison_op_
| operand_2
}
comparison_operator = { eq
| not_eq
| gt_eq
| lt_eq
| contains
| is_contained_by
| overlap
| gt
| lt
}
gt = { ">" }
lt = { "<" }
gt_eq = { ">=" }
lt_eq = { "<=" }
eq = { "==" | "=" }
not_eq = { "<>" | "!="} // 🏴☠️
// https://www.postgresql.org/docs/9.0/functions-array.html
// set operations
contains = {"@>"}
is_contained_by = {"<@"}
overlap = {"&&"}
_comparison_operator_and_operand = { comparison_operator ~ operand_2 }
comparison_op_ = { operand_2 ~ comparison_operator ~ operand_2 }
operand_4 = { is
| operand_3
}
ntf = { "null" | "true" | "false" }
is = { operand_3 ~ "is" ~ not? ~ ntf }
operand_5 = { negated
| operand_4
}
negated = { not ~ operand_4 }
operand_6 = { and
| operand_5
}
and = { operand_5 ~ ("and" ~ operand_5)+ }
operand_7 = { or
| operand_6
}
or = { operand_6 ~ ("or" ~ operand_6)+ }
expression = { operand_7 }
todo_field = { "full_text"
| "is_completed"
| "id"
| "is_blocking_for"
| "is_blocked"
| "blocked_by"
| "creation_date"
| "completion_date"
| "priority"
| "ccontext"
| "contexts"
| "cproject"
| "projects"
| "due_date"
| "threshold_date"
| "is_hidden"
}
select = { "select" ~ select_fields_star
~ "from" ~ select_from
~ "where" ~ expression? }
select_fields_star = { "*" }
select_fields_list = { "(" ~ (todo_field ~ ",")* ~ todo_field ~ ")" }
select_fields = { select_fields_star | select_fields_list }
select_from = { "-" // STDIN
| "todo_txt"
| "done_txt"
// TODO: other files in todo dir
}