def _fix_decl_name_type(self, decl, typename): """ Fixes a declaration. Modifies decl. """ # Reach the underlying basic type type = decl while not isinstance(type, ast.VarDecl): type = type.type decl.name = type.declname # The typename is a list of types. If any type in this # list isn't an Type, it must be the only # type in the list. # If all the types are basic, they're collected in the # Type holder. for tn in typename: if not isinstance(tn, ast.Type): if len(typename) > 1: self._parse_error("Invalid multiple types specified", tn.coord) else: type.type = tn return decl if not typename: # Functions default to returning int if not isinstance(decl.type, ast.FuncDecl): self._parse_error("Missing type in declaration", decl.coord) type.type = ast.Type("int", coord=decl.coord) else: # At this point, we know that typename is a list of Type # nodes. Concatenate all the names into a single list. type.type = ast.Type(typename[0].names, coord=typename[0].coord) return decl
def vFunctionCall(self, node): node.symtab = self.curr_symtab self.visit(node.params) if node.callee: self.visit(node.callee) if node.id == 'sort' and node.params and len( node.params.children) >= 2: par1 = node.params.children[0] if isinstance(par1, ast.FunctionCall) and par1.callee and isinstance( par1.callee.resolveType(), ast.VectorType): tpeSorted = par1.callee.resolveType().subtype.resolveType() node.isSortCall = True node.sortComp = 'standardless' if len(node.params.children) == 3 and isinstance( node.params.children[2], ast.Identifier): node.sortComp = 'f_' + node.params.children[ 2].id + '_' + tpeSorted.type + '_' + tpeSorted.type node.sortFuncName = self.curr_symtab.addSortCall( par1.callee.resolveType(), node.sortComp) node.sortVector = par1.callee node.sortType = par1.callee.resolveType() if len(node.params.children) > 2: (a, b) = self.findFunction( node.symtab, 'f_' + node.params.children[2].id, [node.sortType.subtype, node.sortType.subtype]) #(node.sortFuncOrigName, node.sortFuncType) = self.findFunction(node.symtab, 'f_' + node.params.children[2].id, [node.sortType.subtype, node.sortType.subtype]) node.sortFuncOrigName = a node.sortFuncType = b else: node.sortFuncOrigName = "" node.sortFuncType = ast.Type('error') #print node.sortFuncOrigName #print node.sortFuncType #print node.sortFuncType.type else: funcnames = node.symtab.get('__functionnames__') if isinstance(funcnames, ast.Type) and funcnames.type == 'error': return funcs = funcnames.get(node.id, None) if funcs: bestCandidate = None bestCandidateType = ast.Type('error') for long_name, tpe in funcs.iteritems(): if len(tpe.params) == len(node.params.children): good = True #print tpe.params for i in range(0, len(tpe.params)): if not node.params.children[i].resolveType( ).canCoerceType(tpe.params[i].resolveType()): good = False if good: bestCandidate = long_name bestCandidateType = tpe if bestCandidate: node.id = bestCandidate node.type = bestCandidateType
def p_var_id(p): 'var : ID dim_star' global current_class, current_context, current_modifiers, current_type global current_vartable, current_variable_kind if p[2] == 0: ftype = current_type else: ftype = ast.Type(current_type, params=p[2]) if (current_context == 'class'): if (current_class.lookup_field(p[1])): signal_error( 'Duplicate definition of field {0} in class!'.format(p[1]), p.lineno(1)) else: (v, s) = current_modifiers f = ast.Field(p[1], current_class, v, s, ftype) current_class.add_field(p[1], f) else: # we're in a method/constructor # Then, current_vartable is the current table of variables if (current_vartable.find_in_current_block(p[1])): signal_error( 'Duplicate definition of variable {0} within the same block!'. format(p[1]), p.lineno(1)) else: current_vartable.add_var(p[1], current_variable_kind, ftype)
def p_type_specifier(self, p): """ type_specifier : VOID | CHAR | INT | FLOAT """ p[0] = ast.Type([p[1]], coord=self._token_coord(p, 1))
def p_type_id(p): 'type : ID' global current_type baseclass = ast.lookup(ast.classtable, p[1]) if (baseclass == None): signal_error('Class {0} does not exist!'.format(p[1]), p.lineno(1)) p[0] = current_type = ast.Type(baseclass.name)
def findFunction(self, symtab, id, node_params): funcnames = symtab.get('__functionnames__') #print funcnames bestCandidate = None bestCandidateType = ast.Type('error') if isinstance(funcnames, ast.Type) and funcnames.type == 'error': return (bestCandidate, bestCandidateType) funcs = funcnames.get(id, None) #print id if funcs: #print "here1" for long_name, tpe in funcs.iteritems(): if len(tpe.params) == len(node_params): good = True #print tpe.params for i in range(0, len(tpe.params)): if not node_params[i].resolveType().canCoerceType( tpe.params[i].resolveType()): good = False if good: bestCandidate = long_name bestCandidateType = tpe #if bestCandidate: #node.id = bestCandidate #node.type = bestCandidateType return (bestCandidate, bestCandidateType)
def p_new_array(p): 'new_array : NEW type dim_expr_plus dim_star' if (p[4] == 0): t = p[2] else: t = ast.Type(p[2], params=p[4]) p[0] = ast.NewArrayExpr(t, p[3], p.lineno(1))
def vProgram(self, node): self.root_symtab = Symtab() doubleType = ast.Type('double') doubleType.symtab = self.root_symtab self.root_symtab.entries['M_PI'] = doubleType self.curr_symtab = self.root_symtab self.vNodeList(node) node.symtab = self.root_symtab
def p_type_02(t): '''type : VOID | INT | FLOAT | DOUBLE | CHAR | BOOL | STRING''' t[0] = ast.Type(t[1])
def vAssignmentStatement(self, node): if isinstance( node.expr, ast.Constructor) and node.expr.type.resolveType().isVector(): self.w('New') self.w('(') self.visit(node.lval) cons = node.expr while isinstance(cons, ast.Constructor): self.w(',') #print cons.params self.visit(cons.params.children[0]) if len(cons.params.children) == 1: cons = None break else: cons = cons.params.children[1] if cons != None: print '****************Need to initialize******************' self.w(')') elif isinstance(node.expr, ast.AssignmentStatement): self.visit(node.expr) self.p(';') tmp = node.expr if isinstance(node.expr.lval, str): node.expr = ast.Identifier(node.expr.lval) else: node.expr = node.expr.lval node.expr.symtab = node.symtab self.visit(node) node.expr = tmp else: ident = node.lval ident.symtab = node.symtab oldexpr = node.expr if node.operator != '=': node.expr = ast.BinaryOp( ident, self.assignmentOperators[node.operator], ast.Parenthesis(node.expr)) node.expr.symtab = node.symtab tpe_ident = ident.resolveType().type tpe_expr = node.expr.resolveType().type #if isinstance(ident.resolveType(), ast.StructType): #print ident.resolveType().id #print tpe_ident #if isinstance(node.expr.resolveType().resolveType(), ast.StructType): #print node.expr.resolveType().resolveType().id #print tpe_expr if tpe_ident != tpe_expr and not ( (tpe_ident == 'float' and tpe_expr == 'double') or (tpe_ident == 'double' and tpe_expr == 'float')): node.expr = ast.CastExpression(ast.Type(tpe_ident), node.expr) node.expr.symtab = node.symtab self.visit(node.lval) self.w(':=') self.visit(node.expr) node.expr = oldexpr
def p_method_decl_header_void(p): 'method_header : mod VOID ID' global current_context, current_vartable current_context = 'method' (v, s) = current_modifiers m = ast.Method(p[3], current_class, v, s, ast.Type('void')) current_class.add_method(m) current_vartable = m.vars p[0] = m
def type_spec(self): """type_spec : INTEGER | REAL """ token = self.current_token if self.current_token.type == TokenType.INTEGER: self.eat(TokenType.INTEGER) else: self.eat(TokenType.REAL) node = ast.Type(token) return node
def vBinaryOp(self, node): # falta and or xor bit a bit pascalOp = self.t[node.oper] if (pascalOp == 'AND') or ( pascalOp == 'OR' ): # podriamos necesitar para todos los operadores hacer un in! self.w('(') self.visit(node.left) self.w(')') self.w(pascalOp) self.w('(') self.visit(node.right) self.w(')') elif (pascalOp == 'DIV'): left_type = node.left.resolveType().type right_type = node.right.resolveType().type divOp = 'DIV' if (left_type == 'float' or left_type == 'double' or right_type == 'float' or right_type == 'double'): divOp = '/' self.visit(node.left) self.w(divOp) self.visit(node.right) elif pascalOp == '-' or pascalOp == '+' or pascalOp == '=': left_type = node.left.resolveType().type right_type = node.right.resolveType().type #print "left " + left_type #print "right " + right_type if (left_type == 'char'): node.left = ast.CastExpression(ast.Type('int'), node.left) if (right_type == 'char'): node.right = ast.CastExpression(ast.Type('int'), node.right) self.visit(node.left) self.w(pascalOp) self.visit(node.right) else: self.visit(node.left) self.w(pascalOp) self.visit(node.right)
def get(self, name): """Retrieves the symbol with the given name from the symbol table, recursing upwards through parent symbol tables if it is not found in the current one.""" if self.entries.has_key(name): return self.entries[name] else: if self.parent != None: return self.parent.get(name) else: return ast.Type('error')
def vWhileStatement(self, node): self.w('WHILE') if not node.cond.resolveType().isBool(): cast = ast.CastExpression(ast.Type('bool'), node.cond) cast.type.symtab = node.symtab cast.symtab = node.symtab self.visit(cast) else: self.visit(node.cond) self.w('DO') self.pi('BEGIN') self.visit(node.loop) self.pu() self.w('END')
def vIfStatement(self, node): self.w('IF') if not node.cond.resolveType().isBool(): cast = ast.CastExpression(ast.Type('bool'), node.cond) cast.type.symtab = node.symtab cast.symtab = node.symtab self.visit(cast) else: self.visit(node.cond) #self.visit(node.cond) self.w('THEN') self.pi('BEGIN') self.visit(node.then) self.pu(';') self.w('END') if node.elze: self.p() self.w('ELSE') self.pi('BEGIN') self.visit(node.elze) self.pu(';') self.w('END')
def p_type_float(p): 'type : FLOAT' global current_type p[0] = current_type = ast.Type('float')
def p_type_bool(p): 'type : BOOLEAN' global current_type p[0] = current_type = ast.Type('boolean')
def p_type_int(p): 'type : INT' global current_type p[0] = current_type = ast.Type('int')
def gen_code(stmt): global current_loop_continue_label, current_enter_then_label, current_break_out_else_label # stmt.end_reg is the destination register for each expression stmt.end_reg = None push_labels() if isinstance(stmt, ast.BlockStmt): for stmt_line in stmt.stmtlist: gen_code(stmt_line) elif isinstance(stmt, ast.ExprStmt): gen_code(stmt.expr) elif isinstance(stmt, ast.AssignExpr): gen_code(stmt.rhs) gen_code(stmt.lhs) if stmt.lhs.type == ast.Type('float') and stmt.rhs.type == ast.Type('int'): conv = absmc.ConvertInstr('itof', stmt.rhs.end_reg) stmt.rhs.end_reg = conv.dst if not isinstance(stmt.lhs, ast.FieldAccessExpr): absmc.MoveInstr('move', stmt.lhs.end_reg, stmt.rhs.end_reg) else: absmc.HeapInstr('hstore', stmt.lhs.base.end_reg, stmt.lhs.offset_reg, stmt.rhs.end_reg) elif isinstance(stmt, ast.VarExpr): stmt.end_reg = stmt.var.reg elif isinstance(stmt, ast.ConstantExpr): reg = absmc.Register() if stmt.kind == 'int': absmc.MoveInstr('move_immed_i', reg, stmt.int, True) elif stmt.kind == 'float': absmc.MoveInstr('move_immed_f', reg, stmt.float, True) elif stmt.kind == 'string': pass elif stmt.kind == 'True': absmc.MoveInstr('move_immed_i', reg, 1, True) elif stmt.kind == 'False': absmc.MoveInstr('move_immed_i', reg, 0, True) elif stmt.kind == 'Null': absmc.MoveInstr('move_immed_i', reg, 'Null', True) stmt.end_reg = reg elif isinstance(stmt, ast.BinaryExpr): if stmt.bop not in ['and', 'or']: gen_code(stmt.arg1) gen_code(stmt.arg2) reg = absmc.Register() flt = ast.Type('float') intg = ast.Type('int') if stmt.arg1.type == flt or stmt.arg2.type == flt: expr_type = 'f' else: expr_type = 'i' if stmt.arg1.type == intg and stmt.arg2.type == flt: conv = absmc.Convert('itof', stmt.arg1.end_reg) stmt.arg1.end_reg = conv.dst elif stmt.arg1.type == flt and stmt.arg2.type == intg: conv = absmc.Convert('itof', stmt.arg2.end_reg) stmt.arg2.end_reg = conv.dst if stmt.bop in ['add', 'sub', 'mul', 'div', 'gt', 'geq', 'lt', 'leq']: absmc.ArithInstr(stmt.bop, reg, stmt.arg1.end_reg, stmt.arg2.end_reg, expr_type) elif stmt.bop == 'eq' or stmt.bop == 'neq': absmc.ArithInstr('sub', reg, stmt.arg1.end_reg, stmt.arg2.end_reg, expr_type) if stmt.bop == 'eq': # check if r2 == r3 # 1. perform sub r1, r2, r3 (done above) # 2. branch to set_one if r1 is zero # 3. else, fall through and set r1 to zero # 4. jump out so we don't set r1 to one by accident ieq_set = absmc.BranchLabel(stmt.lines, 'SET_EQ') ieq_out = absmc.BranchLabel(stmt.lines, 'SET_EQ_OUT') absmc.BranchInstr('bz', ieq_set, reg) absmc.MoveInstr('move_immed_i', reg, 0, True) absmc.BranchInstr('jmp', ieq_out) ieq_set.add_to_code() absmc.MoveInstr('move_immed_i', reg, 1, True) ieq_out.add_to_code() if stmt.bop == 'and': and_skip = absmc.BranchLabel(stmt.lines, 'AND_SKIP') gen_code(stmt.arg1) reg = absmc.Register() absmc.MoveInstr('move', reg, stmt.arg1.end_reg) absmc.BranchInstr('bz', and_skip, stmt.arg1.end_reg) gen_code(stmt.arg2) absmc.MoveInstr('move', reg, stmt.arg2.end_reg) and_skip.add_to_code() if stmt.bop == 'or': or_skip = absmc.BranchLabel(stmt.lines, 'OR_SKIP') gen_code(stmt.arg1) reg = absmc.Register() absmc.MoveInstr('move', reg, stmt.arg1.end_reg) absmc.BranchInstr('bnz', or_skip, stmt.arg1.end_reg) gen_code(stmt.arg2) absmc.MoveInstr('move', reg, stmt.arg2.end_reg) or_skip.add_to_code() stmt.end_reg = reg elif isinstance(stmt, ast.ForStmt): # for-loop: # for (i = 0; i < 10; i++) { # body # } # set i's reg equal to 0 # create a label after this, as this is where we jump back to at end of loop # also create the 'out' label which is what we jump to when breaking out of loop # generate code for the 'cond' (test if i's reg is less than 10's reg) # test if the cond evaluated to false with 'bz', if so, break out of loop # else, fall through into the body of the for-loop # when body is over, generate code to update the var (i++) # jump unconditionally back to the cond_label, where we eval if i is still < 10 gen_code(stmt.init) cond_label = absmc.BranchLabel(stmt.lines, 'FOR_COND') current_enter_then_label = entry_label = absmc.BranchLabel(stmt.lines, 'FOR_ENTRY') current_loop_continue_label = continue_label = absmc.BranchLabel(stmt.lines, 'FOR_UPDATE') current_break_out_else_label = out_label = absmc.BranchLabel(stmt.lines, 'FOR_OUT') cond_label.add_to_code() gen_code(stmt.cond) absmc.BranchInstr('bz', out_label, stmt.cond.end_reg) entry_label.add_to_code() gen_code(stmt.body) continue_label.add_to_code() gen_code(stmt.update) absmc.BranchInstr('jmp', cond_label) out_label.add_to_code() elif isinstance(stmt, ast.AutoExpr): gen_code(stmt.arg) if stmt.when == 'post': tmp_reg = absmc.Register() absmc.MoveInstr('move', tmp_reg, stmt.arg.end_reg) one_reg = absmc.Register() # Load 1 into a register absmc.MoveInstr('move_immed_i', one_reg, 1, True) absmc.ArithInstr('add' if stmt.oper == 'inc' else 'sub', stmt.arg.end_reg, stmt.arg.end_reg, one_reg) if stmt.when == 'post': stmt.end_reg = tmp_reg else: stmt.end_reg = stmt.arg.end_reg elif isinstance(stmt, ast.SkipStmt): pass elif isinstance(stmt, ast.ReturnStmt): current_method.returned = True if stmt.expr is None: absmc.ProcedureInstr('ret') return gen_code(stmt.expr) # Load the result into a0 absmc.MoveInstr('move', absmc.Register('a', 0), stmt.expr.end_reg) # Return to caller absmc.ProcedureInstr('ret') elif isinstance(stmt, ast.WhileStmt): current_loop_continue_label = cond_label = absmc.BranchLabel(stmt.lines, 'WHILE_COND') current_enter_then_label = entry_label = absmc.BranchLabel(stmt.lines, 'WHILE_ENTRY') current_break_out_else_label = out_label = absmc.BranchLabel(stmt.lines, 'WHILE_OUT') cond_label.add_to_code() gen_code(stmt.cond) absmc.BranchInstr('bz', out_label, stmt.cond.end_reg) entry_label.add_to_code() gen_code(stmt.body) absmc.BranchInstr('jmp', cond_label) out_label.add_to_code() elif isinstance(stmt, ast.BreakStmt): absmc.BranchInstr('jmp', current_break_out_else_label) elif isinstance(stmt, ast.ContinueStmt): absmc.BranchInstr('jmp', current_loop_continue_label) elif isinstance(stmt, ast.IfStmt): # if (x == y) # ++x; # else # --x; # generate 2 labels, for the else part, and the out part # test if x == y # if not true, jump to the else part # if true, we're falling through to the then part, then must jump # out right before hitting the else part straight to the out part current_enter_then_label = then_part = absmc.BranchLabel(stmt.lines, 'THEN_PART') current_break_out_else_label = else_part = absmc.BranchLabel(stmt.lines, 'ELSE_PART') out_label = absmc.BranchLabel(stmt.lines, 'IF_STMT_OUT') gen_code(stmt.condition) absmc.BranchInstr('bz', else_part, stmt.condition.end_reg) then_part.add_to_code() gen_code(stmt.thenpart) absmc.BranchInstr('jmp', out_label) else_part.add_to_code() gen_code(stmt.elsepart) out_label.add_to_code() elif isinstance(stmt, ast.FieldAccessExpr): gen_code(stmt.base) cls = ast.lookup(ast.classtable, stmt.base.type.typename) field = ast.lookup(cls.fields, stmt.fname) offset_reg = absmc.Register() ret_reg = absmc.Register() absmc.MoveInstr('move_immed_i', offset_reg, field.offset, True) absmc.HeapInstr('hload', ret_reg, stmt.base.end_reg, offset_reg) stmt.offset_reg = offset_reg stmt.end_reg = ret_reg elif isinstance(stmt, ast.ClassReferenceExpr): stmt.end_reg = absmc.Register('sap') elif isinstance(stmt, ast.NewObjectExpr): recd_addr_reg = absmc.Register() size_reg = absmc.Register() absmc.MoveInstr('move_immed_i', size_reg, stmt.classref.size, True) absmc.HeapInstr('halloc', recd_addr_reg, size_reg) if stmt.constr_id is None: stmt.end_reg = recd_addr_reg return saved_regs = [] saved_regs.append(recd_addr_reg) # add a0 if the current method is not static if current_method.storage != 'static': saved_regs.append(absmc.Register('a', 0)) # for each var in each block of the current method, add to save list for block in range(0, len(current_method.vars.vars)): for var in current_method.vars.vars[block].values(): saved_regs.append(var.reg) # save each reg in the saved list for reg in saved_regs: absmc.ProcedureInstr('save', reg) absmc.MoveInstr('move', absmc.Register('a', 0), recd_addr_reg) arg_reg_index = 1 for arg in stmt.args: gen_code(arg) absmc.MoveInstr('move', absmc.Register('a', arg_reg_index), arg.end_reg) arg_reg_index += 1 absmc.ProcedureInstr('call', 'C_{}'.format(stmt.constr_id)) # restore regs from the now-reversed save list for reg in reversed(saved_regs): absmc.ProcedureInstr('restore', reg) stmt.end_reg = recd_addr_reg elif isinstance(stmt, ast.ThisExpr): stmt.end_reg = absmc.Register('a', 0) elif isinstance(stmt, ast.MethodInvocationExpr): gen_code(stmt.base) cls = ast.lookup(ast.classtable, stmt.base.type.typename) for method in cls.methods: if stmt.mname == method.name: break saved_regs = [] arg_reg_index = 0 # first arg goes into a1 if desired method is not static if method.storage != 'static': arg_reg_index += 1 # add a0 if the current method is not static if current_method.storage != 'static': saved_regs.append(absmc.Register('a', 0)) # for each var in each block of the current method, add to save list for block in range(0, len(current_method.vars.vars)): for var in current_method.vars.vars[block].values(): saved_regs.append(var.reg) # save each reg in the saved list for reg in saved_regs: absmc.ProcedureInstr('save', reg) if method.storage != 'static': absmc.MoveInstr('move', absmc.Register('a', 0), stmt.base.end_reg) for arg in stmt.args: gen_code(arg) absmc.MoveInstr('move', absmc.Register('a', arg_reg_index), arg.end_reg) arg_reg_index += 1 absmc.ProcedureInstr('call', 'M_{}_{}'.format(method.name, method.id)) # Store the result in a temporary register stmt.end_reg = absmc.Register() absmc.MoveInstr('move', stmt.end_reg, absmc.Register('a', 0)) # restore regs from the reversed save list for reg in reversed(saved_regs): absmc.ProcedureInstr('restore', reg) elif isinstance(stmt, ast.UnaryExpr): gen_code(stmt.arg) ret = absmc.Register() if stmt.uop == 'uminus': zero_reg = absmc.Register() if stmt.arg.type == ast.Type('float'): prefix = 'f' else: prefix = 'i' # if uminus, put 0 - <reg> into the return reg absmc.MoveInstr('move_immed_{}'.format(prefix), zero_reg, 0, True) absmc.ArithInstr('sub', ret, zero_reg, stmt.arg.end_reg, prefix) else: # if it's a 0, branch to set 1 # if it's a 1, we're falling through, setting to 0, and jumping out set_one_label = absmc.BranchLabel(stmt.lines, 'SET_ONE') out_label = absmc.BranchLabel(stmt.lines, 'UNARY_OUT') absmc.BranchInstr('bz', set_one_label, stmt.arg.end_reg) absmc.MoveInstr('move_immed_i', ret, 0, True) absmc.BranchInstr('jmp', out_label) set_one_label.add_to_code() absmc.MoveInstr('move_immed_i', ret, 1, True) out_label.add_to_code() stmt.end_reg = ret elif isinstance(stmt, ast.SuperExpr): stmt.end_reg = absmc.Register('a', 0) elif isinstance(stmt, ast.ArrayAccessExpr): # Create fake register. stmt.end_reg = absmc.Register('n', 0) print 'Found an array access. Arrays are not supported.' elif isinstance(stmt, ast.NewArrayExpr): # Create fake register. stmt.end_reg = absmc.Register('n', 0) print 'Found an array creation. Arrays are not supported.' else: print 'need instance ' + str(type(stmt)) pop_labels()
def p_type(p): '''type : HASH TYPENAME''' p[0] = ast.Type(p[2], lineno=p.lineno(1))
def vVariableDeclaration(self, node): tpe = node.type.resolveType() tpe.symtab = node.symtab if tpe.isVector() and node.params: self.w('VAR') self.w(node.id) self.w(':') if tpe.isVector() or tpe.isString(): #print "initVectorType" + tpe.type tpe = self.initializeVectorType(tpe, node) tpe.symtab = node.symtab self.visit(tpe) if tpe.isVector() and node.params: self.p(';') self.w('New') self.w('(') self.w(node.id) t = tpe while t.isVector(): if t.size != None: self.w(',') self.visit(t.size) else: print 'Vectors need to be initialized fully at creation.' break t = t.subtype self.w(')') if (tpe.isVector() or tpe.isString()) and node.params and len( node.params.children) == 2: self.w(';') if self.needsInitialization(node): self.p(';') self.initializeVector(node, node.type.resolveType(), [], 1, node.id) return if tpe.constant and node.isTopLevel: self.w('CONST') else: self.w('VAR') self.w(node.id) self.w(':') if tpe.isVector() or tpe.isString(): #print "initVectorType" + tpe.type tpe = self.initializeVectorType(tpe, node) tpe.symtab = node.symtab self.visit(tpe) if tpe.isVector() and node.params: self.w('(') t = tpe while t.isVector(): self.visit(t.size) if t.subtype.isVector(): self.w(',') t = t.subtype self.w(')') elif tpe.isString(): if tpe.size: self.w('[') if not tpe.size.resolveType().isInt(): tpe_int = ast.Type('int') tpe_int.symtab = node.symtab cast = ast.CastExpression(tpe_int, tpe.size) cast.symtab = node.symtab self.visit(cast) else: self.visit(tpe.size) self.w(']') if (tpe.isVector() or tpe.isString()) and node.params and len( node.params.children) == 2: if self.needsInitialization(node): self.p(';') self.initializeVector(node, node.type.resolveType(), [], 1, node.id) elif node.init: expr = node.init tpe_expr = expr.resolveType() tpe_ident = node.type if tpe_ident.type != tpe_expr.type and not ( tpe_ident.isFloatingPoint() and tpe_expr.isFloatingPoint()): expr = ast.CastExpression(tpe_ident, node.init) self.w('=') self.visit(expr)
def makebool(value): b = ast.BoolConst(value) b.ty = ast.Type('bool') return b
def expr_error(expr): '''Return whether or not the expression has a type or resolution error. Also ensures that the type of the expression is calculated. Call this first if you need to use the type of an expression.''' expr.type = None if isinstance(expr, ast.ConstantExpr): if expr.kind == 'int' or expr.kind == 'float' or expr.kind == 'string': expr.type = ast.Type(expr.kind) elif expr.kind == 'Null': expr.type = ast.Type('null') elif expr.kind == 'True' or expr.kind == 'False': expr.type = ast.Type('boolean') else: expr.type = ast.Type('error') signal_error('Unknown type {}'.format(expr.type), expr.lines) elif isinstance(expr, ast.VarExpr): expr.type = expr.var.type elif isinstance(expr, ast.UnaryExpr): arg = expr.arg arg_err = expr_error(arg) if arg_err: expr.type = ast.Type('error') elif expr.uop == 'uminus': if arg.type.is_numeric(): expr.type = arg.type else: signal_error( 'Expecting an integer or float argument to unary ' 'minus. Found {}'.format(arg.type), expr.lines) expr.type = ast.Type('error') elif expr.uop == 'neg': if arg.type == ast.Type('boolean'): expr.type = arg.type else: signal_error( 'Expecting a boolean argument to ! (negation). ' 'Found {}'.format(arg.type), expr.lines) expr.type = ast.Type('error') elif isinstance(expr, ast.BinaryExpr): op_names = { 'add': '+', 'sub': '-', 'mul': '*', 'div': '/', 'and': '&&', 'or': '||', 'eq': '==', 'neq': '!=', 'lt': '<', 'leq': '<=', 'gt': '>', 'geq': '>=' } bop = expr.bop arg1 = expr.arg1 arg2 = expr.arg2 arg1_err = expr_error(arg1) arg2_err = expr_error(arg2) if arg1_err or arg2_err: expr.type = ast.Type('error') elif bop == 'add' or bop == 'sub' or bop == 'mul' or bop == 'div': type1 = arg1.type type2 = arg2.type if type1.is_numeric() and type2.is_numeric(): if type1 == ast.Type('float') or type2 == ast.Type('float'): expr.type = ast.Type('float') else: expr.type = ast.Type('int') else: signal_error( 'Expecting float or integer arguments for the ' 'operator "{}". Found {} on the left and {} on ' 'the right.'.format(op_names[bop], type1, type2), expr.lines) expr.type = ast.Type('error') elif bop == 'and' or bop == 'or': type1 = arg1.type type2 = arg2.type if type1 == ast.Type('boolean') and type2 == ast.Type('boolean'): expr.type = ast.Type('boolean') else: signal_error( 'Expecting boolean arguments for the operator ' '"{}". Found {} on the left and {} on the ' 'right.'.format(op_names[bop], type1, type2), expr.lines) elif bop == 'lt' or bop == 'leq' or bop == 'gt' or bop == 'geq': type1 = arg1.type type2 = arg2.type if type1.is_numeric() and type2.is_numeric(): expr.type = ast.Type('boolean') else: signal_error( 'Expecting int or float arguments for the' 'operator "{}". Found {} on the left and {} on ' 'the right.'.format(op_names[bop], type1, type2), expr.lines) expr.type = ast.Type('error') elif bop == 'eq' or bop == 'neq': type1 = arg1.type type2 = arg2.type if type1.subtype_of(type2) or type2.subtype_of(type1): expr.type = ast.Type('boolean') else: signal_error( 'Expecting compatible arguments for the operator ' '"{}". One argument must be the subtype of the ' 'other. Found {} on the left and {} on the ' 'right.'.format(op_names[bop], type1, type2), expr.lines) expr.type = ast.Type('error') elif isinstance(expr, ast.FieldAccessExpr): err = expr_error(expr.base) if err: expr.type = ast.Type('error') return True cls = ast.lookup(ast.classtable, expr.base.type.typename) cur_cls = cls while cur_cls is not None: field = ast.lookup(cur_cls.fields, expr.fname) if field is not None: # Ensure it's not static, and not accessed by Class.foo, and it's accessable if (expr.base.type.kind == 'class') and (field.storage != 'static') \ and ((field.visibility != 'private') or (expr.base.type.typename == current_class.name)): break # Ensure it's static, and accessed by Class.foo, and it's accessable if (expr.base.type.kind == 'class-literal') and (field.storage == 'static') \ and ((field.visibility != 'private') or (expr.base.type.typename == current_class.name)): break field = None cur_cls = cur_cls.superclass if field is None: signal_error('Could not resolve field {}'.format(expr.fname), expr.lines) expr.type = ast.Type('error') return True expr.type = ast.Type(field.type) elif isinstance(expr, ast.ThisExpr): expr.type = ast.Type(current_class.name) elif isinstance(expr, ast.MethodInvocationExpr): err = expr_error(expr.base) if err: expr.type = ast.Type('error') return True cls = ast.lookup(ast.classtable, expr.base.type.typename) method = None cur_cls = cls while cur_cls is not None: for i in cur_cls.methods: if expr.mname == i.name: method = i break if method is not None: if (expr.base.type.kind == 'class') and (method.storage != 'static') \ and ((method.visibility != 'private') or (expr.base.type.typename == current_class.name)): break if (expr.base.type.kind == 'class-literal') and (method.storage == 'static') \ and ((method.visibility != 'private') or (expr.base.type.typename == current_class.name)): break method = None cur_cls = cur_cls.superclass if method is None: expr.type = ast.Type('error') signal_error('Could not resolve method \'{}\''.format(expr.mname), expr.lines) return True method_params = method.vars.vars[0].values() # Ensure number of params match if len(method_params) != len(expr.args): expr.type = ast.Type('error') signal_error( 'Method \'{}\' expects {} args, received {}'.format( method.name, len(method_params), len(expr.args)), expr.lines) return True for i in range(0, len(method_params)): arg_err = expr_error(expr.args[i]) if arg_err: expr.type = ast.Type('error') return True nth_param = ast.Type(method_params[i].type) nth_arg = ast.Type(expr.args[i].type) if not nth_arg.subtype_of(nth_param): expr.type = ast.Type('error') signal_error( 'Method argument number {0} is not a subtype ' 'of construtor parameter number {0}. Expects \'{1}\', received \'{2}\'.' .format(i + 1, nth_param.typename, nth_arg.typename), expr.lines) return True expr.type = ast.Type(method.rtype) elif isinstance(expr, ast.AssignExpr): lhs_err = expr_error(expr.lhs) rhs_err = expr_error(expr.rhs) if lhs_err or rhs_err: expr.type = ast.Type('error') return True lhs = ast.Type(expr.lhs.type) rhs = ast.Type(expr.rhs.type) if not rhs.subtype_of(lhs): expr.type = ast.Type('error') signal_error('{} not a subtype of {}'.format(rhs, lhs), expr.lines) else: expr.type = ast.Type(rhs) elif isinstance(expr, ast.NewObjectExpr): cls = ast.lookup(ast.classtable, expr.classref.name) expr.constr_id = None # After ensuring the # of args match, if there's no constructor, allow it if len(cls.constructors) == 0 and len(expr.args) == 0: expr.type = ast.Type(expr.classref.name) return False if cls.constructors[0].visibility == 'private': expr.type = ast.Type('error') signal_error( 'Constructor for class {} is private'.format(cls.name), expr.lines) return True # Ensure number of args match if len(cls.constructors[0].vars.vars[0]) != len(expr.args): expr.type = ast.Type('error') signal_error( 'Constructor for class {} expects {} arguments, received {}'. format(cls.name, len(cls.constructors[0].vars.vars[0]), len(expr.args)), expr.lines) return True constr_params = cls.constructors[0].vars.vars[0].values() # Ensure each arg is a subtype of each param for i in range(0, len(constr_params)): arg_err = expr_error(expr.args[i]) if arg_err: expr.type = ast.Type('error') return True nth_param = ast.Type(constr_params[i].type) nth_arg = ast.Type(expr.args[i].type) if not nth_arg.subtype_of(nth_param): expr.type = ast.Type('error') signal_error( 'Constructor argument number {0} is not a subtype ' 'of construtor parameter number {0}. Expects \'{1}\', received \'{2}\'.' .format(i + 1, nth_param.typename, nth_arg.typename), expr.lines) return True expr.constr_id = cls.constructors[0].id expr.type = ast.Type(expr.classref.name) elif isinstance(expr, ast.ClassReferenceExpr): expr.type = ast.Type(expr.classref.name, None, True) elif isinstance(expr, ast.SuperExpr): if current_class.superclass is None: signal_error( 'Class {} has no superclass.'.format(current_class.name), expr.lines) expr.type = ast.Type('error') else: expr.type = ast.Type(current_class.superclass.name) elif isinstance(expr, ast.AutoExpr): err = expr_error(expr.arg) if err: expr.type = ast.Type('error') return True if expr.arg.type.is_numeric(): expr.type = ast.Type(expr.arg.type) else: expr.type = ast.Type('error') signal_error( 'Auto expression must be int or float; received {}'.format( expr.arg.type), expr.lines) elif isinstance(expr, ast.ArrayAccessExpr) or isinstance( expr, ast.NewArrayExpr): expr.type = ast.Type('error') signal_error("Array expression found, this is not supported!", expr.lines) return expr.type.is_error()
def get_random_type(): return ast.Type(get_rand_int(1, ast.Type.count()))