/**
* Module containing the strategies used to post-process a
* parsed PHP-source.
* Post-processing includes:
* - Rewriting HereDoc an DoubleQuoted-parts to lists
*
* @author Eric Bouwers
*/
module php/parse/postprocess
strategies
/**
* Rewrites all the structures of DQ- and HereDoc strings to lists.
* This is needed because a follow-restriction cannot prevent ambiguity
*/
post-process-structures =
bottomup(try( content-to-list
<+ fix-heredoc
)
)
; bottomup(try(check-heredoc)) // needs seperate phase, incorrect heredoc can exists intermediately
strategies
/**
* Fixes the ambigious HereDoc when multiple HereDocs occur in a program.
*/
fix-heredoc =
?amb(lst)
; lst' := <map(fix-and-length)> lst
; list-accum(tup-min)
fix-and-length =
try(fix-conc)
; !(<length>,<id>)
fix-conc =
?Conc(a,b)
; <conc> (<try(fix-heredoc)> a,<try(fix-heredoc)> b)
tup-min =
?((l1,xs1),(l2,xs2))
; if <gt> (l1,l2)
then !xs1
else !xs2
end
strategies
/**
* Checks whether the HereDoc start-tag is equal to the end-tag.
* We can just check if it ends-with the start-tag because otherwise
* the HereDoc would not parse.
*
* @type HereDoc(_,_,_) -> exit
*/
check-heredoc =
?HereDoc(HereDocStart(starttag),_,endtag)
; <not(string-ends-with(|starttag))> endtag
; !(starttag,endtag)
; debug(!"There exist a HereDoc without matching start- and endtag.\n")
; <exit> 1
rules
/**
* Transforms the content of a DoubleQuoted string into a
* list.
* TODO: Integrate both HereDoc- and DQ-content
*
* @type DQContent() -> List()
*/
content-to-list :
DQContent(lit) -> list
where list := <make-list> lit
content-to-list :
HereDocContent(lit) -> list
where list := <make-list> lit
content-to-list :
DQContent(lit1,esc,lit2) -> list
where lit1' := <make-list> lit1
; lit2' := <make-list> lit2
; esc' := <maybe-wrap-in-list> esc
; list := <conc> (lit1',esc',lit2')
content-to-list :
HereDocContent(lit1,esc,lit2) -> list
where lit1' := <make-list> lit1
; lit2' := <make-list> lit2
; esc' := <maybe-wrap-in-list> esc
; list := <conc> (lit1',esc',lit2')
content-to-list :
DQContent(esc1,lit,esc2) -> list
where lit' := <make-list> lit
; esc1' := <maybe-wrap-in-list> esc1
; esc2' := <maybe-wrap-in-list> esc2
; list := <conc> (esc1',lit',esc2')
content-to-list :
HereDocContent(esc1,lit,esc2) -> list
where lit' := <make-list> lit
; esc1' := <maybe-wrap-in-list> esc1
; esc2' := <maybe-wrap-in-list> esc2
; list := <conc> (esc1',lit',esc2')
/**
* Utility function to transform a (possible transformed)
*
*/
make-list:
Some(s) -> [Literal(s)]
make-list:
None() -> []
make-list:
[x | xs ] -> [x | xs]
make-list:
[] -> []
strategies
/**
* Wraps a certain term in a list when it is not a list.
* @type _ -> List(_)
*/
maybe-wrap-in-list= ?esc
; if <?[x | xs]> esc
then esc' := esc
else esc' := [esc]
end