3 +---------------------------------------------------------------------------------+
4 | Copyright (c) 2010 César Rodas and Menéame Comunicacions S.L. |
5 +---------------------------------------------------------------------------------+
6 | Redistribution and use in source and binary forms, with or without |
7 | modification, are permitted provided that the following conditions are met: |
8 | 1. Redistributions of source code must retain the above copyright |
9 | notice, this list of conditions and the following disclaimer. |
11 | 2. Redistributions in binary form must reproduce the above copyright |
12 | notice, this list of conditions and the following disclaimer in the |
13 | documentation and/or other materials provided with the distribution. |
15 | 3. All advertising materials mentioning features or use of this software |
16 | must display the following acknowledgement: |
17 | This product includes software developed by César D. Rodas. |
19 | 4. Neither the name of the César D. Rodas nor the |
20 | names of its contributors may be used to endorse or promote products |
21 | derived from this software without specific prior written permission. |
23 | THIS SOFTWARE IS PROVIDED BY CÉSAR D. RODAS ''AS IS'' AND ANY |
24 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
25 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE |
26 | DISCLAIMED. IN NO EVENT SHALL CÉSAR D. RODAS BE LIABLE FOR ANY |
27 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES |
28 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; |
29 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
30 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
31 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS |
32 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE |
33 +---------------------------------------------------------------------------------+
34 | Authors: César Rodas <crodas@php.net> |
35 +---------------------------------------------------------------------------------+
38 // addslashes_ex($string) {{{
40 * addslashes like function for single quote string ('foo')
44 function addslashes_ex($string)
46 return str_replace("'", "\\'", $string);
51 * Haanga_Generator_PHP class
53 * This class takes the generated AST structure (arrays),
54 * and generated the PHP represantion.
58 class Haanga_Generator_PHP
63 // getCode (AST $op_code) {{{
65 * Transform the AST generated by the Haanga_Compiler class
66 * and return the equivalent PHP code.
68 * @param array $op_code
72 final function getCode($op_code)
76 $size = count($op_code);
77 for ($i=0; $i < $size; $i++
) {
79 if (!isset($op['op'])) {
80 throw new Haanga_Compiler_Exception("Invalid \$op_code ".print_r($op, TRUE));
83 /* echo optimization {{{ */
84 if ($op['op'] == 'print') {
86 $next_op = $op_code[$i+
1];
87 if (!isset($next_op) ||
$next_op['op'] != 'print') {
90 for ($e=0; $e < count($next_op); $e++
) {
91 if (!isset($next_op[$e])) {
101 /* declare optimization {{{ */
102 if ($op['op'] == 'declare' ||
$op['op'] == 'append_var') {
105 ** If a variable declaration, or append variable is followed
106 ** by several append_var, then merge everything into a
111 $next_op = $op_code[$i+
1];
112 if (!isset($next_op) ||
$next_op['op'] != 'append_var' ||
$next_op['name'] != $op['name']) {
115 for ($e=0; $e < count($next_op); $e++
) {
116 if (!isset($next_op[$e])) {
119 $op[] = $next_op[$e];
126 $method = "php_{$op['op']}";
127 if (!is_callable(array($this, $method))) {
128 throw new Exception("CodeGenerator: Missing method $method");
137 $code .= $this->ident();
139 $code .= $this->$method($op);
147 * Get the string for the current tabulation
151 protected function ident()
154 $code .= str_repeat($this->tab
, $this->ident
);
162 * Return code for "else"
166 protected function php_else()
169 $code = $this->ident()."} else {";
177 * Return code for "comments"
181 function php_comment($op)
183 return "/* {$op['comment']} */";
187 // php_function(array $op) {{{
189 * Return the function declaration of the class, for now
190 * it has fixed params, this should change soon to generate
191 * any sort of functions
195 function php_function($op)
197 $code = "function {$op['name']}(\$vars, \$return=FALSE, \$blocks=array())".$this->ident()."{";
203 // php_if(array $op) {{{
205 * Return the "if" declaration and increase $this->ident
209 protected function php_if($op)
211 $code = "if (".$this->php_generate_expr($op['expr']).") {";
219 * Return a stand-alone statement
223 protected function php_expr($op)
225 return $this->php_generate_expr($op[0]).";";
229 // php_end_block() {{{
231 * Finish the current block (if, for, function, etc),
232 * return the final "}", and decrease $this->ident
236 protected function php_end_block()
239 return $this->ident()."}";
243 // php_end_function() {{{
245 * Return code to end a function
249 protected function php_end_function()
251 return $this->php_end_block();
257 * Return code to end a if
261 protected function php_end_if()
263 return $this->php_end_block();
267 // php_end_foreach() {{{
269 * Return code to end a foreach
273 protected function php_end_foreach()
275 return $this->php_end_block();
279 // php_foreach(array $op) {{{
281 * Return the declaration of a "foreach" statement.
285 protected function php_foreach($op)
287 $op['array'] = $this->php_get_varname($op['array']);
288 $op['value'] = $this->php_get_varname($op['value']);
289 $code = "foreach ({$op['array']} as ";
290 if (!isset($op['key'])) {
291 $code .= " {$op['value']}";
293 $op['key'] = $this->php_get_varname($op['key']);
294 $code .= " {$op['key']} => {$op['value']}";
303 // php_append_var(array $op) {{{
305 * Return code to append something to a variable
309 protected function php_append_var($op)
311 return $this->php_declare($op, '.=');
317 * Return code for a function calling.
321 protected function php_exec($op)
324 if (is_string($op['name'])) {
325 $code .= $op['name'];
327 $function = $this->php_get_varname($op['name']);
331 if (isset($op['args'])) {
332 $code .= $this->php_generate_list($op['args']);
339 // php_global($op) {{{
340 function php_global($op)
342 return "global \$".implode(", \$", $op['vars']).";";
346 // php_generate_expr($op) {{{
348 * Return an expression
352 protected function php_generate_expr($expr)
355 if (is_object($expr)) {
356 $expr = $expr->getArray();
358 if (is_array($expr) && isset($expr['op_expr'])) {
359 if ($expr['op_expr'] == 'expr') {
361 $code .= $this->php_generate_expr($expr[0]);
363 } else if ($expr['op_expr'] == 'not') {
364 $code .= "!".$this->php_generate_expr($expr[0]);
366 $code .= $this->php_generate_expr($expr[0]);
367 if (is_object($expr['op_expr'])) {
368 var_dump($expr);die('unexpected error');
370 $code .= " {$expr['op_expr']} ";
371 $code .= $this->php_generate_expr($expr[1]);
374 if (is_array($expr)) {
375 $code .= $this->php_generate_stmt(array($expr));
377 if ($expr === FALSE) {
379 } else if ($expr === TRUE) {
389 // php_generate_list(array ($array) {{{
391 * Return a list of expressions for parameters
396 protected function php_generate_list($array)
399 foreach ($array as $value) {
400 $code .= $this->php_generate_stmt(array($value));
403 return substr($code, 0, -2);
407 // php_generate_stmt(Array $op) {{{
409 * Return the representation of a statement
413 protected function php_generate_stmt($op)
417 for ($i=0; $i < count($op); $i++
) {
418 if (!isset($op[$i])) {
421 if (!is_Array($op[$i])) {
422 throw new Haanga_Compiler_Exception("Malformed declaration ".print_r($op, TRUE));
425 $value = current($op[$i]);
429 $code .= $this->php_generate_list($value);
434 if (strlen($code) != 0 && $code[strlen($code) -1] != '.') {
438 $value = array('name' => $value, 'args' => $op[$i]['args']);
439 $code .= $this->php_exec($value, FALSE);
443 $code .= $this->php_generate_stmt(array($value[0]))." => ".$this->php_generate_stmt(array($value[1]));
446 if ($code != "" && $code[strlen($code)-1] == "'") {
447 $code = substr($code, 0, -1);
451 $html = addslashes_ex($value);
452 //$html = addslashes($value);
453 //$html = str_replace(array('$', "\r", "\t", "\n","\\'"), array('\\$', '\r', '\t', '\n',"'"), $html);
457 if (strlen($code) != 0 && $code[strlen($code) -1] != '.') {
460 $code .= $this->php_get_varname($value).'.';
463 if (!is_numeric($value)) {
464 throw new Exception("$value is not a valid number");
469 if (strlen($code) != 0) {
472 $code .= $this->php_generate_expr($op[$i]);
476 if (strlen($code) != 0) {
479 $code .= $this->php_generate_expr($value);
483 if (strlen($code) != 0) {
487 $code .= $this->php_generate_expr($value);
489 $code .= $this->php_generate_stmt(array($op[$i]['true']));
491 $code .= $this->php_generate_stmt(array($op[$i]['false']));
498 throw new Exception("Don't know how to declare {$key} = {$value} (".print_r($op[$i], TRUE));
502 if ($code != "" && $code[strlen($code)-1] == '.') {
503 $code = substr($code, 0, -1);
510 // php_print(array $op) {{{
512 * Return an echo of an stmt
516 protected function php_print($op)
518 $output = $this->php_generate_stmt($op);
519 if ($output == "' '" && Haanga_Compiler
::getOption('strip_whitespace')) {
520 return; /* ignore this */
522 return 'echo '.$output.';';
526 // php_inc(array $op) {{{
528 * Return increment a variable ($var++)
532 protected function php_inc($op)
534 return $this->php_get_varname($op['name'])."++;";
538 // php_declare(array $op, $assign='=') {{{
540 * Return a variable declaration
544 protected function php_declare($op, $assign=' =')
546 $op['name'] = $this->php_get_varname($op['name']);
547 $code = "{$op['name']} {$assign} ".$this->php_generate_stmt($op).";";
552 // php_get_varname(mixed $var) {{{
560 protected function php_get_varname($var)
562 if (is_array($var)) {
563 if (!is_string($var[0])) {
564 if (count($var) == 1) {
565 return $this->php_get_varname($var[0]);
567 throw new Exception("Invalid variable definition ".print_r($var, TRUE));
570 $var_str = $this->php_get_varname($var[0]);
571 for ($i=1; $i < count($var); $i++
) {
572 if (is_string($var[$i])) {
573 $var_str .= "['".addslashes_ex($var[$i])."']";
574 } else if (is_array($var[$i])) {
575 if (isset($var[$i]['var'])) {
576 /* index is a variable */
577 $var_str .= '['.$this->php_get_varname($var[$i]['var']).']';
578 } else if (isset($var[$i]['string'])) {
579 /* index is a string */
580 $var_str .= "['".addslashes_ex($var[$i]['string'])."']";
581 } else if (isset($var[$i]['number'])) {
582 /* index is a number */
583 $var_str .= '['.$var[$i]['number'].']';
584 } else if (isset($var[$i]['object'])) {
585 /* Accessing a object's property */
586 $var_str .= '->'.$var[$i]['object'];
587 } else if ($var[$i] === array()) {
588 /* index is a NULL (do append) */
591 throw new Haanga_Compiler_Exception('Unknown variable definition '.print_r($var, TRUE));
602 // php_return($op) {{{
608 protected function php_return($op)
610 $code = "return ".$this->php_generate_stmt($op).";";
622 * vim600: sw=4 ts=4 fdm=marker