def typecheck_mult(node, c, method, t_i, c_i): expected_node = ['MultiplyExpression', 'DivideExpression', 'ModuloExpression'] if node.name not in expected_node: logging.error("FATAL ERROR: expected", expected_node) sys.exit(1) if len(node.children) == 0: logging.error("FATAL ERROR: %s has no children in typecheck_mult()" % expected_node) sys.exit(1) elif len(node.children) != 2: logging.error('FATAL ERROR: typecheck_mult got %s node with %d children' % (node.name, len(node.children))) sys.exit(1) else: t1 = typecheck_expr(node[0], c, method, t_i, c_i) t2 = typecheck_expr(node[1], c, method, t_i, c_i) if primitives.is_numeric(t1) and primitives.is_numeric(t2): node.typ = 'Int' return node.typ else: logging.error("typecheck failed: mult/div/mod not num") sys.exit(42)
def typecheck_relational(node, c, method, t_i, c_i): expected_node = ['LessThanExpression', 'LessThanEqualExpression', 'GreaterThanExpression', 'GreaterThanEqualExpression'] if node.name not in expected_node: logging.error("FATAL ERROR: typecheck_relational() expected", expected_node) sys.exit(1) if len(node.children) == 0: logging.error("FATAL ERROR: has no children", expected_node) sys.exit(1) elif len(node.children) != 2: logging.error('FATAL ERROR: typecheck_relational() on expression %s with %d children' % (node.name, len(node.children))) sys.exit(1) else: t1 = typecheck_expr(node[0], c, method, t_i, c_i) t2 = typecheck_expr(node[1], c, method, t_i, c_i) if primitives.is_numeric(t1) and primitives.is_numeric(t2): node.typ = 'Boolean' return node.typ else: logging.error("typecheck failed: Relational:", t1, t2) sys.exit(42)
def typecheck_add(node, c, method, t_i, c_i): expected_node = ['AddExpression', 'SubtractExpression'] if node.name not in expected_node: logging.error("FATAL ERROR: expected", expected_node) sys.exit(1) if len(node.children) == 0: logging.error("FATAL ERROR: %s has no children" % expected_node) sys.exit(1) elif len(node.children) != 2: logging.error('FATAL ERROR: typecheck_add() on expression %s with %d children' % (node.name, len(node.children))) sys.exit(1) else: t1 = typecheck_expr(node[0], c, method, t_i, c_i) t2 = typecheck_expr(node[1], c, method, t_i, c_i) if node.name == 'AddExpression' and \ (t1 == "java.lang.String" or t2 == "java.lang.String"): if t1 != "Void" and t2 != "Void": node.typ = 'java.lang.String' return node.typ else: logging.error("typecheck failed: string add void") sys.exit(42) elif primitives.is_numeric(t1) and primitives.is_numeric(t2): node.typ = 'Int' return node.typ else: logging.error("typecheck failed: Add:", t1, t2) sys.exit(42)
def gen_add_expr(info, node, method_obj): output = [] # Numbers, just add. if primitives.is_numeric(node[0].typ) and primitives.is_numeric(node[1].typ): output.extend(gen_binary_expr_common(info, node, method_obj)) output.append('add eax, ebx') # If they are objects, we do the following: # 1. Use String.valueOf() on each operand. # 2. Do a LHS.concat(RHS), which returns a new string. elif node[0].typ == 'java.lang.String' or node[1].typ == 'java.lang.String': # Convert LHS to a string. output.extend(gen_string_valueof(info, node[0], method_obj)) output.append('push eax') # Convert RHS to a string. output.extend(gen_string_valueof(info, node[1], method_obj)) output.append('push eax') # Receiver is LHS, Argument is RHS (already done!), just need to call # the correct method. output.append('call METHOD~java.lang.String.concat~java.lang.String') # Jump back. output.append('add esp, 8') else: logging.error('FATAL ERROR: invalid add') sys.exit(1) return output
def typecheck_equality(node, c, method, t_i, c_i): expected_node = ['EqualExpression', 'NotEqualExpression'] if node.name not in expected_node: logging.error("FATAL ERROR: expected", expected_node) sys.exit(1) if len(node.children) == 0: logging.error("FATAL ERROR: has no children", expected_node) sys.exit(1) elif len(node.children) != 2: logging.error('FATAL ERROR: typecheck_equality on %d children' % len(node.children)) sys.exit(1) else: t1 = typecheck_expr(node[0], c, method, t_i, c_i) t2 = typecheck_expr(node[1], c, method, t_i, c_i) if primitives.is_numeric(t1) and primitives.is_numeric(t2): node.typ = "Boolean" return node.typ elif t1 == "Boolean" and t2 == "Boolean": node.typ = "Boolean" return node.typ elif is_assignable(t1, t2, c_i) or is_assignable(t2, t1, c_i): node.typ = "Boolean" return node.typ else: logging.error("typecheck failed: equality between", t1, t2) sys.exit(42)
def typecheck_cast_expression(node, c, method, t_i, c_i): if node.name != 'CastExpression': logging.error('FATAL: Invalid node %s for typecheck_cast_expression' % node.name) sys.exit(1) expr_type = typecheck_expr(node[1], c, method, t_i, c_i) if (primitives.is_numeric(expr_type) and primitives.is_numeric(node[0].canon)) \ or is_assignable(expr_type, node[0].canon, c_i) \ or is_assignable(node[0].canon, expr_type, c_i): return node[0].canon else: logging.error('Cast expression of type %s into %s' % (expr_type, node[0].canon)) sys.exit(42)
def typecheck_array_access(node, c, method, t_i, c_i): if node.name != 'ArrayAccess': logging.error('FATAL ERROR: invalid node %s for array access' % node.name) sys.exit(1) receiver_type = None if node[0][0].name == 'Name': receiver_type = typecheck_name(node[0][0]) else: receiver_type = typecheck_expr(node[0][0], c, method, t_i, c_i) # Must be array type. if not is_array_type(receiver_type): logging.error('Cannot index into non-array type') sys.exit(42) # Expression must be a number. expr_type = typecheck_expr(node[1], c, method, t_i, c_i) if not primitives.is_numeric(expr_type): logging.error('Array access with non-numeric type %s' % expr_type) sys.exit(42) node.typ = get_arraytype(receiver_type) return node.typ
def is_assignable(type1, type2, c_i): # Call other helper for anything having to do with arrays. if is_array_type(type1) or is_array_type(type2): return is_array_assignable(type1, type2, c_i) if type1 in ['Void', 'Null'] or type2 == 'Void': return False elif type1 == type2: return True elif primitives.is_reference(type1) and type2 == 'Null': return True elif primitives.is_numeric(type1) and primitives.is_numeric(type2): return primitives.is_widening_conversion(type1, type2) elif primitives.is_reference(type1) and primitives.is_reference(type2): return is_nonstrict_subclass(type1, type2, c_i) else: return False
def typecheck_creation(node, c, method, t_i, c_i): expected_node = 'CreationExpression' if node.name != expected_node: logging.error("FATAL ERROR: expected", expected_node) sys.exit(1) creation_type = node[0].canon if is_array_type(creation_type): if len(node[1].children) > 1: logging.error('Too many args to array creation') sys.exit(42) if len(node[1].children) == 1: expr_type = typecheck_expr(node[1][0], c, method, t_i, c_i) if not primitives.is_numeric(expr_type): logging.error('Invalid array creation argument') sys.exit(42) node.typ = creation_type return node.typ else: cons_name = creation_type.split('.')[-1] # Check that we don't call constructor of an abstract class. if 'Abstract' in c_i[creation_type].mods: logging.error('Cannot call constructor of abstract class') sys.exit(42) arg_types = [] for arg_expr in node[1].children: arg_types.append(typecheck_expr(arg_expr, c, method, t_i, c_i)) cons_decl = name_resolve.constructor_accessable(c_i, t_i, creation_type, cons_name, arg_types, c.name, False) cons = class_hierarchy.Temp_Constructor(cons_name, arg_types) # TODO: Check that cons is not protected, and if it is, we have access # to call it. if cons_decl != None and cons in c_i[creation_type].declare: node.typ = creation_type return node.typ else: logging.error('Invalid constructor call') sys.exit(42)
def gen_string_valueof(info, node, method_obj): output = [] # Evaluate node. Result is in eax. output.extend(gen_expr(info, node, method_obj)) # Based on the type, call the correct method. Primitives have their own # version, objects all use the java.lang.Object version. valueof_method_lbl = '' if primitives.is_numeric(node.typ) or node.typ == 'Boolean' or \ node.typ == 'java.lang.String': valueof_method_lbl = 'STATICMETHOD~java.lang.String.valueOf~%s' % node.typ else: valueof_method_lbl = 'STATICMETHOD~java.lang.String.valueOf~java.lang.Object' output.append('push eax') output.append('call %s' % valueof_method_lbl) # resulting string is in eax output.append('add esp, 4') return output # result is in eax
def typecheck_unary(node, c, method, t_i, c_i): if node.name not in ['NotExpression', 'NegateExpression']: logging.error("FATAL ERROR: typecheck_unary()") sys.exit(1) if len(node.children) == 0: logging.error("FATAL ERROR: UnaryExpression has no children") sys.exit(1) if node.name == 'NotExpression': t = typecheck_expr(node[0], c, method, t_i, c_i) if t != "Boolean": logging.error("typecheck failed: NotOp expects boolean; got:",t) sys.exit(42) node.typ = t return t elif node.name == 'NegateExpression': t = typecheck_expr(node[0], c, method, t_i, c_i) if not primitives.is_numeric(t): logging.error("typecheck failed: SubtractOp expects number; got:",t) sys.exit(42) node.typ = t return t
def try_eval_expr(node): if node.name == 'Literal': if node[0].name == 'BooleanLiteral': return node[0].value.value == "true" elif node[0].name == 'DecimalIntegerLiteral': return int(node[0].value.value) else: pass # TODO STRINGS AND SHIT F**K elif node.name == 'OrExpression': expr1 = try_eval_expr(node[0]) expr2 = try_eval_expr(node[1]) if expr1 != None and expr2 != None: ret = expr1 == True or expr2 == True return ret elif node.name == 'AndExpression': expr1 = try_eval_expr(node[0]) expr2 = try_eval_expr(node[1]) if expr1 != None and expr2 != None: ret = expr1 == True and expr2 == True return ret elif node.name in ['EqualExpression', 'NotEqualExpression']: expr1 = None expr2 = None if node[0].typ == 'Boolean' or primitives.is_numeric(node[0].typ): expr1 = try_eval_expr(node[0]) expr2 = try_eval_expr(node[1]) if expr1 != None and expr2 != None: if node.name == 'EqualExpression': return expr1 == expr2 else: return expr1 != expr2 else: return None else: return None elif node.name in ['LessThanExpression', 'LessThanEqualExpression', 'GreaterThanExpression', 'GreaterThanEqualExpression']: expr1 = None expr2 = None if primitives.is_numeric(node[0].typ): expr1 = try_eval_expr(node[0]) expr2 = try_eval_expr(node[1]) if expr1 != None and expr2 != None: if node.name == 'LessThanExpression': return expr1 < expr2 elif node.name == 'GreaterThanExpression': return expr1 > expr2 elif node.name == 'LessThanEqualExpression': return expr1 <= expr2 elif node.name == 'GreaterThanEqualExpression': return expr1 >= expr2 else: return None elif node.name in ['AddExpression', 'SubtractExpression']: expr1 = None expr2 = None if primitives.is_numeric(node[0].typ): expr1 = try_eval_expr(node[0]) expr2 = try_eval_expr(node[1]) if expr1 != None and expr2 != None: if node.name == 'AddExpression': return expr1 + expr2 elif node.name == 'SubtractExpression': return expr1 - expr2 else: return None elif node.name in ['MultiplyExpression', 'DivideExpression', 'ModuloExpression']: expr1 = None expr2 = None if primitives.is_numeric(node[0].typ): expr1 = try_eval_expr(node[0]) expr2 = try_eval_expr(node[1]) if expr1 != None and expr2 != None: if node.name == 'MultiplyExpression': return expr1 * expr2 elif node.name == 'DivideExpression': return expr1 / expr2 elif node.name == 'ModuloExpression': return None # TODO WHAT MODULO TOO HARD I GIVE UP - Holden else: return None elif node.name in ['NegateExpression', 'NotExpression']: # TODO FUUUUUUUUUUUUUUUUU pass elif node.name == 'CastExpression': return try_eval_expr(node[1]) elif node.name == 'PostfixExpression': return try_eval_expr(node[0]) return None