Improving structs and interfaces validation
This commit is contained in:
parent
f93d46ad5e
commit
a84718215d
|
@ -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]))
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue