Adding more strict resolving of symbols

This commit is contained in:
Pavel Shevaev 2023-08-03 18:03:37 +03:00
parent 4939f05cfc
commit a73126b3e0
2 changed files with 98 additions and 30 deletions

View File

@ -10,10 +10,10 @@ class mtgTypeRef implements mtgType
private $name;
private $file;
private $line;
private $meta;
private $module;
private $resolved;
function __construct($name_or_resolved, mtgMetaInfo $meta = null, $file = '', $line= 0)
function __construct($name_or_resolved, mtgMetaParsedModule $module = null, $file = '', $line= 0)
{
if(is_object($name_or_resolved))
{
@ -22,9 +22,13 @@ class mtgTypeRef implements mtgType
$this->resolved = $name_or_resolved;
}
else
{
$this->name = $name_or_resolved;
if(!$module)
throw new Exception("Module is not set");
}
$this->meta = $meta;
$this->module = $module;
$this->file = $file;
$this->line = $line;
@ -42,17 +46,23 @@ class mtgTypeRef implements mtgType
if($this->resolved)
return $this->resolved;
$u = $this->meta->findUnit($this->name, false/*non strict*/);
$u = $this->module->findUnit($this->name);
if($u)
{
$this->resolved = $u->object;
return $this->resolved;
}
else
{
throw new Exception("{$this->file}@{$this->line} : Symbol '{$this->name}' not found");
}
}
function __toString()
{
if($this->resolved)
return ''.$this->resolved;
else
return $this->name;
}
}
class mtgMetaInfoUnit
@ -89,12 +99,18 @@ class mtgMetaInfo
return $this->units;
}
function findUnit($id, $strict = true)
function findUnit($id)
{
if(isset($this->units[$id]))
return $this->units[$id];
else if($strict)
throw new Exception("Unit '$id' not found");
return null;
}
function getUnit($id)
{
if(isset($this->units[$id]))
return $this->units[$id];
throw new Exception("Unit '$id' not found");
}
}

View File

