
I'm reading the module prepost, and there are a few issues I would like to raise. Disclaimer: I have never programmed in Stratego, the code is most certainly wrong. 1. The complete file ==================== For reference. imports liblib ContractC strategies SearchFunDecl = alltd({ ?|InitDeclarator[ ~Declarator: <id>~ ]| ; debug ; oncetd(?|DirectDeclarator[ ~ID: fun_name~ ]|) ; oncetd( ?|DirectDeclarator[ DirectDeclarator(ParameterTypeList) PreCondition-opt PostCondition-opt ]| ; !PreCondition-opt ; if ?|PreCondition?[ ]| then !|Statement[ ; ]| => pre else ?|PreCondition?[ precondition { ~Assertion+: pre~ } ]| end ; !PostCondition-opt ; if ?|PostCondition?[ ]| then !|Statement[ ; ]| => post ; !|ReturnValueDeclaration?[ ]| => ret else ?|PostCondition?[ postcondition ~ReturnValueDeclaration?: ret~ { ~Assertion+: post~ } ]| end ; !|DirectDeclarator[ DirectDeclarator(ParameterTypeList) ]|) ; rules (PrePost : fun_name -> (pre, ret, post)) }) SearchFunDef = alltd({ ?|ExternalDeclaration[ ~FunctionDefinition: <id> ~ ]| ; oncetd(?|DirectDeclarator[ ~ID: fun_name ~ ]| ; where(<PrePost> fun_name => (pre, ret, post)) ; oncetd(?|BlockItemList[ BlockItem-iter ]| ; !|BlockItemList[ ~BlockItem+: <concat> [ [|BlockItem[ ~CompoundStatement: pre ~ ]|, |BlockItem[ ~CompoundStatement: post ~ ]|], BlockItem-iter ]~]| )) }) prepost = io-wrap(SearchFunDecl ; SearchFunDef) 2. The strategies ================= First of all, why the heck should the alltd be in the rules? And BTW, why the rules are strategies here? As a first improvement, I propose to move the alltd down to the prepost strategy. prepost = io-wrap(alltd (FunDecl) ; alltd (FunDef)) Then you see that there are two alltd. Although this allows to have declarations after the implementation (which is indeed a feature) it goes against the spirit of C. Therefore it should read prepost = io-wrap(alltd (FunDecl ; FunDef)) Also, *save the space*! What is this fashion of starting to implement immediately after `='? FunDecl = { ?|InitDeclarator[ ~Declarator: <id>~ ]| ; debug ; oncetd(?|DirectDeclarator[ ~ID: fun_name~ ]|) ; oncetd( ?|DirectDeclarator[ DirectDeclarator(ParameterTypeList) PreCondition-opt PostCondition-opt ]| ; !PreCondition-opt ; if ?|PreCondition?[ ]| then !|Statement[ ; ]| => pre else ?|PreCondition?[ precondition { ~Assertion+: pre~ } ]| end ; !PostCondition-opt ; if ?|PostCondition?[ ]| then !|Statement[ ; ]| => post ; !|ReturnValueDeclaration?[ ]| => ret else ?|PostCondition?[ postcondition ~ReturnValueDeclaration?: ret~ { ~Assertion+: post~ } ]| end ; !|DirectDeclarator[ DirectDeclarator(ParameterTypeList) ]|) ; rules (PrePost : fun_name -> (pre, ret, post)) } FunDef = { ?|ExternalDeclaration[ ~FunctionDefinition: <id> ~ ]| ; oncetd(?|DirectDeclarator[ ~ID: fun_name ~ ]| ; where(<PrePost> fun_name => (pre, ret, post)) ; oncetd(?|BlockItemList[ BlockItem-iter ]| ; !|BlockItemList[ ~BlockItem+: <concat> [ [|BlockItem[ ~CompoundStatement: pre ~ ]|, |BlockItem[ ~CompoundStatement: post ~ ]|], BlockItem-iter ]~]| )) } 3. The rules ============ The rules exist, and that's because they make sense. Why just making strategies? I know, they are equivalent, but so are for and while loops, and you do use both. What is the InitDeclarator that we start by matching? Apparently it is only for debugging, but that's cluttering the code. What are all these oncetd doing here? This is *so wrong*: the code is trying to match various piece instead of just matching what it's looking for. IMNSHO it should look like: FunDecl = ? |Declarator[fn (arg*) pre post]| ; rules (PrePost : fn -> (cs1*, i, cs2*)) where <?|[precondition { cs1* }]|> (pre); <?|[postcondition (i) { cs2* }]|> (post) Is there a nicer way to match pre*, ret and post*? And we'll see for the function with either a pre- xor a postcondition later... The other rule/strategy is also quite not understandable! What is to be done is to create a dynamic rule *that performs the replacement*!!! Not some pseudo table, which completely defeats the whole point of dynamic rules. We want to write something like: where When you put the two together, you have: FunDecl = ? |Declarator[fn (arg*) pre post]| ; rules (InstallContract : |FunctionDefinition[fn (arg*) { stm* }] => !|[fn (arg*) { stm'* }] where <?|[precondition { cs1* }]|> (pre); <?|[postcondition (i) { cs2* }]|> (post); <install-contract (cs1*, i, cs2*)> (stm) => stm'*) And for an experimental start, I propose install-contract (|cs1*, i, cs2*) = !|[ { cs1* } ~id { cs2*} ]| We will see the complications later. I would like to have detailed answers, and particularly from Jesus. I'm quite sure my code is wrong, but it is probably close to correct, my Stratego is far from fluent.