summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLudovic Pouzenc <ludovic@pouzenc.fr>2012-08-02 21:49:31 +0000
committerLudovic Pouzenc <ludovic@pouzenc.fr>2012-08-02 21:49:31 +0000
commit688d58f51120786b099509ea3785a8057ae36265 (patch)
tree6714c3deab486ff9c7d2bf6b8d60072d7b8c83c0
parente62dfb1a310aff5efa285e8bde018314e6f70b50 (diff)
download2012-php-weave-688d58f51120786b099509ea3785a8057ae36265.tar.gz
2012-php-weave-688d58f51120786b099509ea3785a8057ae36265.tar.bz2
2012-php-weave-688d58f51120786b099509ea3785a8057ae36265.zip
Implémentation pour Cake : étape 1 sur 124684 réalisée :
Fonction detectFramework() implementée. Parse le app/webroot/index.php pour récurérer tous les define() et les évalue statiquement et ça marche ! git-svn-id: file:///var/svn/2012-php-weave/trunk@10 d972a294-176a-4cf9-8ea1-fcd5b0c30f5c
-rw-r--r--poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php106
-rw-r--r--poc/poc02-compiling-cake/src/php-weave/cakephp_weaver.class.php16
2 files changed, 119 insertions, 3 deletions
diff --git a/poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php b/poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php
index 86a07b1..cebe62a 100644
--- a/poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php
+++ b/poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php
@@ -64,12 +64,14 @@ abstract class AbstractWeaver {
public function makeDestPath($page, $result_path) {
return $result_path . '/' . str_replace('/', '_', $page) . ".php";
}
+
public function parseAndWalk($src_filepath, $traverser, $env=array(), $level=0) {
/* Parse a file et traverse the AST.
- * Could be recursive if a traverser call again parseAndWalk for example when finding a include() directive
+ * Could be recursive if a traverser call again parseAndWalk
+ * for example when finding a include() directive.
* The main call should be in this case :
* $w=new XXXWeaver;
- * $nv=new NodeVisitor_XXX($w); // The node visitor
+ * $nv=new NodeVisitor_YYY($w); // The node visitor
* $t=new PHPParser_NodeTraverser; $t->addVisitor($nv);
* w->parseAndWalk($src_mainfile, $t, array('cwd'=>dirname($src_mainfile));
*/
@@ -93,9 +95,107 @@ abstract class AbstractWeaver {
return $stmts;
}
+ public function staticEvalDefine($ast, $magics, $previous_constants=null) {
+ if ($previous_constants==null) {
+ $constants=array('DIRECTORY_SEPARATOR' => DIRECTORY_SEPARATOR);
+ } else {
+ $constants=$previous_constants;
+ }
+ while($stmt=array_shift($ast)) {
+ if ($stmt instanceof PHPParser_Node_Stmt_If) {
+ //TODO try to eval statically the cond
+ if (1) {
+ $constants += $this->staticEvalDefine($stmt->stmts, $magics, $constants);
+ }
+ } elseif ($stmt instanceof PHPParser_Node_Expr_FuncCall) {
+ if ( $stmt->name->parts === array('define') ) {
+ $k=$this->staticReduce($stmt->args[0], $constants, $magics);
+ $v=$this->staticReduce($stmt->args[1], $constants, $magics);
+ if ($k instanceof PHPParser_Node_Scalar_String && $v instanceof PHPParser_Node_Scalar_String) {
+ $k=$k->value;
+ $v=$v->value;
+ dbg(0,"Found '$k' => '$v'");
+ $constants[$k]=$v;
+ }
+ } else {
+ dbg(0,"Skipped funcall: " . $this->prettyPrinter->prettyPrint(array($stmt)));
+ }
+ } else {
+ dbg(0,"Skipped : " . get_class($stmt));
+ }
+ }
+ return $constants;
+ }
+
+ public function staticReduce($stmt, $constants, $magics, $level=0) {
+ //dbg($level,'staticReduce(<'.get_class($stmt).'>, $constants, $magics)');
+
+ // Condition de sortie
+ if ($stmt instanceof PHPParser_Node_Scalar_String) return $stmt;
+ // Propagation d'erreur
+ if (is_integer($stmt)) return $stmt;
+
+ // Cas nominal, action selon type de noeud
+ if ($stmt instanceof PHPParser_Node_Expr_FuncCall) {
+ // Support some string manipulation funcs
+ if ( count($stmt->name->parts)===1 ) {
+ $func=$stmt->name->parts[0];
+ switch($func) {
+ // Unary context insensitive funcs
+ case 'dirname':
+ case 'basename':
+ $arg=$this->staticReduce($stmt->args[0], $constants, $magics, $level+1);
+ if ($arg instanceof PHPParser_Node_Scalar_String) {
+ $res=$func($arg->value); //Real call !!
+ return new PHPParser_Node_Scalar_String($res);
+ }
+ break;
+ default:
+ dbg(0,"Unsupported func '$func'");
+ return 1;
+ }
+ } else {
+ dbg(0,"Unknown multipart funcname");
+ return 2;
+ }
+ } elseif ($stmt instanceof PHPParser_Node_Arg) {
+ // Unbox arguments, ignoring by ref things (static context)
+ return $this->staticReduce($stmt->value, $constants, $magics, $level+1);
+ } elseif ($stmt instanceof PHPParser_Node_Expr_Concat) {
+ $l=$this->staticReduce($stmt->left, $constants, $magics, $level+1);
+ if (! $l instanceof PHPParser_Node_Scalar_String) {
+ return $l;
+ }
+ $r=$this->staticReduce($stmt->right, $constants, $magics, $level+1);
+ if (! $r instanceof PHPParser_Node_Scalar_String) {
+ return $r;
+ }
+ return new PHPParser_Node_Scalar_String($l->value . $r->value);
+ } elseif ($stmt instanceof PHPParser_Node_Expr_ConstFetch) {
+ //TODO : a ConstFetch could be have more than one part in his name ?
+ // What glue between pieces ??
+ //$k=$this->prettyPrinter->prettyPrint(array($stmt));
+ $k=$stmt->name->parts[0];
+ if (array_key_exists($k, $constants)) {
+ return new PHPParser_Node_Scalar_String($constants[$k]);
+ } else {
+ dbg(0,"ConstFetch failed for '$k'");
+ return 3;
+ }
+ } elseif ($stmt instanceof PHPParser_Node_Scalar_FileConst) {
+ $k='__FILE__';
+ if (array_key_exists($k, $magics)) {
+ return new PHPParser_Node_Scalar_String($magics[$k]);
+ } else {
+ dbg(0,"Magic evaluation failed for '$k'");
+ return 4;
+ }
+ }
+ }
+
public function prettyPrint($ast, $dest_filepath) {
dbg(0,"Outputing '$dest_filepath'");
- file_put_contents($dest_filepath, "<?php\n" . $this->prettyPrinter->prettyPrint($ast) . "\n?>");
+ file_put_contents($dest_filepath, "<?php\n" . $this->prettyPrinter->prettyPrint($ast) . "\n");
}
public function dumpAST($ast, $ast_title, $dest_filepath) {
diff --git a/poc/poc02-compiling-cake/src/php-weave/cakephp_weaver.class.php b/poc/poc02-compiling-cake/src/php-weave/cakephp_weaver.class.php
index cc25641..508e509 100644
--- a/poc/poc02-compiling-cake/src/php-weave/cakephp_weaver.class.php
+++ b/poc/poc02-compiling-cake/src/php-weave/cakephp_weaver.class.php
@@ -3,7 +3,23 @@ require_once 'abstract_weaver.class.php';
class CakePHPWeaver extends AbstractWeaver {
public function detectFramework($sourcetree_rootpath) {
+ //FIXME : there is other cases to cover
+ $entrypoint_path=$sourcetree_rootpath.'/app/webroot/index.php';
+ assert('is_readable($entrypoint_path)');
+ $entrypoint_ast=$this->parseAndWalk($entrypoint_path, null);
+ //echo $this->nodeDumper->dump($entrypoint_ast);
+
+ $magics=array('__FILE__' => $entrypoint_path);
+ $fw_props=$this->staticEvalDefine($entrypoint_ast, $magics);
+ if (!is_array($fw_props)) throw new Exception("No properties found in '$entrypoint_path'");
+
+ print_r($fw_props);
+ $required=array('ROOT','APP_DIR','CAKE_CORE_INCLUDE_PATH','WEBROOT_DIR', 'WWW_ROOT');
+ $missing=array_diff($required, array_keys($fw_props));
+ print_r($missing);
+ assert('count($missing)===0;');
+ return array_merge(array('entrypoint_path' => $entrypoint_path), $fw_props);
}
public function parseFrameworkConfig($fw_props) {