@ -6,6 +6,7 @@ class mtgMetaInfoParser
private $current_meta;
private $parsed_files = array();
private $file_stack = array();
private $module = null;
private $file = "";
private $source = "";
private $cursor = 0;
@ -111,7 +112,8 @@ class mtgMetaInfoParser
{
if(isset($this->parsed_files[$file]))
return;
$this->parsed_files[$file] = true;
$module = new mtgMetaParsedModule($file);
$this->parsed_files[$file] = $module;
$this->file_stack[] = $file;
$source = file_get_contents($file);
$is_php = false;
@ -128,9 +130,7 @@ class mtgMetaInfoParser
$is_php = true;
}
else
{
self::resolveIncludes($source, $this->config['include_path'], array($this, '_parse'));
}
$this->_resolveIncludes($module, $source);
}
catch(Exception $e)
{
@ -142,6 +142,7 @@ class mtgMetaInfoParser
if($is_php)
return;
$this->module = $module;
$this->file = $file;
$this->source = $source;
$this->cursor = 0;
@ -177,6 +178,13 @@ class mtgMetaInfoParser
}
}
private function _parseInclude(mtgMetaParsedModule $module, $file)
{
$this->_parse($file);
$module->addInclude($this->parsed_files[$file]);
}
private function _parseSharedTokens(array $tokens)
{
if(!isset($tokens['shared_tokens']))
@ -198,17 +206,17 @@ class mtgMetaInfoParser
if($this->token == self::T_Func)
{
$func_type = $this->_parseFuncType();
$type = new mtgTypeRef($func_type);
$type = new mtgTypeRef($func_type, $this->module, $this->file, $this->line);
}
else if($this->token == self::T_Identifier)
{
$type_name = $this->_parseDotName();
$type = new mtgTypeRef($type_name, $this->current_meta, $this->file, $this->line);
$type = new mtgTypeRef($type_name, $this->module, $this->file, $this->line);
}
else
{
$type_name = $this->attribute;
$type = new mtgTypeRef(new mtgBuiltinType($type_name));
$type = new mtgTypeRef(new mtgBuiltinType($type_name), $this->module, $this->file, $this->line);
$this->_next();
}
@ -216,7 +224,7 @@ class mtgMetaInfoParser
{
$this->_next();
$this->_checkThenNext(']');
$type = new mtgTypeRef(new mtgArrType($type));
$type = new mtgTypeRef(new mtgArrType($type), $this->module, $this->file, $this->line);
}
$types[] = $type;
@ -229,7 +237,7 @@ class mtgMetaInfoParser
}
if(sizeof($types) > 1)
return new mtgTypeRef(new mtgMultiType($types));
return new mtgTypeRef(new mtgMultiType($types), $this->module, $this->file, $this->line);
else
return $types[0];
}
@ -270,15 +278,17 @@ class mtgMetaInfoParser
return $ftype;
}
static function resolveIncludes(&$text, array $include_paths, $callback)
{
private function _resolveIncludes(mtgMetaParsedModule $module, &$text)
{
$include_paths = $this->config['include_path'];
$result = array();
$lines = explode("\n", $text);
foreach($lines as $line)
{
if(preg_match('~^#include\s+(\S+)~', $line, $m))
{
self::processInclude($m[1], $include_paths, $callback);
$this->_processInclude($module, $m[1], $include_paths);
$result[] = "";
}
else
@ -287,7 +297,7 @@ class mtgMetaInfoParser
$text = implode("\n", $result);
}
static function processInclude($include, array $include_paths, $callback)
private function _processInclude(mtgMetaParsedModule $module, $include, array $include_paths)
{
$file = false;
foreach($include_paths as $include_path)
@ -300,7 +310,7 @@ class mtgMetaInfoParser
if($file === false)
throw new Exception("#include {$include} can't be resolved(include path is '". implode(':', $include_paths) . "')");
call_user_func_array($callback, array($file));
$this->_parseInclude($module, $file);
}
private function _parseEnumOrValues()
@ -368,7 +378,7 @@ class mtgMetaInfoParser
$existing->object->override($enum);
}
else
$this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $enum));
$this->_addUnit(new mtgMetaInfoUnit($this->file, $enum));
}
private function _parseFields($next_doer)
@ -483,12 +493,18 @@ class mtgMetaInfoParser
return $fn;
}
private function _addUnit(mtgMetaInfoUnit $unit)
{
$this->current_meta->addUnit($unit);
$this->module->addUnit($unit);
}
private function _parseFreeFunc()
{
$this->_next();
$fn = $this->_parseFunc();
$fn->setTokens(array_merge($this->shared_tokens, $fn->getTokens()));
$this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $fn));
$this->_addUnit(new mtgMetaInfoUnit($this->file, $fn));
}
private function _parseStruct()
@ -501,7 +517,7 @@ class mtgMetaInfoParser
{
$this->_next();
$parent_name = $this->_checkThenNext(self::T_Identifier);
$parent = new mtgTypeRef($parent_name, $this->current_meta, $this->file, $this->line);
$parent = new mtgTypeRef($parent_name, $this->module, $this->file, $this->line);
}
$implements = array();
@ -511,12 +527,12 @@ class mtgMetaInfoParser
{
$this->_next();
$if_name = $this->_checkThenNext(self::T_Identifier);
$implements[] = new mtgTypeRef($if_name, $this->current_meta, $this->file, $this->line);
$implements[] = new mtgTypeRef($if_name, $this->module, $this->file, $this->line);
} while($this->token == ord(','));
}
$s = new mtgMetaStruct($name, array(), $parent, array(), $implements);
$this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $s));
$this->_addUnit(new mtgMetaInfoUnit($this->file, $s));
$tokens = $this->shared_tokens;
if($this->token == self::T_Prop)
@ -553,7 +569,7 @@ class mtgMetaInfoParser
$name = $this->_parseDotName();
$s = new mtgMetaInterface($name);
$this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $s));
$this->_addUnit(new mtgMetaInfoUnit($this->file, $s));
$tokens = $this->shared_tokens;
if($this->token == self::T_Prop)
@ -590,7 +606,7 @@ class mtgMetaInfoParser
$rsp->setFields($rsp_fields);
$rpc = new mtgMetaRPC("RPC_$name", $code, $req, $rsp, $tokens);
$this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $rpc));
$this->_addUnit(new mtgMetaInfoUnit($this->file, $rpc));
}
private function _parsePropTokens()
@ -861,6 +877,42 @@ class mtgMetaInfoParser
}
}
class mtgMetaParsedModule
{
public $file;
public $units = array();
public $includes = array();
function __construct($file)
{
$this->file = $file;
}
function addUnit(mtgMetaInfoUnit $unit)
{
$this->units[$unit->object->getId()] = $unit;
}
function findUnit($id)
{
if(isset($this->units[$id]))
return $this->units[$id];
foreach($this->includes as $include)
{
if(isset($include->units[$id]))
return $include->units[$id];
}
return null;
}
function addInclude(mtgMetaParsedModule $include)
{
$this->includes[] = $include;
}
}
function mtg_parse_meta(array $meta_srcs, $valid_tokens = null, $inc_path = null)
{
if($inc_path === null)