summaryrefslogtreecommitdiff
path: root/poc/poc02-compiling-cake/src/php-weave/abstract_weaver.class.php
blob: 86a07b16d753610ad94a8777b99c0c2ff4127b97 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
<?php
require '../vendor/nikic/php-parser/lib/bootstrap.php';

function dbg($indent, $text) {
	for($i=0;$i<$indent;$i++) echo ".";
	echo "$text\n";
}

abstract class AbstractWeaver {
	protected $parser;
	protected $nodeDumper;
	protected $prettyPrinter;
	protected $ast_dump_before_walk;
	protected $ast_dump_after_walk;

	public function __construct() {
		$this->parser = new PHPParser_Parser(new PHPParser_Lexer);
		$this->nodeDumper = new PHPParser_NodeDumper;
		$this->prettyPrinter = new PHPParser_PrettyPrinter_Zend;
		$this->ast_dump_before_walk="";
		$this->ast_dump_after_walk="";
	}

	public function setASTDumpFiles($ast_dump_before_walk, $ast_dump_after_walk) {
		// Set file to "" to prevent AST dumping
		$this->$ast_dump_before_walk=$ast_dump_before_walk;
		$this->$ast_dump_after_walk=$ast_dump_after_walk;
	}

	public function runAllSteps($sourcetree_rootpath, $cache_path, $result_path) {
		try {
			$step='detectFramework';
			$fw_props=$this->detectFramework($sourcetree_rootpath);
			$step='parseFrameworkConfig';
			$fw_conf=$this->parseFrameworkConfig($fw_props);
			$step='parseFrameworkCode';
			$fw_extra=$this->parseFrameworkCode($fw_props, $fw_conf, $cache_path);
			$step='parseApplicationCode';
			$app_extra=$this->parseApplicationCode($fw_props, $fw_conf, $fw_extra, $cache_path);
			$step='computePageList';
			$app_pages=$this->computePageList($fw_props, $fw_conf, $fw_extra, $app_extra);
			$step='outputMappingFile';
			$this->outputMappingFile($app_pages,  $result_path);
			foreach ($app_pages as $page=>$page_props) {
				$step="makePageFullAST of '$page'";
				$page_full_ast=$this->makePageFullAST($page, $page_props, $fw_props, $fw_conf, $fw_extra, $app_extra, $cache_path);
				$step="analysePageAST of '$page'";
				$page_annotated_ast=$this->analysePageAST($page_full_ast, $page, $page_props, $fw_props, $fw_conf, $fw_extra, $app_extra, $cache_path);
				$step="throwDeadCode of '$page'";
				$this->throwDeadCode($page_annotated_ast);
				$step="weaveCode of '$page'";
				$out_ast=$this->weaveCode($page_annotated_ast);

				$page_dest_path=$this->makeDestPath($page, $result_path);
				$step="prettyPrint to '$page_dest_path'";
				$this->prettyPrint($out_ast, $page_dest_path);
			}

		} catch (Exception $e) {
			echo "Step '$step' failure : ", $e->getMessage();
		}
	}

	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
		 * The main call should be in this case :
		 * $w=new XXXWeaver;
                 * $nv=new NodeVisitor_XXX($w); // The node visitor 
		 * $t=new PHPParser_NodeTraverser; $t->addVisitor($nv);
		 * w->parseAndWalk($src_mainfile, $t, array('cwd'=>dirname($src_mainfile));
		*/
		try {
			dbg($level,"Parsing '$src_filepath'");
			$stmts = $this->parser->parse(file_get_contents($src_filepath));

			$this->dumpAST($stmts, $src_filepath, $this->ast_dump_before_walk);

			if ($traverser) {
				dbg($level,"Transforming '$src_filepath'");
				$stmts = $traverser->traverse($stmts);
				$traverser=null; //Destroy
			}

			$this->dumpAST($stmts, $src_filepath, $this->ast_dump_after_walk);
		
		} catch (PHPParser_Error $e) {
		    echo 'Parse Error: ', $e->getMessage();
		}
		return $stmts;
	}

	public function prettyPrint($ast, $dest_filepath) {
		dbg(0,"Outputing '$dest_filepath'");
		file_put_contents($dest_filepath, "<?php\n" . $this->prettyPrinter->prettyPrint($ast) . "\n?>");
	}

	public function dumpAST($ast, $ast_title, $dest_filepath) {
		if (is_array($ast) && strlen($dest_filepath) > 0 ) {
			dbg($level,"Dumping '$ast_title,' AST to '$dest_filepath'");
			file_put_contents($dest_filepath, $this->nodeDumper->dump($ast));
		}
	}

	// Framework specific code
	abstract public function detectFramework($sourcetree_rootpath);
	abstract public function parseFrameworkConfig($fw_props);
	abstract public function parseFrameworkCode($fw_props, $fw_conf, $cache_path);
	abstract public function parseApplicationCode($fw_props, $fw_conf, $fw_extra, $cache_path);
	abstract public function computePageList($fw_props, $fw_conf, $fw_extra, $app_extra);
	abstract public function outputMappingFile($app_pages,  $result_path);
	abstract public function makePageFullAST($page, $page_props, $fw_props, $fw_conf, $fw_extra, $app_extra, $cache_path);
	abstract public function analysePageAST($page_full_ast, $page, $page_props, $fw_props, $fw_conf, $fw_extra, $app_extra, $cache_path);
	abstract public function throwDeadCode(&$page_annotated_ast);
	abstract public function weaveCode($page_annotated_ast);
}