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