This class takes generated tokens from the Lexer sequentially
and produces an Abstract Syntax Tree (AST) out of it
The AST is an object-tree containing Node-instances
with parent/child relations
This AST is passed to the compiler to generate PHTML out of it
Usage example:
use Tale\Jade\Parser;
$parser = new Parser();
echo $parser->parse($jadeInput);
Prints a human-readable dump of the parsed nodes
public function convert($inputPath) { $this->prependOptions(['paths' => []]); $parser = new Parser(file_get_contents($inputPath), ['filename' => $inputPath, 'includes' => $this->getOption('paths')]); $compiler = new Compiler(!$this->getManager()->getOption('minify')); return $compiler->compile($parser->parse()); }
/** * Loads an imported file and merges the nodes with the current tree. * * @param Node $node the node to import * * @return $this * @throws Exception */ protected function handleImport(Node $node) { $path = $node->path; if ($node->importType === 'include') { $ext = pathinfo($path, \PATHINFO_EXTENSION); if (empty($ext) && $node->filter && in_array($node->filter, $this->options['filterMap'], true)) { //Get our extension from our filter map $ext = array_search($node->filter, $this->options['filterMap']); } if (!empty($ext) && (!in_array(".{$ext}", $this->options['extensions']) || $node->filter)) { if (!$node->filter && isset($this->options['filterMap'][$ext])) { $node->filter = $this->options['filterMap'][$ext]; } $fullPath = $this->resolvePath($path, ".{$ext}"); if (!$fullPath) { $this->throwException("File {$path} not found in " . implode(', ', $this->options['paths']) . ", Include path: " . get_include_path(), $node); } //remove annoying \r and \0 chars completely $text = trim(str_replace(["\r", ""], '', file_get_contents($fullPath))); $newNode = new Node('text'); $newNode->value = $this->interpolate($text); if ($node->filter) { $filter = new Node('filter'); $filter->name = $node->filter; $filter->append($newNode); $newNode = $filter; } //Notice that include might have an expansion before //We'd need to resolve that before we remove the import \Tale\Jade\Parser\Node alltogether if (isset($node->expands)) { $newNode->expands = $node->expands; unset($node->expands); } $node->parent->insertBefore($node, $newNode); $node->parent->remove($node); return $this; } } $fullPath = $this->resolvePath($path); if (!$fullPath) { $this->throwException("File {$path} wasnt found in " . implode(', ', $this->options['paths']) . ", Include path: " . get_include_path(), $node); } $importedNode = $this->parser->parse(file_get_contents($fullPath)); $this->files[] = $fullPath; $this->handleImports($importedNode); array_pop($this->files); //Notice that include might have an expansion before //We'd need to resolve that before we remove the import \Tale\Jade\Parser\Node alltogether if (isset($node->expands)) { $importedNode->expands = $node->expands; unset($node->expands); } $node->parent->insertBefore($node, $importedNode); $node->parent->remove($node); return $this; }
exit; case 'lex': $lexer = new Lexer(); $result = null; try { ob_start(); $lexer->dump($jade); $result = ob_get_clean(); } catch (\Exception $e) { echo json_encode(['success' => false, 'message' => "\n" . get_class($e) . "\n\n" . $e->getMessage()]); exit; } echo json_encode(['success' => true, 'output' => $result]); exit; case 'parse': $parser = new Parser(); $result = null; try { $result = $parser->parse($jade); } catch (\Exception $e) { echo json_encode(['success' => false, 'message' => "\n" . get_class($e) . "\n\n" . $e->getMessage()]); exit; } echo json_encode(['success' => true, 'output' => (string) $result]); exit; default: echo json_encode(['success' => false, 'message' => 'Invalid mode selected']); } } $view = isset($_GET['view']) ? $_GET['view'] : 'index'; $example = isset($_GET['example']) ? $_GET['example'] : 'index';