/* * Copyright 2022, The Cozo Project Authors. * * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. * If a copy of the MPL was not distributed with this file, * You can obtain one at https://mozilla.org/MPL/2.0/. */ script = _{sys_script | imperative_script | query_script} query_script = {SOI ~ (option | rule | const_rule | fixed_rule)+ ~ EOI} query_script_inner = {"{" ~ (option | rule | const_rule | fixed_rule)+ ~ "}"} query_script_inner_no_bracket = { (option | rule | const_rule | fixed_rule)+ } imperative_script = {SOI ~ imperative_stmt+ ~ EOI} sys_script = {SOI ~ "::" ~ (list_relations_op | list_relation_op | remove_relations_op | trigger_relation_op | trigger_relation_show_op | rename_relations_op | running_op | kill_op | explain_op | access_level_op | index_op | compact_op | list_fixed_rules) ~ EOI} index_op = {"index" ~ (index_create | index_drop)} index_create = {"create" ~ compound_ident ~ ":" ~ ident ~ "{" ~ (ident ~ ",")* ~ ident? ~ "}"} index_drop = {"drop" ~ compound_ident ~ ":" ~ ident } compact_op = {"compact"} list_fixed_rules = {"fixed_rules"} running_op = {"running"} kill_op = {"kill" ~ expr} explain_op = {"explain" ~ "{" ~ query_script_inner_no_bracket ~ "}"} list_relations_op = {"relations"} list_relation_op = {"columns" ~ compound_or_index_ident} remove_relations_op = {"remove" ~ (compound_ident ~ ",")* ~ compound_ident } rename_relations_op = {"rename" ~ (rename_pair ~ ",")* ~ rename_pair } access_level_op = {"access_level" ~ access_level ~ (compound_ident ~ ",")* ~ compound_ident} access_level = {("normal" | "protected" | "read_only" | "hidden")} trigger_relation_show_op = {"show_triggers" ~ compound_ident } trigger_relation_op = {"set_triggers" ~ compound_ident ~ trigger_clause* } trigger_clause = { "on" ~ (trigger_put | trigger_rm | trigger_replace) ~ "{" ~ query_script_inner_no_bracket ~ "}" } trigger_put = {"put"} trigger_rm = {"rm"} trigger_replace = {"replace"} rename_pair = {compound_ident ~ "->" ~ compound_ident} from_clause = {"from" ~ expr} to_clause = {"to" ~ expr} WHITESPACE = _{ " " | "\t" | "\r" | "\n" } BLOCK_COMMENT = _{ "/*" ~ (BLOCK_COMMENT | !"*/" ~ ANY)* ~ "*/" } LINE_COMMENT = _{ "#" ~ (!"\n" ~ ANY)* } COMMENT = _{(BLOCK_COMMENT | LINE_COMMENT)} prog_entry = {"?"} var = @{(XID_START | "_") ~ (XID_CONTINUE | "_")*} param = @{"$" ~ (XID_CONTINUE | "_")*} ident = @{XID_START ~ ("_" | XID_CONTINUE)*} underscore_ident = @{("_" | XID_START) ~ ("_" | XID_CONTINUE)*} relation_ident = @{"*" ~ (compound_or_index_ident | underscore_ident)} compound_ident = @{ident ~ ("." ~ ident)*} compound_or_index_ident = @{ident ~ ("." ~ ident)* ~ (":" ~ ident)?} rule = {rule_head ~ ":=" ~ rule_body ~ ";"?} const_rule = {rule_head ~ "<-" ~ expr ~ ";"?} fixed_rule = {rule_head ~ "<~" ~ ident ~ fixed_args_list ~ ";"?} fixed_args_list = {"(" ~ (fixed_arg ~ ",")* ~ fixed_arg? ~ ")"} rule_head = {(prog_entry | ident) ~ "[" ~ (head_arg ~ ",")* ~ head_arg? ~ "]"} head_arg = {aggr_arg | var} aggr_arg = {ident ~ "(" ~ var ~ ("," ~ expr)* ~ ")"} fixed_arg = _{fixed_rel | fixed_opt_pair} fixed_opt_pair = {ident ~ ":" ~ expr} fixed_rel = {fixed_rule_rel | fixed_relation_rel | fixed_named_relation_rel } fixed_rule_rel = {ident ~ "[" ~ (var ~ ",")* ~ var? ~ "]"} fixed_relation_rel = {relation_ident ~ "[" ~ (var ~ ",")* ~ var? ~ validity_clause? ~ "]"} fixed_named_relation_rel = {relation_ident ~ "{" ~ (fixed_named_relation_arg_pair ~ ",")* ~ fixed_named_relation_arg_pair? ~ validity_clause? ~ "}"} fixed_named_relation_arg_pair = {ident ~ (":" ~ ident)?} validity_clause = {"@" ~ expr} rule_body = {(disjunction ~ ",")* ~ disjunction?} rule_apply = {underscore_ident ~ "[" ~ apply_args ~ "]"} relation_named_apply = {relation_ident ~ "{" ~ named_apply_args ~ validity_clause? ~ "}"} relation_apply = {relation_ident ~ "[" ~ apply_args ~ validity_clause? ~ "]"} disjunction = {(atom ~ "or" )* ~ atom} atom = _{ negation | relation_named_apply | relation_apply | rule_apply | unify_multi | unify | expr | grouped} unify = {var ~ "=" ~ expr} unify_multi = {var ~ "in" ~ expr} negation = {"not" ~ atom} apply = {ident ~ "(" ~ apply_args ~ ")"} apply_args = {(expr ~ ",")* ~ expr?} named_apply_args = {(named_apply_pair ~ ",")* ~ named_apply_pair?} named_apply_pair = {ident ~ (":" ~ expr)?} grouped = _{"(" ~ rule_body ~ ")"} expr = {unary_op* ~ term ~ (operation ~ unary_op* ~ term)*} operation = _{ (op_and | op_or | op_pow | op_concat | op_add | op_sub | op_mul | op_div | op_mod | op_ge | op_le | op_gt | op_lt | op_eq | op_ne | op_coalesce )} op_or = { "||" } op_and = { "&&" } op_concat = { "++" } op_add = { "+" } op_sub = { "-" } op_mul = { "*" } op_div = { "/" } op_mod = { "%" } op_eq = { "==" } op_ne = { "!=" } op_gt = { ">" } op_lt = { "<" } op_ge = { ">=" } op_le = { "<=" } op_pow = { "^" } op_coalesce = { "~" } unary_op = _{ minus | negate } minus = { "-" } negate = { "!" } term = _{ literal | param | grouping | apply | var | list } list = { "[" ~ (expr ~ ",")* ~ expr? ~ "]" } grouping = { "(" ~ expr ~ ")" } option = _{(limit_option|offset_option|sort_option|relation_option|timeout_option|sleep_option| assert_none_option|assert_some_option) ~ ";"?} out_arg = @{var ~ ("(" ~ var ~ ")")?} limit_option = {":limit" ~ expr} offset_option = {":offset" ~ expr} sort_option = {(":sort" | ":order") ~ (sort_arg ~ ",")* ~ sort_arg } relation_option = {relation_op ~ (compound_ident | underscore_ident) ~ table_schema?} relation_op = _{relation_create | relation_replace | relation_put | relation_rm | relation_ensure | relation_ensure_not} relation_create = {":create"} relation_replace = {":replace"} relation_put = {":put"} relation_rm = {":rm"} relation_ensure = {":ensure"} relation_ensure_not = {":ensure_not"} timeout_option = {":timeout" ~ expr } sleep_option = {":sleep" ~ expr } sort_arg = { sort_dir? ~ out_arg } sort_dir = _{ sort_asc | sort_desc } sort_asc = {"+"} sort_desc = {"-"} assert_none_option = {":assert" ~ "none"} assert_some_option = {":assert" ~ "some"} // literals quoted_string = ${ "\"" ~ quoted_string_inner ~ "\"" } quoted_string_inner = { char* } char = { !("\"" | "\\") ~ ANY | "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) } s_quoted_string = ${ "\'" ~ s_quoted_string_inner ~ "\'" } s_quoted_string_inner = { s_char* } s_char = { !("\'" | "\\") ~ ANY | "\\" ~ ("\'" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") | "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) } raw_string = { PUSH("_"*) ~ "\"" // push the number signs onto the stack ~ raw_string_inner ~ "\"" ~ POP // match a quotation mark and the number signs } raw_string_inner = { ( !("\"" ~ PEEK) // unless the next character is a quotation mark // followed by the correct amount of number signs, ~ ANY // consume one character )* } string = _{(raw_string | s_quoted_string | quoted_string)} // Boolean and null boolean = { "true" | "false" } null = { "null" } // Numbers pos_int = @{ASCII_DIGIT ~ ("_" | ASCII_DIGIT)*} hex_pos_int = @{"0x" ~ ASCII_HEX_DIGIT ~ ("_" | ASCII_HEX_DIGIT)*} octo_pos_int = @{"0o" ~ ASCII_OCT_DIGIT ~ ("_" | ASCII_OCT_DIGIT)*} bin_pos_int = @{"0b" ~ ASCII_BIN_DIGIT ~ ("_" | ASCII_BIN_DIGIT)*} int = _{(hex_pos_int | octo_pos_int | bin_pos_int | pos_int)} dot_float = @{ ("0" | ASCII_NONZERO_DIGIT ~ ("_" | ASCII_DIGIT)*) ~ ("." ~ ("_" | ASCII_DIGIT)*) } sci_float = @{ ("0" | ASCII_NONZERO_DIGIT ~ ("_" | ASCII_DIGIT)*) ~ ("." ~ ("_" | ASCII_DIGIT)*)? ~ (^"e" ~ ("+" | "-")? ~ ("_" | ASCII_DIGIT)+) } float = _{(sci_float | dot_float)} number = _{(float | int)} literal = _{ null | boolean | number | string} // schema table_schema = {"{" ~ table_cols ~ ("=>" ~ table_cols)? ~ "}"} table_cols = {(table_col ~ ",")* ~ table_col?} table_col = {ident ~ (":" ~ col_type)? ~ (("default" ~ expr) | ("=" ~ out_arg))?} col_type = {(any_type | bool_type | int_type | float_type | string_type | bytes_type | uuid_type | validity_type | list_type | tuple_type) ~ "?"?} col_type_with_term = {SOI ~ col_type ~ EOI} any_type = {"Any"} int_type = {"Int"} float_type = {"Float"} string_type = {"String"} bytes_type = {"Bytes"} uuid_type = {"Uuid"} bool_type = {"Bool"} validity_type = {"Validity"} list_type = {"[" ~ col_type ~ (";" ~ expr)? ~ "]"} tuple_type = {"(" ~ (col_type ~ ",")* ~ col_type? ~ ")"} imperative_stmt = _{ break_stmt | continue_stmt | return_stmt | debug_stmt | query_script_inner | ignore_error_script | if_chain | if_not_chain | loop_block | temp_swap } imperative_condition = _{underscore_ident | query_script_inner} if_chain = {"%if" ~ imperative_condition ~ "%then"? ~ imperative_block ~ ("%else" ~ imperative_block)? ~ "%end" } if_not_chain = {"%if_not" ~ imperative_condition ~ "%then"? ~ imperative_block ~ ("%else" ~ imperative_block)? ~ "%end" } imperative_block = {imperative_stmt+} break_stmt = {"%break" ~ ident?} ignore_error_script = {"%ignore_error" ~ query_script_inner} continue_stmt = {"%continue" ~ ident?} return_stmt = {"%return" ~ (ident | underscore_ident | query_script_inner)*} loop_block = {("%mark" ~ ident)? ~ "%loop" ~ imperative_block ~ "%end"} temp_swap = {"%swap" ~ underscore_ident ~ underscore_ident} debug_stmt = {"%debug" ~ (ident | underscore_ident)} /* yield is no longer necessary! */