1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10: 11:
12:
13:
14:
15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39:
40: class NCoreMacros extends NMacroSet
41: {
42:
43:
44: public static function install(NParser $parser)
45: {
46: $me = new self($parser);
47:
48: $me->addMacro('if', array($me, 'macroIf'), array($me, 'macroEndIf'));
49: $me->addMacro('elseif', 'elseif (%node.args):');
50: $me->addMacro('else', 'else:');
51: $me->addMacro('ifset', 'if (isset(%node.args)):', 'endif');
52: $me->addMacro('elseifset', 'elseif (isset(%node.args)):');
53:
54: $me->addMacro('foreach', array($me, 'macroForeach'), '$iterations++; endforeach; array_pop($_l->its); $iterator = end($_l->its)');
55: $me->addMacro('for', 'for (%node.args):', 'endfor');
56: $me->addMacro('while', 'while (%node.args):', 'endwhile');
57: $me->addMacro('continueIf', 'if (%node.args) continue');
58: $me->addMacro('breakIf', 'if (%node.args) break');
59: $me->addMacro('first', 'if ($iterator->isFirst(%node.args)):', 'endif');
60: $me->addMacro('last', 'if ($iterator->isLast(%node.args)):', 'endif');
61: $me->addMacro('sep', 'if (!$iterator->isLast(%node.args)):', 'endif');
62:
63: $me->addMacro('var', array($me, 'macroVar'));
64: $me->addMacro('assign', array($me, 'macroVar'));
65: $me->addMacro('default', array($me, 'macroVar'));
66: $me->addMacro('dump', array($me, 'macroDump'));
67: $me->addMacro('debugbreak', array($me, 'macroDebugbreak'));
68: $me->addMacro('l', '?>{<?php');
69: $me->addMacro('r', '?>}<?php');
70:
71: $me->addMacro('_', array($me, 'macroTranslate'), array($me, 'macroTranslate'));
72: $me->addMacro('=', array($me, 'macroExpr'));
73: $me->addMacro('?', array($me, 'macroExpr'));
74:
75: $me->addMacro('syntax', array($me, 'macroSyntax'), array($me, 'macroSyntax'));
76: $me->addMacro('capture', array($me, 'macroCapture'), array($me, 'macroCaptureEnd'));
77: $me->addMacro('include', array($me, 'macroInclude'));
78: $me->addMacro('use', array($me, 'macroUse'));
79:
80: $me->addMacro('@href', NULL, NULL);
81: $me->addMacro('@class', array($me, 'macroClass'));
82: $me->addMacro('@attr', array($me, 'macroAttr'));
83: $me->addMacro('attr', array($me, 'macroOldAttr'));
84: }
85:
86:
87:
88: 89: 90: 91:
92: public function finalize()
93: {
94: return array('list($_l, $_g) = NCoreMacros::initRuntime($template, '
95: . var_export($this->parser->templateId, TRUE) . ')');
96: }
97:
98:
99:
100:
101:
102:
103:
104: 105: 106:
107: public function macroIf(NMacroNode $node, $writer)
108: {
109: if ($node->data->capture = ($node->args === '')) {
110: return 'ob_start()';
111: }
112: return $writer->write('if (%node.args):');
113: }
114:
115:
116:
117: 118: 119:
120: public function macroEndIf(NMacroNode $node, $writer)
121: {
122: if ($node->data->capture) {
123: if ($node->args === '') {
124: throw new NLatteException('Missing condition in {if} macro.');
125: }
126: return $writer->write('if (%node.args) ob_end_flush(); else ob_end_clean()');
127: }
128: return 'endif';
129: }
130:
131:
132:
133: 134: 135:
136: public function macroTranslate(NMacroNode $node, $writer)
137: {
138: if ($node->closing) {
139: return $writer->write('echo %modify($template->translate(ob_get_clean()))');
140:
141: } elseif ($node->isEmpty = ($node->args !== '')) {
142: return $writer->write('echo %modify($template->translate(%node.args))');
143:
144: } else {
145: return 'ob_start()';
146: }
147: }
148:
149:
150:
151: 152: 153:
154: public function macroSyntax(NMacroNode $node)
155: {
156: if ($node->closing) {
157: $node->args = 'latte';
158: }
159: switch ($node->args) {
160: case '':
161: case 'latte':
162: $this->parser->setDelimiters('\\{(?![\\s\'"{}])', '\\}');
163: break;
164:
165: case 'double':
166: $this->parser->setDelimiters('\\{\\{(?![\\s\'"{}])', '\\}\\}');
167: break;
168:
169: case 'asp':
170: $this->parser->setDelimiters('<%\s*', '\s*%>');
171: break;
172:
173: case 'python':
174: $this->parser->setDelimiters('\\{[{%]\s*', '\s*[%}]\\}');
175: break;
176:
177: case 'off':
178: $this->parser->setDelimiters('[^\x00-\xFF]', '');
179: break;
180:
181: default:
182: throw new NLatteException("Unknown syntax '$node->args'");
183: }
184: }
185:
186:
187:
188: 189: 190:
191: public function macroInclude(NMacroNode $node, $writer)
192: {
193: $code = $writer->write('NCoreMacros::includeTemplate(%node.word, %node.array? + $template->getParams(), $_l->templates[%var])',
194: $this->parser->templateId);
195:
196: if ($node->modifiers) {
197: return $writer->write('echo %modify(%raw->__toString(TRUE))', $code);
198: } else {
199: return $code . '->render()';
200: }
201: }
202:
203:
204:
205: 206: 207:
208: public function macroUse(NMacroNode $node, $writer)
209: {
210: call_user_func(array($node->tokenizer->fetchWord(), 'install'), $this->parser)
211: ->initialize();
212: }
213:
214:
215:
216: 217: 218:
219: public function macroCapture(NMacroNode $node, $writer)
220: {
221: $variable = $node->tokenizer->fetchWord();
222: if (substr($variable, 0, 1) !== '$') {
223: throw new NLatteException("Invalid capture block variable '$variable'");
224: }
225: $node->data->variable = $variable;
226: return 'ob_start()';
227: }
228:
229:
230:
231: 232: 233:
234: public function macroCaptureEnd(NMacroNode $node, $writer)
235: {
236: return $writer->write("{$node->data->variable} = %modify(ob_get_clean())");
237: }
238:
239:
240:
241: 242: 243:
244: public function macroForeach(NMacroNode $node, $writer)
245: {
246: return '$iterations = 0; foreach ($iterator = $_l->its[] = new NSmartCachingIterator('
247: . preg_replace('#(.*)\s+as\s+#i', '$1) as ', $writer->formatArgs(), 1) . '):';
248: }
249:
250:
251:
252: 253: 254:
255: public function macroClass(NMacroNode $node, $writer)
256: {
257: return $writer->write('if ($_l->tmp = trim(implode(" ", array_unique(%node.array)))) echo \' class="\' . %escape($_l->tmp) . \'"\'');
258: }
259:
260:
261:
262: 263: 264:
265: public function macroAttr(NMacroNode $node, $writer)
266: {
267: return $writer->write('echo NHtml::el(NULL, %node.array)->attributes()');
268: }
269:
270:
271:
272: 273: 274: 275:
276: public function macroOldAttr(NMacroNode $node)
277: {
278: return NStrings::replace($node->args . ' ', '#\)\s+#', ')->');
279: }
280:
281:
282:
283: 284: 285:
286: public function macroDump(NMacroNode $node, $writer)
287: {
288: $args = $writer->formatArgs();
289: return $writer->write('NDebugger::barDump(' . ($node->args ? "array(%var => $args)" : 'get_defined_vars()')
290: . ', "Template " . str_replace(dirname(dirname($template->getFile())), "\xE2\x80\xA6", $template->getFile()))', $args);
291: }
292:
293:
294:
295: 296: 297:
298: public function macroDebugbreak(NMacroNode $node, $writer)
299: {
300: return $writer->write(($node->args == NULL ? '' : 'if (!(%node.args)); else')
301: . 'if (function_exists("debugbreak")) debugbreak(); elseif (function_exists("xdebug_break")) xdebug_break()');
302: }
303:
304:
305:
306: 307: 308: 309:
310: public function macroVar(NMacroNode $node, $writer)
311: {
312: $out = '';
313: $var = TRUE;
314: $tokenizer = $writer->preprocess();
315: while ($token = $tokenizer->fetchToken()) {
316: if ($var && ($token['type'] === NMacroTokenizer::T_SYMBOL || $token['type'] === NMacroTokenizer::T_VARIABLE)) {
317: if ($node->name === 'default') {
318: $out .= "'" . ltrim($token['value'], "$") . "'";
319: } else {
320: $out .= '$' . ltrim($token['value'], "$");
321: }
322: $var = NULL;
323:
324: } elseif (($token['value'] === '=' || $token['value'] === '=>') && $token['depth'] === 0) {
325: $out .= $node->name === 'default' ? '=>' : '=';
326: $var = FALSE;
327:
328: } elseif ($token['value'] === ',' && $token['depth'] === 0) {
329: $out .= $node->name === 'default' ? ',' : ';';
330: $var = TRUE;
331:
332: } elseif ($var === NULL && $node->name === 'default' && $token['type'] !== NMacroTokenizer::T_WHITESPACE) {
333: throw new NLatteException("Unexpected '$token[value]' in {default $node->args}");
334:
335: } else {
336: $out .= $writer->canQuote($tokenizer) ? "'$token[value]'" : $token['value'];
337: }
338: }
339: return $node->name === 'default' ? "extract(array($out), EXTR_SKIP)" : $out;
340: }
341:
342:
343:
344: 345: 346: 347:
348: public function macroExpr(NMacroNode $node, $writer)
349: {
350: return $writer->write(($node->name === '?' ? '' : 'echo ') . '%modify(%node.args)');
351: }
352:
353:
354:
355:
356:
357:
358:
359: 360: 361: 362: 363: 364: 365:
366: public static function includeTemplate($destination, $params, $template)
367: {
368: if ($destination instanceof ITemplate) {
369: $tpl = $destination;
370:
371: } elseif ($destination == NULL) {
372: throw new InvalidArgumentException("Template file name was not specified.");
373:
374: } else {
375: $tpl = clone $template;
376: if ($template instanceof IFileTemplate) {
377: if (substr($destination, 0, 1) !== '/' && substr($destination, 1, 1) !== ':') {
378: $destination = dirname($template->getFile()) . '/' . $destination;
379: }
380: $tpl->setFile($destination);
381: }
382: }
383:
384: $tpl->setParams($params);
385: return $tpl;
386: }
387:
388:
389:
390: 391: 392: 393: 394: 395:
396: public static function initRuntime($template, $templateId)
397: {
398:
399: if (isset($template->_l)) {
400: $local = $template->_l;
401: unset($template->_l);
402: } else {
403: $local = (object) NULL;
404: }
405: $local->templates[$templateId] = $template;
406:
407:
408: if (!isset($template->_g)) {
409: $template->_g = (object) NULL;
410: }
411:
412: return array($local, $template->_g);
413: }
414:
415: }
416: