code_formatter.py revision 13663:9b64aeabf9a5
12292SN/A# Copyright (c) 2006-2009 Nathan Binkert <nate@binkert.org> 27597Sminkyu.jeong@arm.com# All rights reserved. 37597Sminkyu.jeong@arm.com# 47597Sminkyu.jeong@arm.com# Redistribution and use in source and binary forms, with or without 57597Sminkyu.jeong@arm.com# modification, are permitted provided that the following conditions are 67597Sminkyu.jeong@arm.com# met: redistributions of source code must retain the above copyright 77597Sminkyu.jeong@arm.com# notice, this list of conditions and the following disclaimer; 87597Sminkyu.jeong@arm.com# redistributions in binary form must reproduce the above copyright 97597Sminkyu.jeong@arm.com# notice, this list of conditions and the following disclaimer in the 107597Sminkyu.jeong@arm.com# documentation and/or other materials provided with the distribution; 117597Sminkyu.jeong@arm.com# neither the name of the copyright holders nor the names of its 127597Sminkyu.jeong@arm.com# contributors may be used to endorse or promote products derived from 137597Sminkyu.jeong@arm.com# this software without specific prior written permission. 142292SN/A# 152292SN/A# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 162292SN/A# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 172292SN/A# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 182292SN/A# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 192292SN/A# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 202292SN/A# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 212292SN/A# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 222292SN/A# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 232292SN/A# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 242292SN/A# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 252292SN/A# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 262292SN/A 272292SN/Afrom __future__ import print_function 282292SN/A 292292SN/Aimport __builtin__ 302292SN/Aimport inspect 312292SN/Aimport os 322292SN/Aimport re 332292SN/Aimport string 342292SN/A 352292SN/Aclass lookup(object): 362292SN/A def __init__(self, formatter, frame, *args, **kwargs): 372292SN/A self.frame = frame 382292SN/A self.formatter = formatter 392689Sktlim@umich.edu self.dict = self.formatter._dict 402689Sktlim@umich.edu self.args = args 412689Sktlim@umich.edu self.kwargs = kwargs 422292SN/A self.locals = {} 432292SN/A 443326Sktlim@umich.edu def __setitem__(self, item, val): 458229Snate@binkert.org self.locals[item] = val 466658Snate@binkert.org 472733Sktlim@umich.edu def __getitem__(self, item): 482907Sktlim@umich.edu if item in self.locals: 492292SN/A return self.locals[item] 508232Snate@binkert.org 518232Snate@binkert.org if item in self.kwargs: 528232Snate@binkert.org return self.kwargs[item] 532722Sktlim@umich.edu 542669Sktlim@umich.edu if item == '__file__': 552292SN/A return self.frame.f_code.co_filename 562790Sktlim@umich.edu 572790Sktlim@umich.edu if item == '__line__': 582790Sktlim@umich.edu return self.frame.f_lineno 592790Sktlim@umich.edu 602669Sktlim@umich.edu if self.formatter.locals and item in self.frame.f_locals: 612678Sktlim@umich.edu return self.frame.f_locals[item] 622678Sktlim@umich.edu 635606Snate@binkert.org if item in self.dict: 642292SN/A return self.dict[item] 652678Sktlim@umich.edu 662292SN/A if self.formatter.globals and item in self.frame.f_globals: 672292SN/A return self.frame.f_globals[item] 682669Sktlim@umich.edu 692292SN/A if item in __builtin__.__dict__: 702678Sktlim@umich.edu return __builtin__.__dict__[item] 712292SN/A 722678Sktlim@umich.edu try: 732678Sktlim@umich.edu item = int(item) 742678Sktlim@umich.edu return self.args[item] 754319Sktlim@umich.edu except ValueError: 764319Sktlim@umich.edu pass 774319Sktlim@umich.edu raise IndexError("Could not find '%s'" % item) 784319Sktlim@umich.edu 794319Sktlim@umich.educlass code_formatter_meta(type): 802678Sktlim@umich.edu pattern = r""" 812678Sktlim@umich.edu (?: 822292SN/A %(delim)s(?P<escaped>%(delim)s) | # escaped delimiter 832678Sktlim@umich.edu ^(?P<indent>[ ]*)%(delim)s(?P<lone>%(ident)s)$ | # lone identifier 842678Sktlim@umich.edu %(delim)s(?P<ident>%(ident)s) | # identifier 855336Shines@cs.fsu.edu %(delim)s%(lb)s(?P<b_ident>%(ident)s)%(rb)s | # braced identifier 862678Sktlim@umich.edu %(delim)s(?P<pos>%(pos)s) | # positional parameter 874873Sstever@eecs.umich.edu %(delim)s%(lb)s(?P<b_pos>%(pos)s)%(rb)s | # braced positional 882678Sktlim@umich.edu %(delim)s%(ldb)s(?P<eval>.*?)%(rdb)s | # double braced expression 892292SN/A %(delim)s(?P<invalid>) # ill-formed delimiter exprs 902678Sktlim@umich.edu ) 912678Sktlim@umich.edu """ 922678Sktlim@umich.edu def __init__(cls, name, bases, dct): 932678Sktlim@umich.edu super(code_formatter_meta, cls).__init__(name, bases, dct) 942678Sktlim@umich.edu if 'pattern' in dct: 952678Sktlim@umich.edu pat = cls.pattern 967852SMatt.Horsnell@arm.com else: 977852SMatt.Horsnell@arm.com # tuple expansion to ensure strings are proper length 982344SN/A lb,rb = cls.braced 992678Sktlim@umich.edu lb1,lb2,rb2,rb1 = cls.double_braced 1002678Sktlim@umich.edu pat = code_formatter_meta.pattern % { 1014986Ssaidi@eecs.umich.edu 'delim' : re.escape(cls.delim), 1024986Ssaidi@eecs.umich.edu 'ident' : cls.ident, 1036974Stjones1@inf.ed.ac.uk 'pos' : cls.pos, 1046974Stjones1@inf.ed.ac.uk 'lb' : re.escape(lb), 1056974Stjones1@inf.ed.ac.uk 'rb' : re.escape(rb), 1066974Stjones1@inf.ed.ac.uk 'ldb' : re.escape(lb1+lb2), 1076974Stjones1@inf.ed.ac.uk 'rdb' : re.escape(rb2+rb1), 1086974Stjones1@inf.ed.ac.uk } 1096974Stjones1@inf.ed.ac.uk cls.pattern = re.compile(pat, re.VERBOSE | re.DOTALL | re.MULTILINE) 1102678Sktlim@umich.edu 1112820Sktlim@umich.educlass code_formatter(object): 1122678Sktlim@umich.edu __metaclass__ = code_formatter_meta 1132678Sktlim@umich.edu 1146974Stjones1@inf.ed.ac.uk delim = r'$' 1156974Stjones1@inf.ed.ac.uk ident = r'[_A-z]\w*' 1166974Stjones1@inf.ed.ac.uk pos = r'[0-9]+' 1176974Stjones1@inf.ed.ac.uk braced = r'{}' 1186974Stjones1@inf.ed.ac.uk double_braced = r'{{}}' 1196974Stjones1@inf.ed.ac.uk 1202678Sktlim@umich.edu globals = True 1212678Sktlim@umich.edu locals = True 1222678Sktlim@umich.edu fix_newlines = True 1232678Sktlim@umich.edu def __init__(self, *args, **kwargs): 1242678Sktlim@umich.edu self._data = [] 1252344SN/A self._dict = {} 1262307SN/A self._indent_level = 0 1276974Stjones1@inf.ed.ac.uk self._indent_spaces = 4 1286974Stjones1@inf.ed.ac.uk self.globals = kwargs.pop('globals', type(self).globals) 1296974Stjones1@inf.ed.ac.uk self.locals = kwargs.pop('locals', type(self).locals) 1306974Stjones1@inf.ed.ac.uk self._fix_newlines = \ 1312678Sktlim@umich.edu kwargs.pop('fix_newlines', type(self).fix_newlines) 1324032Sktlim@umich.edu 1332678Sktlim@umich.edu if args: 1342292SN/A self.__call__(args) 1352292SN/A 1362292SN/A def indent(self, count=1): 1372292SN/A self._indent_level += self._indent_spaces * count 1382678Sktlim@umich.edu 1392678Sktlim@umich.edu def dedent(self, count=1): 1406974Stjones1@inf.ed.ac.uk assert self._indent_level >= (self._indent_spaces * count) 1412292SN/A self._indent_level -= self._indent_spaces * count 1422292SN/A 1432292SN/A def fix(self, status): 1442292SN/A previous = self._fix_newlines 1452292SN/A self._fix_newlines = status 1465529Snate@binkert.org return previous 1475529Snate@binkert.org 1485529Snate@binkert.org def nofix(self): 1492292SN/A previous = self._fix_newlines 1504329Sktlim@umich.edu self._fix_newlines = False 1514329Sktlim@umich.edu return previous 1524329Sktlim@umich.edu 1534329Sktlim@umich.edu def clear(): 1542292SN/A self._data = [] 1552307SN/A 1562307SN/A def write(self, *args): 1572907Sktlim@umich.edu f = file(os.path.join(*args), "w") 1582907Sktlim@umich.edu for data in self._data: 1592292SN/A f.write(data) 1602292SN/A f.close() 1612329SN/A 1622329SN/A def __str__(self): 1632329SN/A data = string.join(self._data, '') 1642292SN/A self._data = [ data ] 1652292SN/A return data 1662292SN/A 1672292SN/A def __getitem__(self, item): 1688199SAli.Saidi@ARM.com return self._dict[item] 1698199SAli.Saidi@ARM.com 1708199SAli.Saidi@ARM.com def __setitem__(self, item, value): 1712292SN/A self._dict[item] = value 1722292SN/A 1732292SN/A def __delitem__(self, item): 1742292SN/A del self._dict[item] 1752292SN/A 1762292SN/A def __contains__(self, item): 1772292SN/A return item in self._dict 1783492Sktlim@umich.edu 1792329SN/A def __iadd__(self, data): 1802292SN/A self.append(data) 1812292SN/A 1822292SN/A def append(self, data): 1832292SN/A if isinstance(data, code_formatter): 1842292SN/A self._data.extend(data._data) 1852292SN/A else: 1862292SN/A self._append(str(data)) 1872292SN/A 1882292SN/A def _append(self, data): 1892292SN/A if not self._fix_newlines: 1902292SN/A self._data.append(data) 1918247Snate@binkert.org return 1922292SN/A 1932292SN/A initial_newline = not self._data or self._data[-1] == '\n' 1942292SN/A for line in data.splitlines(): 1952292SN/A if line: 1962292SN/A if self._indent_level: 1972727Sktlim@umich.edu self._data.append(' ' * self._indent_level) 1982727Sktlim@umich.edu self._data.append(line) 1992727Sktlim@umich.edu 2002727Sktlim@umich.edu if line or not initial_newline: 2012727Sktlim@umich.edu self._data.append('\n') 2022727Sktlim@umich.edu 2032727Sktlim@umich.edu initial_newline = False 2042727Sktlim@umich.edu 2052727Sktlim@umich.edu def __call__(self, *args, **kwargs): 2062727Sktlim@umich.edu if not args: 2072727Sktlim@umich.edu self._data.append('\n') 2082727Sktlim@umich.edu return 2092727Sktlim@umich.edu 2102727Sktlim@umich.edu format = args[0] 2112727Sktlim@umich.edu args = args[1:] 2122727Sktlim@umich.edu 2132727Sktlim@umich.edu frame = inspect.currentframe().f_back 2142727Sktlim@umich.edu 2152361SN/A l = lookup(self, frame, *args, **kwargs) 2162361SN/A def convert(match): 2172361SN/A ident = match.group('lone') 2182361SN/A # check for a lone identifier 2192727Sktlim@umich.edu if ident: 2202727Sktlim@umich.edu indent = match.group('indent') # must be spaces 2212727Sktlim@umich.edu lone = '%s' % (l[ident], ) 2222727Sktlim@umich.edu 2232727Sktlim@umich.edu def indent_lines(gen): 2242727Sktlim@umich.edu for line in gen: 2252727Sktlim@umich.edu yield indent 2262727Sktlim@umich.edu yield line 2272727Sktlim@umich.edu return ''.join(indent_lines(lone.splitlines(True))) 2282727Sktlim@umich.edu 2292727Sktlim@umich.edu # check for an identifier, braced or not 2302727Sktlim@umich.edu ident = match.group('ident') or match.group('b_ident') 2312727Sktlim@umich.edu if ident is not None: 2322727Sktlim@umich.edu return '%s' % (l[ident], ) 2332727Sktlim@umich.edu 2342727Sktlim@umich.edu # check for a positional parameter, braced or not 2352727Sktlim@umich.edu pos = match.group('pos') or match.group('b_pos') 2362727Sktlim@umich.edu if pos is not None: 2372727Sktlim@umich.edu pos = int(pos) 2382727Sktlim@umich.edu if pos > len(args): 2392727Sktlim@umich.edu raise ValueError \ 2402727Sktlim@umich.edu ('Positional parameter #%d not found in pattern' % pos, 2412727Sktlim@umich.edu code_formatter.pattern) 2424329Sktlim@umich.edu return '%s' % (args[int(pos)], ) 2434329Sktlim@umich.edu 2444329Sktlim@umich.edu # check for a double braced expression 2454329Sktlim@umich.edu eval_expr = match.group('eval') 2464329Sktlim@umich.edu if eval_expr is not None: 2474329Sktlim@umich.edu result = eval(eval_expr, {}, l) 2484329Sktlim@umich.edu return '%s' % (result, ) 2494329Sktlim@umich.edu 2504329Sktlim@umich.edu # check for an escaped delimiter 2514329Sktlim@umich.edu if match.group('escaped') is not None: 2524329Sktlim@umich.edu return '$' 2534329Sktlim@umich.edu 2544329Sktlim@umich.edu # At this point, we have to match invalid 2552292SN/A if match.group('invalid') is None: 2562292SN/A # didn't match invalid! 2572292SN/A raise ValueError('Unrecognized named group in pattern', 2582292SN/A code_formatter.pattern) 2592292SN/A 2602292SN/A i = match.start('invalid') 2612292SN/A if i == 0: 2622292SN/A colno = 1 2632292SN/A lineno = 1 2642292SN/A else: 2652292SN/A lines = format[:i].splitlines(True) 2662292SN/A colno = i - reduce(lambda x,y: x+y, (len(z) for z in lines)) 2672292SN/A lineno = len(lines) 2682292SN/A 2692307SN/A raise ValueError('Invalid format string: line %d, col %d' % 2702307SN/A (lineno, colno)) 2712307SN/A 2722367SN/A d = code_formatter.pattern.sub(convert, format) 2732367SN/A self._append(d) 2742307SN/A 2752367SN/A__all__ = [ "code_formatter" ] 2762307SN/A 2772329SN/Aif __name__ == '__main__': 2782307SN/A from code_formatter import code_formatter 2792307SN/A f = code_formatter() 2802307SN/A 2812307SN/A class Foo(dict): 2822307SN/A def __init__(self, **kwargs): 2832307SN/A self.update(kwargs) 2842307SN/A def __getattr__(self, attr): 2852307SN/A return self[attr] 2862307SN/A 2872307SN/A x = "this is a test" 2882307SN/A l = [ [Foo(x=[Foo(y=9)])] ] 2892307SN/A 2902307SN/A y = code_formatter() 2912307SN/A y(''' 2922307SN/A{ 2932329SN/A this_is_a_test(); 2942307SN/A} 2952307SN/A''') 2962307SN/A f(' $y') 2972307SN/A f('''$__file__:$__line__ 2982307SN/A{''') 2992307SN/A f("${{', '.join(str(x) for x in xrange(4))}}") 3002307SN/A f('${x}') 3012307SN/A f('$x') 3022307SN/A f.indent() 3032307SN/A for i in xrange(5): 3042292SN/A f('$x') 3052292SN/A f('$i') 3062329SN/A f('$0', "zero") 3072329SN/A f('$1 $0', "zero", "one") 3082292SN/A f('${0}', "he went") 3092329SN/A f('${0}asdf', "he went") 3102329SN/A f.dedent() 3112292SN/A 3122292SN/A f(''' 3132292SN/A ${{l[0][0]["x"][0].y}} 3142292SN/A} 3152292SN/A''', 1, 9) 3162329SN/A 3172292SN/A print(f, end=' ') 3182292SN/A