def comparison(self, tree): token_a, token_operator, token_b = tree.children a = self.compileState.toResource(token_a) b = self.compileState.toResource(token_b) operator = ScoreRelation(token_operator) try: node = a.operation_test_relation(self.compileState, operator, b) except TypeError: raise McScriptUnsupportedOperationError(operator.name, a.type(), b.type(), self.compileState) if len(node["conditions"]) == 1 and isinstance(node["conditions"][0], ConditionalNode.IfBool): cond = node["conditions"][0] return BooleanResource(int(cond["val"]), None) # if currently looking for a condition, return it directly if self.compileState.currentContext().user_data.get_is_condition(): return node stack = self.compileState.expressionStack.next() self.compileState.ir.append(StoreFastVarFromResultNode( stack, node )) return BooleanResource(None, stack)
def index_setter(self, tree): accessor, index, value = tree.children accessor = self.visit(accessor) index = self.compileState.toResource(index) value = self.compileState.toResource(value) try: return accessor.operation_set_element(self.compileState, index, value) except TypeError: raise McScriptUnsupportedOperationError("[]=", accessor.type(), None, self.compileState)
def array_accessor(self, tree): """ Accesses an element on an array""" accessor_, index_ = tree.children accessor = self.visit(accessor_) index = self.compileState.toResource(index_) try: self.compileState.currentTree = index_ return accessor.operation_get_element(self.compileState, index) except TypeError: raise McScriptUnsupportedOperationError("[]", accessor.type(), None, self.compileState)
def control_for(self, tree): _, var_name, _, expression, block = tree.children resource = self.compileState.toResource(expression) try: iterator = resource.get_iterator(self.compileState) except TypeError: raise McScriptUnsupportedOperationError("iteration", resource.type(), None, self.compileState) while (value := iterator.next()) is not None: with self.compileState.node_block(ContextType.UNROLLED_LOOP, block.line, block.column) as block_function: self.compileState.currentContext().add_var(var_name, value) self.visit(block) self.compileState.ir.append(FunctionCallNode(block_function))
def binaryOperation(self, *args, assignment_resource: Resource = None): number1, *values = args # whether the first number may be overwritten is_temporary = isinstance(number1, Resource) and not number1.is_variable all_static = all(is_static(i) for i in args[::2]) # the first number can also be a list. Then just do a binary operation with it if isinstance(number1, list): number1 = self.binaryOperation(*number1) is_temporary = True number1 = self.compileState.toResource(number1) # by default all operations are in-place. This is not wanted, so the resource is copied if isinstance(number1, ValueResource) and (not all_static and not is_temporary): # copy, except the assign resource is number1 (OPT) if assignment_resource is None: number1 = number1.copy(self.compileState.expressionStack.next(), self.compileState) for i in range(0, len(values), 2): operator, number2, = values[i:i + 2] if isinstance(number2, list): # number2 is now also temporary, but is will not change anyways number2 = self.binaryOperation(*number2) elif is_static(number1) and not is_static(number2) and number2.is_variable: # if the first value is static and the second a variable, they may not be swapped # so store the first value number1 = number1.store(self.compileState) # get the operator enum type operator = BinaryOperator(operator) number2 = self.compileState.toResource(number2) if not isinstance(number2, ValueResource): raise ValueError( "ToDO: Implement boolean operations for non value-resources") try: number1 = number1.numericOperation( number2, operator, self.compileState) except TypeError: raise McScriptUnsupportedOperationError(operator.value, number1.type(), number2.type(), self.compileState) return number1
def unary_operation(self, tree): # noinspection PyShadowingNames def doOperation(operator: UnaryOperator, value: Resource): if operator == UnaryOperator.MINUS: return value.operation_negate(self.compileState) raise ValueError( f"Unknown unary operator {operator.name} in unary_operation") operator, value = tree.children value = self.compileState.toResource(value) operator = UnaryOperator(operator) # first try to do the operation on the resource itself. # if that is not possible, load the resource and try again try: return doOperation(operator, value) except TypeError: raise McScriptUnsupportedOperationError(operator.name, value.type(), None, self.compileState)
def numericOperation(self, other: ValueResource, operator: BinaryOperator, compileState: CompileState) -> Resource: """ Performs a numeric operation with this resource. The operation should be performed in-place """ if not isinstance(other, type(self)): raise TypeError() try: if operator == BinaryOperator.PLUS: return self.operation_plus(other, compileState) elif operator == BinaryOperator.MINUS: return self.operation_minus(other, compileState) elif operator == BinaryOperator.TIMES: return self.operation_times(other, compileState) elif operator == BinaryOperator.DIVIDE: return self.operation_divide(other, compileState) elif operator == BinaryOperator.MODULO: return self.operation_modulo(other, compileState) except TypeError: raise McScriptUnsupportedOperationError(operator.name, self.type(), other.type(), compileState) raise ValueError("Unknown operator: " + repr(operator))