MethodCallExprAST.py revision 6882
16691Stjones1@inf.ed.ac.uk# Copyright (c) 1999-2008 Mark D. Hill and David A. Wood 26691Stjones1@inf.ed.ac.uk# Copyright (c) 2009 The Hewlett-Packard Development Company 36691Stjones1@inf.ed.ac.uk# All rights reserved. 46691Stjones1@inf.ed.ac.uk# 56691Stjones1@inf.ed.ac.uk# Redistribution and use in source and binary forms, with or without 66691Stjones1@inf.ed.ac.uk# modification, are permitted provided that the following conditions are 76691Stjones1@inf.ed.ac.uk# met: redistributions of source code must retain the above copyright 86691Stjones1@inf.ed.ac.uk# notice, this list of conditions and the following disclaimer; 96691Stjones1@inf.ed.ac.uk# redistributions in binary form must reproduce the above copyright 106691Stjones1@inf.ed.ac.uk# notice, this list of conditions and the following disclaimer in the 116691Stjones1@inf.ed.ac.uk# documentation and/or other materials provided with the distribution; 126691Stjones1@inf.ed.ac.uk# neither the name of the copyright holders nor the names of its 136691Stjones1@inf.ed.ac.uk# contributors may be used to endorse or promote products derived from 146691Stjones1@inf.ed.ac.uk# this software without specific prior written permission. 156691Stjones1@inf.ed.ac.uk# 166691Stjones1@inf.ed.ac.uk# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 176691Stjones1@inf.ed.ac.uk# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 186691Stjones1@inf.ed.ac.uk# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 196691Stjones1@inf.ed.ac.uk# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 206691Stjones1@inf.ed.ac.uk# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 216691Stjones1@inf.ed.ac.uk# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 226691Stjones1@inf.ed.ac.uk# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 236691Stjones1@inf.ed.ac.uk# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 246691Stjones1@inf.ed.ac.uk# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 256691Stjones1@inf.ed.ac.uk# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 266691Stjones1@inf.ed.ac.uk# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 276691Stjones1@inf.ed.ac.uk 286691Stjones1@inf.ed.ac.ukfrom m5.util import code_formatter 296691Stjones1@inf.ed.ac.uk 306691Stjones1@inf.ed.ac.ukfrom slicc.ast.ExprAST import ExprAST 316691Stjones1@inf.ed.ac.uk 326691Stjones1@inf.ed.ac.ukclass MethodCallExprAST(ExprAST): 336691Stjones1@inf.ed.ac.uk def __init__(self, slicc, proc_name, expr_ast_vec): 346691Stjones1@inf.ed.ac.uk super(MethodCallExprAST, self).__init__(slicc) 356691Stjones1@inf.ed.ac.uk self.proc_name = proc_name 366691Stjones1@inf.ed.ac.uk self.expr_ast_vec = expr_ast_vec 376691Stjones1@inf.ed.ac.uk 386691Stjones1@inf.ed.ac.uk def generate(self, code): 396691Stjones1@inf.ed.ac.uk tmp = code_formatter() 406691Stjones1@inf.ed.ac.uk paramTypes = [] 416691Stjones1@inf.ed.ac.uk for expr_ast in self.expr_ast_vec: 426691Stjones1@inf.ed.ac.uk return_type = expr_ast.generate(tmp) 436691Stjones1@inf.ed.ac.uk paramTypes.append(return_type) 446691Stjones1@inf.ed.ac.uk 456691Stjones1@inf.ed.ac.uk obj_type, methodId, prefix = self.generate_prefix(paramTypes) 466691Stjones1@inf.ed.ac.uk 476691Stjones1@inf.ed.ac.uk # generate code 486691Stjones1@inf.ed.ac.uk params = [] 496691Stjones1@inf.ed.ac.uk for expr_ast in self.expr_ast_vec: 506691Stjones1@inf.ed.ac.uk return_type,tcode = expr_ast.inline(True) 516691Stjones1@inf.ed.ac.uk params.append(str(tcode)) 526691Stjones1@inf.ed.ac.uk fix = code.nofix() 536691Stjones1@inf.ed.ac.uk code("$prefix${{self.proc_name}}(${{', '.join(params)}}))") 546691Stjones1@inf.ed.ac.uk code.fix(fix) 556691Stjones1@inf.ed.ac.uk 566691Stjones1@inf.ed.ac.uk # Verify that this is a method of the object 576691Stjones1@inf.ed.ac.uk if methodId not in obj_type.methods: 586691Stjones1@inf.ed.ac.uk self.error("Invalid method call: Type '%s' does not have a method '%s'", 596691Stjones1@inf.ed.ac.uk obj_type, methodId) 606691Stjones1@inf.ed.ac.uk 616691Stjones1@inf.ed.ac.uk if len(self.expr_ast_vec) != \ 626691Stjones1@inf.ed.ac.uk len(obj_type.methods[methodId].param_types): 636691Stjones1@inf.ed.ac.uk # Right number of parameters 646691Stjones1@inf.ed.ac.uk self.error("Wrong number of parameters for function name: '%s', " + \ 656691Stjones1@inf.ed.ac.uk "expected: , actual: ", proc_name, 667532Ssteve.reinhardt@amd.com len(obj_type.methods[methodId].param_types), 676691Stjones1@inf.ed.ac.uk len(self.expr_ast_vec)) 687532Ssteve.reinhardt@amd.com 697532Ssteve.reinhardt@amd.com for actual_type, expected_type in \ 706691Stjones1@inf.ed.ac.uk zip(paramTypes, obj_type.methods[methodId].param_types): 716691Stjones1@inf.ed.ac.uk if actual_type != expected_type and \ 726691Stjones1@inf.ed.ac.uk str(actual_type["interface"]) != str(expected_type): 736691Stjones1@inf.ed.ac.uk self.error("Type mismatch: expected: %s actual: %s", 746691Stjones1@inf.ed.ac.uk expected_type, actual_type) 756691Stjones1@inf.ed.ac.uk 766691Stjones1@inf.ed.ac.uk # Return the return type of the method 776691Stjones1@inf.ed.ac.uk return obj_type.methods[methodId].return_type 786691Stjones1@inf.ed.ac.uk 796691Stjones1@inf.ed.ac.uk def findResources(self, resources): 806691Stjones1@inf.ed.ac.uk pass 816691Stjones1@inf.ed.ac.uk 826691Stjones1@inf.ed.ac.ukclass MemberMethodCallExprAST(MethodCallExprAST): 836691Stjones1@inf.ed.ac.uk def __init__(self, slicc, obj_expr_ast, proc_name, expr_ast_vec): 846691Stjones1@inf.ed.ac.uk s = super(MemberMethodCallExprAST, self) 856691Stjones1@inf.ed.ac.uk s.__init__(slicc, proc_name, expr_ast_vec) 866691Stjones1@inf.ed.ac.uk 876691Stjones1@inf.ed.ac.uk self.obj_expr_ast = obj_expr_ast 886691Stjones1@inf.ed.ac.uk 896691Stjones1@inf.ed.ac.uk def __repr__(self): 906691Stjones1@inf.ed.ac.uk return "[MethodCallExpr: %r%r %r]" % (self.proc_name, 916691Stjones1@inf.ed.ac.uk self.obj_expr_ast, 926691Stjones1@inf.ed.ac.uk self.expr_ast_vec) 936691Stjones1@inf.ed.ac.uk def generate_prefix(self, paramTypes): 946691Stjones1@inf.ed.ac.uk code = code_formatter() 956691Stjones1@inf.ed.ac.uk 966691Stjones1@inf.ed.ac.uk # member method call 976691Stjones1@inf.ed.ac.uk obj_type = self.obj_expr_ast.generate(code) 986691Stjones1@inf.ed.ac.uk methodId = obj_type.methodId(self.proc_name, paramTypes) 996691Stjones1@inf.ed.ac.uk 1006691Stjones1@inf.ed.ac.uk prefix = "" 1016691Stjones1@inf.ed.ac.uk implements_interface = False 1026691Stjones1@inf.ed.ac.uk if methodId not in obj_type.methods: 1036691Stjones1@inf.ed.ac.uk # 1046691Stjones1@inf.ed.ac.uk # The initial method check has failed, but before generating an 1056691Stjones1@inf.ed.ac.uk # error we must check whether any of the paramTypes implement 1066691Stjones1@inf.ed.ac.uk # an interface. If so, we must check if the method ids using 1076691Stjones1@inf.ed.ac.uk # the inherited types exist. 1086691Stjones1@inf.ed.ac.uk # 1096691Stjones1@inf.ed.ac.uk # This code is a temporary fix and only checks for the methodId 1106691Stjones1@inf.ed.ac.uk # where all paramTypes are converted to their inherited type. The 1116691Stjones1@inf.ed.ac.uk # right way to do this is to replace slicc's simple string 1126691Stjones1@inf.ed.ac.uk # comparison for determining the correct overloaded method, with a 1136691Stjones1@inf.ed.ac.uk # more robust param by param check. 1146691Stjones1@inf.ed.ac.uk # 1156691Stjones1@inf.ed.ac.uk implemented_paramTypes = [] 1166691Stjones1@inf.ed.ac.uk for paramType in paramTypes: 1176691Stjones1@inf.ed.ac.uk implemented_paramType = paramType 1186691Stjones1@inf.ed.ac.uk if paramType.isInterface: 1196691Stjones1@inf.ed.ac.uk implements_interface = True 1206691Stjones1@inf.ed.ac.uk implemented_paramType.abstract_ident = paramType["interface"] 1216691Stjones1@inf.ed.ac.uk else: 1226691Stjones1@inf.ed.ac.uk implemented_paramType.abstract_ident = paramType.c_ident 1236691Stjones1@inf.ed.ac.uk 1246691Stjones1@inf.ed.ac.uk implemented_paramTypes.append(implemented_paramType) 1256691Stjones1@inf.ed.ac.uk 1266691Stjones1@inf.ed.ac.uk if implements_interface: 1276691Stjones1@inf.ed.ac.uk implementedMethodId = obj_type.methodIdAbstract(self.proc_name, 1286691Stjones1@inf.ed.ac.uk implemented_paramTypes) 1296691Stjones1@inf.ed.ac.uk else: 1306691Stjones1@inf.ed.ac.uk implementedMethodId = "" 1316691Stjones1@inf.ed.ac.uk 1326691Stjones1@inf.ed.ac.uk if implementedMethodId not in obj_type.methods: 1336691Stjones1@inf.ed.ac.uk self.error("Invalid method call: " \ 1346691Stjones1@inf.ed.ac.uk "Type '%s' does not have a method '%s' nor '%s'", 1356691Stjones1@inf.ed.ac.uk obj_type, methodId, implementedMethodId) 1366691Stjones1@inf.ed.ac.uk else: 1376691Stjones1@inf.ed.ac.uk # 1386691Stjones1@inf.ed.ac.uk # Replace the methodId with the implementedMethodId found in 1396691Stjones1@inf.ed.ac.uk # the method list. 1406691Stjones1@inf.ed.ac.uk # 1416691Stjones1@inf.ed.ac.uk methodId = implementedMethodId 1426691Stjones1@inf.ed.ac.uk 1436691Stjones1@inf.ed.ac.uk return_type = obj_type.methods[methodId].return_type 1446691Stjones1@inf.ed.ac.uk if return_type.isInterface: 1456691Stjones1@inf.ed.ac.uk prefix = "static_cast<%s &>" % return_type.c_ident 1466691Stjones1@inf.ed.ac.uk prefix = "%s((%s)." % (prefix, code) 1476691Stjones1@inf.ed.ac.uk 1486691Stjones1@inf.ed.ac.uk return obj_type, methodId, prefix 1496691Stjones1@inf.ed.ac.uk 1506691Stjones1@inf.ed.ac.uk 1516691Stjones1@inf.ed.ac.ukclass ClassMethodCallExprAST(MethodCallExprAST): 1526691Stjones1@inf.ed.ac.uk def __init__(self, slicc, type_ast, proc_name, expr_ast_vec): 1536691Stjones1@inf.ed.ac.uk s = super(ClassMethodCallExprAST, self) 1546691Stjones1@inf.ed.ac.uk s.__init__(slicc, proc_name, expr_ast_vec) 1556691Stjones1@inf.ed.ac.uk 1566691Stjones1@inf.ed.ac.uk self.type_ast = type_ast 1576691Stjones1@inf.ed.ac.uk 1586691Stjones1@inf.ed.ac.uk def __repr__(self): 1596691Stjones1@inf.ed.ac.uk return "[MethodCallExpr: %r %r]" % (self.proc_name, self.expr_ast_vec) 1606691Stjones1@inf.ed.ac.uk 1616691Stjones1@inf.ed.ac.uk def generate_prefix(self, paramTypes): 1626691Stjones1@inf.ed.ac.uk 1636691Stjones1@inf.ed.ac.uk # class method call 1646691Stjones1@inf.ed.ac.uk prefix = "(%s::" % self.type_ast 1656691Stjones1@inf.ed.ac.uk obj_type = self.type_ast.type 1666691Stjones1@inf.ed.ac.uk methodId = obj_type.methodId(self.proc_name, paramTypes) 1676691Stjones1@inf.ed.ac.uk 1686691Stjones1@inf.ed.ac.uk return obj_type, methodId, prefix 1696691Stjones1@inf.ed.ac.uk 1706691Stjones1@inf.ed.ac.uk__all__ = [ "MemberMethodCallExprAST", "ClassMethodCallExprAST" ] 1716691Stjones1@inf.ed.ac.uk