Namespaces

  • Nette
    • Application
      • Diagnostics
      • Responses
      • Routers
      • UI
    • Caching
      • Storages
    • ComponentModel
    • Config
      • Adapters
      • Extensions
    • Database
      • Diagnostics
      • Drivers
      • Reflection
      • Table
    • DI
      • Diagnostics
    • Diagnostics
    • Forms
      • Controls
      • Rendering
    • Http
    • Iterators
    • Latte
      • Macros
    • Loaders
    • Localization
    • Mail
    • Reflection
    • Security
      • Diagnostics
    • Templating
    • Utils
      • PhpGenerator
  • NetteModule
  • None
  • PHP

Classes

  • Compiler
  • Engine
  • HtmlNode
  • MacroNode
  • MacroTokenizer
  • Parser
  • PhpWriter
  • Token

Interfaces

  • IMacro

Exceptions

  • CompileException
  • Overview
  • Namespace
  • Class
  • Tree
  1: <?php
  2: 
  3: /**
  4:  * This file is part of the Nette Framework (http://nette.org)
  5:  *
  6:  * Copyright (c) 2004 David Grudl (http://davidgrudl.com)
  7:  *
  8:  * For the full copyright and license information, please view
  9:  * the file license.txt that was distributed with this source code.
 10:  */
 11: 
 12: namespace Nette\Latte;
 13: 
 14: use Nette;
 15: 
 16: 
 17: 
 18: /**
 19:  * PHP code generator helpers.
 20:  *
 21:  * @author     David Grudl
 22:  */
 23: class PhpWriter extends Nette\Object
 24: {
 25:     /** @var MacroTokenizer */
 26:     private $argsTokenizer;
 27: 
 28:     /** @var string */
 29:     private $modifiers;
 30: 
 31:     /** @var Compiler */
 32:     private $compiler;
 33: 
 34: 
 35: 
 36:     public static function using(MacroNode $node, $compiler = NULL)
 37:     {
 38:         return new static($node->tokenizer, $node->modifiers, $compiler);
 39:     }
 40: 
 41: 
 42: 
 43:     public function __construct(MacroTokenizer $argsTokenizer, $modifiers = NULL, Compiler $compiler = NULL)
 44:     {
 45:         $this->argsTokenizer = $argsTokenizer;
 46:         $this->modifiers = $modifiers;
 47:         $this->compiler = $compiler;
 48:     }
 49: 
 50: 
 51: 
 52:     /**
 53:      * Expands %node.word, %node.array, %node.args, %escape(), %modify(), %var, %raw in code.
 54:      * @param  string
 55:      * @return string
 56:      */
 57:     public function write($mask)
 58:     {
 59:         $args = func_get_args();
 60:         array_shift($args);
 61:         $word = strpos($mask, '%node.word') === FALSE ? NULL : $this->argsTokenizer->fetchWord();
 62:         $me = $this;
 63:         $mask = Nette\Utils\Strings::replace($mask, '#%escape(\(([^()]*+|(?1))+\))#', function($m) use ($me) {
 64:             return $me->escape(substr($m[1], 1, -1));
 65:         });
 66:         $mask = Nette\Utils\Strings::replace($mask, '#%modify(\(([^()]*+|(?1))+\))#', function($m) use ($me) {
 67:             return $me->formatModifiers(substr($m[1], 1, -1));
 68:         });
 69: 
 70:         return Nette\Utils\Strings::replace($mask, '#([,+]\s*)?%(node\.word|node\.array|node\.args|var|raw)(\?)?(\s*\+\s*)?()#',
 71:             function($m) use ($me, $word, & $args) {
 72:             list(, $l, $macro, $cond, $r) = $m;
 73: 
 74:             switch ($macro) {
 75:             case 'node.word':
 76:                 $code = $me->formatWord($word); break;
 77:             case 'node.args':
 78:                 $code = $me->formatArgs(); break;
 79:             case 'node.array':
 80:                 $code = $me->formatArray();
 81:                 $code = $cond && $code === 'array()' ? '' : $code; break;
 82:             case 'var':
 83:                 $code = var_export(array_shift($args), TRUE); break;
 84:             case 'raw':
 85:                 $code = (string) array_shift($args); break;
 86:             }
 87: 
 88:             if ($cond && $code === '') {
 89:                 return $r ? $l : $r;
 90:             } else {
 91:                 return $l . $code . $r;
 92:             }
 93:         });
 94:     }
 95: 
 96: 
 97: 
 98:     /**
 99:      * Formats modifiers calling.
100:      * @param  string
101:      * @return string
102:      */
103:     public function formatModifiers($var)
104:     {
105:         $modifiers = ltrim($this->modifiers, '|');
106:         if (!$modifiers) {
107:             return $var;
108:         }
109: 
110:         $tokenizer = $this->preprocess(new MacroTokenizer($modifiers));
111:         $inside = FALSE;
112:         while ($token = $tokenizer->fetchToken()) {
113:             if ($token['type'] === MacroTokenizer::T_WHITESPACE) {
114:                 $var = rtrim($var) . ' ';
115: 
116:             } elseif (!$inside) {
117:                 if ($token['type'] === MacroTokenizer::T_SYMBOL) {
118:                     if ($this->compiler && $token['value'] === 'escape') {
119:                         $var = $this->escape($var);
120:                         $tokenizer->fetch('|');
121:                     } else {
122:                         $var = "\$template->" . $token['value'] . "($var";
123:                         $inside = TRUE;
124:                     }
125:                 } else {
126:                     throw new CompileException("Modifier name must be alphanumeric string, '$token[value]' given.");
127:                 }
128:             } else {
129:                 if ($token['value'] === ':' || $token['value'] === ',') {
130:                     $var = $var . ', ';
131: 
132:                 } elseif ($token['value'] === '|') {
133:                     $var = $var . ')';
134:                     $inside = FALSE;
135: 
136:                 } else {
137:                     $var .= $this->canQuote($tokenizer) ? "'$token[value]'" : $token['value'];
138:                 }
139:             }
140:         }
141:         return $inside ? "$var)" : $var;
142:     }
143: 
144: 
145: 
146:     /**
147:      * Formats macro arguments to PHP code.
148:      * @return string
149:      */
150:     public function formatArgs()
151:     {
152:         $out = '';
153:         $tokenizer = $this->preprocess();
154:         while ($token = $tokenizer->fetchToken()) {
155:             $out .= $this->canQuote($tokenizer) ? "'$token[value]'" : $token['value'];
156:         }
157:         return $out;
158:     }
159: 
160: 
161: 
162:     /**
163:      * Formats macro arguments to PHP array.
164:      * @return string
165:      */
166:     public function formatArray()
167:     {
168:         $out = '';
169:         $expand = NULL;
170:         $tokenizer = $this->preprocess();
171:         while ($token = $tokenizer->fetchToken()) {
172:             if ($token['value'] === '(expand)' && $token['depth'] === 0) {
173:                 $expand = TRUE;
174:                 $out .= '),';
175: 
176:             } elseif ($expand && ($token['value'] === ',') && !$token['depth']) {
177:                 $expand = FALSE;
178:                 $out .= ', array(';
179:             } else {
180:                 $out .= $this->canQuote($tokenizer) ? "'$token[value]'" : $token['value'];
181:             }
182:         }
183:         if ($expand === NULL) {
184:             return "array($out)";
185:         } else {
186:             return "array_merge(array($out" . ($expand ? ', array(' : '') ."))";
187:         }
188:     }
189: 
190: 
191: 
192:     /**
193:      * Formats parameter to PHP string.
194:      * @param  string
195:      * @return string
196:      */
197:     public function formatWord($s)
198:     {
199:         return (is_numeric($s) || strspn($s, '\'"$') || in_array(strtolower($s), array('true', 'false', 'null')))
200:             ? $s : '"' . $s . '"';
201:     }
202: 
203: 
204: 
205:     /**
206:      * @return bool
207:      */
208:     public function canQuote($tokenizer)
209:     {
210:         return $tokenizer->isCurrent(MacroTokenizer::T_SYMBOL)
211:             && (!$tokenizer->hasPrev() || $tokenizer->isPrev(',', '(', '[', '=', '=>', ':', '?'))
212:             && (!$tokenizer->hasNext() || $tokenizer->isNext(',', ')', ']', '=', '=>', ':', '|'));
213:     }
214: 
215: 
216: 
217:     /**
218:      * Preprocessor for tokens.
219:      * @return MacroTokenizer
220:      */
221:     public function preprocess(MacroTokenizer $tokenizer = NULL)
222:     {
223:         $tokenizer = $tokenizer === NULL ? $this->argsTokenizer : $tokenizer;
224:         $inTernary = $prev = NULL;
225:         $tokens = $arrays = array();
226:         while ($token = $tokenizer->fetchToken()) {
227:             $token['depth'] = $depth = count($arrays);
228: 
229:             if ($token['type'] === MacroTokenizer::T_COMMENT) {
230:                 continue; // remove comments
231: 
232:             } elseif ($token['type'] === MacroTokenizer::T_WHITESPACE) {
233:                 $tokens[] = $token;
234:                 continue;
235:             }
236: 
237:             if ($token['value'] === '?') { // short ternary operators without :
238:                 $inTernary = $depth;
239: 
240:             } elseif ($token['value'] === ':') {
241:                 $inTernary = NULL;
242: 
243:             } elseif ($inTernary === $depth && ($token['value'] === ',' || $token['value'] === ')' || $token['value'] === ']')) { // close ternary
244:                 $tokens[] = MacroTokenizer::createToken(':') + array('depth' => $depth);
245:                 $tokens[] = MacroTokenizer::createToken('null') + array('depth' => $depth);
246:                 $inTernary = NULL;
247:             }
248: 
249:             if ($token['value'] === '[') { // simplified array syntax [...]
250:                 if ($arrays[] = $prev['value'] !== ']' && $prev['type'] !== MacroTokenizer::T_SYMBOL && $prev['type'] !== MacroTokenizer::T_VARIABLE && $prev['type'] !== MacroTokenizer::T_KEYWORD) {
251:                     $tokens[] = MacroTokenizer::createToken('array') + array('depth' => $depth);
252:                     $token = MacroTokenizer::createToken('(');
253:                 }
254:             } elseif ($token['value'] === ']') {
255:                 if (array_pop($arrays) === TRUE) {
256:                     $token = MacroTokenizer::createToken(')');
257:                 }
258:             } elseif ($token['value'] === '(') { // only count
259:                 $arrays[] = '(';
260: 
261:             } elseif ($token['value'] === ')') { // only count
262:                 array_pop($arrays);
263:             }
264: 
265:             $tokens[] = $prev = $token;
266:         }
267: 
268:         if ($inTernary !== NULL) { // close ternary
269:             $tokens[] = MacroTokenizer::createToken(':') + array('depth' => count($arrays));
270:             $tokens[] = MacroTokenizer::createToken('null') + array('depth' => count($arrays));
271:         }
272: 
273:         $tokenizer = clone $tokenizer;
274:         $tokenizer->reset();
275:         $tokenizer->tokens = $tokens;
276:         return $tokenizer;
277:     }
278: 
279: 
280: 
281:     public function escape($s)
282:     {
283:         switch ($this->compiler->getContentType()) {
284:         case Compiler::CONTENT_XHTML:
285:         case Compiler::CONTENT_HTML:
286:             $context = $this->compiler->getContext();
287:             switch ($context[0]) {
288:             case Compiler::CONTEXT_SINGLE_QUOTED:
289:             case Compiler::CONTEXT_DOUBLE_QUOTED:
290:                 if ($context[1] === Compiler::CONTENT_JS) {
291:                     $s = "Nette\\Templating\\Helpers::escapeJs($s)";
292:                 } elseif ($context[1] === Compiler::CONTENT_CSS) {
293:                     $s = "Nette\\Templating\\Helpers::escapeCss($s)";
294:                 }
295:                 $quote = $context[0] === Compiler::CONTEXT_DOUBLE_QUOTED ? '' : ', ENT_QUOTES';
296:                 return "htmlSpecialChars($s$quote)";
297:             case Compiler::CONTEXT_COMMENT:
298:                 return "Nette\\Templating\\Helpers::escapeHtmlComment($s)";
299:             case Compiler::CONTENT_JS:
300:             case Compiler::CONTENT_CSS:
301:                 return 'Nette\Templating\Helpers::escape' . ucfirst($context[0]) . "($s)";
302:             default:
303:                 return "Nette\\Templating\\Helpers::escapeHtml($s, ENT_NOQUOTES)";
304:             }
305:         case Compiler::CONTENT_XML:
306:         case Compiler::CONTENT_JS:
307:         case Compiler::CONTENT_CSS:
308:         case Compiler::CONTENT_ICAL:
309:             return 'Nette\Templating\Helpers::escape' . ucfirst($this->compiler->getContentType()) . "($s)";
310:         case Compiler::CONTENT_TEXT:
311:             return $s;
312:         default:
313:             return "\$template->escape($s)";
314:         }
315:     }
316: 
317: }
318: 
Nette Framework 2.0.0 API API documentation generated by ApiGen 2.7.0