2022-05-16 14:20:20 +03:00
|
|
|
<?php
|
|
|
|
|
|
|
|
interface mtgType
|
2023-08-16 14:16:13 +03:00
|
|
|
{
|
|
|
|
function getName();
|
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
|
2024-04-04 19:20:38 +03:00
|
|
|
interface mtgScope
|
|
|
|
{
|
|
|
|
function findSymbol($name);
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
class mtgTypeRef implements mtgType
|
|
|
|
{
|
2023-08-03 23:00:31 +03:00
|
|
|
private static $unresolved = array();
|
2022-05-16 14:20:20 +03:00
|
|
|
|
|
|
|
private $name;
|
2024-04-04 19:20:38 +03:00
|
|
|
private $scope;
|
2022-05-16 14:20:20 +03:00
|
|
|
private $resolved;
|
2023-09-27 00:15:44 +03:00
|
|
|
private $origin;
|
2022-05-16 14:20:20 +03:00
|
|
|
|
2024-04-04 19:20:38 +03:00
|
|
|
function __construct($name_or_resolved, mtgScope $scope = null, mtgOrigin $origin = null)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
if(is_object($name_or_resolved))
|
|
|
|
{
|
|
|
|
if(!($name_or_resolved instanceof mtgType))
|
|
|
|
throw new Exception("Bad type");
|
|
|
|
$this->resolved = $name_or_resolved;
|
|
|
|
}
|
|
|
|
else
|
2023-08-03 18:03:37 +03:00
|
|
|
{
|
2022-05-16 14:20:20 +03:00
|
|
|
$this->name = $name_or_resolved;
|
2024-04-04 19:20:38 +03:00
|
|
|
if(!$scope)
|
|
|
|
throw new Exception("Scope is not set");
|
2023-08-03 23:00:31 +03:00
|
|
|
|
|
|
|
self::$unresolved[] = $this;
|
2023-08-03 18:03:37 +03:00
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
|
2024-04-04 19:20:38 +03:00
|
|
|
$this->scope = $scope;
|
2023-09-27 00:15:44 +03:00
|
|
|
$this->origin = $origin ?? new mtgOrigin();
|
2022-05-16 14:20:20 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getName()
|
|
|
|
{
|
|
|
|
if($this->resolved)
|
|
|
|
return ''.$this->resolved;
|
|
|
|
else
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
static function checkAllResolved()
|
|
|
|
{
|
2023-08-03 23:00:31 +03:00
|
|
|
while(sizeof(self::$unresolved) > 0)
|
|
|
|
{
|
|
|
|
$ref = array_shift(self::$unresolved);
|
2024-05-31 20:51:47 +03:00
|
|
|
$resolved = $ref->resolve();
|
|
|
|
if($resolved instanceof mtgMetaFunc && $resolved->getName())
|
|
|
|
throw new Exception("Invalid resolving of named function as type: " . $resolved->getName() . " at " . $ref->origin);
|
2023-08-03 23:00:31 +03:00
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function resolve()
|
|
|
|
{
|
|
|
|
if($this->resolved)
|
|
|
|
return $this->resolved;
|
|
|
|
|
2024-04-04 19:20:38 +03:00
|
|
|
$symb = $this->scope->findSymbol($this->name);
|
|
|
|
if($symb)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
2024-04-04 19:20:38 +03:00
|
|
|
$this->resolved = $symb;
|
2022-05-16 14:20:20 +03:00
|
|
|
return $this->resolved;
|
|
|
|
}
|
|
|
|
else
|
2023-09-27 00:15:44 +03:00
|
|
|
throw new Exception("{$this->origin} : Symbol '{$this->name}' not found");
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
2023-08-03 18:03:37 +03:00
|
|
|
|
|
|
|
function __toString()
|
|
|
|
{
|
2023-08-16 14:16:13 +03:00
|
|
|
return $this->getName();
|
2023-08-03 18:03:37 +03:00
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
class mtgMetaInfoUnit
|
|
|
|
{
|
2023-11-30 18:48:28 +03:00
|
|
|
public ?mtgMetaParsedModule $module = null;
|
2023-08-16 14:16:13 +03:00
|
|
|
public string $file;
|
|
|
|
public mtgMetaUnit $object;
|
2022-05-16 14:20:20 +03:00
|
|
|
|
2023-11-30 18:48:28 +03:00
|
|
|
/**
|
|
|
|
* @param string|mtgMetaParsedModule $file_or_module
|
|
|
|
*/
|
|
|
|
function __construct($file_or_module, mtgMetaUnit $obj)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
2023-11-30 18:48:28 +03:00
|
|
|
if($file_or_module instanceof mtgMetaParsedModule)
|
|
|
|
{
|
|
|
|
$this->module = $file_or_module;
|
|
|
|
$this->file = $file_or_module->file;
|
|
|
|
}
|
|
|
|
else if(is_string($file_or_module))
|
|
|
|
{
|
|
|
|
$this->module = null;
|
|
|
|
$this->file = $file_or_module;
|
|
|
|
}
|
|
|
|
|
|
|
|
$this->object = $obj;
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class mtgMetaInfo
|
|
|
|
{
|
2022-12-09 12:37:55 +03:00
|
|
|
public static $BUILTIN_TYPES = array(
|
|
|
|
'int8', 'int16', 'int32', 'uint8', 'uint16', 'uint32',
|
|
|
|
'float', 'double', 'uint64', 'int64', 'bool', 'string', 'blob'
|
|
|
|
);
|
2022-05-16 14:20:20 +03:00
|
|
|
|
|
|
|
private $units = array();
|
|
|
|
|
|
|
|
function addUnit(mtgMetaInfoUnit $unit)
|
|
|
|
{
|
2023-08-16 14:16:13 +03:00
|
|
|
if(isset($this->units[$unit->object->getMetaId()]))
|
|
|
|
throw new Exception("Meta info unit '{$unit->object->getMetaId()}' already defined in file '{$this->units[$unit->object->getMetaId()]->file}'");
|
2022-05-16 14:20:20 +03:00
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
$this->units[$unit->object->getMetaId()] = $unit;
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
2023-10-23 11:08:48 +03:00
|
|
|
function delUnit(mtgMetaInfoUnit $unit)
|
|
|
|
{
|
|
|
|
unset($this->units[$unit->object->getMetaId()]);
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function getUnits() : array
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
return $this->units;
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function findUnit($id) : ?mtgMetaInfoUnit
|
2023-08-03 18:03:37 +03:00
|
|
|
{
|
|
|
|
if(isset($this->units[$id]))
|
|
|
|
return $this->units[$id];
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function getUnit($id) : mtgMetaInfoUnit
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
if(isset($this->units[$id]))
|
|
|
|
return $this->units[$id];
|
2023-08-03 18:03:37 +03:00
|
|
|
throw new Exception("Unit '$id' not found");
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
2023-09-27 00:15:44 +03:00
|
|
|
|
|
|
|
function validate()
|
|
|
|
{
|
|
|
|
foreach($this->units as $u)
|
|
|
|
$u->object->validate($this);
|
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
abstract class mtgMetaUnit
|
|
|
|
{
|
2023-08-16 14:16:13 +03:00
|
|
|
abstract function getMetaId();
|
2022-05-16 14:20:20 +03:00
|
|
|
|
|
|
|
protected $tokens = array();
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
protected ?mtgOrigin $origin;
|
2023-09-27 00:15:44 +03:00
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
function getTokens()
|
|
|
|
{
|
|
|
|
return $this->tokens;
|
|
|
|
}
|
|
|
|
|
|
|
|
function setTokens(array $tokens)
|
|
|
|
{
|
|
|
|
$this->tokens = $tokens;
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function setToken(string $name, $val)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
$this->tokens[$name] = $val;
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function delToken(string $name)
|
2023-10-23 11:08:48 +03:00
|
|
|
{
|
|
|
|
unset($this->tokens[$name]);
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function getToken(string $name)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
return $this->hasToken($name) ? $this->tokens[$name] : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function hasToken($name)
|
|
|
|
{
|
|
|
|
return array_key_exists($name, $this->tokens);
|
|
|
|
}
|
2023-09-27 00:15:44 +03:00
|
|
|
|
|
|
|
function setOrigin(mtgOrigin $origin)
|
|
|
|
{
|
|
|
|
$this->origin = $origin;
|
|
|
|
}
|
|
|
|
|
2024-03-14 12:50:54 +03:00
|
|
|
function getOrigin() : ?mtgOrigin
|
2023-09-27 00:15:44 +03:00
|
|
|
{
|
|
|
|
return $this->origin;
|
|
|
|
}
|
|
|
|
|
|
|
|
abstract function validate(mtgMetaInfo $meta);
|
|
|
|
}
|
|
|
|
|
|
|
|
class mtgOrigin
|
|
|
|
{
|
|
|
|
public $file;
|
|
|
|
public $line;
|
|
|
|
|
|
|
|
function __construct($file = '', $line = 0)
|
|
|
|
{
|
|
|
|
$this->file = $file;
|
|
|
|
$this->line = $line;
|
|
|
|
}
|
|
|
|
|
|
|
|
function __toString()
|
|
|
|
{
|
|
|
|
return "{$this->file}@{$this->line}";
|
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
2023-09-27 00:15:44 +03:00
|
|
|
abstract class mtgUserType extends mtgMetaUnit implements mtgType
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
protected $name;
|
|
|
|
|
|
|
|
function __construct($name)
|
|
|
|
{
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getMetaId()
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getName()
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
2023-08-16 14:16:13 +03:00
|
|
|
return $this->name;
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function setName($name)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
2023-08-16 14:16:13 +03:00
|
|
|
$this->name = $name;
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
function getClassId()
|
|
|
|
{
|
2023-08-16 14:16:13 +03:00
|
|
|
if($this->hasToken('class_id'))
|
|
|
|
return $this->getToken('class_id');
|
|
|
|
|
2024-04-04 19:20:38 +03:00
|
|
|
//TODO: migrate to crc32 from crc28
|
2022-05-16 14:20:20 +03:00
|
|
|
return crc32($this->name) & 0xFFFFFFF;
|
|
|
|
}
|
|
|
|
|
|
|
|
function __toString()
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class mtgMetaStruct extends mtgUserType
|
|
|
|
{
|
|
|
|
protected $fields = array();
|
|
|
|
protected $funcs = array();
|
|
|
|
protected $parent = null;
|
2023-05-23 13:38:16 +03:00
|
|
|
protected $implements = array();
|
2022-05-16 14:20:20 +03:00
|
|
|
|
2023-05-23 13:38:16 +03:00
|
|
|
function __construct($name, array $fields = array(), mtgTypeRef $parent = null, array $tokens = array(), array $implements = array())
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
parent::__construct($name);
|
|
|
|
|
|
|
|
$this->setFields($fields);
|
|
|
|
$this->parent = $parent;
|
|
|
|
$this->tokens = $tokens;
|
2023-05-23 13:38:16 +03:00
|
|
|
$this->implements = $implements;
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
2023-09-27 00:15:44 +03:00
|
|
|
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);
|
|
|
|
}
|
2024-05-31 20:51:47 +03:00
|
|
|
|
|
|
|
foreach($this->funcs as $func)
|
|
|
|
{
|
|
|
|
$func->validate($meta);
|
|
|
|
}
|
2023-09-27 00:15:44 +03:00
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
function getParent()
|
|
|
|
{
|
|
|
|
return $this->parent ? $this->parent->resolve() : null;
|
|
|
|
}
|
|
|
|
|
2023-05-23 13:38:16 +03:00
|
|
|
function getImplements()
|
|
|
|
{
|
|
|
|
if(!$this->implements)
|
|
|
|
return array();
|
|
|
|
|
|
|
|
$imps = array();
|
|
|
|
foreach($this->implements as $imp)
|
|
|
|
$imps[] = $imp->resolve();
|
|
|
|
return $imps;
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
function getFields()
|
|
|
|
{
|
|
|
|
return $this->fields;
|
|
|
|
}
|
|
|
|
|
2022-12-14 12:34:59 +03:00
|
|
|
function setFields(array $fields, $replace = false)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
2022-12-14 12:34:59 +03:00
|
|
|
if($replace)
|
|
|
|
$this->fields = array();
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
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($name)
|
|
|
|
{
|
|
|
|
return isset($this->fields[$name]);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getField($name)
|
|
|
|
{
|
|
|
|
if(!isset($this->fields[$name]))
|
|
|
|
throw new Exception("No such field '$name'");
|
|
|
|
return $this->fields[$name];
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFuncs()
|
|
|
|
{
|
|
|
|
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($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];
|
|
|
|
}
|
|
|
|
|
2022-12-14 12:34:59 +03:00
|
|
|
//TODO: doesn't belong here
|
2022-05-16 14:20:20 +03:00
|
|
|
function hasTokenInParent($name)
|
|
|
|
{
|
2022-12-14 12:34:59 +03:00
|
|
|
return mtg_try_get_token_in_hierarchy($this, $name, $value);
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-18 13:12:26 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-09-27 00:15:44 +03:00
|
|
|
function validate(mtgMetaInfo $meta) {}
|
|
|
|
|
2022-05-18 13:12:26 +03:00
|
|
|
function getImplements()
|
|
|
|
{
|
2023-06-02 15:38:39 +03:00
|
|
|
if(!$this->implements)
|
|
|
|
return array();
|
|
|
|
|
|
|
|
$imps = array();
|
|
|
|
foreach($this->implements as $imp)
|
|
|
|
$imps[] = $imp->resolve();
|
|
|
|
return $imps;
|
2022-05-18 13:12:26 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
class mtgMetaFunc extends mtgMetaUnit implements mtgType
|
|
|
|
{
|
|
|
|
private $name;
|
|
|
|
private $args = array();
|
|
|
|
private $ret_type;
|
|
|
|
|
|
|
|
function __construct($name)
|
|
|
|
{
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
|
2024-05-31 20:51:47 +03:00
|
|
|
function validate(mtgMetaInfo $meta)
|
|
|
|
{}
|
2023-09-27 00:15:44 +03:00
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getMetaId()
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
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()
|
|
|
|
{
|
|
|
|
return $this->ret_type ? $this->ret_type->resolve() : null;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getName()
|
|
|
|
{
|
|
|
|
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];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class mtgMetaRPC extends mtgMetaUnit
|
|
|
|
{
|
|
|
|
private $name;
|
|
|
|
private $code;
|
|
|
|
private $in;
|
|
|
|
private $out;
|
|
|
|
|
|
|
|
function __construct($name, $code, mtgMetaPacket $in, mtgMetaPacket $out, array $tokens = array())
|
|
|
|
{
|
|
|
|
$this->name = $name;
|
|
|
|
$this->code = $code;
|
|
|
|
$this->in = $in;
|
|
|
|
$this->out = $out;
|
|
|
|
$this->tokens = $tokens;
|
|
|
|
}
|
|
|
|
|
2023-09-27 00:15:44 +03:00
|
|
|
function validate(mtgMetaInfo $meta) {}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getMetaId()
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
return $this->code;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getName()
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCode()
|
|
|
|
{
|
|
|
|
return $this->code;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNumericCode()
|
|
|
|
{
|
|
|
|
return (int)$this->code;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getReq()
|
|
|
|
{
|
|
|
|
return $this->in;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getRsp()
|
|
|
|
{
|
|
|
|
return $this->out;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-04-04 19:20:38 +03:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
class mtgBuiltinType implements mtgType
|
|
|
|
{
|
|
|
|
private $name;
|
|
|
|
|
|
|
|
function __construct($name)
|
|
|
|
{
|
|
|
|
if(!in_array($name, mtgMetaInfo::$BUILTIN_TYPES))
|
|
|
|
throw new Exception("Not a built-in type '$name'");
|
|
|
|
|
|
|
|
$this->name = $name;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getName()
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
function __toString()
|
|
|
|
{
|
|
|
|
return $this->name;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isNumeric()
|
|
|
|
{
|
|
|
|
return !$this->isString() && !$this->isBool() && !$this->isBlob();
|
|
|
|
}
|
|
|
|
|
|
|
|
function isString()
|
|
|
|
{
|
|
|
|
return $this->name === 'string';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isInt()
|
|
|
|
{
|
|
|
|
return strpos($this->name, 'int') === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isUint()
|
|
|
|
{
|
|
|
|
return strpos($this->name, 'uint') === 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
function isUint8()
|
|
|
|
{
|
|
|
|
return $this->name === 'uint8';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isUint16()
|
|
|
|
{
|
|
|
|
return $this->name === 'uint16';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isUint32()
|
|
|
|
{
|
|
|
|
return $this->name === 'uint32';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isUint64()
|
|
|
|
{
|
|
|
|
return $this->name === 'uint64';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isInt64()
|
|
|
|
{
|
|
|
|
return $this->name === 'int64';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isInt8()
|
|
|
|
{
|
|
|
|
return $this->name === 'int8';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isInt16()
|
|
|
|
{
|
|
|
|
return $this->name === 'int16';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isInt32()
|
|
|
|
{
|
|
|
|
return $this->name === 'int32';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isFloat()
|
|
|
|
{
|
|
|
|
return $this->name === 'float';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isDouble()
|
|
|
|
{
|
|
|
|
return $this->name === 'double';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isBool()
|
|
|
|
{
|
|
|
|
return $this->name === 'bool';
|
|
|
|
}
|
|
|
|
|
|
|
|
function isBlob()
|
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getName()
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
$str = '';
|
|
|
|
foreach($this->getValues() as $val)
|
|
|
|
$str .= $val . ';';
|
|
|
|
return $str;
|
|
|
|
}
|
2023-08-16 14:16:13 +03:00
|
|
|
|
|
|
|
function __toString()
|
|
|
|
{
|
|
|
|
return $this->getName();
|
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
class mtgArrType implements mtgType
|
|
|
|
{
|
|
|
|
private $value;
|
|
|
|
|
|
|
|
function __construct(mtgTypeRef $value)
|
|
|
|
{
|
|
|
|
$this->value = $value;
|
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function getName()
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
return $this->getValue() . '[]';
|
|
|
|
}
|
|
|
|
|
2023-08-16 14:16:13 +03:00
|
|
|
function __toString()
|
|
|
|
{
|
|
|
|
return $this->getName();
|
|
|
|
}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
function getValue()
|
|
|
|
{
|
|
|
|
return $this->value->resolve();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
2024-05-31 20:51:47 +03:00
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
class mtgMetaPacket extends mtgMetaStruct
|
|
|
|
{
|
|
|
|
private $code;
|
|
|
|
|
|
|
|
function __construct($code, $name, array $tokens = array())
|
|
|
|
{
|
|
|
|
$this->code = $code;
|
|
|
|
|
|
|
|
parent::__construct($name, array(), null, $tokens);
|
|
|
|
}
|
|
|
|
|
|
|
|
function getPrefix()
|
|
|
|
{
|
|
|
|
list($prefix,) = explode('_', $this->getName());
|
|
|
|
return $prefix;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getFullName()
|
|
|
|
{
|
|
|
|
return $this->code . "_" . $this->getName();
|
|
|
|
}
|
|
|
|
|
|
|
|
function getCode()
|
|
|
|
{
|
|
|
|
return $this->code;
|
|
|
|
}
|
|
|
|
|
|
|
|
function getNumericCode()
|
|
|
|
{
|
|
|
|
return (int)$this->code;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class mtgMetaEnum extends mtgUserType
|
|
|
|
{
|
|
|
|
private $values = array();
|
|
|
|
|
2023-09-27 00:15:44 +03:00
|
|
|
function validate(mtgMetaInfo $meta) {}
|
|
|
|
|
2022-05-16 14:20:20 +03:00
|
|
|
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;
|
2023-07-14 16:21:21 +03:00
|
|
|
foreach($or_keys as $value_name)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2023-07-14 16:21:21 +03:00
|
|
|
|
|
|
|
function override(mtgMetaEnum $other)
|
|
|
|
{
|
|
|
|
$this->tokens = array_merge($this->tokens, $other->getTokens());
|
|
|
|
$this->values = array_merge($this->values, $other->getValues());
|
|
|
|
}
|
2023-11-09 17:47:36 +03:00
|
|
|
|
|
|
|
function replace(mtgMetaEnum $other)
|
|
|
|
{
|
|
|
|
$this->tokens = $other->getTokens();
|
|
|
|
$this->values = $other->getValues();
|
|
|
|
}
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
|
|
|
|
2022-12-08 19:14:25 +03:00
|
|
|
function mtg_get_all_fields(mtgMetaStruct $struct)
|
2022-05-16 14:20:20 +03:00
|
|
|
{
|
2022-12-08 19:14:25 +03:00
|
|
|
$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;
|
2022-05-16 14:20:20 +03:00
|
|
|
}
|
2022-12-14 12:34:59 +03:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|