Packages

  • 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

  • NHtmlNode
  • NLatteCompiler
  • NLatteFilter
  • NLatteToken
  • NMacroNode
  • NMacroTokenizer
  • NParser
  • NPhpWriter

Interfaces

  • IMacro

Exceptions

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