/** * Compiles the file * * @param Compiler $compiler * @param StringsManager $stringsManager */ public function compile(Compiler $compiler, StringsManager $stringsManager) { if (!$this->_ir) { throw new CompilerException('IR related to compiled file is missing'); } /** * External classes should not be compiled as part of the extension */ if ($this->_external) { return; } /** * Compilation context stores common objects required by compilation entities */ $compilationContext = new CompilationContext(); /** * Set global compiler in the compilation context */ $compilationContext->compiler = $compiler; /** * Set global config in the compilation context */ $compilationContext->config = $this->_config; /** * Set global logger in the compilation context */ $compilationContext->logger = $this->_logger; /** * Set global strings manager */ $compilationContext->stringsManager = $stringsManager; $compilationContext->backend = $compiler->backend; /** * Headers manager */ $headersManager = new HeadersManager(); $compilationContext->headersManager = $headersManager; /** * Main code-printer for the file */ $codePrinter = new CodePrinter(); $compilationContext->codePrinter = $codePrinter; /** * Alias manager */ $compilationContext->aliasManager = $this->_aliasManager; $codePrinter->outputBlankLine(); $class = false; $interface = false; foreach ($this->_ir as $topStatement) { switch ($topStatement['type']) { case 'class': if ($interface || $class) { throw new CompilerException("More than one class defined in the same file", $topStatement); } $class = true; $this->compileClass($compilationContext, $this->_namespace, $topStatement); break; case 'interface': if ($interface || $class) { throw new CompilerException("More than one class defined in the same file", $topStatement); } $class = true; $this->compileClass($compilationContext, $this->_namespace, $topStatement); break; case 'comment': $this->compileComment($compilationContext, $topStatement); break; } } /* ensure functions are handled last */ foreach ($this->_functionDefinitions as $funcDef) { $this->compileFunction($compilationContext, $funcDef); } /* apply headers */ $this->applyClassHeaders($compilationContext); $classDefinition = $this->_classDefinition; if (!$classDefinition) { $this->_ir = null; return; } $classDefinition->setOriginalNode($this->_originalNode); $completeName = $classDefinition->getCompleteName(); $path = str_replace('\\', DIRECTORY_SEPARATOR, strtolower($completeName)); $filePath = 'ext/' . $path . '.zep.c'; $filePathHeader = 'ext/' . $path . '.zep.h'; if (strpos($path, DIRECTORY_SEPARATOR)) { $dirname = dirname($filePath); if (!is_dir($dirname)) { mkdir($dirname, 0755, true); } } if ($codePrinter) { /** * If the file does not exists we create it for the first time */ if (!file_exists($filePath)) { file_put_contents($filePath, $codePrinter->getOutput()); if ($compilationContext->headerPrinter) { file_put_contents($filePathHeader, $compilationContext->headerPrinter->getOutput()); } } else { $fileSystem = $compiler->getFileSystem(); /** * Use md5 hash to avoid rewrite the file again and again when it hasn't changed * thus avoiding unnecessary recompilations */ $output = $codePrinter->getOutput(); $hash = $fileSystem->getHashFile('md5', $filePath, true); if (md5($output) != $hash) { file_put_contents($filePath, $output); } if ($compilationContext->headerPrinter) { $output = $compilationContext->headerPrinter->getOutput(); $hash = $fileSystem->getHashFile('md5', $filePathHeader, true); if (md5($output) != $hash) { file_put_contents($filePathHeader, $output); } } } } /** * Add to file compiled */ $this->_compiledFile = $path . '.c'; $this->_ir = null; }