- Added django-yui-layout-templates project with few modifications
[haanga.git] / lib / generator.php
blob7521c5cf239b8fc850e047a08c468b6f2bcdd0c3
1 <?php
2 /*
3 +---------------------------------------------------------------------------------+
4 | Copyright (c) 2010 Haanga |
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. |
10 | |
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. |
14 | |
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. |
18 | |
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. |
22 | |
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 /**
39 * CodeGenerator class
41 * This class takes the generated AST structure (arrays),
42 * and generated the PHP represantion.
46 class Haanga_CodeGenerator
48 protected $ident;
49 protected $tab = " ";
51 // getCode (AST $op_code) {{{
52 /**
53 * Transform the AST generated by the Haanga_Compiler class
54 * and return the equivalent PHP code.
56 * @param array $op_code
58 * @return string
60 final function getCode($op_code)
62 $this->ident = 0;
63 $code = "";
64 foreach ($op_code as $op) {
65 $method = "php_{$op['op']}";
66 if (!is_callable(array($this, $method))) {
67 throw new Exception("CodeGenerator: Missing method $method");
69 switch ($op['op']) {
70 case 'end_foreach':
71 case 'end_if':
72 case 'end_function':
73 case 'else':
74 break;
75 default:
76 $code .= $this->ident();
78 $code .= $this->$method($op);
80 return $code;
82 // }}}
84 // ident() {{{
85 /**
86 * Get the string for the current tabulation
88 * @return string
90 protected function ident()
92 $code = "\n";
93 $code .= str_repeat($this->tab, $this->ident);
95 return $code;
97 // }}}
99 // php_else() {{{
101 * Return code for "else"
103 * @return string
105 protected function php_else()
107 $this->ident--;
108 $code = $this->ident()."} else {";
109 $this->ident++;
110 return $code;
112 // }}}
114 // php_comment() {{{
116 * Return code for "comments"
118 * @return string
120 function php_comment($op)
122 return "/* {$op['comment']} */";
124 // }}}
126 // php_function(array $op) {{{
127 /**
128 * Return the function declaration of the class, for now
129 * it has fixed params, this should change soon to generate
130 * any sort of functions
132 * @return string
134 function php_function($op)
136 $code = "function {$op['name']}(\$vars, \$return=FALSE, \$blocks=array())".$this->ident()."{";
137 $this->ident++;
138 return $code;
140 // }}}
142 // php_if(array $op) {{{
144 * Return the "if" declaration and increase $this->ident
146 * @return string
148 protected function php_if($op)
150 $code = "if (".$this->php_generate_expr($op['expr']).") {";
151 $this->ident++;
152 return $code;
154 // }}}
156 // php_expr($op) {{{
158 * Return a stand-alone statement
160 * @return string
162 protected function php_expr($op)
164 return $this->php_generate_expr($op[0]).";";
166 // }}}
168 // php_end_block() {{{
170 * Finish the current block (if, for, function, etc),
171 * return the final "}", and decrease $this->ident
173 * @return string
175 protected function php_end_block()
177 $this->ident--;
178 return $this->ident()."}";
180 // }}}
182 // php_end_function() {{{
184 * Return code to end a function
186 * @return string
188 protected function php_end_function()
190 return $this->php_end_block();
192 // }}}
194 // php_end_if() {{{
196 * Return code to end a if
198 * @return string
200 protected function php_end_if()
202 return $this->php_end_block();
204 // }}}
206 // php_end_foreach() {{{
208 * Return code to end a foreach
210 * @return string
212 protected function php_end_foreach()
214 return $this->php_end_block();
216 // }}}
218 // php_foreach(array $op) {{{
220 * Return the declaration of a "foreach" statement.
222 * @return string
224 protected function php_foreach($op)
226 $op['array'] = $this->php_get_varname($op['array']);
227 $op['value'] = $this->php_get_varname($op['value']);
228 $code = "foreach ({$op['array']} as ";
229 if (!isset($op['key'])) {
230 $code .= " {$op['value']}";
231 } else {
232 $op['key'] = $this->php_get_varname($op['key']);
233 $code .= " {$op['key']} => {$op['value']}";
236 $code .= ") {";
237 $this->ident++;
238 return $code;
240 // }}}
242 // php_append_var(array $op) {{{
244 * Return code to append something to a variable
246 * @return string
248 protected function php_append_var($op)
250 return $this->php_declare($op, '.=');
252 // }}}
254 // php_exec($op) {{{
256 * Return code for a function calling.
258 * @return string
260 protected function php_exec($op)
262 $code = "";
263 $code .= $op['name'].'(';
264 if (isset($op['args'])) {
265 $code .= $this->php_generate_list($op['args']);
267 $code .= ')';
268 return $code;
270 // }}}
272 // php_generate_expr($op) {{{
274 * Return an expression
276 * @return string
278 protected function php_generate_expr($expr)
280 $code = '';
281 if (is_array($expr) && isset($expr['op_expr'])) {
282 if ($expr['op_expr'] == 'expr') {
283 $code .= "(";
284 $code .= $this->php_generate_expr($expr[0]);
285 $code .= ")";
286 } else {
287 $code .= $this->php_generate_expr($expr[0]);
288 $code .= " {$expr['op_expr']} ";
289 $code .= $this->php_generate_expr($expr[1]);
291 } else {
292 if (is_array($expr)) {
293 $code .= $this->php_generate_stmt(array($expr));
294 } else {
295 if ($expr === FALSE) {
296 $expr = 'FALSE';
297 } else if ($expr === TRUE) {
298 $expr = 'TRUE';
300 $code .= $expr;
303 return $code;
305 // }}}
307 // php_generate_list(array ($array) {{{
309 * Return a list of expressions for parameters
310 * of a function
312 * @return string
314 protected function php_generate_list($array)
316 $code = "";
317 foreach ($array as $value) {
318 $code .= $this->php_generate_stmt(array($value));
319 $code .= ", ";
321 return substr($code, 0, -2);
323 // }}}
325 // php_generate_stmt(Array $op) {{{
327 * Return the representation of a statement
329 * @return string
331 protected function php_generate_stmt($op)
333 $code = "";
335 for ($i=0; $i < count($op); $i++) {
336 if (!isset($op[$i])) {
337 continue;
339 if (!is_Array($op[$i])) {
340 throw new Haanga_CompilerException("Malformed declaration ".print_r($op, TRUE));
342 $key = key($op[$i]);
343 $value = current($op[$i]);
344 switch ($key) {
345 case 'array':
346 $code .= "Array(";
347 $code .= $this->php_generate_list($value);
348 $code .= ")";
349 break;
350 case 'function':
351 case 'exec':
352 if (strlen($code) != 0 && $code[strlen($code) -1] != '.') {
353 $code .= '.';
356 $value = array('name' => $value, 'args' => $op[$i]['args']);
357 $code .= $this->php_exec($value, FALSE);
358 $code .= '.';
359 break;
360 case 'key':
361 $code .= $this->php_generate_stmt(array($value[0]))." => ".$this->php_generate_stmt(array($value[1]));
362 break;
363 case 'string':
364 if ($code != "" && $code[strlen($code)-1] == '"') {
365 $code = substr($code, 0, -1);
366 } else {
367 $code .= '"';
369 $html = addslashes($value);
370 $html = str_replace(array('$', "\r", "\t", "\n","\\'"), array('\\$', '\r', '\t', '\n',"'"), $html);
371 $code .= $html.'"';
372 break;
373 case 'var':
374 if (strlen($code) != 0 && $code[strlen($code) -1] != '.') {
375 $code .= '.';
377 $code .= $this->php_get_varname($value).'.';
378 break;
379 case 'number':
380 if (!is_numeric($value)) {
381 throw new Exception("$value is not a valid number");
383 $code .= $value;
384 break;
385 case 'op_expr':
386 if (strlen($code) != 0) {
387 $code .= '.';
389 $code .= $this->php_generate_expr($op[$i]);
390 $code .= ".";
391 break;
392 case 'expr':
393 if (strlen($code) != 0) {
394 $code .= '.';
396 $code .= $this->php_generate_expr($value);
397 $code .= ".";
398 break;
399 case 'expr_cond':
400 if (strlen($code) != 0) {
401 $code .= '.';
403 $code .= "(";
404 $code .= $this->php_generate_expr($value);
405 $code .= " ? ";
406 $code .= $this->php_generate_stmt(array($op[$i]['true']));
407 $code .= " : ";
408 $code .= $this->php_generate_stmt(array($op[$i]['false']));
409 $code .= ").";
410 break;
411 case 'constant':
412 $code = $value;
413 break;
414 default:
415 throw new Exception("Don't know how to declare {$key} = {$value} (".print_r($op[$i], TRUE));
419 if ($code != "" && $code[strlen($code)-1] == '.') {
420 $code = substr($code, 0, -1);
423 return $code;
425 // }}}
427 // php_print(array $op) {{{
429 * Return an echo of an stmt
431 * @return string
433 protected function php_print($op)
435 return 'echo '.$this->php_generate_stmt($op).';';
437 // }}}
439 // php_inc(array $op) {{{
441 * Return increment a variable ($var++)
443 * @return string
445 protected function php_inc($op)
447 return $this->php_get_varname($op['name'])."++;";
449 // }}}
451 // php_declare(array $op, $assign='=') {{{
453 * Return a variable declaration
455 * @return string
457 protected function php_declare($op, $assign=' =')
459 $op['name'] = $this->php_get_varname($op['name']);
460 $code = "{$op['name']} {$assign} ".$this->php_generate_stmt($op).";";
461 return $code;
463 // }}}
465 // php_get_varname(mixed $var) {{{
467 * Return a variable
469 * @param mixed $var
471 * @return string
473 protected function php_get_varname($var)
475 if (is_array($var)) {
476 if (!is_string($var[0])) {
477 if (count($var) == 1) {
478 return $this->php_get_varname($var[0]);
479 } else {
480 throw new Exception("Invalid variable definition ".print_r($var, TRUE));
483 $var_str = $this->php_get_varname($var[0]);
484 for ($i=1; $i < count($var); $i++) {
485 $var_str .= "[";
486 if (is_string($var[$i])) {
487 $var_str .= '"'.$var[$i].'"';
488 } else if (is_array($var[$i])) {
489 if (isset($var[$i]['var'])) {
490 $var_str .= $this->php_get_varname($var[$i]['var']);
491 } else if (isset($var[$i]['string'])) {
492 $var_str .= '"'.addslashes($var[$i]['string']).'"';
495 $var_str .= "]";
497 return $var_str;
498 } else {
499 return "\$".$var;
502 // }}}
504 // php_return($op) {{{
506 * Return "return"
508 * @return string
510 protected function php_return($op)
512 $code = "return ".$this->php_generate_stmt($op).";";
513 return $code;
515 // }}}
520 * Local variables:
521 * tab-width: 4
522 * c-basic-offset: 4
523 * End:
524 * vim600: sw=4 ts=4 fdm=marker
525 * vim<600: sw=4 ts=4