Пример #1
0
 /**
  * Pre-compiles a Zephir file. Generates the IR and perform basic validations
  *
  * @param Compiler $compiler
  * @throws ParseException
  * @throws CompilerException
  * @throws Exception
  */
 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;
 }
Пример #2
0
 /**
  * Adds a function to the function definitions
  *
  * @param FunctionDefinition $func
  * @param array $statement
  */
 public function addFunction(FunctionDefinition $func, $statement = null)
 {
     $funcName = strtolower($func->getInternalName());
     if (isset($this->functionDefinitions[$funcName])) {
         throw new CompilerException("Function '" . $func->getCompleteName() . "' was defined more than one time", $statement);
     }
     $this->functionDefinitions[$funcName] = $func;
 }