BlockIt
|
00001 #............................................................................ 00002 # Copyright (c) 2009,2010,2011 David Car, david.car7@gmail.com 00003 # Copyright (c) 2009,2010,2011 Michael List, michael.list@gmail.com 00004 # 00005 # This program is free software; you can redistribute it and/or modify it under 00006 # the terms of the GNU General Public License as published by the Free Software 00007 # Foundation; either version 2 of the License, or (at your option) any later 00008 # version. 00009 # 00010 # This program is distributed in the hope that it will be useful, but WITHOUT 00011 # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 00012 # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. 00013 # 00014 # You should have received a copy of the GNU General Public License along with 00015 # this program; if not, write to the Free Software Foundation, Inc., 59 Temple 00016 # Place, Suite 330, Boston, MA 02111-1307 USA 00017 #.......................................................................... 00018 from blockit.parsers import pyp as pp 00019 # pp.ParserElement.enablePackrat() 00020 00021 #................................................................................ 00022 # pyparsing Global ParserElement objects used by all blocks 00023 #................................................................................ 00024 TEMPLATE_TOKENS = ('<','>') 00025 RESERVED_KEYWORDS = ['template'] 00026 LEFT_TEMPTOK, RIGHT_TEMPTOK = map(pp.Literal, TEMPLATE_TOKENS) 00027 COMMENT = pp.Literal( "!" ) + pp.restOfLine 00028 #COMMENT = \ 00029 # pp.originalTextFor( pp.Literal( '!' ) + \ 00030 # pp.Optional( 00031 # pp.OneOrMore( pp.Word( pp.alphanums + '_' ))) +\ 00032 # pp.lineEnd ) 00033 CONTINUATION = pp.Literal( "&" ) 00034 INLINE_CONTINUATION = \ 00035 CONTINUATION + \ 00036 pp.Optional( COMMENT )+ \ 00037 CONTINUATION 00038 # VALIDNAME = pp.Word(pp.alphas+'_', pp.alphanums+'_%').ignore( INLINE_CONTINUATION ) 00039 VALIDNAME = pp.Word(pp.alphas+'_', pp.alphanums+'_%') 00040 VALIDNAME_WITH_PAREN = VALIDNAME+pp.Optional('('+VALIDNAME+')') 00041 VAR_ASSIGNMENT = VALIDNAME + pp.Literal('=') 00042 NUM = pp.Word(pp.nums) 00043 INTEGER = pp.Combine(pp.Optional('-')+pp.Word(pp.nums)) 00044 DECIMAL_NUM = pp.Combine(INTEGER+'.'+pp.Optional(NUM)) 00045 ENGINEERING_NUM = pp.Combine((DECIMAL_NUM|INTEGER) +\ 00046 pp.oneOf('e d', caseless=True) +\ 00047 INTEGER) 00048 00049 PRIVATE = pp.CaselessKeyword('private') 00050 PUBLIC = pp.CaselessKeyword('public') 00051 PROTECTED = pp.CaselessKeyword('protected') 00052 ACCESS_SPEC = PRIVATE ^ PUBLIC ^ PROTECTED 00053 00054 OUT = pp.CaselessKeyword('out') 00055 IN = pp.CaselessKeyword('in') 00056 INOUT = pp.CaselessKeyword('inout') 00057 INTENT = \ 00058 pp.CaselessKeyword('intent') +\ 00059 pp.Suppress('(') +\ 00060 (IN|OUT|INOUT)('intent') +\ 00061 pp.Suppress(')') 00062 00063 NUM.setParseAction(lambda s,l,t: int(t[0])) 00064 INTEGER.setParseAction(lambda s,l,t: int(t[0])) 00065 DECIMAL_NUM.setParseAction(lambda s,l,t: float(t[0])) 00066 00067 TEMPLATE_DECL = pp.Forward() 00068 VALID_TEMPLATE_PARAM = (pp.Literal('*')|TEMPLATE_DECL|VALIDNAME_WITH_PAREN|INTEGER) 00069 TEMPLATE_PARAM_LIST = (VALID_TEMPLATE_PARAM + pp.ZeroOrMore(','+VALID_TEMPLATE_PARAM)) 00070 TEMPLATE_DECL << \ 00071 VALIDNAME +\ 00072 pp.Combine((LEFT_TEMPTOK + TEMPLATE_PARAM_LIST + RIGHT_TEMPTOK), 00073 adjacent=False) 00074 00075 ARGLIST = \ 00076 pp.Group( 00077 pp.Suppress('(')+\ 00078 pp.Optional(pp.delimitedList(VALIDNAME | 00079 pp.quotedString | 00080 (ENGINEERING_NUM | DECIMAL_NUM | INTEGER)))+\ 00081 pp.Suppress(')')) 00082 00083 # Arglist2 is for things with 2 arg lists. we should probably have a dictionary of 00084 # these to allow multiple arg names. 00085 ARGLIST2 = \ 00086 pp.Group( 00087 pp.Suppress('(')+\ 00088 pp.Optional(pp.delimitedList(VALIDNAME | 00089 pp.quotedString | 00090 (ENGINEERING_NUM | DECIMAL_NUM | INTEGER)))+\ 00091 pp.Suppress(')'))('args2') 00092 00093 #........................................ 00094 # Attribute Spec 00095 #........................................ 00096 TARGET = pp.CaselessKeyword('target') 00097 OPTIONAL = pp.CaselessKeyword('optional') 00098 SAVE = pp.CaselessKeyword('save') 00099 POINTER = pp.CaselessKeyword('pointer') 00100 ALLOCATABLE = pp.CaselessKeyword('allocatable') 00101 EXTERNAL = pp.CaselessKeyword('external') 00102 INTRINSIC = pp.CaselessKeyword('intrinsic') 00103 ASYNCHRONOUS = pp.CaselessKeyword('asynchronous') 00104 VALUE = pp.CaselessKeyword('value') 00105 DIMENSION = \ 00106 pp.CaselessKeyword('dimension') +\ 00107 pp.Literal('(') +\ 00108 pp.delimitedList(pp.Literal(':')|pp.Word(pp.nums)) +\ 00109 pp.Literal(')') 00110 ATTR_SPEC = ACCESS_SPEC | INTENT | TARGET | SAVE | POINTER | ALLOCATABLE | \ 00111 EXTERNAL | INTRINSIC | VALUE | DIMENSION | ASYNCHRONOUS 00112 00113 ONLY_CLAUSE = \ 00114 pp.Literal(',')+pp.CaselessKeyword('only')+pp.Literal(':') 00115 00116 #............................................................ 00117 # Types 00118 #............................................................ 00119 INTEGER = \ 00120 pp.originalTextFor( \ 00121 pp.CaselessKeyword( 'integer' ) +\ 00122 pp.Optional( '(' +\ 00123 pp.originalTextFor(VALIDNAME) +\ 00124 ')' \ 00125 ) \ 00126 ) 00127 LOGICAL = \ 00128 pp.originalTextFor( \ 00129 pp.CaselessKeyword('logical') ) 00130 REAL = \ 00131 pp.originalTextFor( \ 00132 pp.CaselessKeyword('real') +\ 00133 pp.Optional( '(' +\ 00134 pp.originalTextFor(VALIDNAME) +\ 00135 ')' \ 00136 ) \ 00137 ) 00138 CHARACTER = pp.CaselessKeyword('character') 00139 INTRINSIC_TYPE = \ 00140 pp.StringStart() +\ 00141 ( INTEGER | REAL | LOGICAL )('name') +\ 00142 pp.Optional(pp.Suppress(',') + pp.delimitedList(ATTR_SPEC)) +\ 00143 pp.Optional(pp.Suppress('::')) +\ 00144 pp.delimitedList(VALIDNAME)('symbolList') 00145 USE_DECL = \ 00146 pp.StringStart() +\ 00147 pp.CaselessKeyword('use')('use') +\ 00148 ( pp.originalTextFor( TEMPLATE_DECL )| VALIDNAME )('name') +\ 00149 pp.Optional(ONLY_CLAUSE) +\ 00150 pp.Optional(pp.delimitedList( pp.originalTextFor( TEMPLATE_DECL ) ^ 00151 VALIDNAME ) )('onlyList') 00152 TEMPLATE_MOD_PROCEDURE_DECL = \ 00153 pp.StringStart() +\ 00154 pp.Suppress( pp.CaselessKeyword('module procedure') ) + \ 00155 ( pp.originalTextFor( TEMPLATE_DECL ) )('name') 00156 IMPORT_DECL = \ 00157 pp.StringStart() +\ 00158 pp.Suppress( pp.CaselessKeyword('import') ) + \ 00159 ( pp.originalTextFor( TEMPLATE_DECL )| VALIDNAME )('name') 00160 TEMPLATE_TYPE = \ 00161 pp.StringStart() +\ 00162 pp.CaselessKeyword('type') +\ 00163 pp.Suppress('(') +\ 00164 pp.originalTextFor(TEMPLATE_DECL ^ VALIDNAME)('name') +\ 00165 pp.Suppress(')') +\ 00166 pp.Optional(pp.Suppress(',') + pp.delimitedList(ATTR_SPEC)) +\ 00167 pp.Suppress('::') +\ 00168 pp.delimitedList(VALIDNAME)('symbolList') 00169 TEMPLATE_SUB = \ 00170 pp.StringStart() +\ 00171 pp.CaselessKeyword('call') +\ 00172 pp.originalTextFor(TEMPLATE_DECL)('name') +\ 00173 pp.Optional(ARGLIST('args')) 00174 TEMPLATE_FUNC = \ 00175 pp.Suppress( pp.oneOf('= ( ,') ) +\ 00176 pp.originalTextFor(TEMPLATE_DECL)('name') +\ 00177 pp.Optional(ARGLIST('args')) 00178 TEMPLATE_SYMBOL = pp.originalTextFor(TEMPLATE_DECL)('name') 00179 00180 # TEMPLATE_FUNC.ignore( INLINE_CONTINUATION ) 00181 00182 #........................................ 00183 # PyF95 directives grammars 00184 #........................................ 00185 PYF95_KEYWORD = pp.LineStart() + pp.Literal('#PyF95') 00186 PYF95_START = \ 00187 PYF95_KEYWORD + \ 00188 pp.Literal( '.start' ) 00189 PYF95_END = \ 00190 PYF95_KEYWORD + \ 00191 pp.Literal( '.end' ) 00192 PYF95_EXTERNAL = \ 00193 pp.Suppress( 00194 PYF95_KEYWORD + \ 00195 pp.Literal( '.external' ) + \ 00196 pp.Literal( ':' ) ) + \ 00197 ( pp.Combine( TEMPLATE_DECL, adjacent=False ) | VALIDNAME )( 'symbol' ) 00198 PYF95_ALWAYSWRITE = \ 00199 pp.Suppress( 00200 PYF95_KEYWORD + \ 00201 pp.Literal( '.alwayswrite' ) + \ 00202 pp.Literal( ':' ) ) + \ 00203 pp.Word( pp.alphas )('bool') 00204 PYF95_BLOCK = pp.Suppress( PYF95_START ) + pp.SkipTo( PYF95_END ) 00205 00206 ######################################################################## 00207 ## 00208 ## Unit-Tests 00209 ## 00210 ######################################################################## 00211 00212 if __name__ == "__main__": 00213 00214 import unittest 00215 00216 #======================================================================= 00217 class TestFGrammar(unittest.TestCase): 00218 #======================================================================= 00219 00220 def setUp(self): pass 00221 00222 def tearDown(self): pass 00223 00224 #------------------------------------------------------------------- 00225 def testUseDecl(self): 00226 #------------------------------------------------------------------- 00227 """Checks parsing of use statements""" 00228 00229 bnf = USE_DECL 00230 00231 # The USE_DECL should only parse 1 occurrance of the match because 00232 # it uses StringStart method. 00233 ctr = 0 00234 for match,s,e in bnf.scanString( """ 00235 use common_area, only: var1,var2, var3 00236 use DLList<String> 00237 """ ): 00238 ctr += 1 00239 self.failUnlessEqual(ctr,1,"Parsed more than one use statement!") 00240 00241 # Make sure it peels out the use and name correctly for a template 00242 try: 00243 output = bnf.parseString("use DLList<String>") 00244 except: 00245 self.fail("Failed to parse string") 00246 self.failUnlessEqual(output['use'], 'use', "Match use not correct") 00247 self.failUnlessEqual(output['name'], 'DLList<String>', "Match name not correct") 00248 00249 # Make sure the only statement works 00250 try: 00251 output = bnf.parseString(" use common_area, only: var1,var2, var3") 00252 except: 00253 self.fail("Failed to parse string") 00254 self.failUnlessEqual(output['use'], 'use',"Match use not correct") 00255 self.failUnlessEqual(output['name'], 'common_area', "Match name not correct") 00256 self.failUnlessEqual(len(output['onlyList']), 3, "Match list len not correct") 00257 for i in xrange(1,4): 00258 self.failUnlessEqual(output['onlyList'][i-1], 'var'+str(i), "Match list varname not correct") 00259 00260 def testIntent(self): 00261 """Checks intent parsing""" 00262 00263 bnf = INTENT 00264 00265 try: 00266 output = bnf.parseString("intent (inout)") 00267 except: 00268 self.fail("Failed to parse string") 00269 self.failUnlessEqual(output['intent'], 'inout', 'Improper parse of intent') 00270 00271 try: 00272 output = bnf.parseString("intent (in)") 00273 except: 00274 self.fail("Failed to parse string") 00275 self.failUnlessEqual(output['intent'], 'in', 'Improper parse of intent') 00276 00277 try: 00278 output = bnf.parseString("intent (out)") 00279 except: 00280 self.fail("Failed to parse string") 00281 self.failUnlessEqual(output['intent'], 'out', 'Improper parse of intent') 00282 00283 00284 suite = unittest.TestLoader().loadTestsFromTestCase(TestFGrammar) 00285 unittest.TextTestRunner(verbosity=2).run(suite)