/**
* Module containing strategies to handle the
* paths in PHP.
*
* @author Eric Bouwers
*/
module php/reflect/inclusion/path
strategies
/**
* Normalizes an _absolute_ path to the normalized path. That means that
* all occurences of '.' are just stripped away and that every occurence
* of '..' is removed together with the directory right before it.
* This will give the path to the same file without walking around.
* The strategy only works with an absolute path!
*
* @type String -> String
*/
normalize-path = ?path;
separator := <get-path-separator> path
; parts := <string-replace(|"/", "!"); string-replace(|"\\", "!"); split-at-bang> path
; parts' := <[ id | filter(not(?"." <+ ?"")) ]> parts
; parts'' := <repeat-until-fixpoint(once-filter-this-and-before(?".."))> parts'
; normalized := <separate-by(|separator); concat-strings> parts''
/**
* Parses a path to a list of directories
*
* @type String -> List(String)
*/
path-to-list =
split-at-char(|58)
/**
* Determine wheter or not a path is relative. A
* path is php-relative if it starts with a '.'
*
* @type String -> String
*/
is-php-relative =
?path
; string-starts-with(|".")
/**
* Takes an _absolute_ path and determines the path separator.
*
* @type String -> String
*/
get-path-separator = ?path;
if <string-starts-with(|"/")> path
then !"/"
else !"\\"
end
/**
* Utility functions, These would better be off in stratego-lib
*/
strategies
/**
* Splits a string at every backslash
*
* @type String -> List(String)
*/
split-at-bang =
split-at-char(|33)
/**
* Splits a string at every occurence of a given character.
*
* @param chr Number of the character to split at
* @type String -> List(String)
*/
split-at-char(|chr) =
explode-string
; CharSplitInit(|chr)
; rec x( CharSplitExit <+ CharSplitNext ; x)
rules
CharSplitInit(|chr) :
x -> ([], [], x, chr)
CharSplitExit :
(xs, cs, [], _) -> <reverse> [<reverse; implode-string> cs|xs]
CharSplitNext :
(xs, cs, [y|ys], chr) -> result
where if <eq> (y,chr)
then result := ([<reverse; implode-string> cs | xs], [], ys, chr)
else result := (xs, [y|cs], ys, chr)
end
/**
* Strategies that are used by both current- and working directory
* paths.
*/
strategies
/**
* we do not use the defined 'find-in-path' because we always want to work with
* the full path to a file.
*/
find-file-in-directory(add-prefix|filename) =
get-php-include-path
; path-to-list
; map(add-prefix)
; ?pathlist
; <fetch-elem(<concat-strings; tmp-file-exists> [<id>,"/",filename])> pathlist
; !FILE(<normalize-path>)
/**
* Add a directory to a path.
*
* @param get-dir The strategy that builds the dir to add
* @param path The path to which the dir should be added
*/
add-dir(get-dir | path ) =
if <is-php-relative> path
then <conc-strings> (<get-dir>, path)
else !path
end
/**
* Saves a path to the configuration table.
*
* @param dir The name to be used in the storage
* @param path The path to save
*/
set-php-direcory(|dir, path) =
phpdir := <php-directory-config-name(|dir)>
; if <not(string-ends-with(|"/"))> path
then path' := <conc-strings> (path,"/")
else path' := path
end
; if <is-php-relative> path'
then <set-config> (phpdir, <conc-strings> (<get-php-working-directory>, path'))
else <set-config> (phpdir, path')
end
/**
* Retrieves a path from the configuration table.
*
* @param dir The name of the path
*/
get-php-direcory(|dir) =
phpdir := <php-directory-config-name(|dir)>
;( <get-config> phpdir
<+ <conc-strings> (<current-working-dir>,"/")
)
/**
* Wrapes a directory within "php-" and "-directory"
*/
php-directory-config-name(|dir) =
<conc-strings> ("php-",<conc-strings> (dir, "-directory") )
/**
* Common utilities neccesary for path strategies.
*/
rules
/**
* This strategy filters 2 elements from a list of the second
* element satisfies a given strategy. It does this once.
*
* @param Strategy that should be satisfied
* @type List(a) -> List(a)
*/
once-filter-this-and-before(s):
[x] -> [x]
once-filter-this-and-before(s):
[before | rest ] -> filtered
where <?[testitem | tail]> rest
; if <s> testitem //succes, delete this and previous node
then filtered := tail
else rest' := <once-filter-this-and-before(s)> rest
; filtered := <conc> ([before],rest')
end
strategies
/**
* Repeats an application of a strategy until the strategy has
* no effect anymore.
*
* @param strategy to be applied
* @type ATerm -> ATerm
*/
repeat-until-fixpoint(s) = ?term;
term' := <s> term
; if <eq> (term,term')
then !term
else <repeat-until-fixpoint(s)> term'
end