Skip to content

Instantly share code, notes, and snippets.

@reverendpaco
Created April 4, 2020 16:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save reverendpaco/fc64863d15539349e856a5e1883b73df to your computer and use it in GitHub Desktop.
Save reverendpaco/fc64863d15539349e856a5e1883b73df to your computer and use it in GitHub Desktop.
@@grammar::dql
############### top markers used by the parser for different contexts
start_query
=
@:top_goal end_marker $
;
start_consult
= { consultable end_marker }* $
;
############################################################
#
# Consult-level
#
#
consultable
=
| datalog_predicate_as_func_form:datalog_predicate_as_func_form
| asserted_data_form:asserted_data
| datalog_rule_form:datalog_rule
| temp_table_form:temp_table
;
asserted_data
= fq_functor:fq_functor "(" ground_terms:ground_datalog_no_under_args ")"
;
datalog_rule
= head_functor:fq_functor head_args:datalog_no_under_args implication ~ rule_body:goal
;
datalog_predicate_as_func_form
= head_functor:fq_functor ":" ~
function_projection:function_projection head_args:datalog_no_under_args implication
function_body:function_forms
;
function_forms
= ",".{ (case_statement+:case_statement
| format_column_as_function+:format_column_as_function
| functional_unification+:functional_unification
| scalar_predicate_expression+:scalar_predicate_expression
| function_form_alone+:function_form
)}+
;
functional_unification
=
| assignment_column:column_name assignment:"=:" case_statement:case_statement
| assignment_column:column_name assignment:"=:" scalar_predicate_expression:scalar_predicate_expression
| assignment_column:column_name assignment:"=:" function_form:function_form
| assignment_column:column_name assignment:"=:" format_column_as_function:format_column_as_function
;
temp_table
= temp_view_name:functor sem_consq temp_view_goal:goal ;
ground_datalog_no_under_args
= ",".{ground_term}+
;
##########################################################################################
#
#
# Query/Repl-level
#
#
top_goal
=
| cte_form:cte_form
| goal_form:goal
| assertion
;
cte_form
= cte_prelude:cte_prelude main_goal:goal
;
cte_prelude
= {sem_consq ~ @:cte_pair end_marker}+
;
cte_pair
= cte_table:cte_table cte_goal:goal;
goal
=
#
# ( binary_relational_op | unary_op_with_pipe )%{ relation_or_select }+ ~
binary_part:( binary_relational_op )%{ relation_or_select }+
[ unary_part:{ unary_op_with_pipe }+ post_unary:[binary_relational_op goal] ]
;
assertion
= ("assert" | "insert") "(" assertable:consultable ")"
;
cte_table
=
cte_table_name:cte_table_name
;
cte_table_name
=
functor:functor [ "(" (",").{column_name:column_name}+ [","] ")" ]
;
datalog_no_under_args
= "(" ",".{@+:head_column}+ ")"
;
head_column
= functional_dependent:[":"] (column_name:column_name | full:full_sigil)
;
relation_or_select
=
| selection_stuff:selection_stuff
| [alias:alias] named_predicate:named_predicate
| [alias:alias] grouped_relation:grouped_relation
| [alias:alias] inline_relation:inline_relation
| [alias:alias] here_table:here_table
;
inline_relation
=
"{{" inline:( /(([^}\\][^}])|(\\})(\\}))+/) "}}"
;
grouped_relation
=
| "(" @:grouped_relation ")" # trick to un-nest excessive groupings
| "(" @:goal ")"
;
selection_stuff
=
| inline_selection:inline_selection
#| scalar_predicate_expression: scalar_predicate_expression
| scalar_predicate_expression: scalar_predicate_expression
;
#scalar_predicate_expression_at_top_level
# =
# | parenthesized_scalar_predicate_expression:( "(" scalar_predicate_expression ")" )
# | lhs:scalar_predicate_side scalar_comparison:sql_scalar_operator rhs:scalar_predicate_side
# ;
inline_selection
= "{" !"{" inline:( /(([^}\\])|(\\}))+/) "}"
;
here_table
=
"[" here_table_data:here_table_data "]" here_table_args+:datalog_no_under_args
;
here_table_data
=
| mulitple_tuples
| one_tuple:one_tuple
;
mulitple_tuples
= ",".{ "[" mulitple_tuples:one_tuple "]" }+
;
one_tuple
= ",".{ scalar_predicate_expression | function_form | ground_term }+
;
#################################################################
###
###
### Named Predicates (i.e. tables or aliases)
###
###
###
named_predicate
=
| globber_named_predicate:globber_named_predicate
| embedder_named_predicate:embedder_named_predicate
| just_double_glob_predicate:just_double_glob_predicate
| just_glob_predicate:just_glob_predicate
| datalog_like_named_predicate:datalog_like_named_predicate
| projector_named_predicate:projector_named_predicate
| eraser_named_predicate:eraser_named_predicate
| rename_named_predicate:rename_named_predicate
;
###
globber_named_predicate
=
fq_functor:fq_functor "(" dimension_globber:dimension_globber ")"
;
embedder_named_predicate
=
fq_functor:fq_functor "(" dimension_embedder:dimension_embedder ")"
;
just_double_glob_predicate
=
fq_functor:fq_functor "(" "**" ")"
;
just_glob_predicate
=
fq_functor:fq_functor "(" "*" ")"
;
datalog_like_named_predicate
=
fq_functor:fq_functor "(" (",").{datalog_like_identifiers:datalog_like_identifiers}+ [","] ")"
;
projector_named_predicate
=
fq_functor:fq_functor "(" dimension_projector:dimension_projector ")"
;
eraser_named_predicate
=
fq_functor:fq_functor "(" dimension_eraser:dimension_eraser ")"
;
rename_named_predicate
=
fq_functor:fq_functor "(" rename_selector:rename_selector ")"
;
###
datalog_like_identifiers
=
| full:full_sigil
| ground:ground_term
| column_name:column_name
;
column_index
=
[column_qualifier:column_qualifier] pound index:index
;
column_range
=
[column_qualifier:column_qualifier] pound range:range
;
fq_column
=
| [ ns:ns_prefix ] column:column_name
| [ ns:ns_prefix ] column:protected_column_name
;
column_qualifier
= [ ns:ns_prefix ] table_or_alias:functor
;
ns_prefix
= { schema:schema period }+
;
index
= /[1-9]+[0-9]*/
;
range
=
| from:index ".." to:index
| ".." to:index
| from:index ".."
;
functor
=
/[A-Za-z_]+[A-Za-z0-9_]*/
;
fq_functor
= [ ns:ns_prefix ] just_name:functor
;
alias
=
(!"_" @:/[A-Za-z_]+[A-Za-z0-9]*/) at
;
binary_relational_op
=
| right_outer_join:right_outer_join
| full_outer_join:full_outer_join
| left_outer_join:left_outer_join
| not_exists:not_exists
| exists:exists
| intersect:intersect
| join:join
| union_all:union_all
| union:union
| excessive_union:excessive_union
| flip_except_minus:flip_except_minus
| except_minus:except_minus
;
#################################################################
###
###
### UNARY OPERATIONS
###
###
###
unary_op_with_pipe
= pipe unary_op:unary_op [ relation_bookmark:relation_bookmark ]
;
unary_op
=
| dimension_embedder:dimension_embedder
| dimension_eraser:dimension_eraser
| dimension_projector:dimension_projector
| dimension_globber:dimension_globber
| double_glob_selector:double_glob_selector
| group_by:group_by [having:having]
| distinct:distinct
| having:having
| limit:limit [order_by:order_by]
| order_by:order_by [limit:limit]
| rename_selector:rename_selector
;
###
dimension_embedder
= "+[" (",").{@+:dimension_embedder_allowed_arguments}+ [","] "]"
;
dimension_eraser
= "-[" (",").{@+:dimension_eraser_allowed_arguments}+ [","] "]"
;
dimension_projector
= "[" (",").{@+:dimension_projection_allowed_arguments}+ "]"
;
dimension_globber
= "*[" (",").{@+:glob_selector_allowed_arguments}+ [","] "]"
;
double_glob_selector
= "(" @:"**" ")"
;
group_by
= "G(" group_by_columns:group_by_columns "," aggregate_functions:aggregate_functions ")"
;
limit
=
| int_like
| "L(" int_like ")"
;
order_by
= "O(" (",").{@+:order_by_allowed_arguments}+ ")"
;
distinct
= "D(" (",").{distinct_allowed_arguments+:distinct_allowed_arguments}* ")"
;
having
= "H(" having_allowed_arguments+:having_allowed_arguments ")"
;
rename_selector
= "r[" (",").{@+:rename_selector_allowed_arguments}+ "]"
;
###
dimension_embedder_allowed_arguments
=
| [lvar:lvar_binding] naked_value:ground_term [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] table_as_scalar:table_as_scalar [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] case_statement:case_statement [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] scalar_predicate_expression:scalar_predicate_expression [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] function_form:function_form [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] format_column:format_column [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] column_name:fq_column [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] inline_column:inline_column [ "as" column_rename:column_rename ]
;
dimension_eraser_allowed_arguments
=
| column_range:column_range
| column_index:column_index
| column_name:fq_column
| regex_columns:regex_of_regex
;
dimension_projection_allowed_arguments
=
# LVARS are not allowed before ranges, duh... nor aliases after
| column_range:column_range
| mapping_form:mapping_form
| [lvar:lvar_binding] naked_value:ground_term [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] table_as_scalar:table_as_scalar [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] scalar_predicate_expression:scalar_predicate_expression [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] case_statement:case_statement [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] function_form:function_form [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] column_index:column_index [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] column_name:fq_column [ "as" column_rename:column_rename ]
| [lvar:lvar_binding] inline_column:inline_column [ "as" column_rename:column_rename ]
| regex_columns:regex_of_regex
;
mapping_form
=
"[" function_to_apply:mapping_function do_as_renaming:do_as_renaming
(",").{mapping_form_arguments:mapping_form_arguments}+ "]"
;
do_as_renaming
=
| "<-"
| "<<-"
;
mapping_function
=
| "x" ~ "as" mapping_as:mapping_as
| function_form:function_form ["as" mapping_as:mapping_as]
;
mapping_as
=
| sed_replace:sedlike_regex ~
| format_column:format_column
;
mapping_form_arguments
=
| column_range:column_range
| column_index:column_index
| regex_columns:regex_of_regex
;
glob_selector_allowed_arguments
= [lvar:lvar_binding] column_name:fq_column
;
order_by_allowed_arguments
=
| [ direction:'+' | direction:'-'] column_name:fq_column
| [ direction:'+' | direction:'-'] column_index:column_index
;
rename_selector_allowed_arguments
=
| column_name:fq_column "as" column_rename:column_rename
| column_index:column_index "as" column_rename:column_rename
;
distinct_allowed_arguments
=
| column_name:fq_column
| column_index:column_index
;
having_allowed_arguments
=
scalar_predicate_expression:scalar_predicate_expression
;
###
aggregate_functions
=
dimension_embedder:dimension_embedder
;
group_by_columns
=
| dimension_projector:dimension_projector
| dimension_eraser:dimension_eraser
| "[" ",".{grouping_set:group_by_columns} "]"
;
function_form
=
| cast_form:"cast:" "(" function_args:function_args "as" type:/[A-Za-z ]+/ ")"
| function_name:functor ":" [ function_projection:function_projection] "(" function_args:function_args ")"
| predicate_function_limited_name:functor "::" [ function_projection:function_projection] "(" correlated_goal:goal ")"
;
function_projection
=
| "[" ",".{ @+:column_name} "]"
| @+:column_name
;
function_args
=
@+:",".{ "*" | scalar_predicate_expression | function_form | numeric | column_name | quoted_value | protected_column_name }*
;
inline_column
= "{" inline:( /(([^}])|(\\}))+/) "}"
;
format_column
= 'f:"' inline:( /(\\\"|[^\"])*/ ) '"'
;
format_column_as_function
= 'f:' [function_projection:column_name] '"' inline:( /(\\\"|[^\"])*/ ) '"'
;
scalar_predicate_expression
=
| lhs:scalar_predicate_side scalar_comparison:sql_scalar_operator rhs:scalar_predicate_side
| parenthesized_scalar_predicate_expression:( "(" scalar_predicate_expression ")" )
# | ( sql_scalar_operator )<{ scalar_predicate_side }+
;
table_as_scalar
=
"scalar{" @:goal "}"
;
case_statement
=
| case:case_multiple
| case_on:case_on
;
case_on
= "case_on:" [ function_projection:column_name] "(" ~ match_from:case_allowed ")"
";".{ ground_term_or_else:(ground_term | else_sigil ) "->" then:case_allowed }+
;
case_multiple
= ("case:" | "if:") ~ [ function_projection:column_name]
";".{ when:when
"->" then:case_allowed }+
;
when
=
| "(" scalar_predicate_expression:scalar_predicate_expression ")"
| else:( "(" "true" ")" )
;
case_allowed
=
| naked_value:ground_term
| table_as_scalar:table_as_scalar
| case_statement:case_statement
| scalar_predicate_expression:scalar_predicate_expression
| function_form:function_form
| format_column:format_column
| column_name:fq_column
| inline_column:inline_column
;
scalar_predicate_side
=
| scalar_predicate_expression:scalar_predicate_expression
| parenthesized_scalar_predicate_expression:( "(" scalar_predicate_expression ")" )
| ground_term:ground_term
| function_form:function_form
| column_name:fq_column
;
lvar_binding
=
| naked_at:at
| lvar_name:column_name at
;
column_rename
=
| column_name:column_name
| protected_column_name:protected_column_name
;
relation_bookmark
=
at @:datalog_like_named_predicate
;
ground_term
=
| text:quoted_value
| number:numeric
;
numeric
=
| real_like
| int_like
;
real_like
=
| /-?[0-9]+\.[0-9]+/
| /-?[0-9]*\.[0-9]+/
;
int_like
=
/-?[0-9]+/
;
quoted_value
=
| "'" quoted_value:{ /(\\\'|[^\'])*/ }* "'"
| '"' quoted_value:{ /(\\\"|[^\"])*/ }* '"'
;
protected_column_name
= '`' protected_value:{ /(\\`|[^`])*/ }* '`'
;
############################################################################
#
#
# Terminals
#
#
end_marker = period;
else_sigil = "_";
at = "@";
pipe = "|>";
glob = "*";
double_glob = "**";
join = ",";
left_outer_join = ">," !"<";
right_outer_join = ",<";
full_outer_join = ">,<";
exists = ",+";
not_exists = ",\+";
period = ".";
union = ">;";
union_all =
| "union" "all"
| ">;<" ;
excessive_union = ";";
intersect = "^";
except_minus = "-";
flip_except_minus = "-~";
comma = ",";
sem_consq = "|=";
column_name = !"_" /[A-Za-z_]+[A-Za-z-1-9_]*/;
full_sigil = "_";
minus_sign = "-";
pound = "#";
schema = /[A-Za-z]+[A-Za-z0-9]*/;
implication = ":-";
regex_of_regex = regex:/\/.+\// [case_insensitive:/i/] [global:/g/] [case_insensitive:/i/] [global:/g/];
sedlike_regex = /s\// sed1:/[^\/]+/ /\// sed2:/[^\/]+/ /\// [global:/g/];
############################################################################
#
#
# SQL Operators
#
#
sql_scalar_operator
=
| sso_concat
| sso_mulitply
| sso_divide
| sso_modulus
| sso_plus
| sso_minus
| sso_shiftleft
| sso_shiftright
| sso_bitand
| sso_bitor
| sso_lessthan
| sso_lessthanequals
| sso_greaterthan
| sso_greaterthanequals
| sso_double_equals
| sso_equals
| sso_not_equals_bang
| sso_not_equals_bracket
| sso_is
| sso_isnot
| sso_like
| sso_glob
| sso_match
| sso_and
| sso_or
;
sso_concat = "||";
sso_mulitply = "*";
sso_divide = "/";
sso_modulus = "%";
sso_plus = "+" !"[";
sso_minus = "-" !"[";
sso_shiftleft = "<<";
sso_shiftright = ">>";
sso_bitand = "&";
sso_bitor = "|";
sso_lessthan = "<" !("=" | "<");
sso_lessthanequals = "<=";
sso_greaterthan = ">" !("=" | "<" | ",");
sso_greaterthanequals = ">=";
sso_equals = "=" !"=";
sso_double_equals = "==";
sso_not_equals_bang = "!=";
sso_not_equals_bracket = "<>";
sso_is = "IS" !"NOT";
sso_isnot = "IS" "NOT";
sso_like = "LIKE";
sso_glob = "GLOB";
sso_match = "MATCH";
sso_and = "AND";
sso_or = "OR";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment