Adding initial support for partial services via @service_partial, also support for service local structs; Restoring tests
Publish PHP Package / docker (push) Successful in 7s Details

This commit is contained in:
Pavel Shevaev 2025-05-12 20:01:28 +03:00
parent 497c6b6b0b
commit 3bcf6c8ad2
6 changed files with 150 additions and 40 deletions

View File

@ -7,7 +7,28 @@ interface mtgType
interface mtgScope
{
function findSymbol($name);
function findSymbol(string $name) : ?mtgMetaUnit;
}
class mtgMultiScope implements mtgScope
{
private array $scopes = array();
function addScope(mtgScope $scope)
{
$this->scopes[] = $scope;
}
function findSymbol(string $name) : ?mtgMetaUnit
{
foreach($this->scopes as $scope)
{
$unit = $scope->findSymbol($name);
if($unit)
return $unit;
}
return null;
}
}
class mtgTypeRef implements mtgType
@ -583,22 +604,35 @@ class mtgMetaRPC extends mtgMetaUnit
class mtgMetaService extends mtgMetaUnit implements mtgScope
{
private $name;
private $parent_scope;
private string $name;
//for partial services
private mtgMultiScope $parent_scope;
private $rpcs = array();
private $events = array();
private $user_types = array();
function __construct($name, mtgScope $parent_scope, array $tokens = array())
function __construct(string $name, mtgScope $parent_scope, array $tokens = array())
{
$this->name = $name;
$this->parent_scope = $parent_scope;
$this->parent_scope = new mtgMultiScope();
$this->parent_scope->addScope($parent_scope);
$this->tokens = $tokens;
}
function getParentScope() : mtgScope
{
return $this->parent_scope;
}
function validate(mtgMetaInfo $meta) {}
function getName()
function addPartial(mtgMetaService $service)
{
$this->setTokens(array_merge($this->getTokens(), $service->getTokens()));
$this->parent_scope->addScope($service->getParentScope());
}
function getName() : string
{
return $this->name;
}
@ -608,7 +642,7 @@ class mtgMetaService extends mtgMetaUnit implements mtgScope
return $this->name;
}
function findSymbol($name)
function findSymbol(string $name) : ?mtgMetaUnit
{
if(isset($this->user_types[$name]))
return $this->user_types[$name];
@ -635,12 +669,12 @@ class mtgMetaService extends mtgMetaUnit implements mtgScope
$this->rpcs[$rpc->getName()] = $rpc;
}
function hasRPC($name)
function hasRPC(string $name) : bool
{
return isset($this->rpcs[$name]);
}
function getRPC($name)
function getRPC(string $name) : mtgMetaRPC
{
if(!isset($this->rpcs[$name]))
throw new Exception("No such RPC '$name'");
@ -660,12 +694,12 @@ class mtgMetaService extends mtgMetaUnit implements mtgScope
$this->user_types[$utype->getName()] = $utype;
}
function hasUserType($name)
function hasUserType(string $name) : bool
{
return isset($this->user_types[$name]);
}
function getUserType($name)
function getUserType(bool $name) : mtgUserType
{
if(!isset($this->user_types[$name]))
throw new Exception("No such user type '$name'");
@ -683,7 +717,7 @@ class mtgMetaService extends mtgMetaUnit implements mtgScope
return $this->events;
}
function getClassId()
function getClassId() : int
{
if($this->hasToken('class_id'))
return $this->getToken('class_id');

View File

@ -26,7 +26,7 @@ class mtgMetaParsedModule implements mtgScope
$this->units[$unit->object->getMetaId()] = $unit;
}
function findSymbol($name)
function findSymbol(string $name) : ?mtgMetaUnit
{
$unit = $this->findUnit($name);
if(!$unit)

View File

@ -127,6 +127,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$config['valid_tokens'][] = 'shared_tokens';
$config['valid_tokens'][] = 'enum_override';
$config['valid_tokens'][] = 'enum_replace';
$config['valid_tokens'][] = 'service_partial';
}
function parse(mtgMetaInfo $meta, string $raw_file)
@ -358,7 +359,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
return $values;
}
private function _parseEnum($is_global = true)
private function _parseEnum($is_global = true) : mtgMetaEnum
{
$this->_nextT();
$name = $this->_parseDotName();
@ -399,11 +400,11 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$existing = $this->current_meta->findUnit($enum->getMetaId());
if(!$existing)
throw new Exception("Not found '{$name}' enum to override values");
$this->_error("Not found '{$name}' enum to override values");
if(!($existing->object instanceof mtgMetaEnum))
throw new Exception("Not an enum struct '{$name}'");
$existing->object->override($enum);
$this->_error("Not an enum struct '{$name}'");
else
$existing->object->override($enum);
}
//NOTE: special case for enums when we allow to 'replace' the original one,
// with additional values
@ -414,11 +415,11 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$existing = $this->current_meta->findUnit($enum->getMetaId());
if(!$existing)
throw new Exception("Not found '{$name}' enum to replace values");
$this->_error("Not found '{$name}' enum to replace values");
if(!($existing->object instanceof mtgMetaEnum))
throw new Exception("Not an enum struct '{$name}'");
$existing->object->replace($enum);
$this->_error("Not an enum struct '{$name}'");
else
$existing->object->replace($enum);
}
else if($is_global)
$this->_addUnit(new mtgMetaInfoUnit($this->module, $enum));
@ -575,7 +576,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$this->_addUnit(new mtgMetaInfoUnit($this->module, $fn));
}
private function _parseStruct()
private function _parseStruct($is_global = true) : mtgMetaStruct
{
$this->_nextT();
$struct_origin = new mtgOrigin($this->file, $this->line);
@ -604,7 +605,9 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$s = new mtgMetaStruct($name, array(), $parent, array(), $implements);
$s->setOrigin($struct_origin);
$this->_addUnit(new mtgMetaInfoUnit($this->module, $s));
if($is_global)
$this->_addUnit(new mtgMetaInfoUnit($this->module, $s));
$tokens = $this->shared_tokens;
if($this->T == self::T_Prop)
@ -633,6 +636,8 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
foreach($funcs as $fn)
$s->addFunc($fn);
}
return $s;
}
private function _parseInterface()
@ -659,7 +664,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$this->_nextT();
}
private function _parseRPC($is_global = true)
private function _parseRPC($is_global = true) : mtgMetaRPC
{
$this->_nextT();
$code = $this->T_value;
@ -704,6 +709,25 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$tokens = array_merge($tokens, $this->_parsePropTokens());
$service->setTokens($tokens);
$existing = null;
if($service->hasToken('service_partial'))
{
$existing = $this->current_meta->findUnit($service->getMetaId());
if($existing)
{
if(!($existing->object instanceof mtgMetaService))
$this->_error("Not a service instance '{$name}'");
else
{
$existing->object->addPartial($service);
//let's replace service with the existing one
$service = $existing->object;
$this->_popScope();
$this->_pushScope($service);
}
}
}
while(true)
{
if($this->_nextIf(self::T_End))
@ -713,13 +737,16 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
$service->addRPC($this->_parseRPC(false));
else if($this->T == self::T_Enum)
$service->addUserType($this->_parseEnum(false));
else if($this->T == self::T_Struct)
$service->addUserType($this->_parseStruct(false));
else
$this->_error("Unsupported type");
}
$this->_popScope();
$this->_addUnit(new mtgMetaInfoUnit($this->module, $service));
if(!$existing)
$this->_addUnit(new mtgMetaInfoUnit($this->module, $service));
}
private function _parsePropTokens() : array

