diff options
Diffstat (limited to 'poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php')
-rw-r--r-- | poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php | 106 |
1 files changed, 103 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) { |