Improving structs and interfaces validation

This commit is contained in:
Pavel Shevaev 2023-09-27 00:15:44 +03:00
parent f93d46ad5e
commit a84718215d
2 changed files with 107 additions and 20 deletions

View File

@ -10,12 +10,11 @@ class mtgTypeRef implements mtgType
private static $unresolved = array();
private $name;
private $file;
private $line;
private $module;
private $resolved;
private $origin;
function __construct($name_or_resolved, mtgMetaParsedModule $module = null, $file = '', $line= 0)
function __construct($name_or_resolved, mtgMetaParsedModule $module = null, mtgOrigin $origin = null)
{
if(is_object($name_or_resolved))
{
@ -33,8 +32,7 @@ class mtgTypeRef implements mtgType
}
$this->module = $module;
$this->file = $file;
$this->line = $line;
$this->origin = $origin ?? new mtgOrigin();
}
@ -67,7 +65,7 @@ class mtgTypeRef implements mtgType
return $this->resolved;
}
else
throw new Exception("{$this->file}@{$this->line} : Symbol '{$this->name}' not found");
throw new Exception("{$this->origin} : Symbol '{$this->name}' not found");
}
function __toString()
@ -123,6 +121,12 @@ class mtgMetaInfo
return $this->units[$id];
throw new Exception("Unit '$id' not found");
}
function validate()
{
foreach($this->units as $u)
$u->object->validate($this);
}
}
abstract class mtgMetaUnit
@ -131,6 +135,8 @@ abstract class mtgMetaUnit
protected $tokens = array();
protected $origin;
function getTokens()
{
return $this->tokens;
@ -155,9 +161,38 @@ abstract class mtgMetaUnit
{
return array_key_exists($name, $this->tokens);
}
function setOrigin(mtgOrigin $origin)
{
$this->origin = $origin;
}
function getOrigin()
{
return $this->origin;
}
abstract function validate(mtgMetaInfo $meta);
}
class mtgUserType extends mtgMetaUnit implements mtgType
class mtgOrigin
{
public $file;
public $line;
function __construct($file = '', $line = 0)
{
$this->file = $file;
$this->line = $line;
}
function __toString()
{
return "{$this->file}@{$this->line}";
}
}
abstract class mtgUserType extends mtgMetaUnit implements mtgType
{
protected $name;
@ -214,6 +249,34 @@ class mtgMetaStruct extends mtgUserType
$this->implements = $implements;
}
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);
}
}
function getParent()
{
return $this->parent ? $this->parent->resolve() : null;
@ -315,6 +378,8 @@ class mtgMetaInterface extends mtgUserType
$this->tokens = $tokens;
}
function validate(mtgMetaInfo $meta) {}
function getImplements()
{
if(!$this->implements)
@ -363,6 +428,8 @@ class mtgMetaFunc extends mtgMetaUnit implements mtgType
$this->name = $name;
}
function validate(mtgMetaInfo $meta) {}
function getMetaId()
{
return $this->name;
@ -445,6 +512,8 @@ class mtgMetaRPC extends mtgMetaUnit
$this->tokens = $tokens;
}
function validate(mtgMetaInfo $meta) {}
function getMetaId()
{
return $this->code;
@ -732,6 +801,8 @@ class mtgMetaEnum extends mtgUserType
{
private $values = array();
function validate(mtgMetaInfo $meta) {}
function addValue($value_name, $value)
{
if(isset($this->values[$value_name]))

View File

@ -105,8 +105,6 @@ class mtgMetaInfoParser
throw new Exception("No such file '$raw_file'");
$this->_parse($file);
mtgTypeRef::checkAllResolved();
}
private function _parse($file)
@ -206,26 +204,30 @@ class mtgMetaInfoParser
if($this->token == self::T_Func)
{
$origin = new mtgOrigin($this->file, $this->line);
$func_type = $this->_parseFuncType();
$type = new mtgTypeRef($func_type, $this->module, $this->file, $this->line);
$type = new mtgTypeRef($func_type, $this->module, $origin);
}
else if($this->token == self::T_Identifier)
{
$origin = new mtgOrigin($this->file, $this->line);
$type_name = $this->_parseDotName();
$type = new mtgTypeRef($type_name, $this->module, $this->file, $this->line);
$type = new mtgTypeRef($type_name, $this->module, $origin);
}
else
{
$origin = new mtgOrigin($this->file, $this->line);
$type_name = $this->attribute;
$type = new mtgTypeRef(new mtgBuiltinType($type_name), $this->module, $this->file, $this->line);
$type = new mtgTypeRef(new mtgBuiltinType($type_name), $this->module, $origin);
$this->_next();
}
if($this->token == ord('['))
{
$origin = new mtgOrigin($this->file, $this->line);
$this->_next();
$this->_checkThenNext(']');
$type = new mtgTypeRef(new mtgArrType($type), $this->module, $this->file, $this->line);
$type = new mtgTypeRef(new mtgArrType($type), $this->module, $origin);
}
$types[] = $type;
@ -238,7 +240,7 @@ class mtgMetaInfoParser
}
if(sizeof($types) > 1)
return new mtgTypeRef(new mtgMultiType($types), $this->module, $this->file, $this->line);
return new mtgTypeRef(new mtgMultiType($types), $this->module, new mtgOrigin($this->file, $this->line));
else
return $types[0];
}
@ -511,14 +513,16 @@ class mtgMetaInfoParser
private function _parseStruct()
{
$this->_next();
$struct_origin = new mtgOrigin($this->file, $this->line);
$name = $this->_parseDotName();
$parent = null;
if($this->token == self::T_Extends)
{
$this->_next();
$origin = new mtgOrigin($this->file, $this->line);
$parent_name = $this->_checkThenNext(self::T_Identifier);
$parent = new mtgTypeRef($parent_name, $this->module, $this->file, $this->line);
$parent = new mtgTypeRef($parent_name, $this->module, $origin);
}
$implements = array();
@ -527,12 +531,14 @@ class mtgMetaInfoParser
do
{
$this->_next();
$origin = new mtgOrigin($this->file, $this->line);
$if_name = $this->_checkThenNext(self::T_Identifier);
$implements[] = new mtgTypeRef($if_name, $this->module, $this->file, $this->line);
$implements[] = new mtgTypeRef($if_name, $this->module, $origin);
} while($this->token == ord(','));
}
$s = new mtgMetaStruct($name, array(), $parent, array(), $implements);
$s->setOrigin($struct_origin);
$this->_addUnit(new mtgMetaInfoUnit($this->file, $s));
$tokens = $this->shared_tokens;
@ -577,10 +583,15 @@ class mtgMetaInfoParser
$tokens = array_merge($tokens, $this->_parsePropTokens());
$s->setTokens($tokens);
$this->_next();
$funcs = $this->_parseFuncs();
foreach($funcs as $fn)
$s->addFunc($fn);
if($this->token !== self::T_End)
{
$this->_next();
$funcs = $this->_parseFuncs();
foreach($funcs as $fn)
$s->addFunc($fn);
}
else
$this->_next();
}
private function _parseRPC()
@ -938,6 +949,11 @@ function mtg_parse_meta(array $meta_srcs, $valid_tokens = null, $inc_path = null
$meta = new mtgMetaInfo();
foreach($meta_srcs as $src)
mtg_load_meta($meta, $meta_parser, $src);
$meta->validate();
mtgTypeRef::checkAllResolved();
return $meta;
}