def read_expression(tokenizer): if vector_length_token.match(tokenizer.file.read_character()) == None: raise SyntaxException( self, "Vector length expression syntax error: no double |'s found") expression = VectorLengthExpression(tokenizer=tokenizer) tokenizer.tokenize(stop_ats=[vector_length_token], tree=expression) if vector_length_token.match(tokenizer.file.read_character()) == None: raise SyntaxException( self, "Vector length expression syntax error: no double |'s found") return expression
def to_script(self): value = "" for expression in self.expressions: value = value + expression.to_script() if value == "": raise SyntaxException(self, f"Variable assignment syntax error: could not find right hand side value '{self.left_hand_expression}'") return f"{self.left_hand_expression.to_script()}{self.assignment_operator.to_script()}{value}{self.handle_semicolon()}"
def to_script(self): value = "" for expression in self.expressions: value = value + expression.to_script() if value == "": raise SyntaxException( self, "Parentheses syntax error: empty expression") return f"({value})"
def create_method(chain, buffer): if buffer == "xyz": return chain elif buffer == "_": return Literal("0") elif buffer in VectorExpression.component_table: method_data = VectorExpression.component_table[buffer] replacement_expression = MethodExpression(method_data[0], tokenizer=expression.tokenizer) for index in range(1, len(method_data)): element = method_data[index] if element == None: replacement_expression.expressions.append(chain) else: replacement_expression.expressions.append(Literal(element)) replacement_expression.convert_expressions_to_arguments() return replacement_expression else: raise SyntaxException(self, f"Component access '{buffer}' not in component table")
def replace_modifier_operation_with_call(self, index_of_left, left_vector, operator, expression=None): if expression == None: expression = self del expression.expressions[index_of_left:index_of_left + 1] if operator.operator not in VectorExpression.modifier_operator_table: raise SyntaxException(self, f"Vector syntax error: {operator.operator} is invalid modifier operator") modifier_method = VectorExpression.modifier_operator_table[operator.operator] expression.expressions[index_of_left] = MethodExpression(modifier_method[0], current_line_index=self.current_line_index, current_index=self.current_index, current_file_name=self.current_file_name) expression.expressions[index_of_left].parent = expression for index in range(1, len(modifier_method)): if modifier_method[index] == None: expression.expressions[index_of_left].expressions.append(left_vector) expression.expressions[index_of_left].convert_expressions_to_arguments() left_vector.parent = expression.expressions[index_of_left] else: expression.expressions[index_of_left].expressions.append(Literal(modifier_method[index])) expression.expressions[index_of_left].convert_expressions_to_arguments()
def to_script(self): if len(self.expressions) == 0: raise SyntaxException(self, "Vector length exception: empty expression") if (len(self.expressions) == 1 and type(self.expressions[0]) == MethodExpression and self.expressions[0].method_symbol.name == "vectorSub"): # change name of the expression self.expressions[0].method_symbol = Symbol("vectorDist") return self.expressions[0].to_script() else: method_expression = MethodExpression( Symbol("vectorLen"), current_line_index=self.current_line_index, current_index=self.current_index, current_file_name=self.current_file_name) method_expression.parent = self.parent method_expression.expressions = self.expressions method_expression.convert_expressions_to_arguments() return method_expression.to_script()
def handle_order_of_operations(self, offset=0, min_precedence=0, expression=None): def is_maybe_scalar_expression(expression): # checking to see if this expression is a scalar expression if ( type(expression) == VectorEscapeExpression or ( type(expression) == MethodExpression and expression.method_symbol.name == "vectorDot" and expression.method_symbol.name == "vectorLen" ) or ( type(expression) == Literal and expression.is_number() ) ): return True else: return False if expression == None: expression = self # fetch operand left_vector = expression.safe_get_index(0 + offset) if hasattr(left_vector, "operator"): # handling special cases where operators are used to modify a vector (-, ^) self.replace_modifier_operation_with_call(offset, expression.safe_get_index(1 + offset), left_vector, expression=expression) left_vector = expression.safe_get_index(0 + offset) # fetch operator operator = expression.safe_get_index(1 + offset) # fetch operand right_vector = expression.safe_get_index(2 + offset) if hasattr(right_vector, "operator"): # handling special cases where operators are used to modify a vector (-, ^) self.replace_modifier_operation_with_call(2 + offset, expression.safe_get_index(3 + offset), right_vector) right_vector = expression.safe_get_index(2 + offset) # fetch operator next_operator = expression.safe_get_index(3 + offset) # if we hit an operator that isn't anything, then we've probably reached the end of our expression. quit if operator == None: return elif ( left_vector == None or (left_vector != None and operator != None and right_vector == None) ): raise SyntaxException(self, "Vector expression syntax error: couldn't find operands") elif operator != None and operator.operator not in VectorExpression.operator_table: raise SyntaxException(self, f"Vector expression syntax error: invalid operator {operator.operator}") elif next_operator != None and next_operator.operator not in VectorExpression.operator_table: raise SyntaxException(self, f"Vector expression syntax error: invalid operator {next_operator.operator}") # check for type errors if ( VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.NO_SCALARS ): if ( ( is_maybe_scalar_expression(left_vector) == True and is_maybe_scalar_expression(right_vector) == False ) or ( is_maybe_scalar_expression(left_vector) == False and is_maybe_scalar_expression(right_vector) == True ) ): raise SyntaxException(self, f"Vector expression syntax error: cannot mix scalars and vectors for operator {operator.operator} at {left_vector.to_script()} {operator.operator} {right_vector.to_script()}") elif ( is_maybe_scalar_expression(left_vector) == True and is_maybe_scalar_expression(right_vector) == True ): raise SyntaxException(self, f"Vector expression syntax error: only vector operations are allowed inside backticks, not {left_vector.to_script()} {operator.operator} {right_vector.to_script()}. To escape, use the vector escape syntax " + "{}") elif ( VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.RIGHT_OR_LEFT_SCALAR or VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.ONLY_RIGHT_SCALAR ): if VectorExpression.operator_allows_scalars[operator.operator] == OperatorScalarOption.ONLY_RIGHT_SCALAR and is_maybe_scalar_expression(left_vector) == True: raise SyntaxException(self, f"Vector expression syntax error: the {operator.operator} operator does not support left-handed scalar operations at {left_vector.to_script()} {operator.operator} {right_vector.to_script()}") elif ( is_maybe_scalar_expression(left_vector) == False and is_maybe_scalar_expression(right_vector) == False ): warn(self, f"Vector expression syntax warning: implicit usage of scalars for operator {operator.operator} at {left_vector.to_script()} {operator.operator} {right_vector.to_script()}. Will only work at run-time if right-hand side is a scalar") elif ( is_maybe_scalar_expression(left_vector) == True and is_maybe_scalar_expression(right_vector) == True ): raise SyntaxException(self, f"Vector expression syntax error: only vector operations are allowed inside backticks, not {left_vector.to_script()} {operator.operator} {right_vector.to_script()}. To escape, use the vector escape syntax " + "{}") # done with syntax errors # do precedence rules if next_operator != None: if OperatorExpression.operator_precedence[operator.operator] >= min_precedence and OperatorExpression.operator_precedence[operator.operator] < OperatorExpression.operator_precedence[next_operator.operator]: self.handle_order_of_operations(offset=offset + 2, min_precedence=OperatorExpression.operator_precedence[next_operator.operator], expression=expression) # these operands may have changed due to precedence rules. re-fetch left_vector = expression.safe_get_index(0 + offset) right_vector = expression.safe_get_index(2 + offset) # determine which vector is a scalar and if we need to flip the sides if ( VectorExpression.operator_allows_scalars[operator.operator] == 1 and is_maybe_scalar_expression(left_vector) ): right_vector = expression.safe_get_index(0 + offset) left_vector = expression.safe_get_index(2 + offset) self.replace_operation_with_call(offset, left_vector, operator, right_vector, expression=expression) self.handle_order_of_operations(offset=offset, expression=expression)