#NEWLINE# def _MathParser( math_stack ) : #NEWLINE# #INDENT# 'Defines the entire math expression for BigQuery queries.\n\n  Converts the expression into postfix notation. The stack is reversed\n  (i.e. the last element acts the top of the stack).\n\n  Actions do not occur unless parseString is called on the BNF returned.\n  The actions will modify the original list that was passed when the BNF\n  was generated.\n\n  The <math_stack> will return the single expression converted to postfix.\n\n  Arguments:\n    math_stack: Returns postfix notation of one math expression.\n\n  Returns:\n    A BNF of an math/string expression.\n  ' #NEWLINE# def PushAggregation( tokens ) : #NEWLINE# #INDENT# 'Pushes aggregation functions onto the stack.\n\n    When the aggregation is pushed, the name is rewritten. The label is\n    prepended with AGGREGATION_ to signal that an aggregation is occurring.\n    Following this prefix is an integer, which represents the number of comma\n    separated arguments that were provided. Finally, the name of the function\n    is appended to the label. For most functions, the aggregation name is\n    simply appended. However, there are special exceptions for COUNT.\n    A normal count function is rewritten as AGGREGATION_i_COUNT. However,\n    a count with the distinct keyword is rewritten to\n    AGGREGATION_i_DISTINCTCOUNT.\n\n    Args:\n      tokens: The function name and arguments in a list object.\n    ' #NEWLINE# function_name = tokens [ 0 ] #NEWLINE# if ( function_name == 'COUNT' ) : #NEWLINE# #INDENT# if ( 'DISTINCT' in list ( tokens ) ) : #NEWLINE# #INDENT# function_name = 'DISTINCTCOUNT' #NEWLINE# #UNINDENT# #UNINDENT# num_args = 1 #NEWLINE# for token in tokens : #NEWLINE# #INDENT# if ( token == ',' ) : #NEWLINE# #INDENT# num_args += 1 #NEWLINE# #UNINDENT# #UNINDENT# math_stack . append ( util . AggregationFunctionToken ( function_name , num_args ) ) #NEWLINE# #UNINDENT# def PushFunction( tokens ) : #NEWLINE# #INDENT# 'Push a function token onto the stack.\n\n    Args:\n      tokens: list of all tokens, tokens[0] is the function name str.\n    ' #NEWLINE# math_stack . append ( util . BuiltInFunctionToken ( tokens [ 0 ] ) ) #NEWLINE# #UNINDENT# def PushSingleToken( tokens ) : #NEWLINE# #INDENT# 'Push the topmost token onto the stack.' #NEWLINE# if util . IsFloat ( tokens [ 0 ] ) : #NEWLINE# #INDENT# try : #NEWLINE# #INDENT# token = int ( tokens [ 0 ] ) #NEWLINE# #UNINDENT# except ValueError : #NEWLINE# #INDENT# token = float ( tokens [ 0 ] ) #NEWLINE# #UNINDENT# #UNINDENT# else : #NEWLINE# #INDENT# if ( tokens [ 0 ] . startswith ( "'" ) or tokens [ 0 ] . startswith ( '"' ) ) : #NEWLINE# #INDENT# token = util . StringLiteralToken ( tokens [ 0 ] ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( tokens [ 0 ] . lower ( ) in util . BIGQUERY_CONSTANTS ) : #NEWLINE# #INDENT# token = util . LiteralToken ( tokens [ 0 ] . lower ( ) , util . BIGQUERY_CONSTANTS [ tokens [ 0 ] . lower ( ) ] ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# token = util . FieldToken ( tokens [ 0 ] ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# math_stack . append ( token ) #NEWLINE# #UNINDENT# def PushCountStar( tokens ) : #NEWLINE# #INDENT# if ( tokens [ 0 ] != '*' ) : #NEWLINE# #INDENT# raise ValueError ( 'Not a count star argument.' ) #NEWLINE# #UNINDENT# math_stack . append ( util . CountStarToken ( ) ) #NEWLINE# #UNINDENT# def PushUnaryOperators( tokens ) : #NEWLINE# #INDENT# for i in reversed ( range ( 0 , len ( tokens ) ) ) : #NEWLINE# #INDENT# if ( tokens [ i ] == '-' ) : #NEWLINE# #INDENT# math_stack . append ( int ( '-1' ) ) #NEWLINE# math_stack . append ( util . OperatorToken ( '*' , 2 ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( tokens [ i ] == '~' ) : #NEWLINE# #INDENT# math_stack . append ( util . OperatorToken ( '~' , 1 ) ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# if ( tokens [ i ] . lower ( ) == 'not' ) : #NEWLINE# #INDENT# math_stack . append ( util . OperatorToken ( 'not' , 1 ) ) #NEWLINE# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# #UNINDENT# def PushBinaryOperator( tokens ) : #NEWLINE# #INDENT# math_stack . append ( util . OperatorToken ( tokens [ 0 ] , 2 ) ) #NEWLINE# #UNINDENT# comma = pp . Literal ( ',' ) #NEWLINE# decimal = pp . Literal ( '.' ) #NEWLINE# exponent_literal = pp . CaselessLiteral ( 'E' ) #NEWLINE# lp = pp . Literal ( '(' ) #NEWLINE# rp = pp . Literal ( ')' ) #NEWLINE# count_star = pp . Literal ( '*' ) #NEWLINE# distinct_keyword = pp . CaselessKeyword ( 'DISTINCT' ) #NEWLINE# label = pp . Word ( pp . alphas , ( ( ( pp . alphas + pp . nums ) + '_' ) + '.' ) ) #NEWLINE# string = pp . quotedString #NEWLINE# integer = pp . Word ( pp . nums ) #NEWLINE# decimal_type1 = pp . Combine ( ( ( integer + decimal ) + pp . Optional ( integer ) ) ) #NEWLINE# decimal_type2 = pp . Combine ( ( decimal + integer ) ) #NEWLINE# real = ( decimal_type1 | decimal_type2 ) #NEWLINE# exponent = ( exponent_literal + pp . Word ( ( '+-' + pp . nums ) , pp . nums ) ) #NEWLINE# number_without_exponent = ( real | integer ) #NEWLINE# number = pp . Combine ( ( number_without_exponent + pp . Optional ( exponent ) ) ) #NEWLINE# integer_argument = pp . Word ( pp . nums ) #NEWLINE# integer_argument . setParseAction ( PushSingleToken ) #NEWLINE# full_expression = pp . Forward ( ) #NEWLINE# avg_function = ( ( ( pp . CaselessKeyword ( 'AVG' ) + lp ) + full_expression ) + rp ) #NEWLINE# count_star . setParseAction ( PushCountStar ) #NEWLINE# count_argument = ( ( pp . Optional ( distinct_keyword ) + full_expression ) | count_star ) #NEWLINE# count_function = ( ( ( ( pp . CaselessKeyword ( 'COUNT' ) + lp ) + count_argument ) + pp . Optional ( ( comma + integer_argument ) ) ) + rp ) #NEWLINE# quantiles_function = ( ( ( ( pp . CaselessKeyword ( 'QUANTILES' ) + lp ) + full_expression ) + pp . Optional ( ( comma + integer_argument ) ) ) + rp ) #NEWLINE# stddev_function = ( ( ( pp . CaselessKeyword ( 'STDDEV' ) + lp ) + full_expression ) + rp ) #NEWLINE# variance_function = ( ( ( pp . CaselessKeyword ( 'VARIANCE' ) + lp ) + full_expression ) + rp ) #NEWLINE# last_function = ( ( ( pp . CaselessKeyword ( 'LAST' ) + lp ) + full_expression ) + rp ) #NEWLINE# max_function = ( ( ( pp . CaselessKeyword ( 'MAX' ) + lp ) + full_expression ) + rp ) #NEWLINE# min_function = ( ( ( pp . CaselessKeyword ( 'MIN' ) + lp ) + full_expression ) + rp ) #NEWLINE# nth_function = ( ( ( ( ( pp . CaselessKeyword ( 'NTH' ) + lp ) + integer_argument ) + comma ) + full_expression ) + rp ) #NEWLINE# group_concat_function = ( ( ( pp . CaselessKeyword ( 'GROUP_CONCAT' ) + lp ) + full_expression ) + rp ) #NEWLINE# sum_function = ( ( ( pp . CaselessKeyword ( 'SUM' ) + lp ) + full_expression ) + rp ) #NEWLINE# top_function = ( ( ( ( pp . CaselessKeyword ( 'TOP' ) + lp ) + full_expression ) + pp . Optional ( ( ( comma + integer_argument ) + pp . Optional ( ( comma + integer_argument ) ) ) ) ) + rp ) #NEWLINE# aggregate_functions = ( ( ( ( ( ( ( ( ( ( ( avg_function | count_function ) | quantiles_function ) | stddev_function ) | variance_function ) | last_function ) | max_function ) | min_function ) | nth_function ) | group_concat_function ) | sum_function ) | top_function ) #NEWLINE# aggregate_functions . setParseAction ( PushAggregation ) #NEWLINE# functions_arguments = pp . Optional ( ( full_expression + pp . ZeroOrMore ( ( comma . suppress ( ) + full_expression ) ) ) ) #NEWLINE# functions = ( ( ( label + lp ) + functions_arguments ) + rp ) #NEWLINE# functions . setParseAction ( PushFunction ) #NEWLINE# literals = ( ( number | string ) | label ) #NEWLINE# literals . setParseAction ( PushSingleToken ) #NEWLINE# atom = ( ( ( ( ( lp + full_expression ) + rp ) | aggregate_functions ) | functions ) | literals ) #NEWLINE# unary_operators = ( ( ( pp . CaselessLiteral ( '+' ) | pp . CaselessLiteral ( '-' ) ) | pp . CaselessLiteral ( '~' ) ) | pp . CaselessKeyword ( 'not' ) ) #NEWLINE# current_expression = ( pp . ZeroOrMore ( unary_operators ) + atom . suppress ( ) ) #NEWLINE# current_expression . setParseAction ( PushUnaryOperators ) #NEWLINE# binary_operators = [ ( ( pp . CaselessLiteral ( '*' ) | pp . CaselessLiteral ( '/' ) ) | pp . CaselessLiteral ( '%' ) ) , ( pp . CaselessLiteral ( '+' ) | pp . CaselessLiteral ( '-' ) ) , ( pp . CaselessLiteral ( '>>' ) | pp . CaselessLiteral ( '<<' ) ) , ( ( ( pp . CaselessLiteral ( '<=' ) | pp . CaselessLiteral ( '>=' ) ) | pp . CaselessLiteral ( '<' ) ) | pp . CaselessLiteral ( '>' ) ) , ( ( pp . CaselessLiteral ( '==' ) | pp . CaselessLiteral ( '=' ) ) | pp . CaselessLiteral ( '!=' ) ) , ( pp . CaselessKeyword ( 'is' ) | pp . CaselessKeyword ( 'contains' ) ) , pp . CaselessLiteral ( '&' ) , pp . CaselessLiteral ( '^' ) , pp . CaselessLiteral ( '|' ) , pp . CaselessKeyword ( 'and' ) , pp . CaselessKeyword ( 'or' ) ] #NEWLINE# for operator_set in binary_operators : #NEWLINE# #INDENT# operator_expression = ( operator_set + current_expression ) #NEWLINE# operator_expression . setParseAction ( PushBinaryOperator ) #NEWLINE# current_expression = ( current_expression + pp . ZeroOrMore ( operator_expression ) ) #NEWLINE# #UNINDENT# ( full_expression << current_expression ) #NEWLINE# return full_expression