diff --git a/metagen.inc.php b/metagen.inc.php index c853754..e50acb4 100644 --- a/metagen.inc.php +++ b/metagen.inc.php @@ -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'); diff --git a/parser.inc.php b/parser.inc.php index 6ab6f09..14d5dcf 100644 --- a/parser.inc.php +++ b/parser.inc.php @@ -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) diff --git a/parser1.inc.php b/parser1.inc.php index 7a92909..00b6c37 100644 --- a/parser1.inc.php +++ b/parser1.inc.php @@ -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 diff --git a/parser2.inc.php b/parser2.inc.php index 963cbf3..24b3c49 100644 --- a/parser2.inc.php +++ b/parser2.inc.php @@ -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 diff --git a/tests/meta/DataAll.meta b/tests/meta/DataAll.meta index 54a8119..4b43c66 100644 --- a/tests/meta/DataAll.meta +++ b/tests/meta/DataAll.meta @@ -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 diff --git a/tests/run.php b/tests/run.php index d967b6b..d18d98b 100755 --- a/tests/run.php +++ b/tests/run.php @@ -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);