def test_insert_sub_node_and_add(): exp = '10+20*30*40+40' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.BinaryOperatorNode( operator='+', a=expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(10), b=expnodes.BinaryOperatorNode( operator='*', a=expnodes.BinaryOperatorNode( operator='*', a=expnodes.ValueNode(20), b=expnodes.ValueNode(30) ), b=expnodes.ValueNode(40) ) ), b=expnodes.ValueNode(40) ) assert node == expected assert node_end == len(exp)
def get_first_node_without_spaces(exp): """ Get the first node in an expression string :param exp: The expression string :return: (ExpressionNode node_object, int end_index) """ if not exp: raise SyntaxError("Empty node") if exp[0] == OPEN_PARENTHESIS: return get_parenthesis_exp(exp) if exp[0].isdigit(): return get_number(exp) if exp.startswith('0x'): return get_number(exp[2:], base=16) if exp[0] in ['@', '$']: var_end_index = get_name_end(exp[1:]) + 1 var_name = exp[:var_end_index] # Variable containing a function if len(exp) > var_end_index and exp[var_end_index] == OPEN_PARENTHESIS: return get_function_call(var_name, exp[var_end_index:]) # Normal variable usage else: return expnodes.VariableNode(name=var_name), var_end_index if exp[0] in ['"', "'"]: return get_string(exp) if exp[0] == OPEN_BRACKETS: return get_array(exp) name_end = get_name_end(exp) name = exp[:name_end] if name == 'True': return expnodes.ValueNode(True), name_end if name == 'False': return expnodes.ValueNode(False), name_end if name == 'Not': return get_not_node(exp, name_end) if len(exp) > name_end and exp[name_end] == OPEN_PARENTHESIS: return get_function_call(name, exp[name_end:]) if len(name) > 0: return expnodes.FunctionReferenceNode(function_name=name), name_end raise SyntaxError('Error parsing value from {0}'.format(exp))
def test_basic_addition(): exp = '10 + 20' node, node_end = expressions.parse_expression(exp) expected = expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(10), b=expnodes.ValueNode(20) ) assert node == expected assert node_end == len(exp)
def test_multi_char_operators(): exp = 'True <> False' node, node_end = expressions.parse_expression(exp) assert node == expnodes.BinaryOperatorNode( operator='<>', a=expnodes.ValueNode(True), b=expnodes.ValueNode(False) ) assert node_end == len(exp)
def test_string_nodes(): exp = '"Bye" & "\'Hello\'"' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.BinaryOperatorNode( operator='&', a=expnodes.ValueNode("Bye"), b=expnodes.ValueNode("\'Hello\'") ) assert node == expected assert node_end == len(exp)
def test_boolean_node(): exp = 'False And True' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.BinaryOperatorNode( operator='And', a=expnodes.ValueNode(False), b=expnodes.ValueNode(True) ) assert node == expected assert node_end == len(exp)
def test_var_function_call(): var = '$var' call = '$var(1, 2)' node, node_end = expressions.parse_expression(call) assert expnodes.FunctionCallNode( function_name=var, arguments=[ expnodes.ValueNode(1), expnodes.ValueNode(2) ] ) == node assert node_end == len(call)
def test_additions_without_spacing(): exp = '10+20+30' node, node_end = expressions.parse_expression(exp) expected = expnodes.BinaryOperatorNode( operator='+', a=expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(10), b=expnodes.ValueNode(20) ), b=expnodes.ValueNode(30) ) assert node == expected assert node_end == len(exp)
def test_not_call(): exp = 'Not (10 = 12)' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.NotNode( value=expnodes.BinaryOperatorNode( operator='=', a=expnodes.ValueNode(10), b=expnodes.ValueNode(12) ) ) assert node == expected assert node_end == len(exp)
def test_function_call(): exp = 'MyFunc(10, 20)' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.FunctionCallNode( function_name='MyFunc', arguments=[ expnodes.ValueNode(10), expnodes.ValueNode(20) ] ) assert node == expected assert node_end == len(exp)
def parse_first_assignment(cls, assignment): c_index, c = lineparse.find_first( lambda current_char: current_char in (',', '='), assignment) if c_index == -1: # If assignment / next variable not found c_index = len(assignment) variable_name = assignment[:c_index].strip() if not variable_name.startswith('$'): raise SyntaxError( "Variable name must start in '$'! Variable: {variable}".format( variable=variable_name)) # Initialized with an expression if c == '=': # Parse the expression if len(assignment) == c_index: raise SyntaxError("Empty Assignment Value") exp_str = assignment[c_index + 1:] exp_tree, exp_end = expressions.parse_expression( exp_str, end_options=(',', ), allow_more=True) variable_value = exp_tree else: variable_value = expnodes.ValueNode(value='') exp_end = len(assignment) return variable_name, variable_value, c_index + 1 + exp_end + 1
def test_variable_exp(): exp = '10+$value*12' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.BinaryOperatorNode( operator='+', b=expnodes.BinaryOperatorNode( operator='*', a=expnodes.VariableNode("$value"), b=expnodes.ValueNode(12) ), a=expnodes.ValueNode(10) ) assert node == expected assert node_end == len(exp)
def test_basic_parenthesis(): exp = '10+(200+300)' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.BinaryOperatorNode( operator='+', b=expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(200), b=expnodes.ValueNode(300) ), a=expnodes.ValueNode(10) ) assert node == expected assert node_end == len(exp)
def test_nested_parenthesis(): exp = '10+((1+2)*(3+4))+30' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.BinaryOperatorNode( operator='+', a=expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(10), b=expnodes.BinaryOperatorNode( operator='*', a=expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(1), b=expnodes.ValueNode(2) ), b=expnodes.BinaryOperatorNode( operator='+', a=expnodes.ValueNode(3), b=expnodes.ValueNode(4) ) ) ), b=expnodes.ValueNode(30) ) assert node == expected assert node_end == len(exp)
def get_number(exp, base=10): end_index, dot_index = get_number_end(exp) number_value = exp[:end_index] if not number_value: raise SyntaxError("Number is empty") if dot_index != -1: if base == 16: raise SyntaxError("Hex values cannot contain dots: {0}".format(number_value)) number_value = float(number_value) else: number_value = int(number_value, base) return expnodes.ValueNode(value=number_value), end_index
def get_string(exp): enclosing = exp[0] current_index = 1 output_string = "" while True: if current_index == len(exp): raise SyntaxError("Missing closing {0}".format(enclosing)) if exp[current_index] == enclosing: if (current_index+1) == len(exp) or \ exp[current_index+1] != enclosing: break else: current_index += 1 output_string += exp[current_index] current_index += 1 return expnodes.ValueNode(output_string), current_index+1
def test_array_node(): exp = '[1, 2, 4, 5, 20+30]' node, node_end = expressions.parse_expression(exp) expected = \ expnodes.ArrayNode( [ expnodes.ValueNode(1), expnodes.ValueNode(2), expnodes.ValueNode(4), expnodes.ValueNode(5), expnodes.BinaryOperatorNode(operator='+', a=expnodes.ValueNode(20), b=expnodes.ValueNode(30) ) ] ) assert node == expected assert node_end == len(exp)