Changeset 106:3ed5f8f4f9fc

Show
Ignore:
Timestamp:
02/20/10 14:33:55 (7 months ago)
Author:
Roger Gammans <rgammans@…>
Branch:
right-recursive-macro-grammar
Message:

A right-recursive version of our grammar which allows Expr to used as literals.

In my opinion at the moment this is a dead-end , as the grammar is
ambigous with the extensions to the query op to allow expression
in all places. Additionally I don't think this ambiguity wins us
anything in practice as I can't imagine where we would use it.

However I'm committed it as a dead-head in case it becomes usefiul
later

Files:
2 modified

Legend:

Unmodified
Added
Removed
  • MysteryMachine/parsetools/grammar.py

    r105 r106  
    22 
    33###Grammar stuff 
    4 from pyparsing import  Regex,Optional,ZeroOrMore, QuotedString , Literal, Word, alphas , nums , printables  , CharsNotIn , stringEnd 
     4from pyparsing import Group, Forward,Regex,Optional,ZeroOrMore, QuotedString , Literal, Word, alphas , nums , CharsNotIn , stringEnd 
    55from functools import partial 
    66 
     
    2626 
    2727ExprLimit  =   Regex("[^ \n\t]*[ \n\t]") 
    28 Value      =   QuotedString('"')  
     28LiteralVal =   QuotedString('"')  
     29 
     30def outparseState(s,loc,toks): 
     31    print s,loc,toks 
     32    return toks 
     33 
     34class BoolPartVal: 
     35    """ 
     36    Store the left hand part of a bool expr for later evalation. 
     37    """ 
     38    def  __init__(self,op,value,*args): 
     39        self.opsense = (op == "!=") 
     40        self.value   = value 
     41 
     42    def cmp(self,ovalue): 
     43        return self.opsense ^ (self.value == ovalue) 
     44 
     45 
     46class QueryExprVal: 
     47    """ 
     48    Store the left hand part of a query expr for later evalution. 
     49    """ 
     50    def  __init__(self,boolpart,query,tval,seperator,fval,*args): 
     51        self.boolpart = boolpart 
     52        self.tval     = tval 
     53        self.fval     = fval 
     54        assert(query == "?") 
     55        assert(seperator == "/") 
     56 
     57    def eval(self,oval): 
     58        if self.boolpart.cmp(oval): 
     59            return self.tval 
     60        else: return self.fval 
     61 
     62def EvalExpr(s,loc,toks): 
     63    """ 
     64    Walk down a list of query expression resovling them as we go 
     65    """     
     66    c=toks[0] 
     67    for q in toks[1:]: 
     68        c=q.eval(c) 
     69    return c 
     70 
     71 
     72def getField(s,loc,toks): 
     73        modlogger.debug( "getField(%s)\n" % toks) 
     74        field=toks[2] 
     75        obj=toks[0] 
     76        return obj[field] 
    2977 
    3078 
     
    3684 
    3785    NamedField  =   ObjectUID + seperator +fieldName 
    38     ExprField   =   ObjectUID ^  \ 
    39                 NamedField 
    4086 
    41     BoolExpr   =    ExprField + cfoperator + Value.copy()  
    42     QueryExpr  =    BoolExpr + queryOp + Value.copy() + "/" +Value.copy() 
     87    LValue     =    Forward() 
    4388 
    44     ExprText   =    ExprField ^ \ 
    45                 QueryExpr 
     89    ExprField   =   ObjectUID ^ \ 
     90                    NamedField 
    4691 
    47     #Error      =   openExpr + ExprLimit  
     92    #""" 
    4893 
    49     #These production are about handling expressions 
    50     # in run of text. The use is mainly historical. 
    51     Expr       =   openExpr + ExprText + closeExpr 
     94    LToken      =   LiteralVal ^ \ 
     95                    ExprField 
    5296 
    53     textEle    =   NonExpr  ^ \ 
    54                    Expr  
    55         
    56     text       =   ZeroOrMore(textEle) 
     97    BoolPart    =   cfoperator + LValue.copy() 
     98    QueryExpr   =   BoolPart  + queryOp + LValue.copy() + "/" + LValue.copy() 
     99    ExprText    =   LToken + ZeroOrMore(QueryExpr) 
     100    LValue      <<  ( ExprText ^ LToken ) 
    57101 
    58102 
     103    BoolPart.setParseAction(lambda s,loc,toks:BoolPartVal(*toks)) 
     104    QueryExpr.setParseAction(lambda s,loc,toks:QueryExprVal(*toks)) 
     105    ExprText.setParseAction(EvalExpr) 
    59106    ## Functions for parsing. 
    60  
    61     def getField(s,loc,toks): 
    62         modlogger.debug( "getField(%s)\n" % toks) 
    63         field=toks[2] 
    64         obj=toks[0] 
    65         return obj[field] 
    66  
    67  
    68     def doBool(s,loc,toks): 
    69         modlogger.debug( "getbol\n") 
    70         sense=(toks[1]=="!=") 
    71         return sense ^ ( str(toks[0]) == toks[2]) 
    72  
    73  
    74     def doQuery(s,loc,toks): 
    75         modlogger.debug( "doing query\n") 
    76         if toks[0]: 
    77                 return toks[2] 
    78         else: 
    79                 return toks[4] 
    80107 
    81108    def initFromParse(s,loc,toks): 
     
    86113        else:              return home.get_root().get_object(toks[0],toks[2]) 
    87114 
    88     #def gotError(s,loc,toks): 
    89     #   sys.stderr.write("BARR") 
    90  
    91     ## Bind functions to parse actions 
    92115     
    93116    NamedField.setParseAction(getField) 
    94  
    95     BoolExpr.setParseAction(doBool) 
    96     QueryExpr.setParseAction(doQuery) 
    97     Expr.setParseAction(lambda s,loc,tok:tok[1]) 
    98     #Error.setParseAction(gotError) 
    99  
    100117    ObjectUID.setParseAction(initFromParse) 
    101118     
     119    ExprText.enablePackrat()  
     120    ExprText.validate()  
    102121    return ExprText + stringEnd 
     122 
     123 
     124if __name__ == "__main__": 
     125    f = Grammar(None) 
     126    print f.parseString(":name=\"X\"?\"Y\"/\"Z\"") 
     127    #This is ambigous the second query could be have he first as it paramater 
     128    # or be inside he final element of the first. 
     129    print f.parseString(":name=\"X\"?\"Y\"/\"Z\"=\"Z\"?\"R\"/\"S\"") 
  • tests/grammarTest.py

    r105 r106  
    1919#  
    2020""" 
    21 Tests for the MysteryMachine.VersionNr class 
     21Tests for the MysteryMachine.parsetools.gramar file 
    2222""" 
    2323 
    24 from MysteryMachine import *  
    2524from MysteryMachine.parsetools.grammar import Grammar 
    2625  
     
    6160class GraamarTest(unittest.TestCase): 
    6261    def setUp(self): 
    63         StartApp(["--cfgengine=ConfigDict", "--cfgfile=test.cfg", "--testmode"])  
    64         self.parserA=Grammar( ObjectProxy( name="TestName",  title="A Title") ) 
     62        self.A = ( ObjectProxy( name="TestName",  title="A Title", yes="YEAH!", no="Nope") ) 
     63        self.parserA=Grammar( self.A ) 
    6564        self.parserB=Grammar( ObjectProxy( name="WrongName", title="A Title") ) 
    6665 
     
    9291        self.assertEqual(helper(self.parserA,":name=\"TestName\"?\"Yes\"/\"No\""),"Yes") 
    9392        self.assertEqual(helper(self.parserA,":name=\"WrongName\"?\":Yes\"/\"No\""),"No") 
     93        #Now check with different lvalues.. 
     94        self.assertEqual(helper(self.parserA,":name=\"TestName\"?:yes/:no"),"YEAH!") 
     95        self.assertEqual(helper(self.parserA,":name=\"WrongName\"?:yes/:no"),"Nope") 
     96        self.assertEqual(helper(self.parserA,":name=:title?:yes/:no"),"Nope") 
     97        #Check Not equals 
     98        self.assertEqual(helper(self.parserA,":name!=\"WrongName\"?:yes/:no"),"YEAH!") 
     99 
    94100 
    95101    # Test handling of parse errors.