Exemplo n.º 1
0
 public function scan()
 {
     require_once $this->path;
     $ns = "";
     $_ns = "";
     $ns_bracket = false;
     $aliases = [];
     $tokens = new Tokenizer(FS::get($this->path));
     while ($tokens->valid()) {
         if ($tokens->is(T_NAMESPACE)) {
             $ns = "";
             $_ns = "";
             $tokens->next();
             if ($tokens->is(T_STRING)) {
                 $ns = $this->_parseName($tokens);
                 if ($tokens->is('{')) {
                     $tokens->skip();
                     $ns_bracket = true;
                 } else {
                     $tokens->skipIf(';');
                 }
                 $_ns = $ns . '\\';
             } elseif ($tokens->is('{')) {
                 $ns_bracket = true;
                 $tokens->next();
             }
         } elseif ($tokens->is(T_USE)) {
             do {
                 $tokens->next();
                 $name = $this->_parseName($tokens);
                 if ($tokens->is(T_AS)) {
                     $aliases[$tokens->next()->get(T_STRING)] = $name;
                     $tokens->next();
                 } else {
                     if (strpos($name, '\\') === false) {
                         $aliases[$name] = $name;
                     } else {
                         $aliases[ltrim('\\', strrchr($name, '\\'))] = $name;
                     }
                 }
             } while ($tokens->is(','));
             $tokens->need(';')->next();
         } elseif ($tokens->is(T_CONST)) {
             $name = $tokens->next()->get(T_STRING);
             $constant = new EntityConstant($_ns . $name);
             $constant->setValue(constant($_ns . $name));
             $constant->setLine($this->line($tokens->getLine()));
             $this->constants[$_ns . $name] = $constant;
             $tokens->forwardTo(';')->next();
         } elseif ($tokens->is(T_FUNCTION)) {
             $name = $tokens->next()->get(T_STRING);
             $function = new EntityFunction($_ns . $name);
             $function->setLine($this->line($tokens->getLine()));
             $function->setAliases($aliases);
             $this->parseCallable($function, new \ReflectionFunction($function->name));
             $function->setBody($tokens->forwardTo('{')->getScope());
             $tokens->next();
             $this->functions[$function->name] = $function;
         } elseif ($tokens->is(T_FINAL, T_ABSTRACT, T_INTERFACE, T_TRAIT, T_CLASS)) {
             $tokens->forwardTo(T_STRING);
             $name = $tokens->current();
             $class = new EntityClass($_ns . $name);
             $ref = new \ReflectionClass($class->name);
             $doc = $ref->getDocComment();
             //                if($name == "NamesInterface") {
             //                    drop($ref);
             //                }
             if ($ref->isInterface()) {
                 $class->addFlag(Flags::IS_INTERFACE);
             } elseif ($ref->isTrait()) {
                 $class->addFlag(Flags::IS_TRAIT);
             } else {
                 $class->addFlag(Flags::IS_CLASS);
             }
             if ($ref->isAbstract()) {
                 $class->addFlag(Flags::IS_ABSTRACT);
             } elseif ($ref->isFinal()) {
                 $class->addFlag(Flags::IS_FINAL);
             }
             if ($doc) {
                 $info = ToolKit::parseDoc($doc);
                 $class->setDescription($info['desc']);
                 $class->addOptions($info['options']);
             }
             $class->setAliases($aliases);
             $class->setLine($this->line($tokens->getLine()));
             $tokens->next();
             if ($tokens->is(T_EXTENDS)) {
                 // process 'extends' keyword
                 do {
                     $tokens->next();
                     $root = $tokens->is(T_NS_SEPARATOR);
                     $parent = $this->_parseName($tokens);
                     if ($root) {
                         // extends from root namespace
                         $class->setParent($parent, $class->isInterface());
                     } elseif (isset($aliases[$parent])) {
                         $class->setParent($aliases[$parent], $class->isInterface());
                     } else {
                         $class->setParent($_ns . $parent, $class->isInterface());
                     }
                 } while ($tokens->is(','));
             }
             if ($tokens->is(T_IMPLEMENTS)) {
                 // process 'implements' keyword
                 do {
                     $tokens->next();
                     $root = $tokens->is(T_NS_SEPARATOR);
                     $parent = $this->_parseName($tokens);
                     if ($root) {
                         // extends from root namespace
                         $class->addInterface($parent);
                     } elseif (isset($aliases[$parent])) {
                         $class->addInterface($aliases[$parent]);
                     } else {
                         $class->addInterface($_ns . $parent);
                     }
                 } while ($tokens->is(','));
             }
             $tokens->forwardTo('{')->next();
             while ($tokens->forwardTo(T_CONST, T_FUNCTION, '{', '}', T_VARIABLE) && $tokens->valid()) {
                 switch ($tokens->key()) {
                     case T_CONST:
                         $constant = new EntityConstant($class->name . '::' . $tokens->next()->get(T_STRING));
                         $constant->setValue(constant($constant->name));
                         $constant->setLine(new Line($this, $tokens->getLine()));
                         $class->addConstant($constant);
                         break;
                     case T_VARIABLE:
                         $property = new EntityProperty(ltrim($tokens->getAndNext(), '$'));
                         $ref = new \ReflectionProperty($class->name, $property->name);
                         $doc = $ref->getDocComment();
                         if ($doc) {
                             $property->setDescription(ToolKit::parseDoc($doc)['desc']);
                         }
                         if ($ref->isPrivate()) {
                             $property->addFlag(Flags::IS_PRIVATE);
                         } elseif ($ref->isProtected()) {
                             $property->addFlag(Flags::IS_PROTECTED);
                         } else {
                             $property->addFlag(Flags::IS_PUBLIC);
                         }
                         if ($ref->isStatic()) {
                             $property->addFlag(Flags::IS_STATIC);
                         }
                         if ($ref->isDefault()) {
                             $property->setValue($ref->getDeclaringClass()->getDefaultProperties()[$property->name]);
                         }
                         $class->addProperty($property);
                         break;
                     case T_FUNCTION:
                         $method = new EntityMethod($name . '::' . $tokens->next()->get(T_STRING));
                         $method->setLine($this->line($tokens->getLine()));
                         $this->parseCallable($method, $ref = new \ReflectionMethod($class->name, $method->short));
                         if ($ref->isPrivate()) {
                             $method->addFlag(Flags::IS_PRIVATE);
                         } elseif ($ref->isProtected()) {
                             $method->addFlag(Flags::IS_PROTECTED);
                         } else {
                             $method->addFlag(Flags::IS_PUBLIC);
                         }
                         if ($ref->isStatic()) {
                             $method->addFlag(Flags::IS_STATIC);
                         }
                         if ($ref->isAbstract()) {
                             $method->addFlag(Flags::IS_ABSTRACT);
                             $method->addFlag(Flags::IS_ABSTRACT_IMPLICIT);
                         } elseif ($ref->isFinal()) {
                             $method->addFlag(Flags::IS_FINAL);
                         }
                         if (isset($method->options['deprecated'])) {
                             $method->addFlag(Flags::IS_DEPRECATED);
                         }
                         $tokens->forwardTo(')')->next();
                         if ($tokens->is('{')) {
                             $method_body = $tokens->getScope();
                             $method->setBody($method_body);
                         }
                         $tokens->next();
                         $class->addMethod($method);
                         break;
                     case '{':
                         // use traits scope
                         $tokens->forwardTo('}')->next();
                         break;
                     case '}':
                         // end of class
                         $tokens->next();
                         $this->classes[$class->name] = $class;
                         break 2;
                 }
             }
         } elseif ($tokens->is('}') && $ns_bracket) {
             $tokens->next();
             $ns_bracket = false;
         } else {
             drop($tokens->curr);
             if ($tokens->valid()) {
                 throw new UnexpectedTokenException($tokens);
             }
             break;
         }
     }
 }
