Adding initial support for service type
Publish PHP Package / docker (push) Successful in 6s
Details
Publish PHP Package / docker (push) Successful in 6s
Details
This commit is contained in:
parent
ada7729320
commit
5dcffe2c80
128
metagen.inc.php
128
metagen.inc.php
|
@ -5,16 +5,21 @@ interface mtgType
|
|||
function getName();
|
||||
}
|
||||
|
||||
interface mtgScope
|
||||
{
|
||||
function findSymbol($name);
|
||||
}
|
||||
|
||||
class mtgTypeRef implements mtgType
|
||||
{
|
||||
private static $unresolved = array();
|
||||
|
||||
private $name;
|
||||
private $module;
|
||||
private $scope;
|
||||
private $resolved;
|
||||
private $origin;
|
||||
|
||||
function __construct($name_or_resolved, mtgMetaParsedModule $module = null, mtgOrigin $origin = null)
|
||||
function __construct($name_or_resolved, mtgScope $scope = null, mtgOrigin $origin = null)
|
||||
{
|
||||
if(is_object($name_or_resolved))
|
||||
{
|
||||
|
@ -25,13 +30,13 @@ class mtgTypeRef implements mtgType
|
|||
else
|
||||
{
|
||||
$this->name = $name_or_resolved;
|
||||
if(!$module)
|
||||
throw new Exception("Module is not set");
|
||||
if(!$scope)
|
||||
throw new Exception("Scope is not set");
|
||||
|
||||
self::$unresolved[] = $this;
|
||||
}
|
||||
|
||||
$this->module = $module;
|
||||
$this->scope = $scope;
|
||||
$this->origin = $origin ?? new mtgOrigin();
|
||||
|
||||
}
|
||||
|
@ -58,10 +63,10 @@ class mtgTypeRef implements mtgType
|
|||
if($this->resolved)
|
||||
return $this->resolved;
|
||||
|
||||
$u = $this->module->findUnit($this->name);
|
||||
if($u)
|
||||
$symb = $this->scope->findSymbol($this->name);
|
||||
if($symb)
|
||||
{
|
||||
$this->resolved = $u->object;
|
||||
$this->resolved = $symb;
|
||||
return $this->resolved;
|
||||
}
|
||||
else
|
||||
|
@ -245,8 +250,7 @@ abstract class mtgUserType extends mtgMetaUnit implements mtgType
|
|||
if($this->hasToken('class_id'))
|
||||
return $this->getToken('class_id');
|
||||
|
||||
//TODO: use more flexible schema, maybe get rid of this method
|
||||
//NOTE: using crc28 actually, leaving some extra reserved space
|
||||
//TODO: migrate to crc32 from crc28
|
||||
return crc32($this->name) & 0xFFFFFFF;
|
||||
}
|
||||
|
||||
|
@ -569,6 +573,110 @@ class mtgMetaRPC extends mtgMetaUnit
|
|||
}
|
||||
}
|
||||
|
||||
class mtgMetaService extends mtgMetaUnit implements mtgScope
|
||||
{
|
||||
private $name;
|
||||
private $parent_scope;
|
||||
private $rpcs = array();
|
||||
private $user_types = array();
|
||||
|
||||
function __construct($name, mtgScope $parent_scope, array $tokens = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->parent_scope = $parent_scope;
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
function validate(mtgMetaInfo $meta) {}
|
||||
|
||||
function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function getMetaId()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function findSymbol($name)
|
||||
{
|
||||
if(isset($this->user_types[$name]))
|
||||
return $this->user_types[$name];
|
||||
|
||||
return $this->parent_scope->findSymbol($name);
|
||||
}
|
||||
|
||||
function getRPCs()
|
||||
{
|
||||
return $this->rpcs;
|
||||
}
|
||||
|
||||
function addRPC(mtgMetaRPC $rpc)
|
||||
{
|
||||
foreach($this->rpcs as $name => $_rpc)
|
||||
{
|
||||
if($name == $rpc->getName())
|
||||
throw new Exception("Service '{$this->name}' already has RPC '{$rpc->getName()}'");
|
||||
|
||||
if($rpc->getNumericCode() == $_rpc->getNumericCode())
|
||||
throw new Exception("Service '{$this->name}' already has RPC '{$_rpc->getName()}' with code '{$rpc->getNumericCode()}'");
|
||||
}
|
||||
|
||||
$this->rpcs[$rpc->getName()] = $rpc;
|
||||
}
|
||||
|
||||
function hasRPC($name)
|
||||
{
|
||||
return isset($this->rpcs[$name]);
|
||||
}
|
||||
|
||||
function getRPC($name)
|
||||
{
|
||||
if(!isset($this->rpcs[$name]))
|
||||
throw new Exception("No such RPC '$name'");
|
||||
return $this->rpcs[$name];
|
||||
}
|
||||
|
||||
function getUserTypes()
|
||||
{
|
||||
return $this->user_types;
|
||||
}
|
||||
|
||||
function addUserType(mtgUserType $utype)
|
||||
{
|
||||
if($this->hasRPC($utype->getName()))
|
||||
throw new Exception("Service '{$this->name}' already has type '{$utype->getName()}'");
|
||||
|
||||
$this->user_types[$utype->getName()] = $utype;
|
||||
}
|
||||
|
||||
function hasUserType($name)
|
||||
{
|
||||
return isset($this->user_types[$name]);
|
||||
}
|
||||
|
||||
function getUserType($name)
|
||||
{
|
||||
if(!isset($this->user_types[$name]))
|
||||
throw new Exception("No such user type '$name'");
|
||||
return $this->user_types[$name];
|
||||
}
|
||||
|
||||
function getClassId()
|
||||
{
|
||||
if($this->hasToken('class_id'))
|
||||
return $this->getToken('class_id');
|
||||
|
||||
return crc32($this->name);
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
class mtgBuiltinType implements mtgType
|
||||
{
|
||||
private $name;
|
||||
|
|
107
parser.inc.php
107
parser.inc.php
|
@ -31,7 +31,8 @@ class mtgMetaInfoParser
|
|||
const T_int64 = 1029;
|
||||
const T_bool = 1030;
|
||||
const T_blob = 1031;
|
||||
const T_MaxType = 1032; //built-in types end mark
|
||||
const T_Service = 1032;
|
||||
const T_MaxType = 1033; //built-in types end mark
|
||||
|
||||
private array $config = array();
|
||||
private mtgMetaInfo $current_meta;
|
||||
|
@ -54,6 +55,7 @@ class mtgMetaInfoParser
|
|||
/** @var array<int,string>*/
|
||||
private $T2descr = array();
|
||||
private array $shared_tokens = array();
|
||||
private array $scopes = array();
|
||||
|
||||
function __construct($config = array())
|
||||
{
|
||||
|
@ -90,6 +92,7 @@ class mtgMetaInfoParser
|
|||
"interface" => self::T_Interface,
|
||||
"enum" => self::T_Enum,
|
||||
"RPC" => self::T_RPC,
|
||||
"service" => self::T_Service,
|
||||
"end" => self::T_End,
|
||||
"extends" => self::T_Extends,
|
||||
"implements" => self::T_Implements,
|
||||
|
@ -104,6 +107,7 @@ class mtgMetaInfoParser
|
|||
$this->T2descr[self::T_FloatConstant] = '<FloatConstant>';
|
||||
$this->T2descr[self::T_Enum] = '<enum>';
|
||||
$this->T2descr[self::T_RPC] = '<RPC>';
|
||||
$this->T2descr[self::T_Service] = '<Service>';
|
||||
$this->T2descr[self::T_End] = '<end>';
|
||||
$this->T2descr[self::T_UserSymbol] = '<Identifier>';
|
||||
$this->T2descr[self::T_Struct] = '<struct>';
|
||||
|
@ -184,6 +188,8 @@ class mtgMetaInfoParser
|
|||
$this->_parseFreeFunc();
|
||||
else if($this->T == self::T_RPC)
|
||||
$this->_parseRPC();
|
||||
else if($this->T == self::T_Service)
|
||||
$this->_parseService();
|
||||
else
|
||||
$this->_error("Unexpected symbol ('" . $this->_toStr($this->T) . "' " . $this->T_value . ")");
|
||||
}
|
||||
|
@ -223,19 +229,19 @@ class mtgMetaInfoParser
|
|||
{
|
||||
$origin = new mtgOrigin($this->file, $this->line);
|
||||
$func_type = $this->_parseFuncType();
|
||||
$type = new mtgTypeRef($func_type, $this->module, $origin);
|
||||
$type = new mtgTypeRef($func_type, $this->_scope(), $origin);
|
||||
}
|
||||
else if($this->T == self::T_UserSymbol)
|
||||
{
|
||||
$origin = new mtgOrigin($this->file, $this->line);
|
||||
$type_name = $this->_parseDotName();
|
||||
$type = new mtgTypeRef($type_name, $this->module, $origin);
|
||||
$type = new mtgTypeRef($type_name, $this->_scope(), $origin);
|
||||
}
|
||||
else
|
||||
{
|
||||
$origin = new mtgOrigin($this->file, $this->line);
|
||||
$type_name = $this->T_value;
|
||||
$type = new mtgTypeRef(new mtgBuiltinType($type_name), $this->module, $origin);
|
||||
$type = new mtgTypeRef(new mtgBuiltinType($type_name), $this->_scope(), $origin);
|
||||
$this->_nextT();
|
||||
}
|
||||
|
||||
|
@ -244,7 +250,7 @@ class mtgMetaInfoParser
|
|||
$origin = new mtgOrigin($this->file, $this->line);
|
||||
$this->_nextT();
|
||||
$this->_checkThenNext(ord(']'));
|
||||
$type = new mtgTypeRef(new mtgArrType($type), $this->module, $origin);
|
||||
$type = new mtgTypeRef(new mtgArrType($type), $this->_scope(), $origin);
|
||||
}
|
||||
$types[] = $type;
|
||||
|
||||
|
@ -257,7 +263,7 @@ class mtgMetaInfoParser
|
|||
}
|
||||
|
||||
if(sizeof($types) > 1)
|
||||
return new mtgTypeRef(new mtgMultiType($types), $this->module, new mtgOrigin($this->file, $this->line));
|
||||
return new mtgTypeRef(new mtgMultiType($types), $this->_scope(), new mtgOrigin($this->file, $this->line));
|
||||
else
|
||||
return $types[0];
|
||||
}
|
||||
|
@ -352,7 +358,7 @@ class mtgMetaInfoParser
|
|||
return $values;
|
||||
}
|
||||
|
||||
private function _parseEnum()
|
||||
private function _parseEnum($is_global = true)
|
||||
{
|
||||
$this->_nextT();
|
||||
$name = $this->_parseDotName();
|
||||
|
@ -388,6 +394,9 @@ class mtgMetaInfoParser
|
|||
// with additional values
|
||||
if($enum->hasToken('enum_override'))
|
||||
{
|
||||
if(!$is_global)
|
||||
$this->_error("Override supported for global enums only");
|
||||
|
||||
$existing = $this->current_meta->findUnit($enum->getMetaId());
|
||||
if(!$existing)
|
||||
throw new Exception("Not found '{$name}' enum to override values");
|
||||
|
@ -400,6 +409,9 @@ class mtgMetaInfoParser
|
|||
// with additional values
|
||||
else if($enum->hasToken('enum_replace'))
|
||||
{
|
||||
if(!$is_global)
|
||||
$this->_error("Replace supported for global enums only");
|
||||
|
||||
$existing = $this->current_meta->findUnit($enum->getMetaId());
|
||||
if(!$existing)
|
||||
throw new Exception("Not found '{$name}' enum to replace values");
|
||||
|
@ -408,8 +420,10 @@ class mtgMetaInfoParser
|
|||
|
||||
$existing->object->replace($enum);
|
||||
}
|
||||
else
|
||||
else if($is_global)
|
||||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $enum));
|
||||
|
||||
return $enum;
|
||||
}
|
||||
|
||||
static private function _isBuiltinType(int $t) : bool
|
||||
|
@ -417,6 +431,24 @@ class mtgMetaInfoParser
|
|||
return $t > self::T_MinType && $t < self::T_MaxType;
|
||||
}
|
||||
|
||||
private function _pushScope(mtgScope $scope)
|
||||
{
|
||||
$this->scopes[] = $scope;
|
||||
}
|
||||
|
||||
private function _popScope()
|
||||
{
|
||||
array_shift($this->scopes);
|
||||
}
|
||||
|
||||
private function _scope() : mtgScope
|
||||
{
|
||||
if(!$this->scopes)
|
||||
return $this->module;
|
||||
|
||||
return $this->scopes[count($this->scopes)-1];
|
||||
}
|
||||
|
||||
private function _parseFields(callable $next_doer)
|
||||
{
|
||||
$flds = array();
|
||||
|
@ -555,7 +587,7 @@ class mtgMetaInfoParser
|
|||
$this->_nextT();
|
||||
$origin = new mtgOrigin($this->file, $this->line);
|
||||
$parent_name = $this->_parseDotName();
|
||||
$parent = new mtgTypeRef($parent_name, $this->module, $origin);
|
||||
$parent = new mtgTypeRef($parent_name, $this->_scope(), $origin);
|
||||
}
|
||||
|
||||
$implements = array();
|
||||
|
@ -566,7 +598,7 @@ class mtgMetaInfoParser
|
|||
$this->_nextT();
|
||||
$origin = new mtgOrigin($this->file, $this->line);
|
||||
$if_name = $this->_parseDotName();
|
||||
$implements[] = new mtgTypeRef($if_name, $this->module, $origin);
|
||||
$implements[] = new mtgTypeRef($if_name, $this->_scope(), $origin);
|
||||
} while($this->T == ord(','));
|
||||
}
|
||||
|
||||
|
@ -627,7 +659,7 @@ class mtgMetaInfoParser
|
|||
$this->_nextT();
|
||||
}
|
||||
|
||||
private function _parseRPC()
|
||||
private function _parseRPC($is_global = true)
|
||||
{
|
||||
$this->_nextT();
|
||||
$code = $this->T_value;
|
||||
|
@ -646,13 +678,48 @@ class mtgMetaInfoParser
|
|||
{ return $this->_nextIf(self::T_End); }
|
||||
);
|
||||
|
||||
$req = new mtgMetaPacket($code, "RPC_REQ_$name");
|
||||
$req = new mtgMetaPacket($code, $is_global ? "RPC_REQ_$name" : $name);
|
||||
$req->setFields($req_fields);
|
||||
$rsp = new mtgMetaPacket($code, "RPC_RSP_$name");
|
||||
$rsp = new mtgMetaPacket($code, $is_global ? "RPC_RSP_$name" : $name);
|
||||
$rsp->setFields($rsp_fields);
|
||||
|
||||
$rpc = new mtgMetaRPC("RPC_$name", $code, $req, $rsp, $tokens);
|
||||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $rpc));
|
||||
$rpc = new mtgMetaRPC($is_global ? "RPC_$name" : $name, $code, $req, $rsp, $tokens);
|
||||
|
||||
if($is_global)
|
||||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $rpc));
|
||||
|
||||
return $rpc;
|
||||
}
|
||||
|
||||
private function _parseService()
|
||||
{
|
||||
$this->_nextT();
|
||||
$name = $this->_parseDotName();
|
||||
|
||||
$service = new mtgMetaService($name, $this->_scope());
|
||||
$this->_pushScope($service);
|
||||
|
||||
$tokens = $this->shared_tokens;
|
||||
if($this->T == self::T_Prop)
|
||||
$tokens = array_merge($tokens, $this->_parsePropTokens());
|
||||
$service->setTokens($tokens);
|
||||
|
||||
while(true)
|
||||
{
|
||||
if($this->_nextIf(self::T_End))
|
||||
break;
|
||||
$key = $this->T_value;
|
||||
if($this->T == self::T_RPC)
|
||||
$service->addRPC($this->_parseRPC(false));
|
||||
else if($this->T == self::T_Enum)
|
||||
$service->addUserType($this->_parseEnum(false));
|
||||
else
|
||||
$this->_error("Unsupported type");
|
||||
}
|
||||
|
||||
$this->_popScope();
|
||||
|
||||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $service));
|
||||
}
|
||||
|
||||
private function _parsePropTokens() : array
|
||||
|
@ -904,7 +971,7 @@ class mtgMetaInfoParser
|
|||
}
|
||||
}
|
||||
|
||||
class mtgMetaParsedModule
|
||||
class mtgMetaParsedModule implements mtgScope
|
||||
{
|
||||
public string $file;
|
||||
public $units = array();
|
||||
|
@ -920,6 +987,14 @@ class mtgMetaParsedModule
|
|||
$this->units[$unit->object->getMetaId()] = $unit;
|
||||
}
|
||||
|
||||
function findSymbol($name)
|
||||
{
|
||||
$unit = $this->findUnit($name);
|
||||
if(!$unit)
|
||||
return null;
|
||||
return $unit->object;
|
||||
}
|
||||
|
||||
function findUnit($id)
|
||||
{
|
||||
if(isset($this->units[$id]))
|
||||
|
|
Loading…
Reference in New Issue