TypePHP 编译器 https://swoole.com/aot/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

210 lines
6.6 KiB

<?php
/**
* This file is part of TypePHP.
*
* @link https://www.swoole.com/
* @contact service@swoole.com
*/
namespace TypePhp\Context;
use PhpParser\Node\Expr\Variable;
use PhpParser\NodeAbstract;
use TypePhp\Entity\ClassDef;
use TypePhp\Entity\FunctionDef;
use TypePhp\Entity\InterfaceDef;
use TypePhp\Exception\Skip;
trait CompilationStateTrait
{
protected function addLocalVar(string $name, string $type): void
{
$this->context->localVars[$name] = $type;
}
protected function registerStdType(string $key): int
{
if (isset($this->stdTypeMap[$key])) {
return $this->stdTypeMap[$key];
}
$typeId = count($this->stdTypeMap) + 1;
$this->stdTypeMap[$key] = $typeId;
return $typeId;
}
protected function addTmpVar(string $type): string
{
$var = $this->genTmpVarName();
$this->addLocalVar($var, $type);
return $var;
}
protected function addStaticVar(Variable $var, string $name, string $type): string
{
if ($this->hasVar($name)) {
$this->fatalError($var, 'Duplicate variable `$' . $var->name . '`');
}
$this->context->staticVars[$name] = $type;
// 静态变量实际上是一个全局变量的引用
$globalVar = $this->escapeStaticVar($name);
$this->addGlobalVar($globalVar, $type);
return $globalVar;
}
protected function hasArgument(string $name): bool
{
return isset($this->context->arguments[$name]);
}
protected function addArgument(string $name, string $type): void
{
$this->context->arguments[$name] = $type;
$this->addLocalVar($name, $type);
}
protected function addLiteralString(string $value): int
{
$index = $this->literalStringIndex++;
$this->literalStrings[$value] = $index;
return $index;
}
protected function addGlobalVar(string $name, string $type): void
{
$this->globalVars[$name] = $type;
}
protected function promoteGlobalOrStaticToNativeObject(
string $name,
string $class,
?NodeAbstract $node = null,
): void
{
$class = ltrim($class, '\\');
if ($this->hasStaticVar($name)) {
$slot = $this->escapeStaticVar($name);
$this->context->staticVars[$name] = $this->getNativeObjectPointerType($class);
} elseif ($this->hasScopeGlobalVar($name)) {
$slot = $name;
$this->context->globalVars[$name] = $this->getNativeObjectPointerType($class);
} else {
return;
}
if (isset($this->nativeGlobalObjects[$slot])) {
$existing = $this->nativeGlobalObjects[$slot];
if (!$this->isObjectClassStaticallyAssignableTo($class, $existing)) {
$message = "Native global/static slot cannot change from `{$existing}` to `{$class}`";
if ($node !== null) {
$this->fatalError($node, $message);
}
$this->error($message);
}
// The first assignment fixes the C++ slot type. A derived object
// remains assignable, but must not narrow later uses of the slot.
$class = $existing;
}
$this->globalVars[$slot] = $this->getNativeObjectPointerType($class);
$this->nativeGlobalObjects[$slot] = $class;
$this->addNativeObject($name, $class);
}
protected function addScopeGlobalVar(string $name, string $type): void
{
$this->context->globalVars[$name] = $type;
}
protected function addObject(string $name, string $class): void
{
if ($this->isNativeObjectClass($class)) {
$this->addNativeObject($name, $class);
return;
}
// Interfaces have no concrete method body for native calls. Abstract classes may have concrete methods.
if ($this->isInterface($class)) {
$this->context->declaredObjects[$name] = $class;
} elseif ($this->isNativeClass($class) or $this->isInternalClass($class)) {
$this->context->objects[$name] = $class;
}
}
protected function hasVar(string $name): bool
{
return $this->hasLocalVar($name) || $this->hasStaticVar($name) || $this->hasScopeGlobalVar($name) || $this->isSuperGlobal($name);
}
protected function hasLocalVar(string $name): bool
{
return isset($this->context->localVars[$name]);
}
protected function hasObjectPropVar(string $name): bool
{
return isset($this->context->objectProps[$name]);
}
protected function addFunction(string $name, FunctionDef $functionDef): void
{
$this->symbols->putFunction($this->escapeFunction($name), $functionDef);
}
/**
* @param string $name 必须传入带有完整命名空间的类名,将会自动转义为 native name
*/
protected function hasFunction(string $name): bool
{
return $this->symbols->hasFunction($this->escapeFunction($name));
}
protected function getFunction(string $name): FunctionDef
{
return $this->symbols->function($this->escapeFunction($name));
}
protected function addClass(string $name, ClassDef $classDef): void
{
$this->symbols->putClass($this->escapeClass($name), $classDef);
}
protected function getClass(string $name): ClassDef
{
return $this->symbols->class($this->escapeClass($name));
}
public function getClassDef(string $name): ?ClassDef
{
return $this->symbols->findClass($this->escapeClass($name));
}
public function getParentClass(string $class): string
{
return $this->symbols->parent(strtolower(ltrim($class, '\\')));
}
protected function hasClass(string $name): bool
{
return $this->symbols->hasClass($this->escapeClass($name));
}
protected function hasInterface(string $name): bool
{
return $this->symbols->hasInterface($this->escapeClass($name));
}
protected function getInterface(string $name): InterfaceDef
{
return $this->symbols->interface($this->escapeClass($name));
}
protected function checkFunction(string $name): void
{
// 在预处理阶段检测到函数声明,但是未定义,说明在当前文件,但是顺序错误
// 跳过,稍后再处理
if (isset($this->symbolDeclInFile[$name])
and $this->symbolDeclInFile[$name] === $this->file
and !$this->hasFunction($name)) {
$this->redoAfterDeclare[$name] = true;
throw new Skip();
}
}
}