From a73126b3e0a67ba995712e306c0e07421670712d Mon Sep 17 00:00:00 2001 From: Pavel Shevaev Date: Thu, 3 Aug 2023 18:03:37 +0300 Subject: [PATCH] Adding more strict resolving of symbols --- metagen.inc.php | 34 +++++++++++++----- parser.inc.php | 94 ++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 98 insertions(+), 30 deletions(-) diff --git a/metagen.inc.php b/metagen.inc.php index a3fd95f..d389220 100644 --- a/metagen.inc.php +++ b/metagen.inc.php @@ -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"); } } diff --git a/parser.inc.php b/parser.inc.php index 01d9443..97bb73b 100644 --- a/parser.inc.php +++ b/parser.inc.php @@ -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)