public function preCompile(Compiler $compiler)
{
$ir = $this->genIR($compiler);
if (!is_array($ir)) {
throw new Exception("Cannot parse file: " . realpath($this->_filePath));
}
if (isset($ir['type']) && $ir['type'] == 'error') {
throw new ParseException($ir['message'], $ir);
}
/**
* 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;
/**
* Alias manager
*/
$compilationContext->aliasManager = $this->_aliasManager;
$compilationContext->backend = $compiler->backend;
/**
* Traverse the top level statements looking for the namespace
*/
$namespace = null;
foreach ($ir as $topStatement) {
switch ($topStatement['type']) {
case 'namespace':
if ($namespace !== null) {
throw new CompilerException("The namespace must be defined just one time", $topStatement);
}
$namespace = $topStatement['name'];
$this->_namespace = $namespace;
if (!preg_match('/^[A-Z]/', $namespace)) {
throw new CompilerException("Namespace '" . $namespace . "' must be in camelized-form", $topStatement);
}
break;
case 'cblock':
$this->_headerCBlocks[] = $topStatement['value'];
break;
case 'function':
/* Just do the precompilation of the function */
$functionDefinition = new FunctionDefinition($namespace, $topStatement['name'], isset($topStatement['parameters']) ? new ClassMethodParameters($topStatement['parameters']) : null, isset($topStatement['statements']) ? new StatementsBlock($topStatement['statements']) : null, isset($topStatement['return-type']) ? $topStatement['return-type'] : null, $topStatement);
$functionDefinition->preCompile($compilationContext);
$this->addFunction($compiler, $functionDefinition, $topStatement);
break;
}
}
if (!$namespace) {
throw new CompilerException("A namespace is required", $topStatement);
}
/* Set namespace and flag as global, if before namespace declaration */
foreach ($this->_functionDefinitions as $funcDef) {
if ($funcDef->getNamespace() == null) {
$funcDef->setGlobal(true);
$funcDef->setNamespace($compiler->getConfig()->get('namespace'));
}
}
$class = false;
$interface = false;
$lastComment = null;
foreach ($ir as $topStatement) {
switch ($topStatement['type']) {
case 'class':
if ($class || $interface) {
throw new CompilerException("More than one class/interface defined in the same file", $topStatement);
}
$class = true;
$name = $topStatement['name'];
$this->preCompileClass($compilationContext, $namespace, $topStatement, $lastComment);
$this->_originalNode = $topStatement;
$lastComment = null;
break;
case 'interface':
if ($class || $interface) {
throw new CompilerException("More than one class/interface defined in the same file", $topStatement);
}
$interface = true;
$name = $topStatement['name'];
$this->preCompileInterface($namespace, $topStatement, $lastComment);
$this->_originalNode = $topStatement;
$lastComment = null;
break;
case 'use':
if ($interface || $class) {
throw new CompilerException("Aliasing must be done before declaring any class or interface", $topStatement);
}
$this->_aliasManager->add($topStatement);
break;
case 'comment':
$lastComment = $topStatement;
break;
}
}
if (!$class && !$interface) {
throw new CompilerException("Every file must contain at least a class or an interface", $topStatement);
}
if (!$this->_external) {
$expectedPath = strtolower(str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR . $name) . '.zep';
if (strtolower($this->_filePath) != $expectedPath) {
$className = str_replace('\\', '/', $namespace) . '\\' . $name;
$message = 'Unexpected class name ' . $className . ' in file: ' . $this->_filePath . ', expected: ' . $expectedPath;
throw new CompilerException($message);
}
}
if ($compilationContext->classDefinition) {
if ($extendsClass = $compilationContext->classDefinition->getExtendsClass()) {
$compiler->isClass($extendsClass);
}
if ($interfaces = $compilationContext->classDefinition->getImplementedInterfaces()) {
foreach ($interfaces as $interface) {
$compiler->isInterface($interface);
}
}
}
$this->_ir = $ir;
}