Exemplo n.º 2
0
    /**
     * @param EntityClass $class
     * @return string
     */
    public function classC(EntityClass $class)
    {
        $escaped = addslashes($class->name);
        $name = $class->cname;
        $path = str_replace('\\', '/', $class->name);
        ob_start();
        echo <<<TOP
/* Extension */
#include "php.h"
#include "koda_helper.h"
#include "{$path}.h"

zend_class_entry *ce_{$name};
zend_object_handlers handlers_{$name};

BEGIN_EXTERN_C();

TOP;
        if ($class->methods) {
            $method_table = [];
            foreach ($class->methods as $method) {
                if ($method->isAbstract()) {
                    $method_table[] = "ZEND_FENTRY({$method->short}, NULL, arginfo_{$method->short}, {$this->_meFlags($method)})";
                } else {
                    $method_table[] = "ZEND_ME({$name}, {$method->short}, arginfo_{$method->short}, {$this->_meFlags($method)})";
                }
                if ($method->arguments) {
                    $arginfo = [];
                    foreach ($method->arguments as $argument) {
                        $arginfo[] = $this->_arginfo($argument) . " // {$argument->dump()}";
                    }
                    $arginfo = "\n    " . implode("\n    ", $arginfo);
                } else {
                    $arginfo = "";
                }
                if (!$method->isAbstract()) {
                    $scope = new Scope($method);
                    $body = $scope->convert();
                    echo <<<METHOD

/* proto {$method->dump()} */
PHP_METHOD({$name}, {$method->short}) {
    {$body}
}

METHOD;
                }
                echo <<<METHOD

ZEND_BEGIN_ARG_INFO_EX(arginfo_{$method->short}, 0, {$method->isReturnRef()}, {$method->required}){$arginfo}
ZEND_END_ARG_INFO();


METHOD;
            }
            $method_table = implode("\n    ", $method_table);
        } else {
            $method_table = "";
        }
        echo <<<REGISTER_METHODS
/* Register methods */
static const zend_function_entry {$name}_methods[] = {
    {$method_table}
    {NULL, NULL, NULL}
};

REGISTER_METHODS;
        if ($class->constants) {
            $constants = ["/* Class constants */"];
            foreach ($class->constants as $constant) {
                $constants[] = "/* {$constant->dump()} */";
                $constants[] = $this->_constant($constant);
            }
            $constants = "\n     " . implode("\n    ", $constants) . "\n";
        } else {
            $constants = "";
        }
        if ($class->properties) {
            $properties = ["/* Class properties */"];
            foreach ($class->properties as $prop) {
                $properties[] = "/* {$prop->dump()} */";
                $properties[] = $this->_property($prop);
            }
            $properties = "\n     " . implode("\n    ", $properties) . "\n";
        } else {
            $properties = "";
        }
        $register = $inherit = [];
        if ($class->flags & Flags::IS_INTERFACE) {
            $register[] = "ce_{$name} = zend_register_internal_interface(&ce TSRMLS_CC);";
            if ($class->parents) {
                foreach ($class->parents as $parent) {
                    $inherit[] = "if(!kd_extend_class(ce_{$name} TSRMLS_CC, {$parent->quote('strtolower')})) {";
                    $inherit[] = "    zend_error(E_CORE_ERROR, \"{$this->project->name}: {$class->getEscapedName()} can't extends {$parent->getEscapedName()}\");";
                    $inherit[] = "    return FAILURE;";
                    $inherit[] = "}";
                }
            }
        } else {
            $register[] = "ce_{$name} = zend_register_internal_class(&ce TSRMLS_CC);";
            if ($class->parent) {
                $inherit[] = "if(!kd_extend_class(ce_{$name} TSRMLS_CC, {$class->parent->quote('strtolower')})) {";
                $inherit[] = "    zend_error(E_CORE_ERROR, \"{$this->project->name}: {$class->getEscapedName()} can't extends {$class->parent->getEscapedName()}\");";
                $inherit[] = "    return FAILURE;";
                $inherit[] = "}";
            } else {
                $register[] = "memcpy(&handlers_{$name}, zend_get_std_object_handlers(), sizeof(zend_object_handlers));";
            }
            if ($class->flags & Flags::IS_ABSTRACT) {
                $register[] = "ce_{$name}->ce_flags |= ZEND_ACC_EXPLICIT_ABSTRACT_CLASS;";
            }
            if ($class->flags & Flags::IS_ABSTRACT_IMPLICIT) {
                $register[] = "ce_{$name}->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;";
            }
            if ($class->flags & Flags::IS_FINAL) {
                $register[] = "ce_{$name}->ce_flags |= ZEND_ACC_FINAL_CLASS;";
            }
        }
        if ($class->interfaces) {
            $interfaces = implode('", "', array_map('strtolower', array_map('addslashes', array_keys($class->interfaces))));
            $inherit[] = "kd_implements_class(ce_{$name} TSRMLS_CC, " . count($class->interfaces) . ", \"{$interfaces}\");";
        }
        $register = implode("\n    ", $register);
        $inherit = implode("\n    ", $inherit);
        echo <<<REGISTER_CLASS

/* Init class */
PHP_MINIT_FUNCTION(init_{$name}) {
    zend_class_entry ce;

    /* Init class entry */
    INIT_CLASS_ENTRY(ce, "{$escaped}", {$name}_methods);
    {$register}
    {$constants}
    {$properties}
    return SUCCESS;
}

/* Extending and implementing */
PHP_MINIT_FUNCTION(load_{$name}) {
    {$inherit}
    return SUCCESS;
}

END_EXTERN_C();

REGISTER_CLASS;
        return ob_get_clean();
    }