View File

@ -127,6 +127,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
$config['valid_tokens'][] = 'shared_tokens';
$config['valid_tokens'][] = 'enum_override';
$config['valid_tokens'][] = 'enum_replace';
$config['valid_tokens'][] = 'service_partial';
}
function parse(mtgMetaInfo $meta, string $raw_file)
@ -401,11 +402,11 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
$existing = $this->current_meta->findUnit($enum->getMetaId());
if(!$existing)
throw new Exception("Not found '{$name}' enum to override values");
$this->_error("Not found '{$name}' enum to override values");
if(!($existing->object instanceof mtgMetaEnum))
throw new Exception("Not an enum struct '{$name}'");
$existing->object->override($enum);
$this->_error("Not an enum struct '{$name}'");
else
$existing->object->override($enum);
}
//NOTE: special case for enums when we allow to 'replace' the original one,
// with additional values
@ -416,11 +417,11 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
$existing = $this->current_meta->findUnit($enum->getMetaId());
if(!$existing)
throw new Exception("Not found '{$name}' enum to replace values");
$this->_error("Not found '{$name}' enum to replace values");
if(!($existing->object instanceof mtgMetaEnum))
throw new Exception("Not an enum struct '{$name}'");
$existing->object->replace($enum);
$this->_error("Not an enum struct '{$name}'");
else
$existing->object->replace($enum);
}
else if($is_global)
$this->_addUnit(new mtgMetaInfoUnit($this->module, $enum));
@ -744,6 +745,25 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
$tokens = array_merge($tokens, $this->_parsePropTokens());
$service->setTokens($tokens);
$existing = null;
if($service->hasToken('service_partial'))
{
$existing = $this->current_meta->findUnit($service->getMetaId());
if($existing)
{
if(!($existing->object instanceof mtgMetaService))
$this->_error("Not a service instance '{$name}'");
else
{
$existing->object->addPartial($service);
//let's replace service with the existing one
$service = $existing->object;
$this->_popScope();
$this->_pushScope($service);
}
}
}
while(true)
{
if($this->_nextIf(ord('}')))
@ -761,7 +781,8 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
$this->_popScope();
$this->_addUnit(new mtgMetaInfoUnit($this->module, $service));
if(!$existing)
$this->_addUnit(new mtgMetaInfoUnit($this->module, $service));
}
private function _parsePropTokens() : array

