diff --git a/metagen.inc.php b/metagen.inc.php index 20633ff..154cbe3 100644 --- a/metagen.inc.php +++ b/metagen.inc.php @@ -392,6 +392,50 @@ class mtgMetaStruct extends mtgUserType } } +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; + } + + function getImplements() + { + return $this->parent ? $this->parent->resolve() : null; + } + + 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]; + } +} + class mtgMetaFunc extends mtgMetaUnit implements mtgType { private $name; @@ -740,30 +784,32 @@ class mtgMetaInfoParser private $idltypes = array(); private $token_strs = array(); - const T_EOF = 1001; - const T_StringConstant = 1002; - const T_IntegerConstant = 1003; - const T_FloatConstant = 1004; - const T_Enum = 1005; - const T_RPC = 1006; - const T_End = 1007; - const T_Identifier = 1008; - const T_Struct = 1009; - const T_Prop = 1010; - const T_Extends = 1011; - const T_Func = 1012; - const T_string = 1020; - const T_uint32 = 1021; - const T_int32 = 1022; - const T_uint16 = 1023; - const T_int16 = 1024; - const T_uint8 = 1025; - const T_int8 = 1026; - const T_float = 1027; - const T_uint64 = 1028; - const T_int64 = 1029; - const T_bool = 1030; - const T_blob = 1031; + const T_EOF = 1001; + const T_StringConstant = 1002; + const T_IntegerConstant = 1003; + const T_FloatConstant = 1004; + const T_Enum = 1005; + const T_RPC = 1006; + const T_End = 1007; + const T_Identifier = 1008; + const T_Struct = 1009; + const T_Prop = 1010; + const T_Extends = 1011; + const T_Func = 1012; + const T_RawStringConstant = 1013; + const T_Interface = 1014; + const T_string = 1020; + const T_uint32 = 1021; + const T_int32 = 1022; + const T_uint16 = 1023; + const T_int16 = 1024; + const T_uint8 = 1025; + const T_int8 = 1026; + const T_float = 1027; + const T_uint64 = 1028; + const T_int64 = 1029; + const T_bool = 1030; + const T_blob = 1031; function __construct($config = array()) { @@ -789,6 +835,7 @@ class mtgMetaInfoParser $this->token_strs = array_flip($this->idltypes); $this->token_strs[self::T_EOF] = ''; $this->token_strs[self::T_StringConstant] = ''; + $this->token_strs[self::T_RawStringConstant] = ''; $this->token_strs[self::T_IntegerConstant] = ''; $this->token_strs[self::T_FloatConstant] = ''; $this->token_strs[self::T_Enum] = ''; @@ -796,6 +843,7 @@ class mtgMetaInfoParser $this->token_strs[self::T_End] = ''; $this->token_strs[self::T_Identifier] = ''; $this->token_strs[self::T_Struct] = ''; + $this->token_strs[self::T_Interface] = ''; $this->token_strs[self::T_Prop] = '<@prop>'; $this->token_strs[self::T_Extends] = ''; $this->token_strs[self::T_Func] = ''; @@ -865,6 +913,8 @@ class mtgMetaInfoParser $this->_parseEnum(); else if($this->token == self::T_Struct) $this->_parseStruct(); + else if($this->token == self::T_Interface) + $this->_parseInterface(); else if($this->token == self::T_Func) $this->_parseFreeFunc(); else if($this->token == self::T_RPC) @@ -886,19 +936,20 @@ class mtgMetaInfoParser while(true) { $type = null; - $type_name = $this->attribute; - if($this->token == self::T_Identifier) - { - $type = new mtgTypeRef($type_name, $this->current_meta, $this->file, $this->line); - $this->_next(); - } - else if($this->token == self::T_Func) + + if($this->token == self::T_Func) { $func_type = $this->_parseFuncType(); $type = new mtgTypeRef($func_type); } + else if($this->token == self::T_Identifier) + { + $type_name = $this->_parseDotName(); + $type = new mtgTypeRef($type_name, $this->current_meta, $this->file, $this->line); + } else { + $type_name = $this->attribute; $type = new mtgTypeRef(new mtgBuiltinType($type_name)); $this->_next(); } @@ -1019,7 +1070,7 @@ class mtgMetaInfoParser { $this->_next(); - $name = $this->_checkThenNext(self::T_Identifier); + $name = $this->_parseDotName(); $enum = new mtgMetaEnum($name); $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $enum)); @@ -1073,9 +1124,7 @@ class mtgMetaInfoParser $fld = new mtgMetaField($name, $type); if($this->token == self::T_Prop) - { $fld->setTokens($this->_parsePropTokens()); - } $flds[] = $fld; } @@ -1112,15 +1161,31 @@ class mtgMetaInfoParser return $funcs; } + private function _parseDotName() + { + $dot_name = ''; + + while(true) + { + if($this->token != self::T_Identifier) + $this->_error("unexpected name token"); + + $dot_name .= $this->attribute; + $this->_next(); + if($this->token != ord('.')) + break; + $dot_name .= '.'; + $this->_next(); + } + + return $dot_name; + } + private function _parseFunc() { - if($this->token != self::T_Identifier) - $this->_error("unexpected func token"); - - $name = $this->attribute; + $name = $this->_parseDotName(); $fn = new mtgMetaFunc($name); - $this->_next(); $this->_checkThenNext('('); if($this->token == self::T_Prop) $fn->setTokens($this->_parsePropTokens()); @@ -1157,7 +1222,7 @@ class mtgMetaInfoParser private function _parseStruct() { $this->_next(); - $name = $this->_checkThenNext(self::T_Identifier); + $name = $this->_parseDotName(); $parent = null; if($this->token == self::T_Extends) @@ -1171,9 +1236,7 @@ class mtgMetaInfoParser $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $s)); if($this->token == self::T_Prop) - { $s->setTokens($this->_parsePropTokens()); - } $seen_funcs = false; $flds = $this->_parseFields( @@ -1199,6 +1262,23 @@ class mtgMetaInfoParser } } + private function _parseInterface() + { + $this->_next(); + $name = $this->_parseDotName(); + + $s = new mtgMetaInterface($name); + $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $s)); + + if($this->token == self::T_Prop) + $s->setTokens($this->_parsePropTokens()); + + $this->_next(); + $funcs = $this->_parseFuncs(); + foreach($funcs as $fn) + $s->addFunc($fn); + } + private function _parseRPC() { $this->_next(); @@ -1254,13 +1334,15 @@ class mtgMetaInfoParser $this->_next(); break; } - - $tmp = $this->attribute; - if($this->token == self::T_StringConstant) - $tmp = "\"$tmp\""; - if($value === null) - $value = ''; - $value .= $tmp; + else + { + $tmp = $this->attribute; + if($this->token == self::T_StringConstant) + $tmp = "\"$tmp\""; + if($value === null) + $value = ''; + $value .= $tmp; + } } } if($value && substr($value, 0, 1) == '{') @@ -1273,12 +1355,12 @@ class mtgMetaInfoParser } } $this->_validatePropToken($name, $value); - + $prop_tokens[$name] = $value; } return $prop_tokens; } - + private function _validatePropToken($name, $value) { if(!isset($this->config['valid_tokens']) || !$this->config['valid_tokens']) @@ -1354,6 +1436,17 @@ class mtgMetaInfoParser $this->cursor++; return; + case '`': + $this->attribute = ""; + while($this->_symbol() != '`') + { + $this->attribute .= $this->_symbol(); + $this->cursor++; + } + $this->token = self::T_RawStringConstant; + $this->cursor++; + return; + case '/': if($this->_symbol() == '/') { @@ -1398,12 +1491,13 @@ class mtgMetaInfoParser } //check for declaration keywords: - if($this->attribute == "struct") { $this->token = self::T_Struct; return; } - if($this->attribute == "enum") { $this->token = self::T_Enum; return; } - if($this->attribute == "RPC") { $this->token = self::T_RPC; return; } - if($this->attribute == "end") { $this->token = self::T_End; return; } - if($this->attribute == "extends") { $this->token = self::T_Extends; return; } - if($this->attribute == "func") { $this->token = self::T_Func; return; } + if($this->attribute == "struct") { $this->token = self::T_Struct; return; } + if($this->attribute == "interface") { $this->token = self::T_Interface; return; } + if($this->attribute == "enum") { $this->token = self::T_Enum; return; } + if($this->attribute == "RPC") { $this->token = self::T_RPC; return; } + if($this->attribute == "end") { $this->token = self::T_End; return; } + if($this->attribute == "extends") { $this->token = self::T_Extends; return; } + if($this->attribute == "func") { $this->token = self::T_Func; return; } //if not it's a user defined identifier $this->token = self::T_Identifier; @@ -1979,7 +2073,7 @@ function mtg_run(mtgGenerator $gen, array $config) foreach($targets as $t) $t->execute(); - + $METAGEN_CONFIG = $config_copy; }