Starting major cleanup and preparation for namespaces
Publish PHP Package / docker (push) Successful in 6s
Details
Publish PHP Package / docker (push) Successful in 6s
Details
This commit is contained in:
parent
d3eec0db1f
commit
3718958480
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
|
||||
class mtgMetaEnum extends mtgUserType
|
||||
{
|
||||
private $values = array();
|
||||
|
||||
function validate(mtgMetaInfo $meta) {}
|
||||
|
||||
function addValue($value_name, $value)
|
||||
{
|
||||
if(isset($this->values[$value_name]))
|
||||
throw new Exception("Enum '{$this->name}' already has value with name '{$value_name}'");
|
||||
|
||||
if(in_array($value, $this->values))
|
||||
throw new Exception("Enum '{$this->name}' already has value '{$value}'");
|
||||
|
||||
$this->values[$value_name] = $value;
|
||||
}
|
||||
|
||||
function calcOrValue($or_keys)
|
||||
{
|
||||
$res = 0;
|
||||
foreach($or_keys as $value_name)
|
||||
{
|
||||
if(!isset($this->values[$value_name]))
|
||||
throw new Exception("Enum '{$this->name}' has no value '{$value_name}'");
|
||||
$res |= $this->values[$value_name];
|
||||
}
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
function addOrValues($values)
|
||||
{
|
||||
foreach($values as $value_name => $or_keys)
|
||||
$this->addValue($value_name, $this->calcOrValue($or_keys));
|
||||
}
|
||||
|
||||
function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
|
||||
function override(mtgMetaEnum $other)
|
||||
{
|
||||
$this->tokens = array_merge($this->tokens, $other->getTokens());
|
||||
$this->values = array_merge($this->values, $other->getValues());
|
||||
}
|
||||
|
||||
function replace(mtgMetaEnum $other)
|
||||
{
|
||||
$this->tokens = $other->getTokens();
|
||||
$this->values = $other->getValues();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
<?php
|
||||
|
||||
class mtgMetaFunc extends mtgMetaUnit implements mtgType
|
||||
{
|
||||
private string $name;
|
||||
private $args = array();
|
||||
private $ret_type;
|
||||
|
||||
function __construct($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function validate(mtgMetaInfo $meta)
|
||||
{}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
$str = "func ";
|
||||
|
||||
$str .= $this->name.'(';
|
||||
foreach($this->getArgs() as $arg)
|
||||
$str .= $arg->getType() . ',';
|
||||
$str = rtrim($str, ',');
|
||||
$str .= ')';
|
||||
if($ret_type = $this->getReturnType())
|
||||
$str .= ':'.$ret_type;
|
||||
return $str;
|
||||
}
|
||||
|
||||
function setReturnType(mtgTypeRef $type)
|
||||
{
|
||||
$this->ret_type = $type;
|
||||
}
|
||||
|
||||
function getReturnType() : ?mtgType
|
||||
{
|
||||
return $this->ret_type ? $this->ret_type->resolve() : null;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function getArgs()
|
||||
{
|
||||
return $this->args;
|
||||
}
|
||||
|
||||
function setArgs(array $args)
|
||||
{
|
||||
foreach($args as $arg)
|
||||
$this->addArg($arg);
|
||||
}
|
||||
|
||||
function addArg(mtgMetaField $arg)
|
||||
{
|
||||
if($this->hasArg($arg->getName()))
|
||||
throw new Exception("Func '{$this->name}' already has arg '{$arg->getName()}'");
|
||||
|
||||
$this->args[$arg->getName()] = $arg;
|
||||
}
|
||||
|
||||
function hasArg($name)
|
||||
{
|
||||
return isset($this->args[$name]);
|
||||
}
|
||||
|
||||
function getArg($name)
|
||||
{
|
||||
if(!isset($this->args[$name]))
|
||||
throw new Exception("No such arg '$name'");
|
||||
return $this->args[$name];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,54 @@
|
|||
<?php
|
||||
|
||||
class mtgMetaInterface extends mtgUserType
|
||||
{
|
||||
protected $funcs = array();
|
||||
protected $implements = null;
|
||||
|
||||
function __construct($name, array $implements = array(), $tokens = array())
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->implements = $implements;
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
function validate(mtgMetaInfo $meta) {}
|
||||
|
||||
function getImplements()
|
||||
{
|
||||
if(!$this->implements)
|
||||
return array();
|
||||
|
||||
$imps = array();
|
||||
foreach($this->implements as $imp)
|
||||
$imps[] = $imp->resolve();
|
||||
return $imps;
|
||||
}
|
||||
|
||||
function getFuncs()
|
||||
{
|
||||
return $this->funcs;
|
||||
}
|
||||
|
||||
function addFunc(mtgMetaFunc $fn)
|
||||
{
|
||||
if($this->hasFunc($fn->getName()))
|
||||
throw new Exception("Interface '{$this->name}' already has func '{$fn->getName()}'");
|
||||
|
||||
$this->funcs[$fn->getName()] = $fn;
|
||||
}
|
||||
|
||||
function hasFunc($name)
|
||||
{
|
||||
return isset($this->funcs[$name]);
|
||||
}
|
||||
|
||||
function getFunc($name)
|
||||
{
|
||||
if(!isset($this->funcs[$name]))
|
||||
throw new Exception("No such funcs '$name'");
|
||||
return $this->funcs[$name];
|
||||
}
|
||||
}
|
||||
|
1095
metagen.inc.php
1095
metagen.inc.php
File diff suppressed because it is too large
Load Diff
|
@ -23,7 +23,7 @@ class mtgMetaParsedModule implements mtgScope
|
|||
|
||||
function addUnit(mtgMetaInfoUnit $unit)
|
||||
{
|
||||
$this->units[$unit->object->getMetaId()] = $unit;
|
||||
$this->units[$unit->object->getName()] = $unit;
|
||||
}
|
||||
|
||||
function findSymbol(string $name) : ?mtgMetaUnit
|
||||
|
@ -54,7 +54,13 @@ class mtgMetaParsedModule implements mtgScope
|
|||
}
|
||||
}
|
||||
|
||||
function mtg_parse_meta(array $meta_srcs, $valid_tokens = null, $inc_path = null, $version = null, string $extension = '.meta')
|
||||
function mtg_parse_meta(
|
||||
array $meta_srcs,
|
||||
$valid_tokens = null,
|
||||
$inc_path = null,
|
||||
$version = null,
|
||||
string $extension = '.meta'
|
||||
) : mtgMetaInfo
|
||||
{
|
||||
if($inc_path === null)
|
||||
{
|
||||
|
@ -122,7 +128,7 @@ function mtg_resolve_files(string $dir_or_file, string $extension = '.meta') : a
|
|||
return $files;
|
||||
}
|
||||
|
||||
function mtg_find_meta_files($dir, $extension = '.meta')
|
||||
function mtg_find_meta_files($dir, $extension = '.meta') : array
|
||||
{
|
||||
$items = scandir($dir);
|
||||
if($items === false)
|
||||
|
|
|
@ -359,7 +359,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
return $values;
|
||||
}
|
||||
|
||||
private function _parseEnum($is_global = true) : mtgMetaEnum
|
||||
private function _parseEnum(bool $is_global = true) : mtgMetaEnum
|
||||
{
|
||||
$this->_nextT();
|
||||
$name = $this->_parseDotName();
|
||||
|
@ -398,7 +398,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
if(!$is_global)
|
||||
$this->_error("Override supported for global enums only");
|
||||
|
||||
$existing = $this->current_meta->findUnit($enum->getMetaId());
|
||||
$existing = $this->current_meta->findUnit($enum->getName());
|
||||
if(!$existing)
|
||||
$this->_error("Not found '{$name}' enum to override values");
|
||||
if(!($existing->object instanceof mtgMetaEnum))
|
||||
|
@ -413,7 +413,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
if(!$is_global)
|
||||
$this->_error("Replace supported for global enums only");
|
||||
|
||||
$existing = $this->current_meta->findUnit($enum->getMetaId());
|
||||
$existing = $this->current_meta->findUnit($enum->getName());
|
||||
if(!$existing)
|
||||
$this->_error("Not found '{$name}' enum to replace values");
|
||||
if(!($existing->object instanceof mtgMetaEnum))
|
||||
|
@ -564,6 +564,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
|
||||
private function _addUnit(mtgMetaInfoUnit $unit)
|
||||
{
|
||||
$unit->object->setScope($this->_scope());
|
||||
$this->current_meta->addUnit($unit);
|
||||
$this->module->addUnit($unit);
|
||||
}
|
||||
|
@ -576,7 +577,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $fn));
|
||||
}
|
||||
|
||||
private function _parseStruct($is_global = true) : mtgMetaStruct
|
||||
private function _parseStruct(bool $is_global = true) : mtgMetaStruct
|
||||
{
|
||||
$this->_nextT();
|
||||
$struct_origin = new mtgOrigin($this->file, $this->line);
|
||||
|
@ -664,7 +665,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
$this->_nextT();
|
||||
}
|
||||
|
||||
private function _parseRPC($is_global = true) : mtgMetaRPC
|
||||
private function _parseRPC(bool $is_global = true) : mtgMetaRPC
|
||||
{
|
||||
$this->_nextT();
|
||||
$code = $this->T_value;
|
||||
|
@ -683,12 +684,12 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
{ return $this->_nextIf(self::T_End); }
|
||||
);
|
||||
|
||||
$req = new mtgMetaPacket($code, $is_global ? "RPC_REQ_$name" : "Request");
|
||||
$req = new mtgMetaPacket(intval($code), $is_global ? "RPC_REQ_$name" : "Request");
|
||||
$req->setFields($req_fields);
|
||||
$rsp = new mtgMetaPacket($code, $is_global ? "RPC_RSP_$name" : "Response");
|
||||
$rsp = new mtgMetaPacket(intval($code), $is_global ? "RPC_RSP_$name" : "Response");
|
||||
$rsp->setFields($rsp_fields);
|
||||
|
||||
$rpc = new mtgMetaRPC($is_global ? "RPC_$name" : $name, $code, $req, $rsp, $tokens);
|
||||
$rpc = new mtgMetaRPC($is_global ? "RPC_$name" : $name, intval($code), $req, $rsp, $tokens);
|
||||
|
||||
if($is_global)
|
||||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $rpc));
|
||||
|
@ -712,7 +713,7 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
$existing = null;
|
||||
if($service->hasToken('service_partial'))
|
||||
{
|
||||
$existing = $this->current_meta->findUnit($service->getMetaId());
|
||||
$existing = $this->current_meta->findUnit($service->getName());
|
||||
if($existing)
|
||||
{
|
||||
if(!($existing->object instanceof mtgMetaService))
|
||||
|
@ -734,11 +735,11 @@ class mtgMetaInfoParser implements mtgIMetaInfoParser
|
|||
break;
|
||||
$key = $this->T_value;
|
||||
if($this->T == self::T_RPC)
|
||||
$service->addRPC($this->_parseRPC(false));
|
||||
$service->addRPC($this->_parseRPC(is_global: false));
|
||||
else if($this->T == self::T_Enum)
|
||||
$service->addUserType($this->_parseEnum(false));
|
||||
$service->addUserType($this->_parseEnum(is_global: false));
|
||||
else if($this->T == self::T_Struct)
|
||||
$service->addUserType($this->_parseStruct(false));
|
||||
$service->addUserType($this->_parseStruct(is_global: false));
|
||||
else
|
||||
$this->_error("Unsupported type");
|
||||
}
|
||||
|
|
|
@ -359,7 +359,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
return $values;
|
||||
}
|
||||
|
||||
private function _parseEnum($is_global = true) : mtgMetaEnum
|
||||
private function _parseEnum(bool $is_global = true) : mtgMetaEnum
|
||||
{
|
||||
$this->_nextT();
|
||||
$name = $this->_parseDotName();
|
||||
|
@ -400,7 +400,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
if(!$is_global)
|
||||
$this->_error("Override supported for global enums only");
|
||||
|
||||
$existing = $this->current_meta->findUnit($enum->getMetaId());
|
||||
$existing = $this->current_meta->findUnit($enum->getName());
|
||||
if(!$existing)
|
||||
$this->_error("Not found '{$name}' enum to override values");
|
||||
if(!($existing->object instanceof mtgMetaEnum))
|
||||
|
@ -415,7 +415,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
if(!$is_global)
|
||||
$this->_error("Replace supported for global enums only");
|
||||
|
||||
$existing = $this->current_meta->findUnit($enum->getMetaId());
|
||||
$existing = $this->current_meta->findUnit($enum->getName());
|
||||
if(!$existing)
|
||||
$this->_error("Not found '{$name}' enum to replace values");
|
||||
if(!($existing->object instanceof mtgMetaEnum))
|
||||
|
@ -566,6 +566,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
|
||||
private function _addUnit(mtgMetaInfoUnit $unit)
|
||||
{
|
||||
$unit->object->setScope($this->_scope());
|
||||
$this->current_meta->addUnit($unit);
|
||||
$this->module->addUnit($unit);
|
||||
}
|
||||
|
@ -609,7 +610,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
return $s;
|
||||
}
|
||||
|
||||
private function _parseStruct()
|
||||
private function _parseStruct(bool $is_global = true) : mtgMetaStruct
|
||||
{
|
||||
$this->_nextT();
|
||||
$struct_origin = new mtgOrigin($this->file, $this->line);
|
||||
|
@ -640,7 +641,9 @@ class mtgMetaInfoParser2 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)
|
||||
|
@ -669,6 +672,8 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
foreach($funcs as $fn)
|
||||
$s->addFunc($fn);
|
||||
}
|
||||
|
||||
return $s;
|
||||
}
|
||||
|
||||
private function _parseInterface()
|
||||
|
@ -695,7 +700,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
$this->_nextT();
|
||||
}
|
||||
|
||||
private function _parseRPC($is_global = true) : mtgMetaRPC
|
||||
private function _parseRPC(bool $is_global = true) : mtgMetaRPC
|
||||
{
|
||||
$this->_nextT();
|
||||
$code = $this->T_value;
|
||||
|
@ -717,12 +722,12 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
{ return $this->_nextIf(ord('}')); }
|
||||
);
|
||||
|
||||
$req = new mtgMetaPacket($code, $is_global ? "RPC_REQ_$name" : "Request");
|
||||
$req = new mtgMetaPacket(intval($code), $is_global ? "RPC_REQ_$name" : "Request");
|
||||
$req->setFields($req_fields);
|
||||
$rsp = new mtgMetaPacket($code, $is_global ? "RPC_RSP_$name" : "Response");
|
||||
$rsp = new mtgMetaPacket(intval($code), $is_global ? "RPC_RSP_$name" : "Response");
|
||||
$rsp->setFields($rsp_fields);
|
||||
|
||||
$rpc = new mtgMetaRPC($is_global ? "RPC_$name" : $name, $code, $req, $rsp, $tokens);
|
||||
$rpc = new mtgMetaRPC($is_global ? "RPC_$name" : $name, intval($code), $req, $rsp, $tokens);
|
||||
|
||||
if($is_global)
|
||||
$this->_addUnit(new mtgMetaInfoUnit($this->module, $rpc));
|
||||
|
@ -748,7 +753,7 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
$existing = null;
|
||||
if($service->hasToken('service_partial'))
|
||||
{
|
||||
$existing = $this->current_meta->findUnit($service->getMetaId());
|
||||
$existing = $this->current_meta->findUnit($service->getName());
|
||||
if($existing)
|
||||
{
|
||||
if(!($existing->object instanceof mtgMetaService))
|
||||
|
@ -770,9 +775,11 @@ class mtgMetaInfoParser2 implements mtgIMetaInfoParser
|
|||
break;
|
||||
$key = $this->T_value;
|
||||
if($this->T == self::T_RPC)
|
||||
$service->addRPC($this->_parseRPC(false));
|
||||
$service->addRPC($this->_parseRPC(is_global: false));
|
||||
else if($this->T == self::T_Enum)
|
||||
$service->addUserType($this->_parseEnum(false));
|
||||
$service->addUserType($this->_parseEnum(is_global: false));
|
||||
else if($this->T == self::T_Struct)
|
||||
$service->addUserType($this->_parseStruct(is_global: false));
|
||||
else if($this->T == self::T_Event)
|
||||
$service->addEvent($this->_parseEvent());
|
||||
else
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
interface mtgScope
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,217 @@
|
|||
<?php
|
||||
|
||||
class mtgMetaService extends mtgMetaUnit implements mtgScope
|
||||
{
|
||||
private string $name;
|
||||
//to better handle partial services, since we need to lookup in multiple scopes
|
||||
private mtgMultiScope $merged_scope;
|
||||
private $rpcs = array();
|
||||
private $events = array();
|
||||
private $user_types = array();
|
||||
private $partials = array();
|
||||
|
||||
function __construct(string $name, mtgScope $scope, array $tokens = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->merged_scope = new mtgMultiScope();
|
||||
$this->merged_scope->addScope($scope);
|
||||
$this->scope = $scope;
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
function validate(mtgMetaInfo $meta) {}
|
||||
|
||||
function addPartial(mtgMetaParsedModule $module, mtgMetaService $service)
|
||||
{
|
||||
$this->setTokens(array_merge($this->getTokens(), $service->getTokens()));
|
||||
$this->merged_scope->addScope($service->getScope());
|
||||
$this->partials[$module->file] = $service;
|
||||
}
|
||||
|
||||
function getPartials() : array
|
||||
{
|
||||
return $this->partials;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function findSymbol(string $name) : ?mtgMetaUnit
|
||||
{
|
||||
if(isset($this->user_types[$name]))
|
||||
return $this->user_types[$name];
|
||||
|
||||
return $this->merged_scope->findSymbol($name);
|
||||
}
|
||||
|
||||
function getRPCs() : array
|
||||
{
|
||||
return $this->rpcs;
|
||||
}
|
||||
|
||||
function addRPC(mtgMetaRPC $rpc)
|
||||
{
|
||||
$rpc->setScope($this);
|
||||
|
||||
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(string $name) : bool
|
||||
{
|
||||
return isset($this->rpcs[$name]);
|
||||
}
|
||||
|
||||
function getRPC(string $name) : mtgMetaRPC
|
||||
{
|
||||
if(!isset($this->rpcs[$name]))
|
||||
throw new Exception("No such RPC '$name'");
|
||||
return $this->rpcs[$name];
|
||||
}
|
||||
|
||||
function getUserTypes() : array
|
||||
{
|
||||
return $this->user_types;
|
||||
}
|
||||
|
||||
function addUserType(mtgUserType $utype)
|
||||
{
|
||||
$utype->setScope($this);
|
||||
|
||||
if($this->hasRPC($utype->getName()) || $this->hasUserType($utype->getName()))
|
||||
throw new Exception("Service '{$this->name}' already has user type with name '{$utype->getName()}'");
|
||||
|
||||
$this->user_types[$utype->getName()] = $utype;
|
||||
}
|
||||
|
||||
function hasUserType(string $name) : bool
|
||||
{
|
||||
return isset($this->user_types[$name]);
|
||||
}
|
||||
|
||||
function getUserType(bool $name) : mtgUserType
|
||||
{
|
||||
if(!isset($this->user_types[$name]))
|
||||
throw new Exception("No such user type '$name'");
|
||||
return $this->user_types[$name];
|
||||
}
|
||||
|
||||
function addEvent(mtgMetaStruct $evt)
|
||||
{
|
||||
$evt->setScope($this);
|
||||
|
||||
$this->events[] = $evt;
|
||||
$this->addUserType($evt);
|
||||
}
|
||||
|
||||
function getEvents() : array
|
||||
{
|
||||
return $this->events;
|
||||
}
|
||||
|
||||
function getClassId() : int
|
||||
{
|
||||
if($this->hasToken('class_id'))
|
||||
return $this->getToken('class_id');
|
||||
|
||||
return crc32($this->name);
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
class mtgMetaRPC extends mtgMetaUnit
|
||||
{
|
||||
private string $name;
|
||||
private int $code;
|
||||
private mtgMetaPacket $in;
|
||||
private mtgMetaPacket $out;
|
||||
|
||||
function __construct(string $name, int $code, mtgMetaPacket $in, mtgMetaPacket $out, array $tokens = array())
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->code = $code;
|
||||
$this->in = $in;
|
||||
$this->out = $out;
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
function validate(mtgMetaInfo $meta) {}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function getCode() : int
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
// deprecated?
|
||||
function getNumericCode() : int
|
||||
{
|
||||
return (int)$this->code;
|
||||
}
|
||||
|
||||
function getReq() : mtgMetaPacket
|
||||
{
|
||||
return $this->in;
|
||||
}
|
||||
|
||||
function getRsp() : mtgMetaPacket
|
||||
{
|
||||
return $this->out;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class mtgMetaPacket extends mtgMetaStruct
|
||||
{
|
||||
private int $code;
|
||||
|
||||
function __construct(int $code, string $name, array $tokens = array())
|
||||
{
|
||||
$this->code = $code;
|
||||
|
||||
parent::__construct($name, array(), null, $tokens);
|
||||
}
|
||||
|
||||
// deprecated
|
||||
function getPrefix() : string
|
||||
{
|
||||
list($prefix,) = explode('_', $this->getName());
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
function getFullName() : string
|
||||
{
|
||||
return $this->code . "_" . $this->getName();
|
||||
}
|
||||
|
||||
function getCode() : int
|
||||
{
|
||||
return $this->code;
|
||||
}
|
||||
|
||||
// deprecated
|
||||
function getNumericCode() : int
|
||||
{
|
||||
return (int)$this->code;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,232 @@
|
|||
<?php
|
||||
|
||||
class mtgMetaStruct extends mtgUserType
|
||||
{
|
||||
protected array $fields = array();
|
||||
protected array $funcs = array();
|
||||
protected ?mtgTypeRef $parent = null;
|
||||
protected array $implements = array();
|
||||
|
||||
private ?int $crc_class_id = null;
|
||||
|
||||
function __construct(string $name, array $fields = array(),
|
||||
mtgTypeRef $parent = null, array $tokens = array(),
|
||||
array $implements = array())
|
||||
{
|
||||
parent::__construct($name);
|
||||
|
||||
$this->setFields($fields);
|
||||
$this->parent = $parent;
|
||||
$this->tokens = $tokens;
|
||||
$this->implements = $implements;
|
||||
}
|
||||
|
||||
function getClassId() : int
|
||||
{
|
||||
if($this->hasToken('class_id'))
|
||||
return $this->getToken('class_id');
|
||||
|
||||
if(is_null($this->crc_class_id))
|
||||
{
|
||||
if($this->scope != null)
|
||||
$this->crc_class_id = crc32($this->getFullName());
|
||||
else
|
||||
//TODO: migrate to crc32 from crc28
|
||||
$this->crc_class_id = crc32($this->name) & 0xFFFFFFF;
|
||||
}
|
||||
|
||||
return $this->crc_class_id;
|
||||
}
|
||||
|
||||
function getFullName() : string
|
||||
{
|
||||
$full_name = $this->getName();
|
||||
$scope = $this->getScope();
|
||||
while($scope != null && !($scope instanceof mtgMetaParsedModule))
|
||||
{
|
||||
$full_name = $scope->getName() . '.' . $full_name;
|
||||
$scope = $scope->getScope();
|
||||
}
|
||||
return $full_name;
|
||||
}
|
||||
|
||||
function validate(mtgMetaInfo $meta)
|
||||
{
|
||||
$parent = $this->getParent();
|
||||
while($parent != null)
|
||||
{
|
||||
foreach($this->fields as $name => $_)
|
||||
if($parent->hasField($name))
|
||||
throw new Exception("{$this->origin} : Parent struct '{$parent->getName()}' already has field '{$name}'");
|
||||
|
||||
foreach($this->funcs as $name => $_)
|
||||
if($parent->hasFunc($name))
|
||||
throw new Exception("{$this->origin} : Parent struct '{$parent->getName()}' already has func '{$name}'");
|
||||
|
||||
$parent = $parent->getParent();
|
||||
}
|
||||
|
||||
$s = new SplObjectStorage();
|
||||
foreach($this->getImplements() as $imp)
|
||||
{
|
||||
if(!($imp instanceof mtgMetaInterface))
|
||||
throw new Exception("{$this->origin} : Not an interface '{$imp}'");
|
||||
|
||||
if($s->contains($imp))
|
||||
throw new Exception("{$this->origin} : Duplicate interface reference '{$imp->getName()}'");
|
||||
$s->attach($imp);
|
||||
}
|
||||
|
||||
foreach($this->funcs as $func)
|
||||
{
|
||||
$func->validate($meta);
|
||||
}
|
||||
}
|
||||
|
||||
function getParent() : ?mtgMetaStruct
|
||||
{
|
||||
if(!$this->parent)
|
||||
return null;
|
||||
$resolved = $this->parent->resolve();
|
||||
if(!($resolved instanceof mtgMetaStruct))
|
||||
throw new Exception("Bad parent type");
|
||||
return $resolved;
|
||||
}
|
||||
|
||||
function getImplements() : array
|
||||
{
|
||||
if(!$this->implements)
|
||||
return array();
|
||||
|
||||
$imps = array();
|
||||
foreach($this->implements as $imp)
|
||||
$imps[] = $imp->resolve();
|
||||
return $imps;
|
||||
}
|
||||
|
||||
function getFields() : array
|
||||
{
|
||||
return $this->fields;
|
||||
}
|
||||
|
||||
function setFields(array $fields, bool $replace = false)
|
||||
{
|
||||
if($replace)
|
||||
$this->fields = array();
|
||||
|
||||
foreach($fields as $field)
|
||||
$this->addField($field);
|
||||
}
|
||||
|
||||
function addField(mtgMetaField $field)
|
||||
{
|
||||
if($this->hasField($field->getName()))
|
||||
throw new Exception("Struct '{$this->name}' already has field '{$field->getName()}'");
|
||||
|
||||
$this->fields[$field->getName()] = $field;
|
||||
}
|
||||
|
||||
function delField(mtgMetaField $field)
|
||||
{
|
||||
if(isset($this->fields[$field->getName()]))
|
||||
unset($this->fields[$field->getName()]);
|
||||
}
|
||||
|
||||
function hasField(string $name) : bool
|
||||
{
|
||||
return isset($this->fields[$name]);
|
||||
}
|
||||
|
||||
function getField(string $name) : mtgMetaField
|
||||
{
|
||||
if(!isset($this->fields[$name]))
|
||||
throw new Exception("No such field '$name'");
|
||||
return $this->fields[$name];
|
||||
}
|
||||
|
||||
function getFuncs() : array
|
||||
{
|
||||
return $this->funcs;
|
||||
}
|
||||
|
||||
function addFunc(mtgMetaFunc $fn)
|
||||
{
|
||||
if($this->hasFunc($fn->getName()))
|
||||
throw new Exception("Struct '{$this->name}' already has func '{$fn->getName()}'");
|
||||
|
||||
$this->funcs[$fn->getName()] = $fn;
|
||||
}
|
||||
|
||||
function hasFunc(string $name) : bool
|
||||
{
|
||||
return isset($this->funcs[$name]);
|
||||
}
|
||||
|
||||
function getFunc(string $name) : mtgMetaFunc
|
||||
{
|
||||
if(!isset($this->funcs[$name]))
|
||||
throw new Exception("No such funcs '$name'");
|
||||
return $this->funcs[$name];
|
||||
}
|
||||
|
||||
//TODO: doesn't belong here
|
||||
function hasTokenInParent(string $name) : bool
|
||||
{
|
||||
return mtg_try_get_token_in_hierarchy($this, $name, $value);
|
||||
}
|
||||
}
|
||||
|
||||
class mtgMetaField
|
||||
{
|
||||
private $name;
|
||||
private $type;
|
||||
private $tokens = array();
|
||||
|
||||
function __construct($name, mtgTypeRef $type)
|
||||
{
|
||||
$this->name = $name;
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function getType()
|
||||
{
|
||||
return $this->type->resolve();
|
||||
}
|
||||
|
||||
function getTokens()
|
||||
{
|
||||
return $this->tokens;
|
||||
}
|
||||
|
||||
function setTokens(array $tokens)
|
||||
{
|
||||
$this->tokens = $tokens;
|
||||
}
|
||||
|
||||
function setToken($name, $val)
|
||||
{
|
||||
$this->tokens[$name] = $val;
|
||||
}
|
||||
|
||||
function hasToken($name)
|
||||
{
|
||||
return array_key_exists($name, $this->tokens);
|
||||
}
|
||||
|
||||
function getToken($name)
|
||||
{
|
||||
return $this->hasToken($name) ? $this->tokens[$name] : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,272 @@
|
|||
<?php
|
||||
|
||||
interface mtgType
|
||||
{
|
||||
function getName() : string;
|
||||
function __toString() : string;
|
||||
}
|
||||
|
||||
class mtgTypeRef implements mtgType
|
||||
{
|
||||
//TODO: not sure if it must be static
|
||||
private static $unresolved = array();
|
||||
|
||||
private string $name;
|
||||
private ?mtgScope $scope = null;
|
||||
private ?mtgType $resolved = null;
|
||||
private ?mtgOrigin $origin = null;
|
||||
|
||||
function __construct($name_or_resolved, mtgScope $scope = null, mtgOrigin $origin = null)
|
||||
{
|
||||
if(is_object($name_or_resolved))
|
||||
{
|
||||
if(!($name_or_resolved instanceof mtgType))
|
||||
throw new Exception("Bad type");
|
||||
$this->resolved = $name_or_resolved;
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->name = $name_or_resolved;
|
||||
if(!$scope)
|
||||
throw new Exception("Scope is not set");
|
||||
|
||||
self::$unresolved[] = $this;
|
||||
}
|
||||
|
||||
$this->scope = $scope;
|
||||
$this->origin = $origin ?? new mtgOrigin();
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
if($this->resolved)
|
||||
return ''.$this->resolved;
|
||||
else
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
static function checkAllResolved()
|
||||
{
|
||||
while(sizeof(self::$unresolved) > 0)
|
||||
{
|
||||
$ref = array_shift(self::$unresolved);
|
||||
$resolved = $ref->resolve();
|
||||
if($resolved instanceof mtgMetaFunc && $resolved->getName())
|
||||
throw new Exception("Invalid resolving of named function as type: " . $resolved->getName() . " at " . $ref->origin);
|
||||
}
|
||||
}
|
||||
|
||||
function resolve() : mtgType
|
||||
{
|
||||
if($this->resolved)
|
||||
return $this->resolved;
|
||||
|
||||
$symb = $this->scope->findSymbol($this->name);
|
||||
if($symb)
|
||||
{
|
||||
if(!($symb instanceof mtgType))
|
||||
throw new Exception("{$this->origin} : Symbol '{$this->name}' is not type");
|
||||
$this->resolved = $symb;
|
||||
return $this->resolved;
|
||||
}
|
||||
else
|
||||
throw new Exception("{$this->origin} : Symbol '{$this->name}' not found");
|
||||
}
|
||||
|
||||
function __toString()
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class mtgUserType extends mtgMetaUnit implements mtgType
|
||||
{
|
||||
protected string $name;
|
||||
|
||||
function __construct(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function setName(string $name)
|
||||
{
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function __toString() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
||||
|
||||
class mtgBuiltinType implements mtgType
|
||||
{
|
||||
private string $name;
|
||||
|
||||
function __construct(string $name)
|
||||
{
|
||||
if(!in_array($name, mtgMetaInfo::$BUILTIN_TYPES))
|
||||
throw new Exception("Not a built-in type '$name'");
|
||||
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function __toString() : string
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
function isNumeric() : bool
|
||||
{
|
||||
return !$this->isString() && !$this->isBool() && !$this->isBlob();
|
||||
}
|
||||
|
||||
function isString() : bool
|
||||
{
|
||||
return $this->name === 'string';
|
||||
}
|
||||
|
||||
function isInt() : bool
|
||||
{
|
||||
return strpos($this->name, 'int') === 0;
|
||||
}
|
||||
|
||||
function isUint() : bool
|
||||
{
|
||||
return strpos($this->name, 'uint') === 0;
|
||||
}
|
||||
|
||||
function isUint8() : bool
|
||||
{
|
||||
return $this->name === 'uint8';
|
||||
}
|
||||
|
||||
function isUint16() : bool
|
||||
{
|
||||
return $this->name === 'uint16';
|
||||
}
|
||||
|
||||
function isUint32() : bool
|
||||
{
|
||||
return $this->name === 'uint32';
|
||||
}
|
||||
|
||||
function isUint64() : bool
|
||||
{
|
||||
return $this->name === 'uint64';
|
||||
}
|
||||
|
||||
function isInt64() : bool
|
||||
{
|
||||
return $this->name === 'int64';
|
||||
}
|
||||
|
||||
function isInt8() : bool
|
||||
{
|
||||
return $this->name === 'int8';
|
||||
}
|
||||
|
||||
function isInt16() : bool
|
||||
{
|
||||
return $this->name === 'int16';
|
||||
}
|
||||
|
||||
function isInt32() : bool
|
||||
{
|
||||
return $this->name === 'int32';
|
||||
}
|
||||
|
||||
function isFloat() : bool
|
||||
{
|
||||
return $this->name === 'float';
|
||||
}
|
||||
|
||||
function isDouble() : bool
|
||||
{
|
||||
return $this->name === 'double';
|
||||
}
|
||||
|
||||
function isBool() : bool
|
||||
{
|
||||
return $this->name === 'bool';
|
||||
}
|
||||
|
||||
function isBlob() : bool
|
||||
{
|
||||
return $this->name === 'blob';
|
||||
}
|
||||
}
|
||||
|
||||
class mtgMultiType implements mtgType
|
||||
{
|
||||
private $values = array();
|
||||
|
||||
function __construct(array $values = array())
|
||||
{
|
||||
foreach($values as $v)
|
||||
$this->addValue($v);
|
||||
}
|
||||
|
||||
function addValue(mtgTypeRef $val)
|
||||
{
|
||||
$this->values[] = $val;
|
||||
}
|
||||
|
||||
function getValues()
|
||||
{
|
||||
$vals = array();
|
||||
foreach($this->values as $val)
|
||||
$vals[] = $val->resolve();
|
||||
|
||||
return $vals;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
$str = '';
|
||||
foreach($this->getValues() as $val)
|
||||
$str .= $val . ';';
|
||||
return $str;
|
||||
}
|
||||
|
||||
function __toString() : string
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
}
|
||||
|
||||
class mtgArrType implements mtgType
|
||||
{
|
||||
private mtgTypeRef $value;
|
||||
|
||||
function __construct(mtgTypeRef $value)
|
||||
{
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
function getName() : string
|
||||
{
|
||||
return $this->getValue() . '[]';
|
||||
}
|
||||
|
||||
function __toString() : string
|
||||
{
|
||||
return $this->getName();
|
||||
}
|
||||
|
||||
function getValue() : mixed
|
||||
{
|
||||
return $this->value->resolve();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
function mtg_get_all_fields(mtgMetaStruct $struct)
|
||||
{
|
||||
$fields = $struct->getFields();
|
||||
$parent = $struct->getParent();
|
||||
if($parent)
|
||||
//NOTE: order is important, parent fields must come first
|
||||
$fields = array_merge(mtg_get_all_fields($parent), $fields);
|
||||
return $fields;
|
||||
}
|
||||
|
||||
function mtg_find_field_owner(mtgMetaStruct $struct, $name)
|
||||
{
|
||||
$tmp = $struct;
|
||||
while($tmp)
|
||||
{
|
||||
$fields = $tmp->getFields();
|
||||
if(isset($fields[$name]))
|
||||
return $tmp;
|
||||
$tmp = $tmp->getParent();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function mtg_try_get_token_in_hierarchy(mtgMetaStruct $struct, $name, &$value)
|
||||
{
|
||||
$tmp = $struct;
|
||||
while($tmp)
|
||||
{
|
||||
if($tmp->hasToken($name))
|
||||
{
|
||||
$value = $tmp->getToken($name);
|
||||
return true;
|
||||
}
|
||||
$tmp = $tmp->getParent();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
Loading…
Reference in New Issue