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;
}