def add(node: ASTNode, _): isatLeastOneString = Types.isStrictlyString( node.left) or Types.isStrictlyString(node.right) if isatLeastOneString: node.value = str(node.left.value) + str(node.right.value) node.dataType = Types.STRING else: node.value = node.left.value + node.right.value node.dataType = Types.NUMERIC
def reverse_string(node: ASTNode): left = node.left if TypeChecker.isStrictlyString(left): node.dataType = TypeChecker.STRING return Result(True) else: return Result(False, getUniaryOpTypeErr(node))
def negate(node: ASTNode): left = node.left if TypeChecker.isLooselyNumeric(left): node.dataType = TypeChecker.NUMERIC return Result(True) else: return Result(False, getUniaryOpTypeErr(node))
def not_op(node: ASTNode): left = node.left if TypeChecker.isLooselyNumeric(left) or TypeChecker.isStrictlyBoolean( left): node.dataType = TypeChecker.BOOLEAN return Result(True) else: return Result(False, getUniaryOpTypeErr(node))
def logicalOp(node: ASTNode, _): left = node.left.value right = node.right.value if node.nodeType == ASTNode.AND: node.value = left and right else: node.value = left or right node.dataType = Types.BOOLEAN
def array(node: ASTNode, _): if Types.isAtomic(node.left): node.left.value = [node.left.value] node.value = node.left.value node.value.append(node.right.value) isLooselyNumeric = lambda type: type == Types.NUMERICARRAY or type == Types.INTARRAY isNumericBool = lambda type: type == Types.INTARRAY or type == Types.NUMERICARRAY or type == Types.BOOLEANARRAY or type == Types.NUMERIC_BOOL_ARR if Types.isAtomic(node.left): ltype = Types.getArrayTypeBasedOnAtomic(node.left) else: ltype = node.left.dataType rtype = Types.getArrayTypeBasedOnAtomic(node.right) if ltype == rtype: node.dataType = ltype elif isLooselyNumeric(ltype) and isLooselyNumeric(rtype): node.dataType = Types.NUMERICARRAY elif isNumericBool(ltype) and isNumericBool(rtype): node.dataType = Types.NUMERIC_BOOL_ARR
def relationOp(node: ASTNode): left = node.left right = node.right if not TypeChecker.isEqual(left, right): return Result( False, f'incomparables types: {left.dataType} and {right.dataType}') else: node.dataType = TypeChecker.BOOLEAN return Result(True)
def logical_op(node: ASTNode): left = node.left right = node.right valid = lambda node: TypeChecker.isStrictlyBoolean( node) or TypeChecker.isLooselyNumeric(node) if valid(left) and valid(right): node.dataType = TypeChecker.BOOLEAN return Result(True) else: return Result(False, getBinaryOpTypeErr(node))
def hybridAdd(node: ASTNode): left = node.left right = node.right validType = lambda node: TypeChecker.isStrictlyString( node) or TypeChecker.isLooselyNumeric(node) if validType(left) and validType(right): node.dataType = TypeChecker.NUMERIC if TypeChecker.isLooselyNumeric( left) and TypeChecker.isLooselyNumeric( right) else TypeChecker.STRING return Result(True) else: return Result(False, getBinaryOpTypeErr(node))
def binaryArithmeticOp(node: ASTNode, _): left = node.left.value right = node.right.value if node.nodeType == ASTNode.MULT: node.value = left * right elif node.nodeType == ASTNode.SUB: node.value = left - right elif node.nodeType == ASTNode.DIV: if right == 0: raise ZeroDivisionError("cannot divide with zero") node.value = left / right else: node.value = left**right node.dataType = Types.NUMERIC
def array_sep(node: ASTNode): left, right = node.left, node.right status, err = None, None isLooselyNumeric = lambda type: type == TypeChecker.NUMERICARRAY or type == TypeChecker.INTARRAY isNumericBool = lambda type: type == TypeChecker.INTARRAY or type == TypeChecker.NUMERICARRAY or type == TypeChecker.BOOLEANARRAY or type == TypeChecker.NUMERIC_BOOL_ARR if TypeChecker.isAtomic(left): ltype = TypeChecker.getArrayTypeBasedOnAtomic(left) else: ltype = left.dataType rtype = TypeChecker.getArrayTypeBasedOnAtomic(right) if ltype == rtype: node.dataType = ltype status = True elif isLooselyNumeric(ltype) and isLooselyNumeric(rtype): node.dataType = TypeChecker.NUMERICARRAY status = True elif isNumericBool(ltype) and isNumericBool(rtype): node.dataType = TypeChecker.NUMERIC_BOOL_ARR status = True else: status = False err = f"Array cannot hold different types: {TypeChecker.getAtomicTypeBasedOnArray(ltype)} and {TypeChecker.getAtomicTypeBasedOnArray(rtype)}" return Result(status, err)
def strictArithmeticBinaryOp(node: ASTNode): """ Apply type system rules for '*', '/', '-', '^' :param node: :return: """ left = node.left right = node.right if TypeChecker.isLooselyNumeric(left) and TypeChecker.isLooselyNumeric( right): node.dataType = TypeChecker.NUMERIC return Result(True) else: return Result(False, getBinaryOpTypeErr(node))
def binaryComparisonOp(node: ASTNode, _): left = node.left.value right = node.right.value if node.nodeType == ASTNode.EQ: node.value = left == right elif node.nodeType == ASTNode.NE: node.value = left != right elif node.nodeType == ASTNode.GT: node.value = left > right elif node.nodeType == ASTNode.LT: node.value = left < right elif node.nodeType == ASTNode.GTE: node.value = left >= right else: node.value = left <= right node.dataType = Types.BOOLEAN
def undefined(node: ASTNode): node.dataType = TypeChecker.UNDEFINED return Result(True)
def var(node: ASTNode, env): #DATABASE QUERY THAT CHECKS IF VAR EXISTS node.dataType = env(node) return Result(True)
def enum(node: ASTNode, env): node.dataType = TypeChecker.ENUM return Result(True)
def string(node: ASTNode): node.dataType = TypeChecker.STRING return Result(True)
def integer(node: ASTNode): node.dataType = TypeChecker.INTEGER return Result(True)
def boolconstant(node: ASTNode): node.dataType = TypeChecker.BOOLEAN return Result(True)
def undefined(node: ASTNode, _): node.dataType = Types.UNDEFINED
def string(node: ASTNode, _): node.dataType = Types.STRING
def negate(node: ASTNode, _): node.value = -node.left.value node.dataType = Types.NUMERIC
def reverse_string(node: ASTNode, _): node.value = node.left.value[::-1] node.dataType = Types.STRING
def notOp(node: ASTNode, _): node.value = not node.left.value node.dataType = Types.BOOLEAN
def boolConst(node: ASTNode, _): node.dataType = Types.BOOLEAN
def integer(node: ASTNode, _): node.dataType = Types.INTEGER