View File

@ -60,3 +60,21 @@ end
struct ConfStock
id : EnumStock
end
service GameService
enum ErrorCode
OK = 0
Err = 1
end
struct DataPing
value : int32
end
RPC 10 PING(
value : DataPing
)
error : ErrorCode
value : int32
end
end

View File

@ -4,12 +4,15 @@
require_once(__DIR__ . '/../metagen.inc.php');
require_once(__DIR__ . '/../parser.inc.php');
assert_options(ASSERT_ACTIVE, true);
assert_options(ASSERT_BAIL, true);
assert_options(ASSERT_WARNING, true);
ini_set('zend.assertions', 1);
touch(__DIR__ . '/meta/DataAll.meta');
$meta = mtg_parse_meta(array(__DIR__ . '/meta/'));
//we don't need that right now
//touch(__DIR__ . '/meta/DataAll.meta');
$meta = mtg_parse_meta(
[__DIR__ . '/meta/'],
['POD', 'table', 'pkey', 'bhl_ret_type', 'bhl_args',
'strmax', 'default', 'virtual'],
);
$u = $meta->findUnit("DataPlayer");
assert($u->object instanceof mtgMetaStruct);
@ -83,3 +86,10 @@ $u = $meta->findUnit("ConfStock");
assert($u->object instanceof mtgMetaStruct);
assert(sizeof($u->object->getFields()) == 1);
assert($u->object->getFields()["id"]->getType() == "EnumStock");
$u = $meta->findUnit("GameService");
assert($u->object instanceof mtgMetaService);
assert($u->object->getRPC("PING") instanceof mtgMetaRPC);
assert($u->object->findSymbol("DataPing") instanceof mtgMetaStruct);
assert($u->object->findSymbol("ErrorCode") instanceof mtgMetaEnum);