/** * 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