diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6e92f57 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +tags diff --git a/composer.json b/composer.json index ad5761f..e0cf535 100644 --- a/composer.json +++ b/composer.json @@ -8,7 +8,7 @@ "autoload": { "classmap": [ "metagen.inc.php", - "targets/" + "parser.inc.php" ] } } diff --git a/metagen.inc.php b/metagen.inc.php index 154cbe3..baa3634 100644 --- a/metagen.inc.php +++ b/metagen.inc.php @@ -1,102 +1,5 @@ -* --long-param -* --long-param= -* --long-param -* -*/ -function mtg_parse_argv($params, $noopt = array()) -{ - $result = array(); - reset($params); - while (list($tmp, $p) = each($params)) - { - if($p[0] == '-') - { - $pname = substr($p, 1); - $value = true; - if($pname[0] == '-') - { - // long-opt (--) - $pname = substr($pname, 1); - if(strpos($p, '=') !== false) - { - // value specified inline (--=) - list($pname, $value) = explode('=', substr($p, 2), 2); - } - } - // check if next parameter is a descriptor or a value - $nextparm = current($params); - if(!in_array($pname, $noopt) && $value === true && $nextparm !== false && $nextparm[0] != '-') - list($tmp, $value) = each($params); - $result[$pname] = $value; - } - else - // param doesn't belong to any option - $result[] = $p; - } - return $result; -} - -function mtg_read_from_stdin($timeout_sec = 5) -{ - $read = array(STDIN); - $write = NULL; - $except = NULL; - $stdin = ''; - if(false === ($num_changed_streams = stream_select($read, $write, $except, $timeout_sec))) - throw new Exception("Unknown stream select error happened"); - elseif ($num_changed_streams > 0) - $stdin = stream_get_contents(STDIN); - else - throw new Exception("No data in stdin"); - return $stdin; -} - -function mtg_extract_files($string) -{ - return mtg_split_and_process($string, '~\s+~', 'realpath'); -} - -function mtg_split_and_process($string, $regex = '~\s+~', $proc = '') -{ - $items = preg_split($regex, trim($string)); - $result = array(); - foreach($items as $item) - { - $item = trim($item); - if(!$item) - continue; - - if($proc) - $item = $proc($item); - - $result[] = $item; - } - return $result; -} - -function mtg_argv2conf($argv) -{ - global $METAGEN_CONFIG; - - $parsed = mtg_parse_argv($argv); - foreach($parsed as $key => $value) - { - if(!is_string($key)) - continue; - - $METAGEN_CONFIG[preg_replace('~^-+~', '', $key)] = $value; - } -} - function mtg_conf($key) { global $METAGEN_CONFIG; @@ -769,1116 +672,6 @@ class mtgMetaField } } -class mtgMetaInfoParser -{ - private $config = array(); - private $current_meta; - private $parsed_files = array(); - private $file_stack = array(); - private $file = ""; - private $source = ""; - private $cursor = 0; - private $line = 0; - private $token = ""; - private $attribute = ""; - 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_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()) - { - $this->config = $config; - if(!isset($this->config['include_path'])) - $this->config['include_path'] = array('.'); - - $this->idltypes = array( - "string" => self::T_string, - "uint32" => self::T_uint32, - "int32" => self::T_int32, - "uint16" => self::T_uint16, - "int16" => self::T_int16, - "uint8" => self::T_uint8, - "int8" => self::T_int8, - "float" => self::T_float, - "double" => self::T_float, - "uint64" => self::T_uint64, - "int64" => self::T_int64, - "bool" => self::T_bool, - "blob" => self::T_blob, - ); - $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] = ''; - $this->token_strs[self::T_RPC] = ''; - $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] = ''; - } - - function parse(mtgMetaInfo $meta, $raw_file) - { - $this->current_meta = $meta; - - $file = realpath($raw_file); - if($file === false) - throw new Exception("No such file '$raw_file'"); - - $this->_parse($file); - - mtgTypeRef::checkAllResolved(); - } - - private function _parse($file) - { - if(isset($this->parsed_files[$file])) - return; - $this->parsed_files[$file] = true; - $this->file_stack[] = $file; - $source = file_get_contents($file); - $is_php = false; - - try - { - if($source === false) - throw new Exception("Could not read file '$file'"); - - //PHP include - if(strpos($source, 'config['include_path'], array($this, '_parse')); - } - } - catch(Exception $e) - { - throw new Exception(end($this->file_stack) . " : " . $e->getMessage()); - } - - array_pop($this->file_stack); - - if($is_php) - return; - - $this->file = $file; - $this->source = $source; - $this->cursor = 0; - $this->line = 1; - - try - { - $this->_next(); - while($this->token != self::T_EOF) - { - //echo "TOKEN : " . $this->token . " " . $this->attribute . " " . $this->line . "\n"; - - if($this->token == self::T_Enum) - $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) - $this->_parseRPC(); - else - $this->_error("unexpected token ('" . $this->_toStr($this->token) . "' " . $this->attribute . ")"); - } - } - catch(Exception $e) - { - throw new Exception("$file@{$this->line} : " . $e->getMessage() . " " . $e->getTraceAsString()); - } - } - - private function _parseType($can_be_multi = false) - { - $types = array(); - - while(true) - { - $type = null; - - 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(); - } - - if($this->token == ord('[')) - { - $this->_next(); - $this->_checkThenNext(']'); - $type = new mtgTypeRef(new mtgArrType($type)); - } - $types[] = $type; - - if(!$can_be_multi) - break; - - if($this->token != ord(',')) - break; - $this->_next(); - } - - if(sizeof($types) > 1) - return new mtgTypeRef(new mtgMultiType($types)); - else - return $types[0]; - } - - private function _parseFuncType() - { - $ftype = new mtgMetaFunc(''); - - $this->_next(); - - $this->_checkThenNext('('); - - $c = 0; - while(true) - { - if($this->token == ord(')')) - { - $this->_next(); - break; - } - else if($c > 0) - { - $this->_checkThenNext(','); - } - - $arg_type = $this->_parseType(); - $c++; - $arg = new mtgMetaField("_$c", $arg_type); - $ftype->addArg($arg); - } - - if($this->token == ord(':')) - { - $this->_next(); - $ret_type = $this->_parseType(true/*can be multi-type*/); - $ftype->setReturnType($ret_type); - } - return $ftype; - } - - static function resolveIncludes(&$text, array $include_paths, $callback) - { - $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); - $result[] = ""; - } - else - $result[] = $line; - } - $text = implode("\n", $result); - } - - static function processInclude($include, array $include_paths, $callback) - { - $file = false; - foreach($include_paths as $include_path) - { - $file = realpath($include_path . "/" . $include); - if($file !== false) - break; - } - - 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)); - } - - private function _parseEnumOrValues() - { - $values = array(); - while(true) - { - if($this->token == self::T_Identifier) - { - $values[] = $this->attribute; - $this->_next(); - if($this->token != ord('|')) - break; - else - $this->_next(); - } - else - break; - } - - return $values; - } - - private function _parseEnum() - { - $this->_next(); - - $name = $this->_parseDotName(); - - $enum = new mtgMetaEnum($name); - $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $enum)); - - if($this->token == self::T_Prop) - { - $enum->setTokens($this->_parsePropTokens()); - } - - $or_values = array(); - while(true) - { - if($this->_nextIf(self::T_End)) - break; - $key = $this->_checkThenNext(self::T_Identifier); - $this->_checkThenNext('='); - if($this->token == self::T_Identifier) - { - $or_values[$key] = $this->_parseEnumOrValues(); - } - else - { - $value = $this->_checkThenNext(self::T_IntegerConstant); - $enum->addValue($key, $value); - } - } - $enum->addOrValues($or_values); - } - - private function _parseFields($next_doer) - { - $flds = array(); - - while(true) - { - if($next_doer()) - break; - - if($this->token == self::T_Identifier) - { - $name = $this->attribute; - $this->_next(); - $this->_checkThenNext(':'); - - if($this->token == self::T_Identifier || - $this->token == self::T_Func || - ($this->token >= self::T_string && $this->token <= self::T_blob)) - { - $type = $this->_parseType(); - - $fld = new mtgMetaField($name, $type); - - if($this->token == self::T_Prop) - $fld->setTokens($this->_parsePropTokens()); - - $flds[] = $fld; - } - else - $this->_error("type expected"); - } - else - $this->_error("unexpected fields token"); - } - - return $flds; - } - - private function _parseFuncs() - { - $end_token = self::T_End; - - $funcs = array(); - - while(true) - { - $fn = $this->_parseFunc(); - $funcs[] = $fn; - - if($this->token == $end_token) - { - $this->_next(); - break; - } - - $this->_next(); - } - - 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() - { - $name = $this->_parseDotName(); - $fn = new mtgMetaFunc($name); - - $this->_checkThenNext('('); - if($this->token == self::T_Prop) - $fn->setTokens($this->_parsePropTokens()); - $args = $this->_parseFields(function() - { return $this->_nextIf(')'); } - ); - $fn->setArgs($args); - - $ret_type = null; - if($this->token == ord(':')) - { - $this->_next(); - if($this->token == self::T_Identifier || - $this->token == self::T_Func || - ($this->token >= self::T_string && $this->token <= self::T_bool)) - { - $ret_type = $this->_parseType(true/*can be multi-type*/); - $fn->setReturnType($ret_type); - } - else - $this->_error("unexpected func type token"); - } - - return $fn; - } - - private function _parseFreeFunc() - { - $this->_next(); - $fn = $this->_parseFunc(); - $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $fn)); - } - - private function _parseStruct() - { - $this->_next(); - $name = $this->_parseDotName(); - - $parent = null; - if($this->token == self::T_Extends) - { - $this->_next(); - $parent_name = $this->_checkThenNext(self::T_Identifier); - $parent = new mtgTypeRef($parent_name, $this->current_meta, $this->file, $this->line); - } - - $s = new mtgMetaStruct($name, array(), $parent); - $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( - function() use(&$seen_funcs) - { - if($this->_nextIf(self::T_End)) - return true; - if($this->_nextIf(self::T_Func)) - { - $seen_funcs = true; - return true; - } - } - ); - foreach($flds as $fld) - $s->addField($fld); - - if($seen_funcs) - { - $funcs = $this->_parseFuncs(); - foreach($funcs as $fn) - $s->addFunc($fn); - } - } - - 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(); - $code = $this->_checkThenNext(self::T_IntegerConstant); - $name = $this->_checkThenNext(self::T_Identifier); - $this->_checkThenNext('('); - - $tokens = array(); - if($this->token == self::T_Prop) - $tokens = $this->_parsePropTokens(); - - $req_fields = $this->_parseFields(function() - { return $this->_nextIf(')'); } - ); - $rsp_fields = $this->_parseFields(function() - { return $this->_nextIf(self::T_End); } - ); - - $req = new mtgMetaPacket($code, "RPC_REQ_$name"); - $req->setFields($req_fields); - $rsp = new mtgMetaPacket($code, "RPC_RSP_$name"); - $rsp->setFields($rsp_fields); - - $rpc = new mtgMetaRPC("RPC_$name", $code, $req, $rsp, $tokens); - $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $rpc)); - } - - private function _parsePropTokens() - { - $new_line = ord("\n"); - - $prop_tokens = array(); - - while(true) - { - if($this->token != self::T_Prop) - break; - - $name = ltrim($this->attribute, '@'); - $this->_next(); - - $value = null; - if($this->token == ord(':')) - { - while(true) - { - $this->_next(false/*don't skip new line*/); - if($this->token == $new_line || - $this->token == self::T_Prop) - { - //let's skip it - if($this->token == $new_line) - $this->_next(); - break; - } - else - { - $tmp = $this->attribute; - if($this->token == self::T_StringConstant) - $tmp = "\"$tmp\""; - if($value === null) - $value = ''; - $value .= $tmp; - } - } - } - if($value && substr($value, 0, 1) == '{') - { - $json = json_decode($value); - if($json === null) - { - --$this->line; //hack for more precise reporting - $this->_error("bad json"); - } - } - $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']) - return; - - if(!in_array($name, $this->config['valid_tokens'])) - throw new Exception("Unknown token '$name'"); - } - - private function _symbol() - { - return substr($this->source, $this->cursor, 1); - } - - private function _next($skip_newlines = true) - { - $this->__next($skip_newlines); - //for debug - //var_dump("NEXT " . $this->token . " " . $this->attribute); - //debug_print_backtrace(0, 1); - } - - private function __next($skip_newlines = true) - { - while(true) - { - $c = $this->_symbol(); - //NOTE: dealing with PHP's types juggling - if($c === false || $c === '') - $c = -1; - - $this->token = ord($c); - ++$this->cursor; - $this->attribute = $c; - - switch($c) - { - case -1: $this->cursor--; $this->token = self::T_EOF; return; - case ' ': case "\r": case "\t": break; - case "\n": $this->line++; if($skip_newlines) break; else return; - case '{': case '}': case '(': case ')': case '[': case ']': case '|': return; - case ',': case ':': case ';': case '=': return; - case '.': - if(!ctype_digit($this->_symbol())) return; - $this->_error("floating point constant can't start with ."); - break; - case '"': - $this->attribute = ""; - while($this->_symbol() != '"') - { - if(ord($this->_symbol()) < ord(' ') && ord($this->_symbol()) >= 0) - $this->_error("illegal character in string constant"); - if($this->_symbol() == '\\') - { - $this->cursor++; - switch($this->_symbol()) - { - case 'n': $this->attribute .= "\n"; $this->cursor++; break; - case 't': $this->attribute .= "\t"; $this->cursor++; break; - case 'r': $this->attribute .= "\r"; $this->cursor++; break; - case '"': $this->attribute .= '"'; $this->cursor++; break; - case '\\': $this->attribute .= '\\'; $this->cursor++; break; - default: $this->_error("unknown escape code in string constant"); break; - } - } - else // printable chars + UTF-8 bytes - { - $this->attribute .= $this->_symbol(); - $this->cursor++; - } - } - $this->token = self::T_StringConstant; - $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() == '/') - { - $this->cursor++; - while($this->_symbol() !== false && $this->_symbol() != "\n") $this->cursor++; - break; - } - - case '#': - while($this->_symbol() !== false && $this->_symbol() != "\n") $this->cursor++; - break; - - case '@': - $start = $this->cursor - 1; - while(ctype_alnum($this->_symbol()) || $this->_symbol() == '_') - $this->cursor++; - $this->token = self::T_Prop; - $this->attribute = substr($this->source, $start, $this->cursor - $start); - return; - - //fall thru - default: - - if(ctype_alpha($c)) - { - //collect all chars of an identifier - $start = $this->cursor - 1; - while(ctype_alnum($this->_symbol()) || $this->_symbol() == '_') - $this->cursor++; - $this->attribute = substr($this->source, $start, $this->cursor - $start); - - if(isset($this->idltypes[$this->attribute])) - { - $this->token = $this->idltypes[$this->attribute]; - return; - } - - if($this->attribute == "true" || $this->attribute == "false") - { - $this->token = self::T_IntegerConstant; - return; - } - - //check for declaration keywords: - 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; - return; - } - else if(ctype_digit($c) || $c == '-') - { - $start = $this->cursor - 1; - while(ctype_digit($this->_symbol())) $this->cursor++; - if($this->_symbol() == '.') - { - $this->cursor++; - while(ctype_digit($this->_symbol())) $this->cursor++; - // see if this float has a scientific notation suffix. Both JSON - // and C++ (through strtod() we use) have the same format: - if($this->_symbol() == 'e' || $this->_symbol() == 'E') - { - $this->cursor++; - if($this->_symbol() == '+' || $this->_symbol() == '-') $this->cursor++; - while(ctype_digit($this->_symbol())) $this->cursor++; - } - $this->token = self::T_FloatConstant; - } - else - $this->token = self::T_IntegerConstant; - $this->attribute = substr($this->source, $start, $this->cursor - $start); - return; - } - - $this->_error("illegal character '$c'"); - } - } - } - - private function _nextIf($t) - { - if(is_string($t)) - $t = ord($t); - $yes = $t === $this->token; - if($yes) - $this->_next(); - return $yes; - } - - private function _checkThenNext($t) - { - if(is_string($t)) - $t = ord($t); - if($t !== $this->token) - { - $this->_error("Expecting '" . $this->_toStr($t) . "' instead got '" . $this->_toStr($this->token) . "'"); - } - - $attr = $this->attribute; - $this->_next(); - return $attr; - } - - private function _toStr($t) - { - if($t < 1000) - return chr($t); - return $this->token_strs[$t]; - } - - private function _error($msg) - { - throw new Exception($msg . "(token: {$this->token}, attr: {$this->attribute}})"); - } -} - -function mtg_get_file_deps(mtgMetaInfo $info, mtgMetaInfoUnit $unit) -{ - $deps = array(); - $deps[] = $unit->file; - - if($unit->object instanceof mtgMetaStruct) - { - foreach($unit->object->getFields() as $field) - { - $type = $field->getType(); - if($type instanceof mtgArrType) - $type = $type->getValue(); - - if($type instanceof mtgUserType) - $deps[] = $info->findUnit($type->getName())->file; - } - - $parent = $unit->object->getParent(); - if($parent) - $deps = array_merge($deps, mtg_get_file_deps($info, $info->findUnit($parent->getName()))); - } - - return $deps; -} - -function mtg_get_all_fields(mtgMetaInfo $info, mtgMetaStruct $struct) -{ - $fields = $struct->getFields(); - $parent = $struct->getParent(); - if($parent) - //NOTE: order is important, parent fields must come first - $fields = array_merge(mtg_get_all_fields($info, $parent), $fields); - return $fields; -} - -function mtg_load_meta(mtgMetaInfo $meta, mtgMetaInfoParser $meta_parser, $dir_or_file) -{ - $files = array(); - if(is_dir($dir_or_file)) - $files = mtg_find_meta_files($dir_or_file); - else if(is_file($dir_or_file)) - $files[] = $dir_or_file; - else - throw new Exception("Bad meta source '$dir_or_file'"); - - foreach($files as $file) - $meta_parser->parse($meta, $file); -} - -function mtg_find_meta_files($dir) -{ - $items = scandir($dir); - if($items === false) - throw new Exception("Directory '$dir' is invalid"); - - $files = array(); - foreach($items as $item) - { - if($item[0] == '.') - continue; - - if(strpos($item, ".meta") !== (strlen($item)-5)) - continue; - - $file = $dir . '/' . $item; - if(is_file($file) && !is_dir($file)) - $files[] = $file; - } - return $files; -} - -function mtg_is_filtered($name, $filters) -{ - foreach($filters as $filter) - { - if(!$filter) - continue; - if(strpos($name, $filter) !== false) - return false; - } - return true; -} - -function mtg_is_win() -{ - return DIRECTORY_SEPARATOR == '\\'; -} - -function mtg_which($bin) -{ - if(mtg_is_win()) - $bin .= ".exe"; - $path = exec("which $bin", $out, $ret); - if($ret != 0) - throw new Exception("Exection error 'which $bin': " . implode($out)); - return $path; -} - -function mtg_ensure_write_to_file($file, $body) -{ - if(file_put_contents($file, $body) === false) - throw new Exception("Could not write file '$file'"); - echo "> $file\n"; -} - -function mtg_fill_template($tpl, $replaces) -{ - return str_replace(array_keys($replaces), array_values($replaces), $tpl); -} - -function mtg_write_template($tpl, $replaces, $file, $exists_check = false) -{ - if($exists_check && file_exists($file)) - { - echo "! $file\n"; - return; - } - $body = mtg_fill_template($tpl, $replaces); - mtg_ensure_write_to_file($file, $body); -} - -function mtg_write_template_once($tpl, $replaces, $file) -{ - mtg_write_template($tpl, $replaces, $file, true); -} - -function mtg_append_to_slot($slot, $replace, &$contents) -{ - $contents = str_replace($slot, $slot . $replace, $contents); -} - -function mtg_prepend_to_slot($slot, $replace, &$contents) -{ - $contents = str_replace($slot, $replace . $slot, $contents); -} - -function mtg_apply_script($script, $args) -{ - $class = current(explode('.', basename($script))); - include_once($script); - $obj = new $class(); - call_user_func_array(array($obj, 'apply'), $args); -} - -function mtg_paginate($total, $step) -{ - //pages are returned as an array where each element is in interval [N, Y) - $pages = array(); - - $steps = (int)($total/$step); - $rest = $total % $step; - - for($i=1;$i<=$steps;++$i) - $pages[] = array(($i-1)*$step, $i*$step); - - if($rest != 0) - $pages[] = array(($i-1)*$step, ($i-1)*$step + $rest); - - return $pages; -} - -function mtg_mkdir($dir) -{ - if(!is_dir($dir)) - mkdir($dir, 0777, true); -} - -function mtg_rm($path) -{ - if(is_file($path)) - { - unlink($path); - return; - } - - if(!is_dir($path)) - return; - - $path= rtrim($path, '/').'/'; - $handle = opendir($path); - if($handle === false) - throw new Exception("Could not open directory '$path' for reading"); - for(;false !== ($file = readdir($handle));) - { - if($file != "." and $file != ".." ) - { - $fullpath= $path.$file; - if( is_dir($fullpath) ) - { - mtg_rm($fullpath); - rmdir($fullpath); - } - else - unlink($fullpath); - } - } - closedir($handle); -} - -//returns a name of the temp file to use, temp file IS NOT created -function mtg_get_tmpfile($prefix = '__') -{ - $MAX_TRIES = 1000; - $tries = 0; - while($tries < $MAX_TRIES) - { - $tmp_file = sys_get_temp_dir() . '/' . $prefix . uniqid(); - if(!is_file($tmp_file)) - break; - ++$tries; - } - - if($tries == $MAX_TRIES) - throw new Exception("Could not make unique temp file name"); - - return $tmp_file; -} - -function mtg_normalize_path($file) -{ - if(mtg_is_win()) - { - //strtolower drive letters - if(strpos($file, ':') === 1) - $file = strtolower(substr($file, 0, 1)) . substr($file, 1); - } - - $file = str_replace('\\', '/', $file); - $file = str_replace('//', '/', $file); - return $file; -} - -class mtgGenTarget -{ - public $file; - public $deps = array(); - public $func; - public $args = array(); - public $content_check; - - function __construct($file, array $deps, array $callback, $content_check = true) - { - if(!$callback) - throw new Exception("Bad bind arg"); - - if(!is_callable($callback[0])) - throw new Exception("Callback arg 0, not callable:" . serialize($callback[0])); - - $this->file = $file; - $this->deps = $deps; - $this->func = array_shift($callback); - $this->args = array_merge(array($this->file, $this->deps), $callback); - $this->content_check = $content_check; - } - - function execute() - { - if(!mtg_need_to_regen($this->file, $this->deps)) - return false; - - $res = call_user_func_array($this->func, $this->args); - - $exists_check = false; - if(is_array($res)) - { - $exists_check = $res[0]; - $text = $res[1]; - } - else if(is_string($res)) - $text = $res; - else - throw new Exception("Bad result:" . serialize($res)); - - if($exists_check && file_exists($this->file)) - { - //too verbose - //echo "! {$this->file}\n"; - return false; - } - - if($this->content_check) - { - if(file_exists($this->file) && file_get_contents($this->file) === $text) - return false; - } - - mtg_ensure_write_to_file($this->file, $text); - return true; - } -} - -class mtgGenBundleTarget extends mtgGenTarget -{ - function execute() - { - $bundle_info = $this->file . '.bndl'; - $prev_amount = 0; - - if(is_file($bundle_info)) - $prev_amount = 1*file_get_contents($bundle_info); - - //if the amount of bundled files has changed we need to update bundle info - if($prev_amount != sizeof($this->deps)) - file_put_contents($bundle_info, sizeof($this->deps)); - - $this->deps[] = $bundle_info; - return parent::execute(); - } -} - class mtgMetaPacket extends mtgMetaStruct { private $code; @@ -1952,145 +745,12 @@ class mtgMetaEnum extends mtgUserType } } -abstract class mtgGenerator +function mtg_get_all_fields(mtgMetaStruct $struct) { - abstract function makeTargets(mtgMetaInfo $info); + $fields = $struct->getFields(); + $parent = $struct->getParent(); + if($parent) + //NOTE: order is important, parent fields must come first + $fields = array_merge(mtg_get_all_fields($parent), $fields); + return $fields; } - -abstract class mtgCodegen -{ - protected $info; - private $tmp_cmds = array(); - - abstract function genUnit(mtgMetaInfoUnit $unit); - - function setMetaInfo(mtgMetaInfo $info) - { - $this->info = $info; - } - - function nextId() - { - static $id = 0; - $id++; - return $id; - } - - function tempRenameField($field, $new_name) - { - $prev_name = $field->getName(); - $field->setName($new_name); - - $this->tmp_cmds[] = array(1, $field, $prev_name); - } - - function addTempField(mtgMetaStruct $struct, mtgMetaField $new_fld) - { - $struct->addField($new_fld); - - $this->tmp_cmds[] = array(2, $struct, $new_fld); - } - - function undoTemp() - { - foreach($this->tmp_cmds as $cmd) - { - if($cmd[0] == 1) - { - $cmd[1]->setName($cmd[2]); - } - else if($cmd[0] == 2) - { - $cmd[1]->delField($cmd[2]); - } - else - throw new Exception("Unknown temp cmd"); - } - } -} - -function mtg_new_file($file, array $deps, array $callback, $content_check = false) -{ - return new mtgGenTarget($file, $deps, $callback, $content_check); -} - -function mtg_new_bundle($file, array $deps, array $callback, $content_check = false) -{ - return new mtgGenBundleTarget($file, $deps, $callback, $content_check); -} - -function mtg_need_to_regen($file, array $deps) -{ - if(!is_file($file)) - return true; - $fmtime = filemtime($file); - foreach($deps as $dep) - { - if(is_file($dep) && (filemtime($dep) > $fmtime)) - return true; - } - return false; -} - -function mtg_parse_meta(array $meta_srcs) -{ - $meta_dirs = array(); - foreach($meta_srcs as $src) - { - if(is_dir($src)) - $meta_dirs[] = $src; - else if(is_file($src)) - $meta_dirs[] = dirname($src); - } - - $meta_parser = new mtgMetaInfoParser( - array( - 'include_path' => $meta_dirs, - 'valid_tokens' => mtg_conf('valid-tokens', null) - ) - ); - $meta = new mtgMetaInfo(); - foreach($meta_srcs as $src) - mtg_load_meta($meta, $meta_parser, $src); - return $meta; -} - -function mtg_run(mtgGenerator $gen, array $config) -{ - global $METAGEN_CONFIG; - - $config_copy = $METAGEN_CONFIG; - foreach($config as $k => $v) - $METAGEN_CONFIG[$k] = $v; - - $meta = mtg_conf('meta', null); - if(!($meta instanceof mtgMetaInfo)) - { - $meta_dirs = mtg_conf('meta-dir'); - $meta = mtg_parse_meta($meta_dirs); - } - $targets = $gen->makeTargets($meta); - - foreach($targets as $t) - $t->execute(); - - $METAGEN_CONFIG = $config_copy; -} - -function mtg_crc28($what) -{ - return crc32($what) & 0xFFFFFFF; -} - -function mtg_static_hash($whar) -{ - $hash = 0; - for($i = 0; $i < strlen($whar); ++$i) - { - $hash = ((65599 * $hash) & 0x0FFFFFFF) + ord($whar[$i]); - } - - return ($hash ^ ($hash >> 16)); -} - - diff --git a/parser.inc.php b/parser.inc.php new file mode 100644 index 0000000..4871afe --- /dev/null +++ b/parser.inc.php @@ -0,0 +1,860 @@ +config = $config; + if(!isset($this->config['include_path'])) + $this->config['include_path'] = array('.'); + + $this->idltypes = array( + "string" => self::T_string, + "uint32" => self::T_uint32, + "int32" => self::T_int32, + "uint16" => self::T_uint16, + "int16" => self::T_int16, + "uint8" => self::T_uint8, + "int8" => self::T_int8, + "float" => self::T_float, + "double" => self::T_float, + "uint64" => self::T_uint64, + "int64" => self::T_int64, + "bool" => self::T_bool, + "blob" => self::T_blob, + ); + $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] = ''; + $this->token_strs[self::T_RPC] = ''; + $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] = ''; + } + + function parse(mtgMetaInfo $meta, $raw_file) + { + $this->current_meta = $meta; + + $file = realpath($raw_file); + if($file === false) + throw new Exception("No such file '$raw_file'"); + + $this->_parse($file); + + mtgTypeRef::checkAllResolved(); + } + + private function _parse($file) + { + if(isset($this->parsed_files[$file])) + return; + $this->parsed_files[$file] = true; + $this->file_stack[] = $file; + $source = file_get_contents($file); + $is_php = false; + + try + { + if($source === false) + throw new Exception("Could not read file '$file'"); + + //PHP include + if(strpos($source, 'config['include_path'], array($this, '_parse')); + } + } + catch(Exception $e) + { + throw new Exception(end($this->file_stack) . " : " . $e->getMessage()); + } + + array_pop($this->file_stack); + + if($is_php) + return; + + $this->file = $file; + $this->source = $source; + $this->cursor = 0; + $this->line = 1; + + try + { + $this->_next(); + while($this->token != self::T_EOF) + { + //echo "TOKEN : " . $this->token . " " . $this->attribute . " " . $this->line . "\n"; + + if($this->token == self::T_Enum) + $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) + $this->_parseRPC(); + else + $this->_error("unexpected token ('" . $this->_toStr($this->token) . "' " . $this->attribute . ")"); + } + } + catch(Exception $e) + { + throw new Exception("$file@{$this->line} : " . $e->getMessage() . " " . $e->getTraceAsString()); + } + } + + private function _parseType($can_be_multi = false) + { + $types = array(); + + while(true) + { + $type = null; + + 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(); + } + + if($this->token == ord('[')) + { + $this->_next(); + $this->_checkThenNext(']'); + $type = new mtgTypeRef(new mtgArrType($type)); + } + $types[] = $type; + + if(!$can_be_multi) + break; + + if($this->token != ord(',')) + break; + $this->_next(); + } + + if(sizeof($types) > 1) + return new mtgTypeRef(new mtgMultiType($types)); + else + return $types[0]; + } + + private function _parseFuncType() + { + $ftype = new mtgMetaFunc(''); + + $this->_next(); + + $this->_checkThenNext('('); + + $c = 0; + while(true) + { + if($this->token == ord(')')) + { + $this->_next(); + break; + } + else if($c > 0) + { + $this->_checkThenNext(','); + } + + $arg_type = $this->_parseType(); + $c++; + $arg = new mtgMetaField("_$c", $arg_type); + $ftype->addArg($arg); + } + + if($this->token == ord(':')) + { + $this->_next(); + $ret_type = $this->_parseType(true/*can be multi-type*/); + $ftype->setReturnType($ret_type); + } + return $ftype; + } + + static function resolveIncludes(&$text, array $include_paths, $callback) + { + $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); + $result[] = ""; + } + else + $result[] = $line; + } + $text = implode("\n", $result); + } + + static function processInclude($include, array $include_paths, $callback) + { + $file = false; + foreach($include_paths as $include_path) + { + $file = realpath($include_path . "/" . $include); + if($file !== false) + break; + } + + 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)); + } + + private function _parseEnumOrValues() + { + $values = array(); + while(true) + { + if($this->token == self::T_Identifier) + { + $values[] = $this->attribute; + $this->_next(); + if($this->token != ord('|')) + break; + else + $this->_next(); + } + else + break; + } + + return $values; + } + + private function _parseEnum() + { + $this->_next(); + + $name = $this->_parseDotName(); + + $enum = new mtgMetaEnum($name); + $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $enum)); + + if($this->token == self::T_Prop) + { + $enum->setTokens($this->_parsePropTokens()); + } + + $or_values = array(); + while(true) + { + if($this->_nextIf(self::T_End)) + break; + $key = $this->_checkThenNext(self::T_Identifier); + $this->_checkThenNext('='); + if($this->token == self::T_Identifier) + { + $or_values[$key] = $this->_parseEnumOrValues(); + } + else + { + $value = $this->_checkThenNext(self::T_IntegerConstant); + $enum->addValue($key, $value); + } + } + $enum->addOrValues($or_values); + } + + private function _parseFields($next_doer) + { + $flds = array(); + + while(true) + { + if($next_doer()) + break; + + if($this->token == self::T_Identifier) + { + $name = $this->attribute; + $this->_next(); + $this->_checkThenNext(':'); + + if($this->token == self::T_Identifier || + $this->token == self::T_Func || + ($this->token >= self::T_string && $this->token <= self::T_blob)) + { + $type = $this->_parseType(); + + $fld = new mtgMetaField($name, $type); + + if($this->token == self::T_Prop) + $fld->setTokens($this->_parsePropTokens()); + + $flds[] = $fld; + } + else + $this->_error("type expected"); + } + else + $this->_error("unexpected fields token"); + } + + return $flds; + } + + private function _parseFuncs() + { + $end_token = self::T_End; + + $funcs = array(); + + while(true) + { + $fn = $this->_parseFunc(); + $funcs[] = $fn; + + if($this->token == $end_token) + { + $this->_next(); + break; + } + + $this->_next(); + } + + 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() + { + $name = $this->_parseDotName(); + $fn = new mtgMetaFunc($name); + + $this->_checkThenNext('('); + if($this->token == self::T_Prop) + $fn->setTokens($this->_parsePropTokens()); + $args = $this->_parseFields(function() + { return $this->_nextIf(')'); } + ); + $fn->setArgs($args); + + $ret_type = null; + if($this->token == ord(':')) + { + $this->_next(); + if($this->token == self::T_Identifier || + $this->token == self::T_Func || + ($this->token >= self::T_string && $this->token <= self::T_bool)) + { + $ret_type = $this->_parseType(true/*can be multi-type*/); + $fn->setReturnType($ret_type); + } + else + $this->_error("unexpected func type token"); + } + + return $fn; + } + + private function _parseFreeFunc() + { + $this->_next(); + $fn = $this->_parseFunc(); + $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $fn)); + } + + private function _parseStruct() + { + $this->_next(); + $name = $this->_parseDotName(); + + $parent = null; + if($this->token == self::T_Extends) + { + $this->_next(); + $parent_name = $this->_checkThenNext(self::T_Identifier); + $parent = new mtgTypeRef($parent_name, $this->current_meta, $this->file, $this->line); + } + + $s = new mtgMetaStruct($name, array(), $parent); + $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( + function() use(&$seen_funcs) + { + if($this->_nextIf(self::T_End)) + return true; + if($this->_nextIf(self::T_Func)) + { + $seen_funcs = true; + return true; + } + } + ); + foreach($flds as $fld) + $s->addField($fld); + + if($seen_funcs) + { + $funcs = $this->_parseFuncs(); + foreach($funcs as $fn) + $s->addFunc($fn); + } + } + + 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(); + $code = $this->_checkThenNext(self::T_IntegerConstant); + $name = $this->_checkThenNext(self::T_Identifier); + $this->_checkThenNext('('); + + $tokens = array(); + if($this->token == self::T_Prop) + $tokens = $this->_parsePropTokens(); + + $req_fields = $this->_parseFields(function() + { return $this->_nextIf(')'); } + ); + $rsp_fields = $this->_parseFields(function() + { return $this->_nextIf(self::T_End); } + ); + + $req = new mtgMetaPacket($code, "RPC_REQ_$name"); + $req->setFields($req_fields); + $rsp = new mtgMetaPacket($code, "RPC_RSP_$name"); + $rsp->setFields($rsp_fields); + + $rpc = new mtgMetaRPC("RPC_$name", $code, $req, $rsp, $tokens); + $this->current_meta->addUnit(new mtgMetaInfoUnit($this->file, $rpc)); + } + + private function _parsePropTokens() + { + $new_line = ord("\n"); + + $prop_tokens = array(); + + while(true) + { + if($this->token != self::T_Prop) + break; + + $name = ltrim($this->attribute, '@'); + $this->_next(); + + $value = null; + if($this->token == ord(':')) + { + while(true) + { + $this->_next(false/*don't skip new line*/); + if($this->token == $new_line || + $this->token == self::T_Prop) + { + //let's skip it + if($this->token == $new_line) + $this->_next(); + break; + } + else + { + $tmp = $this->attribute; + if($this->token == self::T_StringConstant) + $tmp = "\"$tmp\""; + if($value === null) + $value = ''; + $value .= $tmp; + } + } + } + if($value && substr($value, 0, 1) == '{') + { + $json = json_decode($value); + if($json === null) + { + --$this->line; //hack for more precise reporting + $this->_error("bad json"); + } + } + $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']) + return; + + if(!in_array($name, $this->config['valid_tokens'])) + throw new Exception("Unknown token '$name'"); + } + + private function _symbol() + { + return substr($this->source, $this->cursor, 1); + } + + private function _next($skip_newlines = true) + { + $this->__next($skip_newlines); + //for debug + //var_dump("NEXT " . $this->token . " " . $this->attribute); + //debug_print_backtrace(0, 1); + } + + private function __next($skip_newlines = true) + { + while(true) + { + $c = $this->_symbol(); + //NOTE: dealing with PHP's types juggling + if($c === false || $c === '') + $c = -1; + + $this->token = ord($c); + ++$this->cursor; + $this->attribute = $c; + + switch($c) + { + case -1: $this->cursor--; $this->token = self::T_EOF; return; + case ' ': case "\r": case "\t": break; + case "\n": $this->line++; if($skip_newlines) break; else return; + case '{': case '}': case '(': case ')': case '[': case ']': case '|': return; + case ',': case ':': case ';': case '=': return; + case '.': + if(!ctype_digit($this->_symbol())) return; + $this->_error("floating point constant can't start with ."); + break; + case '"': + $this->attribute = ""; + while($this->_symbol() != '"') + { + if(ord($this->_symbol()) < ord(' ') && ord($this->_symbol()) >= 0) + $this->_error("illegal character in string constant"); + if($this->_symbol() == '\\') + { + $this->cursor++; + switch($this->_symbol()) + { + case 'n': $this->attribute .= "\n"; $this->cursor++; break; + case 't': $this->attribute .= "\t"; $this->cursor++; break; + case 'r': $this->attribute .= "\r"; $this->cursor++; break; + case '"': $this->attribute .= '"'; $this->cursor++; break; + case '\\': $this->attribute .= '\\'; $this->cursor++; break; + default: $this->_error("unknown escape code in string constant"); break; + } + } + else // printable chars + UTF-8 bytes + { + $this->attribute .= $this->_symbol(); + $this->cursor++; + } + } + $this->token = self::T_StringConstant; + $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() == '/') + { + $this->cursor++; + while($this->_symbol() !== false && $this->_symbol() != "\n") $this->cursor++; + break; + } + + case '#': + while($this->_symbol() !== false && $this->_symbol() != "\n") $this->cursor++; + break; + + case '@': + $start = $this->cursor - 1; + while(ctype_alnum($this->_symbol()) || $this->_symbol() == '_') + $this->cursor++; + $this->token = self::T_Prop; + $this->attribute = substr($this->source, $start, $this->cursor - $start); + return; + + //fall thru + default: + + if(ctype_alpha($c)) + { + //collect all chars of an identifier + $start = $this->cursor - 1; + while(ctype_alnum($this->_symbol()) || $this->_symbol() == '_') + $this->cursor++; + $this->attribute = substr($this->source, $start, $this->cursor - $start); + + if(isset($this->idltypes[$this->attribute])) + { + $this->token = $this->idltypes[$this->attribute]; + return; + } + + if($this->attribute == "true" || $this->attribute == "false") + { + $this->token = self::T_IntegerConstant; + return; + } + + //check for declaration keywords: + 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; + return; + } + else if(ctype_digit($c) || $c == '-') + { + $start = $this->cursor - 1; + while(ctype_digit($this->_symbol())) $this->cursor++; + if($this->_symbol() == '.') + { + $this->cursor++; + while(ctype_digit($this->_symbol())) $this->cursor++; + // see if this float has a scientific notation suffix. Both JSON + // and C++ (through strtod() we use) have the same format: + if($this->_symbol() == 'e' || $this->_symbol() == 'E') + { + $this->cursor++; + if($this->_symbol() == '+' || $this->_symbol() == '-') $this->cursor++; + while(ctype_digit($this->_symbol())) $this->cursor++; + } + $this->token = self::T_FloatConstant; + } + else + $this->token = self::T_IntegerConstant; + $this->attribute = substr($this->source, $start, $this->cursor - $start); + return; + } + + $this->_error("illegal character '$c'"); + } + } + } + + private function _nextIf($t) + { + if(is_string($t)) + $t = ord($t); + $yes = $t === $this->token; + if($yes) + $this->_next(); + return $yes; + } + + private function _checkThenNext($t) + { + if(is_string($t)) + $t = ord($t); + if($t !== $this->token) + { + $this->_error("Expecting '" . $this->_toStr($t) . "' instead got '" . $this->_toStr($this->token) . "'"); + } + + $attr = $this->attribute; + $this->_next(); + return $attr; + } + + private function _toStr($t) + { + if($t < 1000) + return chr($t); + return $this->token_strs[$t]; + } + + private function _error($msg) + { + throw new Exception($msg . "(token: {$this->token}, attr: {$this->attribute}})"); + } +} + +function mtg_parse_meta(array $meta_srcs, $valid_tokens = null) +{ + $meta_dirs = array(); + foreach($meta_srcs as $src) + { + if(is_dir($src)) + $meta_dirs[] = $src; + else if(is_file($src)) + $meta_dirs[] = dirname($src); + } + + $meta_parser = new mtgMetaInfoParser( + array( + 'include_path' => $meta_dirs, + 'valid_tokens' => $valid_tokens + ) + ); + $meta = new mtgMetaInfo(); + foreach($meta_srcs as $src) + mtg_load_meta($meta, $meta_parser, $src); + return $meta; +} + +function mtg_load_meta(mtgMetaInfo $meta, mtgMetaInfoParser $meta_parser, $dir_or_file) +{ + $files = array(); + if(is_dir($dir_or_file)) + $files = mtg_find_meta_files($dir_or_file); + else if(is_file($dir_or_file)) + $files[] = $dir_or_file; + else + throw new Exception("Bad meta source '$dir_or_file'"); + + foreach($files as $file) + $meta_parser->parse($meta, $file); +} + +function mtg_find_meta_files($dir) +{ + $items = scandir($dir); + if($items === false) + throw new Exception("Directory '$dir' is invalid"); + + $files = array(); + foreach($items as $item) + { + if($item[0] == '.') + continue; + + if(strpos($item, ".meta") !== (strlen($item)-5)) + continue; + + $file = $dir . '/' . $item; + if(is_file($file) && !is_dir($file)) + $files[] = $file; + } + return $files; +} diff --git a/targets/cs/cs.inc.php b/targets/cs/cs.inc.php deleted file mode 100644 index ed57387..0000000 --- a/targets/cs/cs.inc.php +++ /dev/null @@ -1,702 +0,0 @@ -object; - if($obj instanceof mtgMetaEnum) - return $this->genEnum($obj); - else if($obj instanceof mtgMetaStruct) - return $this->genStruct($obj); - else if($obj instanceof mtgMetaRPC) - return $this->genRPC($obj); - else - { - echo "WARN: skipping meta unit '{$obj->getId()}'\n"; - return ''; - } - } - - function genEnum(mtgMetaEnum $struct) - { - $templater = new mtg_cs_templater(); - - $repl = array(); - $repl['%namespace%'] = $this->namespace; - $repl['%class%'] = $struct->getName(); - $repl['%class_id%'] = $struct->getClassId(); - - $tpl = $templater->tpl_enum(); - - $this->fillEnumRepls($struct, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function fillEnumRepls(mtgMetaEnum $enum, &$repl) - { - $repl['%fields%'] = ''; - $repl['%attributes%'] = ''; - $fields =& $repl['%fields%']; - if($enum->hasToken('cs_attributes')) - { - $attrs = explode(",", $enum->getToken('cs_attributes')); - foreach($attrs as $attr) - $repl['%attributes%'] .= "[$attr] "; - } - foreach($enum->getValues() as $vname => $value) - $fields .= sprintf("\n %s = %s,", $vname, $value); - } - - function genRPC(mtgMetaRPC $rpc) - { - $templater = new mtg_cs_templater(); - - $repl = array(); - $repl['%namespace%'] = $this->namespace; - $repl['%class%'] = $rpc->getName(); - $repl['%code%'] = $rpc->getCode(); - $repl['%req_class%'] = $rpc->getReq()->getName(); - $repl['%rsp_class%'] = $rpc->getRsp()->getName(); - - $tpl = $templater->tpl_rpc(); - - return - mtg_fill_template($tpl, $repl) . - $this->genStruct($rpc->getReq()) . - $this->genStruct($rpc->getRsp()); - } - - function genStruct(mtgMetaStruct $struct) - { - $templater = new mtg_cs_templater(); - - $repl = array(); - $repl['%namespace%'] = $this->namespace; - $repl['%class%'] = $struct->getName(); - $repl['%class_id%'] = $struct->getClassId(); - - $tpl = $templater->tpl_struct(); - - $this->fillStructRepls($struct, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function preprocessField(mtgMetaStruct $struct, mtgMetaField $field) - {} - - function countFields(mtgMetaStruct $struct) - { - $fields = $struct->getFields(); - $count = 0; - foreach($fields as $field) - { - if($field->hasToken('i18n')) - $count += 2; - else - $count += 1; - } - - return $count; - } - - function fillStructRepls(mtgMetaStruct $struct, &$repl) - { - foreach($struct->getFields() as $field) - $this->preprocessField($struct, $field); - - $all_fields = mtg_get_all_fields($this->info, $struct); - $all_fields_count = $this->countAllFields($struct); - - $repl['%includes%'] = ''; - $repl['%fields%'] = ''; - $repl['%fields_reset%'] = ''; - $repl['%attributes%'] = ''; - - $repl['%sync_buffer%'] = ''; - $repl['%fields_count%'] = $all_fields_count; - $repl["%ext_methods%"] = ""; - - $repl['%new_method%'] = ''; - $repl['%virt_method%'] = ' virtual '; - $repl['%commented_in_child_begin%'] = ''; - $repl['%commented_in_child_end%'] = ''; - $repl['%commented_in_pod_begin%'] = ''; - $repl['%commented_in_pod_end%'] = ''; - - $has_bitfields_token = $struct->hasToken("bitfields"); - - $bitctx_name = 'bitctx'; - - $repl['%bitfields_sync_context%'] = ""; - if($has_bitfields_token) - { - $repl['%bitfields_sync_context%'] .= $this->offset(2)."var $bitctx_name = new Meta.BitfieldsContext(ctx, fields_mask);\n"; - $repl['%bitfields_sync_context%'] .= $this->offset(2)."$bitctx_name.SyncMaskHeader();\n"; - } - - if($struct->hasToken('cs_attributes')) - { - $attrs = explode(",", $struct->getToken('cs_attributes')); - foreach($attrs as $attr) - $repl['%attributes%'] .= "[$attr] "; - } - - $parent = $struct->getParent(); - $is_pod = $struct->hasToken('POD'); - - if($parent && $has_bitfields_token) - throw new Exception("@bitfields struct can't have a parent: {$struct->getName()}"); - - if($is_pod) - { - $fields = $all_fields; - $repl['%type_name%'] = 'struct'; - $repl['%parent%'] = " : IMetaStruct"; - $repl['%virt_method%'] = ''; - $repl['%commented_in_pod_begin%'] = '/*'; - $repl['%commented_in_pod_end%'] = '*/'; - } - else - { - $repl['%type_name%'] = 'class'; - $repl['%parent%'] = " : " . ($parent ? $parent : " BaseMetaStruct"); - if($parent) - $repl['%sync_buffer%'] .= "\n base.syncFields(ctx);\n"; - $repl['%commented_in_child_begin%'] = '/*'; - $repl['%commented_in_child_end%'] = '*/'; - $repl['%virt_method%'] = " override "; - - if($parent) - { - $repl['%new_method%'] = " new "; - $repl['%fields_reset%'] = "base.reset();\n"; - } - - $fields = $struct->getFields(); - } - - $repl['%copy_fields%'] = ''; - $repl['%virt_clone_method%'] = ''; - - if($struct->hasToken("cloneable")) - { - $repl['%parent%'] .= ",IMetaCloneable"; - $repl['%commented_in_non_cloneable_begin%'] = ''; - $repl['%commented_in_non_cloneable_end%'] = ''; - - if($is_pod) - $repl['%virt_clone_method%'] = ''; - else if($parent && $parent->hasTokenInParent("cloneable")) - $repl['%virt_clone_method%'] = ' override '; - else - $repl['%virt_clone_method%'] = ' virtual '; - } - else - { - $repl['%commented_in_non_cloneable_begin%'] = '/*'; - $repl['%commented_in_non_cloneable_end%'] = '*/'; - } - - $field_index = 0; - foreach($fields as $field) - { - $repl['%fields%'] .= $this->offset() . $this->genFieldDecl($struct, $field)."\n"; - - $repl['%fields_reset%'] .= $this->offset() . $this->genFieldReset($field)."\n"; - - $sync_opts = $this->resolveSyncOpts($struct, $bitctx_name); - - $repl['%sync_buffer%'] .= $this->offset(2) . $this->genBufSyncRegular($field, "ctx", $sync_opts)."\n"; - - $field_index++; - } - - if($has_bitfields_token) - { - $repl['%fields%'] .= "\n".$this->offset()."public long fields_mask;\n"; - - $repl['%ext_methods%'] .= "\n".$this->genBitmaskHelpers($struct, $fields); - - $repl['%copy_fields%'] .= $this->offset() . "fields_mask = other.fields_mask;\n"; - $repl['%fields_reset%'] .= $this->offset() . "fields_mask = 0L;\n"; - - $repl['%dirty_fields_count%'] = "Meta.GetDirtyFieldsCount(fields_mask, fields_count: $all_fields_count) + Meta.MASK_HEADER_FIELDS_COUNT"; - } - else - $repl['%dirty_fields_count%'] = "$all_fields_count /* equal to getFieldsCount */ "; - - $repl['%fields%'] = trim($repl['%fields%'], "\n "); - - $this->undoTemp(); - } - - function resolveSyncOpts(mtgMetaStruct $struct, string $bitctx_name) - { - $opts = array(); - if($struct->hasToken("bitfields")) - $opts[] = "$bitctx_name.GetNextOpts()"; - - if(count($opts) == 0) - return "0"; - - return implode(" | ", $opts); - } - - function countAllFields(mtgMetaStruct $struct) - { - $count = count($struct->getFields()); //preprocessed fields list - - //raw fields lists - $curr = $struct->getParent(); - while($curr) - { - $count += $this->countFields($curr); - $curr = $curr->getParent(); - } - - return $count; - } - - function genNativePlainType(mtgType $type) - { - if($type instanceof mtgBuiltinType) - { - switch($type->getName()) - { - case "int8": - return "sbyte"; - case "uint8": - return "byte"; - case "int16": - return "short"; - case "uint16": - return "ushort"; - case "int32": - case "int": - return "int"; - case "uint32": - case "uint": - return "uint"; - case "float": - return "float"; - case "double": - return "double"; - case "uint64": - return "ulong"; - case "int64": - return "long"; - case "string": - return "string"; - case "bool": - return "bool"; - case "blob": - return "byte[]"; - } - throw new Exception("Unknown type '{$type}'"); - } - return $type->getName(); - } - - function genTypePrefix(mtgType $type) - { - switch($type->getName()) - { - case "float": - return "Float"; - case "double": - return "Double"; - case "uint64": - return "U64"; - case "int64": - return "I64"; - case "uint": - case "uint32": - return "U32"; - case "uint16": - return "U16"; - case "uint8": - return "U8"; - case "int": - case "int32": - return "I32"; - case "int16": - return "I16"; - case "int8": - return "I8"; - case "string": - return "String"; - case "bool": - return "Bool"; - case "blob": - return "Blob"; - default: - throw new Exception("Unknown type '{$type}'"); - } - } - - function genBufSyncRegular(mtgMetaField $field, $buf, $opts = "") - { - return $this->genBufSync($field->getName(), $field, $buf, $opts); - } - - function genBufSync(string $fname, mtgMetaField $field, $buf, $opts) - { - return $this->genBufSyncEx($fname, $field->getType(), $buf, $field->getTokens(), $opts); - } - - function genBufSyncEx($fname, mtgType $type, $buf, array $tokens = array(), $opts = "") - { - $optional = array_key_exists('optional', $tokens); - if($optional) - $opts .= " | MetaSyncFieldOpts.SKIP_OPTIONAL"; - - $str = ''; - if($type instanceof mtgBuiltinType) - { - $str .= "Meta.Sync({$buf}, ref {$fname}, {$opts});\n"; - } - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - $str .= "{$fname} = ({$type->getName()})Meta.SyncGeneric({$buf}, {$fname}, {$opts});\n"; - else - $str .= "Meta.Sync({$buf}, ref {$fname}, {$opts});\n"; - } - else if($type instanceof mtgMetaEnum) - { - $str .= "int __tmp_{$fname} = (int)$fname;\n"; - $str .= "Meta.Sync({$buf}, ref __tmp_{$fname}, {$opts});\n"; - $str .= "if($buf.is_read) {$fname} = ({$type->getName()})__tmp_{$fname};\n"; - } - else if($type instanceof mtgArrType) - { - if(array_key_exists('virtual', $tokens)) - $str .= "Meta.SyncGeneric({$buf}, {$fname}, {$opts});\n"; - else - { - if($type->getValue() instanceof mtgMetaEnum) - { - $str .= "Meta.tmp_enums_list.Clear(); if(!{$buf}.is_read) { foreach(var _enum_tmp in {$fname}) Meta.tmp_enums_list.Add((int)_enum_tmp); }\n"; - $str .= "Meta.Sync({$buf}, Meta.tmp_enums_list, {$opts});\n"; - $str .= "if({$buf}.is_read) foreach(var _int_tmp in Meta.tmp_enums_list) { {$fname}.Add(({$type->getValue()->getName()}) _int_tmp); }\n"; - } - else - $str .= "Meta.Sync({$buf}, {$fname}, {$opts});\n"; - } - } - else - throw new Exception("Unknown type '$type'"); - - return $str; - } - - function genConstructArgs($type) - { - if($type == "string") - return '""'; - return "new {$type}()"; - } - - function isPOD(mtgMetaStruct $struct) - { - return $struct->hasToken('POD'); - } - - function genFieldDecl(mtgMetaStruct $struct, mtgMetaField $field) - { - $str = ""; - - if($field->hasToken('cs_attributes')) - { - $attrs = explode(",", $field->getToken('cs_attributes')); - foreach($attrs as $attr) - $str .= "[$attr] "; - } - - $str .= "public " . $this->genFieldNativeType($field) . " "; - - if(!$this->isPOD($struct)) - $str .= $this->genFieldDeclInit($field); - else - $str .= $this->genFieldName($field) . ";"; - - return $str; - } - - function offset($amount = 1) - { - return str_repeat(" ", $amount); - } - - function genFieldCopy(mtgMetaField $field) - { - $tokens = $field->getTokens(); - $name = $this->genFieldName($field); - $type = $field->getType(); - $str = ''; - - if($type instanceof mtgArrType) - { - $str .= "for(int i=0;other.{$name} != null && igetValue(); - if($vtype instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - $str .= $this->offset(3)."var tmp = ({$vtype->getName()})other.{$name}[i].clone();\n"; - else - $str .= $this->offset(3)."var tmp = new {$vtype->getName()}(); tmp.copyFrom(other.{$name}[i]);\n"; - $str .= $this->offset(3)."{$name}.Add(tmp);\n"; - } - else - $str .= $this->offset(3)."{$name}.Add(other.{$name}[i]);\n"; - - $str .= $this->offset(2)."}\n"; - } - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - $str .= $this->offset(2)."{$name} = ({$type->getName()})other.{$name}.clone();\n"; - else - $str .= $this->offset(2)."{$name}.copyFrom(other.{$name});\n"; - } - else - $str .= $this->offset()."{$name} = other.{$name};\n"; - - return $str; - } - - function genFieldDeclInit(mtgMetaField $field) - { - $tokens = $field->getTokens(); - - $str = $this->genFieldName($field); - $type = $field->getType(); - if($type instanceof mtgBuiltinType) - { - if($type->isString()) - $str .= ' = ""'; - } - else - $str .= " = new ".$this->genFieldNativeType($field)."()"; - $str .= ";"; - return $str; - } - - function genFieldReset(mtgMetaField $field) - { - $tokens = $field->getTokens(); - $default = array_key_exists('default', $tokens) ? $tokens['default'] : null; - - return $this->genFieldResetEx($this->genFieldName($field), $field->getType(), $default); - } - - function genFieldResetEx($name, mtgType $type, $default = null) - { - $str = ''; - if($type instanceof mtgBuiltinType) - { - if($type->isNumeric()) - { - $str = $name; - //NOTE: numeric check is against str2num - if($default && is_numeric($default)) - { - if($type->isFloat()) - $default .= "f"; - $str .= " = $default;"; - } - else - $str .= " = 0;"; - } - else if($type->isString()) - { - $str = $name; - if($default) - { - $str .= " = \"".trim($default, '"')."\";"; - } - else - $str .= ' = "";'; - } - else if($type->isBool()) - { - $str = $name; - if($default) - { - $str .= " = ".trim($default, '"').";"; - } - else - $str .= ' = false;'; - } - else if($type->isBlob()) - { - $str = $name; - if($default) - { - $str .= " = ".trim($default, '"').";"; - } - else - $str .= ' = null;'; - } - else - throw new Exception("Unknown type '$type'"); - } - else if($type instanceof mtgArrType) - { - $str = "Meta.ClearList(ref $name);"; - - if($default) - { - $default_arr = is_array($default) ? $default : json_decode($default, true); - if(!is_array($default_arr)) - throw new Exception("Bad default value for array: '$default'"); - - if($default_arr) - { - $type_str = $this->genNativeType($type->getValue()); - $str .= "{ $type_str tmp__"; - if($this->isNullableType($type->getValue())) - $str .= " = null"; - $str .= ";"; - foreach($default_arr as $v) - { - $str .= $this->genFieldResetEx("tmp__", $type->getValue(), $v); - $str .= "$name.Add(tmp__);"; - } - $str .= "}"; - } - } - } - else if($type instanceof mtgMetaEnum) - { - if($default) - $str = "$name = ".$this->genNativeType($type).".".trim($default,'"')."; "; - else - $str = "$name = new ".$this->genNativeType($type)."(); "; - } - else if($type instanceof mtgMetaStruct) - { - $str = ""; - $is_pod = $type->hasToken('POD'); - if($is_pod) - $str .= "$name.reset(); "; - else - $str .= "Meta.Reset(ref $name); "; - - if($default) - { - $default = is_array($default) ? $default : json_decode($default, true); - if(!is_array($default)) - throw new Exception("Bad default value for struct: $default"); - - foreach($default as $k => $v) - { - $kf = $type->getField($k); - $str .= $this->genFieldResetEx("$name." . $this->genFieldName($kf), $kf->getType(), $v); - } - } - } - else - throw new Exception("Bad type '$type'"); - return $str; - } - - function isNullableType(mtgType $type) - { - return $type instanceof mtgArrType || - ($type instanceof mtgMetaStruct && !$type->hasToken('POD')); - } - - function genFieldName(mtgMetaField $field) - { - return $field->getName(); - } - - function genFieldNativeType(mtgMetaField $field) - { - return $this->genNativeType($field->getType(), $field->getTokens()); - } - - function genNativeType(mtgType $type, array $tokens = array()) - { - if($type instanceof mtgBuiltinType || $type instanceof mtgUserType) - return $this->genNativePlainType($type); - else if($type instanceof mtgArrType) - return "List<" . $this->genNativePlainType($type->getValue()) . ">"; - else - throw new Exception("Unknown type '{$type}'"); - } - - function genBitmaskHelpers(mtgMetaStruct $struct, array $fields) - { - //RESET FIELD MASK - $str = $this->offset()."public void ResetFieldMask()\n"; - $str .= $this->offset()."{\n"; - $str .= $this->offset(2)."fields_mask = 0L;\n"; - $str .= $this->offset()."}\n\n"; - - //SET PRIMARY FIELDS CHANGED - $primary_fields = array(); - if($struct->hasToken("id")) - $primary_fields[] = $struct->getToken("id"); - - if($struct->hasToken("owner")) - $primary_fields[] = $struct->getToken("owner"); - - if($struct->hasToken("pkey")) - { - foreach(explode(",", $struct->getToken("pkey")) as $name) - $primary_fields[] = $name; - } - - $str .= $this->offset()."public void SetPrimaryFieldsChanged()\n"; - $str .= $this->offset()."{\n"; - $field_index = 0; - foreach($fields as $field) - { - if(in_array($field->getName(), $primary_fields)) - $str .= $this->offset(2)."Meta.SetFieldDirty(ref fields_mask, $field_index);\n"; - - $field_index++; - } - $str .= $this->offset()."}\n\n"; - - //DIRTY FIELD MASK - $str .= $this->offset()."public void SetDirtyMask()\n"; - $str .= $this->offset()."{\n"; - $str .= $this->offset(2)."fields_mask = ~0L;\n"; - $str .= $this->offset()."}\n\n"; - - $str .= $this->offset()."public void SetDirtyMaskDeep()\n"; - $str .= $this->offset()."{\n"; - $str .= $this->offset(2)."SetDirtyMask();\n"; - foreach($fields as $field) - { - $type = $field->getType(); - - if($type instanceof mtgMetaStruct && $type->hasToken("bitfields")) - $str .= $this->offset(2)."{$field->getName()}.SetDirtyMaskDeep();\n"; - else if($type instanceof mtgArrType && $type->getValue() instanceof mtgMetaStruct && $type->getValue()->hasToken("bitfields")) - { - $str .= $this->offset(2)."for(int i=0;i<{$field->getName()}.Count;++i) {\n"; - $str .= $this->offset(2)."var __tmp = {$field->getName()}[i];\n"; - $str .= $this->offset(2)."__tmp.SetDirtyMaskDeep();\n"; - $str .= $this->offset(2)."{$field->getName()}[i] = __tmp;\n"; - $str .= $this->offset(2)."}\n"; - } - } - $str .= $this->offset()."}\n\n"; - - return $str; - } - -} diff --git a/targets/cs/cs_generator.inc.php b/targets/cs/cs_generator.inc.php deleted file mode 100644 index 20e5b25..0000000 --- a/targets/cs/cs_generator.inc.php +++ /dev/null @@ -1,87 +0,0 @@ -setMetaInfo($meta); - - $refl = new ReflectionClass($codegen); - $SHARED_DEPS = array( - dirname(__FILE__) . '/cs.inc.php', - dirname(__FILE__) . '/cs_tpl.inc.php', - __FILE__, - $refl->getFileName() - ); - - $units = array(); - $files = array(); - foreach($meta->getUnits() as $unit) - { - $units[] = $unit; - $files = array_merge($files, mtg_get_file_deps($meta, $unit)); - } - $files = array_unique($files); - - $bundle = mtg_conf("bundle", null); - if($bundle && $units) - { - $targets[] = mtg_new_bundle($bundle, - array_merge($SHARED_DEPS, $files), - array(array($this, 'genBundle'), $meta, $codegen, $units)); - } - - return $targets; - } - - function genBundle($OUT, array $DEPS, mtgMetaInfo $meta, mtgCsCodegen $codegen, array $units) - { - $units_src = ''; - $id2type = ''; - $create_struct_by_crc28 = ''; - $create_rpc_by_id = ''; - - foreach($units as $unit) - { - if($unit->object instanceof mtgMetaRPC) - { - $units_src .= $codegen->genUnit($unit); - $rpc = $unit->object; - $create_rpc_by_id .= "\n case {$rpc->getCode()}: { return new {$rpc->getName()}(); };"; - } - else if($unit->object instanceof mtgMetaEnum || $unit->object instanceof mtgMetaStruct) - { - $units_src .= $codegen->genUnit($unit) . "\n"; - - if($unit->object->hasToken('POD') || $unit->object instanceof mtgMetaEnum) - continue; - - $id2type .= "\n case {$unit->object->getClassId()}: { return typeof({$unit->object->getName()}); };"; - $create_struct_by_crc28 .= "\n case {$unit->object->getClassId()}: { return new {$unit->object->getName()}(); };"; - } - } - - $templater = new mtg_cs_templater(); - $tpl = $templater->tpl_bundle(); - return mtg_fill_template($tpl, array( - '%namespace%' => $codegen->namespace, - '%units_src%' => $units_src, - '%id2type%' => $id2type, - '%create_struct_by_crc28%' => $create_struct_by_crc28, - '%create_rpc_by_id%' => $create_rpc_by_id, - )); - } -} - -function gen_cs_struct($OUT, array $DEPS, mtgCsCodegen $codegen, mtgMetaInfoUnit $unit) -{ - return $codegen->genUnit($unit); -} diff --git a/targets/cs/cs_tpl.inc.php b/targets/cs/cs_tpl.inc.php deleted file mode 100644 index fc408a6..0000000 --- a/targets/cs/cs_tpl.inc.php +++ /dev/null @@ -1,216 +0,0 @@ - factory; - public MetaSyncContextOpts opts; - - public bool CanReadField(MetaSyncFieldOpts opts) - { - return is_read && (opts & MetaSyncFieldOpts.SKIP_NOT_IN_MASK) != MetaSyncFieldOpts.SKIP_NOT_IN_MASK; - } - - public bool CanWriteField(MetaSyncFieldOpts opts) - { - return !is_read && (opts & MetaSyncFieldOpts.SKIP_NOT_IN_MASK) != MetaSyncFieldOpts.SKIP_NOT_IN_MASK; - } - - public bool IsMaskUsed() - { - return (opts & MetaSyncContextOpts.USE_MASK) > 0; - } - - public static MetaSyncContext NewForRead(Func factory, IDataReader reader, MetaSyncContextOpts opts = 0) - { - var ctx = new MetaSyncContext() { - is_read = true, - reader = reader, - writer = null, - factory = factory, - opts = opts - }; - return ctx; - } - - public static MetaSyncContext NewForWrite(IDataWriter writer, MetaSyncContextOpts opts = 0) - { - var ctx = new MetaSyncContext() { - is_read = false, - reader = null, - writer = writer, - opts = opts - }; - return ctx; - } -} - -public interface IMetaStruct -{ - uint CLASS_ID(); - - int getFieldsCount(); - int getWritableFieldsCount(); - - void syncFields(MetaSyncContext ctx); - - void reset(); -} - -public interface IMetaCloneable -{ - void copy(IMetaStruct source); - IMetaStruct clone(); -} - -public abstract class BaseMetaStruct : IMetaStruct -{ - public virtual uint CLASS_ID() { return 0; } - - public virtual int getFieldsCount() { return 0; } - public virtual int getWritableFieldsCount() { return 0; } - - public virtual void reset() {} - - public virtual void syncFields(MetaSyncContext ctx) {} -} - -public interface IRpcError -{ - bool isOk(); -} - -public interface IRpc -{ - int getCode(); - IMetaStruct getRequest(); - IMetaStruct getResponse(); - IRpcError getError(); - void setError(IRpcError err); -} - -public interface IDataReader -{ - MetaIoError ReadI8(ref sbyte v); - MetaIoError ReadU8(ref byte v); - MetaIoError ReadI16(ref short v); - MetaIoError ReadU16(ref ushort v); - MetaIoError ReadI32(ref int v); - MetaIoError ReadU32(ref uint v); - MetaIoError ReadU64(ref ulong v); - MetaIoError ReadI64(ref long v); - MetaIoError ReadFloat(ref float v); - MetaIoError ReadBool(ref bool v); - MetaIoError ReadDouble(ref double v); - MetaIoError ReadString(ref string v); - MetaIoError ReadRaw(ref byte[] v, ref int vlen); - MetaIoError ReadNil(); - MetaIoError BeginContainer(); - MetaIoError GetContainerSize(ref int v); - MetaIoError EndContainer(); -} - -public interface IDataWriter -{ - MetaIoError WriteI8(sbyte v); - MetaIoError WriteU8(byte v); - MetaIoError WriteI16(short v); - MetaIoError WriteU16(ushort v); - MetaIoError WriteI32(int v); - MetaIoError WriteU32(uint v); - MetaIoError WriteI64(long v); - MetaIoError WriteU64(ulong v); - MetaIoError WriteFloat(float v); - MetaIoError WriteBool(bool v); - MetaIoError WriteDouble(double v); - MetaIoError WriteString(string v); - MetaIoError WriteRaw(byte[] v); - MetaIoError BeginContainer(int len); - MetaIoError EndContainer(); - MetaIoError End(); - MetaIoError WriteNil(); -} - -public static class Meta -{ - public delegate void LogCb(string text); - public static LogCb LogError = DefaultLog; - public static LogCb LogWarn = DefaultLog; - public static LogCb LogDebug = DefaultLog; - - public struct BitfieldsContext - { - long fields_mask; - int curr_field_idx; - - MetaSyncContext ctx; - - readonly bool use_mask; - - public BitfieldsContext(MetaSyncContext ctx, long fields_mask) - { - this.ctx = ctx; - this.use_mask = ctx.IsMaskUsed(); - this.fields_mask = fields_mask; - this.curr_field_idx = -1; - } - - public void SyncMaskHeader() - { - if(!use_mask) - return; - - if(ctx.is_read) - { - ensure(ctx.reader.ReadNil()); - ensure(ctx.reader.ReadI64(ref fields_mask)); - } - else - { - ensure(ctx.writer.WriteNil()); - ensure(ctx.writer.WriteI64(fields_mask)); - } - } - - public MetaSyncFieldOpts GetCurrentOpts() - { - if(!use_mask || curr_field_idx < 0 || curr_field_idx > 63) - return 0; - - long curr_field_ptr = 1L << curr_field_idx; - if((curr_field_ptr & fields_mask) == 0) - return MetaSyncFieldOpts.SKIP_NOT_IN_MASK; - - return 0; - } - - public MetaSyncFieldOpts GetNextOpts() - { - Advance(); - return GetCurrentOpts(); - } - - public void Advance() - { - curr_field_idx++; -#if DEBUG - if(curr_field_idx > 64) - { - LogError("overflow in @bitfields struct. Does it have > 64 fields?"); - throw new MetaException(MetaIoError.GENERIC); - } -#endif - } - } - - public const int MASK_HEADER_FIELDS_COUNT = 2; - - public static List tmp_enums_list = new List(); - - static void DefaultLog(string s) - {} - - public delegate string L_TCb(string text); - public static L_TCb L_T; - - public delegate string L_FromListCb(IList list); - public static L_FromListCb L_FromList; - - public delegate string L_PFromListCb(IList list, double force_n = double.NaN); - public static L_PFromListCb L_Pluralize; - - public delegate bool L_PListCheckCb(IList list, string plural_mark); - public static L_PListCheckCb L_IsPlural; - - public static void ensure(MetaIoError err) - { - if(err != 0) - throw new MetaException(err); - } - - static bool canSkipOptionalRead(MetaIoError err, MetaSyncFieldOpts opts) - { - return err != 0 && (opts & MetaSyncFieldOpts.SKIP_OPTIONAL) == MetaSyncFieldOpts.SKIP_OPTIONAL; - } - - static MetaIoError checkRead(MetaIoError err, MetaSyncFieldOpts opts) - { - if(canSkipOptionalRead(err, opts)) - { - LogWarn("Skipping optional field"); - return MetaIoError.NONE; - } - else - return err; - } - - public static void Sync(MetaSyncContext ctx, ref byte[] v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - int len = 0; - ensure(checkRead(ctx.reader.ReadRaw(ref v, ref len), opts)); - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteRaw(v)); - } - - public static void Sync(MetaSyncContext ctx, ref string v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadString(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteString(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredString v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - string tmp = string.Empty; - ensure(checkRead(ctx.reader.ReadString(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteString(v)); - } - - public static void Sync(MetaSyncContext ctx, ref long v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadI64(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI64(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredLong v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - long tmp = 0; - ensure(checkRead(ctx.reader.ReadI64(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI64(v)); - } - - public static void Sync(MetaSyncContext ctx, ref int v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadI32(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI32(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredInt v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - int tmp = 0; - ensure(checkRead(ctx.reader.ReadI32(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI32(v)); - } - - public static void Sync(MetaSyncContext ctx, ref short v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadI16(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI16(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredShort v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - short tmp = 0; - ensure(checkRead(ctx.reader.ReadI16(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI16(v)); - } - - public static void Sync(MetaSyncContext ctx, ref sbyte v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadI8(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI8(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredSByte v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - sbyte tmp = 0; - ensure(checkRead(ctx.reader.ReadI8(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteI8(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ulong v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadU64(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU64(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredULong v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - ulong tmp = 0; - ensure(checkRead(ctx.reader.ReadU64(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU64(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ushort v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadU16(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU16(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredUShort v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - ushort tmp = 0; - ensure(checkRead(ctx.reader.ReadU16(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU16(v)); - } - - public static void Sync(MetaSyncContext ctx, ref uint v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadU32(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU32(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredUInt v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - uint tmp = 0; - ensure(checkRead(ctx.reader.ReadU32(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU32(v)); - } - - public static void Sync(MetaSyncContext ctx, ref byte v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadU8(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU8(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredByte v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - byte tmp = 0; - ensure(checkRead(ctx.reader.ReadU8(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteU8(v)); - } - - public static void Sync(MetaSyncContext ctx, ref bool v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadBool(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteBool(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredBool v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - bool tmp = false; - ensure(checkRead(ctx.reader.ReadBool(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteBool(v)); - } - - public static void Sync(MetaSyncContext ctx, ref float v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadFloat(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteFloat(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredFloat v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - float tmp = 0f; - ensure(checkRead(ctx.reader.ReadFloat(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteFloat(v)); - } - - public static void Sync(MetaSyncContext ctx, ref double v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - ensure(checkRead(ctx.reader.ReadDouble(ref v), opts)); - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteDouble(v)); - } - - public static void Sync(MetaSyncContext ctx, ref ObscuredDouble v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - double tmp = 0; - ensure(checkRead(ctx.reader.ReadDouble(ref tmp), opts)); - v = tmp; - } - else if(ctx.CanWriteField(opts)) - ensure(ctx.writer.WriteDouble(v)); - } - - static int SyncBeginListGetSize(MetaSyncContext ctx, IList v, MetaSyncFieldOpts opts) - { - if(ctx.CanReadField(opts)) - { - var err = ctx.reader.BeginContainer(); - if(canSkipOptionalRead(err, opts)) - { - LogWarn("Skipping optional array field"); - return -1; - } - ensure(err); - - int size = 0; - ensure(ctx.reader.GetContainerSize(ref size)); - - return size; - } - else if(ctx.CanWriteField(opts)) - { - int size = v == null ? 0 : v.Count; - ensure(ctx.writer.BeginContainer(size)); - return size; - } - else - return -1; - } - - static int SyncBeginList(MetaSyncContext ctx, List v, ref MetaSyncFieldOpts opts) - { - int size = SyncBeginListGetSize(ctx, v, opts); - if(size == -1) - return size; - - if(ctx.is_read && v.Capacity < size) - v.Capacity = size; - - //NOTE: unsetting opts for array items - opts &= ~MetaSyncFieldOpts.SKIP_OPTIONAL; - opts &= ~MetaSyncFieldOpts.SKIP_NOT_IN_MASK; - return size; - } - - static void SyncEndList(MetaSyncContext ctx, IList v) - { - if(ctx.is_read) - ensure(ctx.reader.EndContainer()); - else - ensure(ctx.writer.EndContainer()); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? "" : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(long) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(int) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(short) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(sbyte) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(ulong) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(uint) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(ushort) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(byte) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(bool) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(float) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? default(double) : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct, new() - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - - if(ctx.is_read) - v.Clear(); - - for(int i = 0; i < size; ++i) - { - var tmp = ctx.is_read ? new T() : v[i]; - Sync(ctx, ref tmp, opts); - if(ctx.is_read) - v.Add(tmp); - } - SyncEndList(ctx, v); - } - - public static IMetaStruct SyncGeneric(MetaSyncContext ctx, IMetaStruct v, MetaSyncFieldOpts opts = 0) - { - if(ctx.CanReadField(opts)) - { - ensure(ctx.reader.BeginContainer()); - - uint clid = 0; - ensure(ctx.reader.ReadU32(ref clid)); - - //NOTE: when reading we ignore the passed argument - v = ctx.factory(clid); - if(v == null) - { - LogError("Could not create struct: " + clid); - ensure(MetaIoError.TYPE_DONT_MATCH); - } - - v.reset(); - v.syncFields(ctx); - ensure(ctx.reader.EndContainer()); - } - else if(ctx.CanWriteField(opts)) - { - ensure(ctx.writer.BeginContainer(v.getFieldsCount() + 1)); - ensure(ctx.writer.WriteU32(v.CLASS_ID())); - v.syncFields(ctx); - ensure(ctx.writer.EndContainer()); - - } - return v; - } - - public static void SyncGeneric(MetaSyncContext ctx, List v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct, new() - { - int size = SyncBeginList(ctx, v, ref opts); - if(size == -1) - return; - for(int i = 0; i < size; ++i) - { - var tmp = SyncGeneric(ctx, ctx.is_read ? default(T) : v[i]); - if(ctx.is_read) - v.Add((T)tmp); - } - SyncEndList(ctx, v); - } - - public static void Sync(MetaSyncContext ctx, ref T v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct - { - if(ctx.CanReadField(opts)) - { - var err = ctx.reader.BeginContainer(); - if(canSkipOptionalRead(err, opts)) - { - LogWarn("Skipping optional struct field"); - return; - } - - ensure(err); - v.reset(); - v.syncFields(ctx); - ensure(ctx.reader.EndContainer()); - } - else if(ctx.CanWriteField(opts)) - { - int array_size = getWriteFieldsCount(ctx, v); - ensure(ctx.writer.BeginContainer(array_size)); - v.syncFields(ctx); - ensure(ctx.writer.EndContainer()); - } - } - - public static MetaIoError SyncSafe(MetaSyncContext ctx, ref T v, MetaSyncFieldOpts opts = 0) where T : IMetaStruct - { - try - { - Sync(ctx, ref v, opts); - } - catch(MetaException e) - { - LogError(e.Message + " " + e.StackTrace); - return e.err; - } - catch(Exception e) - { - LogError(e.Message + " " + e.StackTrace); - return MetaIoError.GENERIC; - } - return MetaIoError.NONE; - } - - static int getWriteFieldsCount(MetaSyncContext ctx, IMetaStruct v) - { - if(ctx.IsMaskUsed()) - return v.getWritableFieldsCount(); - else - return v.getFieldsCount(); - } - - public static MetaSyncContext PrepareForClone(ref T src) where T : IMetaStruct - { - var stream = new MemoryStream(); - - var ctx = new MetaSyncContext() { - is_read = false, - reader = new MsgPackDataReader(stream), - writer = new MsgPackDataWriter(stream), - opts = 0 - }; - - Sync(ctx, ref src); - - ctx.is_read = true; - stream.Position = 0; - - return ctx; - } - - //Shared mask utils below - - public static int GetDirtyFieldsCount(long fields_mask, int fields_count) - { - int changed_fields = 0; - long ptr = 1L; - for(int i=0; i(ref List v) - { - if(v == null) - v = new List(); - v.Clear(); - } - - public static string I18NPick(string raw_val, List list_val, string plural_marker, double pluralize_for_n) - { - if(raw_val.Length != 0) - return Meta.L_T(raw_val); - - if(Meta.L_IsPlural(list_val, plural_marker)) - return Meta.L_Pluralize(list_val, pluralize_for_n); - - return Meta.L_FromList(list_val); - } - - public static void Reset(ref T v) where T : IMetaStruct, new() - { - if(v == null) - v = new T(); - v.reset(); - } -} - -public class MsgPackDataWriter : IDataWriter -{ - Stream stream; - MsgPackWriter io; - Stack space = new Stack(); - - public MsgPackDataWriter(Stream _stream) - { - reset(_stream); - } - - public void reset(Stream _stream) - { - stream = _stream; - io = new MsgPackWriter(stream); - space.Clear(); - space.Push(1); - } - - MetaIoError decSpace() - { - if(space.Count == 0) - return MetaIoError.NO_SPACE_LEFT_IN_ARRAY; - - int left = space.Pop(); - left--; - if(left < 0) - return MetaIoError.NO_SPACE_LEFT_IN_ARRAY; - - space.Push(left); - return 0; - } - - public MetaIoError BeginContainer(int size) - { - MetaIoError err = decSpace(); - if(err != 0) - return err; - - space.Push(size); - io.WriteArrayHeader(size); - return 0; - } - - public MetaIoError EndContainer() - { - if(space.Count <= 1) - return MetaIoError.ARRAY_STACK_IS_EMPTY; - - int left = space.Pop(); - if(left != 0) - return MetaIoError.HAS_LEFT_SPACE; - - return 0; - } - - public MetaIoError End() - { - if(space.Count != 1) - return MetaIoError.ARRAY_STACK_IS_EMPTY; - - return 0; - } - - public MetaIoError WriteI8(sbyte v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteU8(byte v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteI16(short v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteU16(ushort v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteI32(int v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteU32(uint v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteU64(ulong v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteI64(long v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteBool(bool v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteFloat(float v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteDouble(double v) - { - io.Write(v); - return decSpace(); - } - - public MetaIoError WriteString(string v) - { - if(v == null) - io.Write(""); - else - io.Write(v); - - return decSpace(); - } - - public MetaIoError WriteNil() - { - io.WriteNil(); - - return decSpace(); - } - - public MetaIoError WriteRaw(byte[] v) - { - io.Write(v); - - return decSpace(); - } -} - -public class MsgPackDataReader : IDataReader -{ - Stream stream; - MsgPackReader io; - - public struct ContainerPosition - { - public int max; - public int curr; - - public ContainerPosition(int length) - { - curr = 0; - max = length - 1; - } - } - - Stack stack = new Stack(); - - public MsgPackDataReader(Stream _stream) - { - reset(_stream); - } - - public void reset(Stream _stream) - { - stream = _stream; - stack.Clear(); - io = new MsgPackReader(stream); - } - - public void setPos(long pos) - { - stream.Position = pos; - stack.Clear(); - } - - int nextInt(ref MetaIoError err) - { - if(!ContainerPositionValid()) - { - err = MetaIoError.DATA_MISSING; - return 0; - } - - if(!io.Read()) - { - err = MetaIoError.FAIL_READ; - return 0; - } - - ContainerPositionMoveNext(); - - if(io.IsSigned()) - return io.ValueSigned; - else if(io.IsUnsigned()) - return (int)io.ValueUnsigned; - else - { - Meta.LogWarn("Got type: " + io.Type); - err = MetaIoError.TYPE_DONT_MATCH; - return 0; - } - } - - uint nextUint(ref MetaIoError err) - { - if(!ContainerPositionValid()) - { - err = MetaIoError.DATA_MISSING; - return 0; - } - - if(!io.Read()) - { - err = MetaIoError.FAIL_READ; - return 0; - } - - ContainerPositionMoveNext(); - - if(io.IsUnsigned()) - return io.ValueUnsigned; - else if(io.IsSigned()) - return (uint)io.ValueSigned; - else - { - Meta.LogWarn("Got type: " + io.Type); - err = MetaIoError.TYPE_DONT_MATCH; - return 0; - } - } - - bool nextBool(ref MetaIoError err) - { - if(!ContainerPositionValid()) - { - err = MetaIoError.DATA_MISSING; - return false; - } - - if(!io.Read()) - { - err = MetaIoError.FAIL_READ; - return false; - } - - ContainerPositionMoveNext(); - - if(io.IsBoolean()) - return (bool)io.ValueBoolean; - else if(io.IsUnsigned()) - return io.ValueUnsigned != 0; - else if(io.IsSigned()) - return (uint)io.ValueSigned != 0; - else - { - Meta.LogWarn("Got type: " + io.Type); - err = MetaIoError.TYPE_DONT_MATCH; - return false; - } - } - - ulong nextUint64(ref MetaIoError err) - { - if(!ContainerPositionValid()) - { - err = MetaIoError.DATA_MISSING; - return 0; - } - - if(!io.Read()) - { - err = MetaIoError.FAIL_READ; - return 0; - } - - ContainerPositionMoveNext(); - - if(io.IsUnsigned()) - return io.ValueUnsigned; - else if(io.IsSigned()) - return (ulong)io.ValueSigned; - else if(io.IsUnsigned64()) - return io.ValueUnsigned64; - else if(io.IsSigned64()) - return (ulong)io.ValueSigned64; - else - { - Meta.LogWarn("Got type: " + io.Type); - err = MetaIoError.TYPE_DONT_MATCH; - return 0; - } - } - - long nextInt64(ref MetaIoError err) - { - if(!ContainerPositionValid()) - { - err = MetaIoError.DATA_MISSING; - return 0; - } - - if(!io.Read()) - { - err = MetaIoError.FAIL_READ; - return 0; - } - - ContainerPositionMoveNext(); - - if(io.IsUnsigned()) - return (long)io.ValueUnsigned; - else if(io.IsSigned()) - return io.ValueSigned; - else if(io.IsUnsigned64()) - return (long)io.ValueUnsigned64; - else if(io.IsSigned64()) - return io.ValueSigned64; - else - { - Meta.LogWarn("Got type: " + io.Type); - err = MetaIoError.TYPE_DONT_MATCH; - return 0; - } - } - - public MetaIoError ReadI8(ref sbyte v) - { - MetaIoError err = 0; - v = (sbyte) nextInt(ref err); - return err; - } - - public MetaIoError ReadI16(ref short v) - { - MetaIoError err = 0; - v = (short) nextInt(ref err); - return err; - } - - public MetaIoError ReadI32(ref int v) - { - MetaIoError err = 0; - v = nextInt(ref err); - return err; - } - - public MetaIoError ReadU8(ref byte v) - { - MetaIoError err = 0; - v = (byte) nextUint(ref err); - return err; - } - - public MetaIoError ReadU16(ref ushort v) - { - MetaIoError err = 0; - v = (ushort) nextUint(ref err); - return err; - } - - public MetaIoError ReadU32(ref uint v) - { - MetaIoError err = 0; - v = nextUint(ref err); - return err; - } - - public MetaIoError ReadU64(ref ulong v) - { - MetaIoError err = 0; - v = nextUint64(ref err); - return err; - } - - public MetaIoError ReadI64(ref long v) - { - MetaIoError err = 0; - v = nextInt64(ref err); - return err; - } - - public MetaIoError ReadBool(ref bool v) - { - MetaIoError err = 0; - v = nextBool(ref err); - return err; - } - - public MetaIoError ReadFloat(ref float v) - { - if(!ContainerPositionValid()) - return MetaIoError.DATA_MISSING; - - if(!io.Read()) - { - return MetaIoError.FAIL_READ; - } - - if(io.IsUnsigned()) - { - v = io.ValueUnsigned; - } - else if(io.IsSigned()) - { - v = io.ValueSigned; - } - else - { - switch(io.Type) - { - case TypePrefixes.Float: - v = io.ValueFloat; - break; - case TypePrefixes.Double: - var tmp = io.ValueDouble; - //TODO: - //if(tmp > float.MaxValue || tmp < float.MinValue) - //{ - // Meta.LogWarn("Double -> Float bad conversion: " + tmp); - // return MetaIoError.TYPE_DONT_MATCH; - //} - v = (float) tmp; - break; - default: - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - } - ContainerPositionMoveNext(); - return 0; - } - - public MetaIoError ReadDouble(ref double v) - { - if(!ContainerPositionValid()) - return MetaIoError.DATA_MISSING; - - if(!io.Read()) - { - return MetaIoError.FAIL_READ; - } - - if(io.IsUnsigned()) - { - v = io.ValueUnsigned; - } - else if(io.IsSigned()) - { - v = io.ValueSigned; - } - else - { - switch(io.Type) - { - case TypePrefixes.Float: - v = (double) io.ValueFloat; - break; - case TypePrefixes.Double: - v = io.ValueDouble; - break; - case TypePrefixes.UInt64: - v = (double) io.ValueUnsigned64; - break; - case TypePrefixes.Int64: - v = (double) io.ValueSigned64; - break; - default: - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - } - ContainerPositionMoveNext(); - return 0; - } - - public MetaIoError ReadRaw(ref byte[] v, ref int vlen) - { - if(!ContainerPositionValid()) - return MetaIoError.DATA_MISSING; - - if(!io.Read()) - return MetaIoError.FAIL_READ; - - if(!io.IsRaw()) - { - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - - vlen = (int)io.Length; - if(v == null) - v = new byte[vlen]; - else if(v.Length < vlen) - Array.Resize(ref v, vlen); - io.ReadValueRaw(v, 0, vlen); - ContainerPositionMoveNext(); - return 0; - } - - public MetaIoError ReadNil() - { - if(!ContainerPositionValid()) - return MetaIoError.DATA_MISSING; - - if(!io.Read()) - return MetaIoError.FAIL_READ; - - if(io.Type != TypePrefixes.Nil) - { - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - - ContainerPositionMoveNext(); - return 0; - } - - public MetaIoError ReadString(ref string v) - { - if(!ContainerPositionValid()) - return MetaIoError.DATA_MISSING; - - if(!io.Read()) - return MetaIoError.FAIL_READ; - - if(!io.IsRaw()) - { - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - - //TODO: use shared buffer for strings loading - byte[] strval = new byte[io.Length]; - io.ReadValueRaw(strval, 0, strval.Length); - v = System.Text.Encoding.UTF8.GetString(strval); - ContainerPositionMoveNext(); - return 0; - } - - public MetaIoError BeginContainer() - { - if(!ContainerPositionValid()) - return MetaIoError.DATA_MISSING; - - if(!io.Read()) - return MetaIoError.FAIL_READ; - - if(!io.IsArray()) - { - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - - ContainerPosition ap = new ContainerPosition((int)io.Length); - stack.Push(ap); - return 0; - } - - public MetaIoError GetContainerSize(ref int v) - { - if(!io.IsArray()) - { - Meta.LogWarn("Got type: " + io.Type); - return MetaIoError.TYPE_DONT_MATCH; - } - - v = (int) io.Length; - return 0; - } - - void SkipField() - { - if(!io.Read()) - return; - - if(!io.IsArray() && !io.IsMap()) - { - //NOTE: if value is a raw string we need to read all of its data - if(io.IsRaw()) - io.ReadRawString(); - return; - } - - uint array_len = io.Length; - for(uint i=0; i -1) - { - SkipField(); - ContainerPositionMoveNext(); - } - } - - public MetaIoError EndContainer() - { - SkipTrailingFields(); - stack.Pop(); - ContainerPositionMoveNext(); - return 0; - } - - int ContainerEntriesLeft() - { - if(stack.Count == 0) - return 0; - ContainerPosition ap = stack.Peek(); - return ap.max - ap.curr; - } - - bool ContainerPositionValid() - { - return ContainerEntriesLeft() >= 0; - } - - void ContainerPositionMoveNext() - { - if(stack.Count > 0) - { - ContainerPosition ap = stack.Pop(); - ap.curr++; - stack.Push(ap); - } - } -} - -} //namespace metagen diff --git a/targets/go/go.inc.php b/targets/go/go.inc.php deleted file mode 100644 index 66c2602..0000000 --- a/targets/go/go.inc.php +++ /dev/null @@ -1,628 +0,0 @@ -object; - if($obj instanceof mtgMetaRPC) - return $this->genRPC($obj); - if($obj instanceof mtgMetaEnum) - return $this->genEnum($obj); - else if($obj instanceof mtgMetaStruct) - return $this->genStruct($obj); - else - { - echo "WARN: skipping meta unit '{$obj->getId()}'\n"; - return ''; - } - } - - function genEnum(mtgMetaEnum $struct) - { - $templater = new mtg_go_templater(); - - $repl = array(); - $repl['%class%'] = $struct->getName(); - $repl['%class_id%'] = $struct->getClassId(); - - $tpl = $templater->tpl_enum(); - - $this->fillEnumRepls($struct, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function fillEnumRepls(mtgMetaEnum $enum, &$repl) - { - $repl['%values%'] = ''; - $repl['%vnames_list%'] = ''; - $repl['%values_list%'] = ''; - - $vnames = array(); - $values = array(); - $values_map = array(); - $default_value = null; - $consts = array(); - - $enum_name = $enum->getName(); - $map = array(); - foreach($enum->getValues() as $vname => $value) - { - $map[$vname] = $value; - $vnames[] = "'$vname'"; - $values[] = $value; - if(!$default_value) - $default_value = "$value; // $vname"; - $consts[$value] = "{$enum->getName()}_{$vname} {$enum->getName()} = $value"; - } - - // must be sorted - sort($values, SORT_NUMERIC); - - $repl['%vnames_list%'] = implode(',', $vnames); - $repl['%values_list%'] = implode(',', $values); - $repl['%values_map%'] = $this->genIntMap($map); - $repl['%default_enum_value%'] = $default_value; - $repl['%consts%'] = "\n " . implode("\n ", $consts) . "\n"; - } - - function preprocessField(mtgMetaStruct $struct, mtgMetaField $field) {} - - function genRPC(mtgMetaRPC $rpc) - { - return $this->genRPCPacket($rpc->getReq()) . - $this->genRPCPacket($rpc->getRsp()) . - $this->genRPCReqResp($rpc); - } - - function genRPCReqResp(mtgMetaRPC $rpc) - { - $templater = new mtg_go_templater(); - - $repl = array(); - $repl['%code%'] = $rpc->getCode(); - $repl['%rpc_name%'] = $rpc->getName(); - $repl['%rpc_req_name%'] = $rpc->getReq()->getName(); - $repl['%rpc_rsp_name%'] = $rpc->getRsp()->getName(); - - $tpl = $templater->tpl_rpc(); - return mtg_fill_template($tpl, $repl); - } - - function genRPCPacket(mtgMetaPacket $packet) - { - $templater = new mtg_go_templater(); - - $repl = array(); - $repl['%type%'] = $packet->getName(); - $repl['%code%'] = $packet->getNumericCode(); - $repl['%class%'] = $packet->getName(); - $repl['%class_id%'] = $packet->getClassId(); - $repl['%parent_class%'] = ''; - - if(strpos($packet->getName(), '_RSP_') !== false) - $repl['%class_invert%'] = str_replace('_RSP_', '_REQ_', $packet->getName()); - else - $repl['%class_invert%'] = str_replace('_REQ_', '_RSP_', $packet->getName()); - - $fields = $packet->getFields(); - - $tpl = $templater->tpl_packet(); - - $this->fillStructRepls($packet, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function genStruct(mtgMetaStruct $struct) - { - $templater = new mtg_go_templater(); - - $repl = array(); - $repl['%class%'] = $struct->getName(); - $repl['%class_id%'] = $struct->getClassId(); - $repl['%parent_class%'] = $struct->getParent() ? ''.$struct->getParent() : ""; - - $tpl = $templater->tpl_struct(); - - $this->fillStructRepls($struct, $repl); - - $result = mtg_fill_template($tpl, $repl); - - if($struct->hasToken("id") && $struct->hasToken("table") && $struct->hasToken("owner")) - $result .= "\n" . str_replace(array_keys($repl), array_values($repl), $templater->tpl_collection_item()); - return $result; - } - - function fillStructRepls(mtgMetaStruct $struct, &$repl) - { - foreach($struct->getFields() as $field) - $this->preprocessField($struct, $field); - - $repl['%includes%'] = ''; - $repl['%fields%'] = ''; - $repl['%fields_names%'] = '[]string{'; - $repl['%fields_props%'] = 'map[string]map[string]string{'; - $repl['%fields_types%'] = 'map[string]string{'; - $repl['%fields_reset%'] = ''; - $repl['%read_buffer%'] = ''; - $repl['%write_buffer%'] = ''; - $repl['%total_top_fields%'] = sizeof($struct->getFields()); - $repl['%ext_methods%'] = ""; - $repl['%analytics_methods%'] = ""; - - $repl['%class_props%'] = 'map[string]string{' . $this->genStrMap($struct->getTokens()) . '}'; - - if($struct->hasToken("bitfields")) - { - $repl['%read_buffer%'] .= "\n use_mask, mask, err := reader.TryReadMask()\n"; - $repl['%read_buffer%'] .= "\n if err != nil {\n"; - $repl['%read_buffer%'] .= "\n return err\n"; - $repl['%read_buffer%'] .= "\n }\n"; - $repl['%read_buffer%'] .= "\n self.fieldsMask = mask\n"; - } - - $parent = $struct->getParent(); - $all_fields = mtg_get_all_fields($this->info, $struct); - - foreach($all_fields as $field) - { - $name = $field->getName(); - $repl['%fields_names%'] .= '"' . $name . '",'; - $repl['%fields_props%'] .= '"' . $this->genFieldName($field) . '" : map[string]string{' . $this->genStrMap($field->getTokens()) . "},"; - $field_type = $field->getType(); - $repl['%fields_types%'] .= '"' . $name . '" : "' . $field_type . '",'; - } - if($struct->hasToken('statist')) - { - $table_name = $struct->getToken('statist'); - - $repl['%analytics_methods%'] .= "func (self *".$struct->getName().") Table() string {\n"; - $repl['%analytics_methods%'] .= "\t return \"$table_name\"\n"; - $repl['%analytics_methods%'] .= "}\n"; - - $repl['%analytics_methods%'] .= "func (self *".$struct->getName().") Columns() []string {\n"; - $repl['%analytics_methods%'] .= "\treturn []string{\n"; - foreach($all_fields as $field) - { - if ($field->hasToken('statist_skip')) - continue; - - $column_name = $field->hasToken('statist_alias') ? $field->getToken('statist_alias') : $field->getName(); - - $repl['%analytics_methods%'] .= "\t\t\"$column_name\",\n"; - } - $repl['%analytics_methods%'] .= "\t}\n"; - $repl['%analytics_methods%'] .= "}\n"; - - $repl['%analytics_methods%'] .= "func (self *".$struct->getName().") Values() []interface{} {\n"; - $repl['%analytics_methods%'] .= "\treturn []interface{}{\n"; - foreach($all_fields as $field) - { - if ($field->hasToken('statist_skip')) - continue; - - $repl['%analytics_methods%'] .= "\t\tself." . ucfirst($field->getName()) . ",\n"; - } - $repl['%analytics_methods%'] .= "\t}\n"; - $repl['%analytics_methods%'] .= "}\n"; - } - - $repl['%read_buffer%'] .= "\n _cont_size, err := reader.GetContainerSize()"; - $repl['%read_buffer%'] .= "\n if err != nil {"; - $repl['%read_buffer%'] .= "\n return err"; - $repl['%read_buffer%'] .= "\n }"; - - $optional = 0; - foreach($struct->getFields() as $field) - { - if($field->hasToken('optional')) - $optional++; - } - $initial_fields_amount = count($struct->getFields()) - $optional; - $repl['%read_buffer%'] .= "\n if _cont_size < $initial_fields_amount {"; - $repl['%read_buffer%'] .= "\n _cont_size = $initial_fields_amount"; - $repl['%read_buffer%'] .= "\n }"; - - if($struct->hasToken('POD')) - { - $fields = $all_fields; - } - else - { - if($parent = $struct->getParent()) - { - $repl['%read_buffer%'] .= "\n if err := self." . $parent . ".ReadFields(reader); err != nil { return err }"; - $repl['%write_buffer%'] .= "\n if err := self." . $parent . ".WriteFields(writer); err != nil { return err }"; - } - $fields = $struct->getFields(); - } - - $field_index = -1; - foreach($fields as $field) - { - ++$field_index; - $options = $this->readFieldOptions($field); - - $repl['%fields%'] .= "\n " . $this->genFieldDecl($field); - $repl['%fields_reset%'] .= "\n " . $this->genFieldReset($field); - $repl['%read_buffer%'] .= "\n if _cont_size <= 0 {"; - $repl['%read_buffer%'] .= "\n return nil"; - $repl['%read_buffer%'] .= "\n }"; - if($struct->hasToken("bitfields")) - $repl['%read_buffer%'] .= "\n if !use_mask {"; - $repl['%read_buffer%'] .= "\n _cont_size--"; - if($struct->hasToken("bitfields")) - $repl['%read_buffer%'] .= "\n }"; - if($struct->hasToken("bitfields")) - $repl['%read_buffer%'] .= "\n if !use_mask || (use_mask && self.HasValue($field_index)) {"; - $repl['%read_buffer%'] .= "\n " . $this->genBufRead($field->getName(), $options['fname'], $field->getType(), $options['buf'], $field->getTokens()); - if($struct->hasToken("bitfields")) - $repl['%read_buffer%'] .= "\n }"; - $repl['%write_buffer%'] .= "\n " . $this->genBufWrite($field, "writer", $field->hasToken("virtual")); - } - - $repl['%fields%'] = trim($repl['%fields%'], "\n "); - - $repl['%fields_names%'] .= '}'; - $repl['%fields_props%'] .= '}'; - $repl['%fields_types%'] .= '}'; - - $repl['%import_from_mysql%'] = ''; - $repl["%export_to_arr%"] = ""; - if($struct->hasToken("table")) - { - $ind = 0; - - $repl['%import_from_mysql%'] .= "\n row := data.(".$struct->getName().")"; - foreach($all_fields as $field) - { - $name = $this->genFieldName($field); - $repl['%import_from_mysql%'] .= sprintf("\n self.%s = row.%s", $name, $name); - $repl['%export_to_arr%'] .= sprintf("\n data[%d] = self.%s", $ind, $name); - $ind++; - } - } - - $repl["%table_name%"] = $struct->getToken("table"); - $repl["%owner%"] = $struct->getToken("owner"); - $repl["%id_field_name%"] = $struct->getToken("id"); - $repl["%id_field%"] = ucfirst($struct->getToken("id")); - - if($struct->hasToken("bitfields")) - { - $repl['%fields%'] .= "\nfieldsMask uint64\n"; - - $repl['%fields_reset%'] .= "\nself.fieldsMask = 0\n"; - - $repl['%ext_methods%'] .= "func(self *".$struct->getName().") HasValue(index uint64) bool {\n"; - $repl['%ext_methods%'] .= " value := uint64(1 << index)\n"; - $repl['%ext_methods%'] .= " return (self.fieldsMask & value) > 0\n"; - $repl['%ext_methods%'] .= "}\n"; - - $repl['%ext_methods%'] .= "func(self *".$struct->getName().") SetFieldChanged(index uint64) {\n"; - $repl['%ext_methods%'] .= " value := uint64(1 << index)\n"; - $repl['%ext_methods%'] .= " self.fieldsMask |= value\n"; - $repl['%ext_methods%'] .= "}\n"; - - $repl['%ext_methods%'] .= "func(self *".$struct->getName().") IsMaskFilled() bool {\n"; - $repl['%ext_methods%'] .= " return self.fieldsMask > 0\n"; - $repl['%ext_methods%'] .= "}\n"; - - $repl['%ext_methods%'] .= "func(self *".$struct->getName().") GetMask() uint64 {\n"; - $repl['%ext_methods%'] .= " return self.fieldsMask\n"; - $repl['%ext_methods%'] .= "}\n"; - } - } - - function readFieldOptions(mtgMetaField $field) - { - return array( - 'fname' => 'self.'.ucfirst($field->getName()), - 'buf' => "reader", - ); - } - - function genReadBuiltinField($name, $fname, mtgType $type, $buf, array $tokens) - { - return $this->genRead($tokens, $buf.'.Read'.$this->genBuiltinTypePrefix($type).'(&'.$fname.', "'.$name.'")'); - } - - function genBufRead($name, $fname, mtgType $type, $buf, array $tokens = array(), $is_ptr = false) - { - $str = ''; - - if($type instanceof mtgBuiltinType) - { - $str .= $this->genReadBuiltinField($name, $fname, $type, $buf, $tokens); - } - else if($type instanceof mtgMetaEnum) - { - $str .= $this->genRead($tokens, "{$buf}.ReadI32((*int32)(&{$fname}), \"$name\")"); - $str .= "\n if !{$fname}.IsValid() { return errors.Errorf(\"Bad enum value %d for $name\", $fname) }"; - } - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - $str .= "if v, err := meta.ReadStructGeneric($buf, CreateById, \"{$name}\"); err != nil { return err } else { {$fname} = v.(I{$type}) }"; - else - $str .= $this->genRead($tokens, "meta.ReadStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")"); - } - else if($type instanceof mtgArrType) - { - $is_virtual = array_key_exists("virtual", $tokens); - $native_type = $this->genNativeType($type->getValue(), $tokens); - $offset = "\n "; - $str .= "/*[]{$name}*/"; - $str .= $offset . $this->genRead($tokens, "{$buf}.BeginContainer(\"$name\")"); - //we don't want to propagate 'optionalness' below - unset($tokens['optional']); - $str .= $offset . "_{$name}_size, err := {$buf}.GetContainerSize()"; - $str .= $offset . "if err != nil { return err }"; - - $need_new = !$is_virtual && $type->getValue() instanceof mtgMetaStruct; - - $str .= $offset . "for ; _{$name}_size > 0; _{$name}_size-- {"; - $offset = "\n "; - $str .= $offset . "var tmp_{$name} {$native_type}"; - - $str .= $offset . $this->genBufRead("", "tmp_{$name}", $type->getValue(), $buf, $tokens, $is_virtual); - $str .= $offset . "{$fname} = append({$fname}, ".($need_new?"&":"")."tmp_{$name})"; - - $offset = "\n "; - $str .= $offset . "}"; - $str .= $offset . $this->genRead($tokens, "{$buf}.EndContainer()"); - $str .= "\n"; - } - else - throw new Exception("Unknown type '{$type}'"); - - return $str; - } - - function genRead(array $tokens, $op) - { - return "if err := $op; err != nil { return " . (array_key_exists("optional", $tokens) ? "/*optional*/nil" : "err"). " }"; - } - - function genWrite($op) - { - return "if err := $op; err != nil { return err }"; - } - - function genBufWrite(mtgMetaField $field, $buf, $is_ptr = false) - { - return $this->genBufWriteEx($field->getName(), "self.".ucfirst($field->getName()), $field->getType(), $buf, $field->getTokens(), $is_ptr); - } - - function genBufWriteEx($name, $fname, mtgType $type, $buf, array $tokens = array(), $is_ptr = false) - { - $str = ''; - - if($type instanceof mtgBuiltinType) - { - $str .= $this->genWrite("{$buf}.Write".$this->genBuiltinTypePrefix($type)."($fname, \"$name\")")."\n"; - } - else if($type instanceof mtgMetaEnum) - { - $str .= $this->genWrite("{$buf}.WriteI32(int32($fname), \"$name\")"); - } - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - $str .= $this->genWrite("meta.WriteStructGeneric($buf, ".($is_ptr?"":"&")."$fname, \"$name\")"); - else - $str .= $this->genWrite("meta.WriteStruct($buf, ".($is_ptr?"":"&")."$fname, \"$name\")"); - } - else if($type instanceof mtgArrType) - { - $is_virtual = array_key_exists("virtual", $tokens); - - $str .= "{$buf}.BeginContainer(\"{$name}\")\n"; - $str .= " for _, v := range({$fname}) {\n"; - $str .= " ".$this->genBufWriteEx("", "v", $type->getValue(), $buf, $tokens, true)."\n"; - $str .= " }\n"; - $str .= " ".$this->genWrite("{$buf}.EndContainer()")."\n"; - } - else - throw new Exception("Unknown type '$type'"); - - return $str; - } - - function genFieldDecl(mtgMetaField $field) - { - return $this->genFieldName($field) . " " . - $this->genFieldNativeType($field) . - ($field->getName()[0] != '_' ? " `json:\"{$field->getName()}\"`" : "") - ; - } - - function genFieldName(mtgMetaField $field) - { - return ucfirst($field->getName()); - } - - function genFieldReset(mtgMetaField $field) - { - $tokens = $field->getTokens(); - - $str = ''; - $name = $this->genFieldName($field); - - $type = $field->getType(); - - if($type instanceof mtgBuiltinType) - { - if($type->isNumeric()) - { - //NOTE: numeric check is against str2num - if(array_key_exists('default', $tokens) && is_numeric($tokens['default'])) - $str .= "self.$name = ".$tokens['default']; - else - $str .= " self.$name = 0"; - } - else if($type->isString()) - { - if(array_key_exists('default', $tokens)) - $str .= "self.$name = ".$tokens['default']; - else - $str .= "self.$name = \"\""; - } - else if($type->isBool()) - { - if(array_key_exists('default', $tokens)) - $str .= "self.$name = ".$tokens['default']; - else - $str .= "self.$name = false"; - } - else if($type->isBlob()) - { - if(array_key_exists('default', $tokens)) - $str .= "self.$name = ".$tokens['default']; - else - $str .= "self.$name = nil"; - } - else - throw new Exception("Unknown type '$type'"); - } - else if($type instanceof mtgArrType) - { - $str = "if self.$name == nil { \nself.$name = make(".$this->genFieldNativeType($field).",0) \n}\n "; - $str .= "self.$name = self.{$name}[0:0]"; - } - else if($type instanceof mtgMetaEnum) - { - if(array_key_exists('default', $tokens)) - $str = "self.$name = ".$this->genFieldNativeType($field)."_".trim($tokens['default'], '"'); - else - $str = "self.$name = 0"; - } - else if($type instanceof mtgMetaStruct) - { - $is_virtual = array_key_exists("virtual", $tokens); - if($is_virtual) - $str .= "self.$name = New".ltrim($this->genFieldNativeType($field),'I')."() "; - else - $str .= "self.$name.Reset()"; - } - else - throw new Exception("Unknown type '$type'"); - return $str; - } - - function genFieldNativeType(mtgMetaField $field) - { - return $this->genNativeType($field->getType(), $field->getTokens()); - } - - function genNativeType(mtgType $type, array $tokens = array()) - { - if($type instanceof mtgArrType) - { - $vtype = $type->getValue(); - - $native = $this->genNativePlainType($vtype); - - $str = "[]"; - if(array_key_exists("virtual", $tokens)) - $str .= "I"; - else - $str .= $vtype instanceof mtgMetaStruct ? "*" : ""; - - $str .= $native; - - return $str; - } - else - return $this->genNativePlainType($type, $tokens); - } - - function genBuiltinTypePrefix(mtgBuiltinType $type) - { - switch($type->getName()) - { - case "string": - return "String"; - case "bool": - return "Bool"; - case "blob": - return "Blob"; - case "float": - return "Float"; - case "double": - return "Double"; - case "uint64": - return "U64"; - case "int64": - return "I64"; - case "uint": - case "uint32": - return "U32"; - case "uint16": - return "U16"; - case "uint8": - return "U8"; - case "int": - case "int32": - return "I32"; - case "int16": - return "I16"; - case "int8": - return "I8"; - default: - throw new Exception("Unknown type '{$type}'"); - } - } - - function genNativePlainType(mtgType $type, array $tokens = array()) - { - if($type instanceof mtgBuiltinType) - { - if($type->isFloat()) - return "float32"; - else if($type->isDouble()) - return "float64"; - else if($type->isBlob()) - return "[]byte"; - else - return $type->getName(); - } - else if($type instanceof mtgMetaEnum) - return $type->getName(); - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists("virtual", $tokens)) - return "I{$type->getName()}"; - else - return $type->getName(); - } - else - throw new Exception("Unknown type '$type'"); - } - - function genStrMap(array $source) - { - $str = ''; - foreach($source as $k => $v) - $str .= '"' . $k . '": "' . ($v ? str_replace('"', '\\"', $v) : "") . '",'; - return $str; - } - - function genIntMap(array $source) - { - $str = ''; - foreach($source as $k => $v) - $str .= "\"$k\": {$v},"; - return $str; - } - - function offset($num = 1) - { - return str_repeat(" ", $num); - } -} diff --git a/targets/go/go_generator.inc.php b/targets/go/go_generator.inc.php deleted file mode 100644 index bf7ca6b..0000000 --- a/targets/go/go_generator.inc.php +++ /dev/null @@ -1,93 +0,0 @@ -setMetaInfo($meta); - - $refl = new ReflectionClass($codegen); - $SHARED_DEPS = array( - dirname(__FILE__) . '/go.inc.php', - dirname(__FILE__) . '/go_tpl.inc.php', - __FILE__, - $refl->getFileName() - ); - - mtg_mkdir(mtg_conf('out-dir')); - - $units = $meta->getUnits(); - $files = array(); - foreach($units as $unit) - $files = array_merge($files, mtg_get_file_deps($meta, $unit)); - $files = array_unique($files); - - $bundle = mtg_conf("bundle", null); - if($bundle && $units) - { - $targets[] = mtg_new_bundle($bundle, - array_merge($SHARED_DEPS, $files), - array('gen_go_bundle', $meta, $codegen, $units)); - } - - return $targets; - } -} - -function gen_go_struct($OUT, array $DEPS, mtgCodegen $codegen, mtgMetaInfoUnit $unit) -{ - return $codegen->genUnit($unit); -} - -function gen_go_bundle($OUT, array $DEPS, mtgMetaInfo $meta, mtgGoCodegen $codegen, array $units) -{ - $bundle = ''; - $units_src = ''; - $create_struct_by_crc28 = ''; - $create_struct_by_name = ''; - $create_rpc_by_code = ''; - - foreach($units as $unit) - { - if($unit->object instanceof mtgMetaEnum || - $unit->object instanceof mtgMetaStruct || - $unit->object instanceof mtgMetaRPC - ) - $units_src .= $codegen->genUnit($unit); - } - - foreach($units as $unit) - { - if($unit->object instanceof mtgMetaRPC) - { - $rpc = $unit->object; - $create_rpc_by_code .= "\n case {$rpc->getCode()}: { return New{$rpc->getName()}(), nil; }"; - continue; - } - - if($unit->object->hasToken('POD') || - $unit->object instanceof mtgMetaFunc || - $unit->object instanceof mtgMetaEnum - ) - continue; - - $create_struct_by_crc28 .= "\n case {$unit->object->getClassId()}: { return New{$unit->object->getName()}(), nil }"; - $create_struct_by_name .= "\n case \"{$unit->object->getName()}\": { return New{$unit->object->getName()}(), nil }"; - } - - $templater = new mtg_go_templater(); - $tpl = $templater->tpl_bundle(); - return mtg_fill_template($tpl, - array('%bundle%' => $bundle, - '%units_src%' => $units_src, - '%create_struct_by_name%' => $create_struct_by_name, - '%create_struct_by_crc28%' => $create_struct_by_crc28, - '%create_rpc_by_code%' => $create_rpc_by_code, - )); -} diff --git a/targets/go/go_tpl.inc.php b/targets/go/go_tpl.inc.php deleted file mode 100644 index faf599e..0000000 --- a/targets/go/go_tpl.inc.php +++ /dev/null @@ -1,402 +0,0 @@ -filter_aliases = $filter_aliases; - } - - function genUnit(mtgMetaInfoUnit $unit) - { - $obj = $unit->object; - if($obj instanceof mtgMetaRPC) - return $this->genRPC($obj); - if($obj instanceof mtgMetaEnum) - return $this->genEnum($obj); - else if($obj instanceof mtgMetaStruct) - return $this->genStruct($obj); - else - { - echo "WARN: skipping meta unit '{$obj->getId()}'\n"; - return ''; - } - } - - function genEnum(mtgMetaEnum $struct) - { - $templater = new mtg_php_templater(); - - $repl = array(); - $repl['%class%'] = $struct->getName(); - $repl['%class_id%'] = $struct->getClassId(); - - $tpl = $templater->tpl_enum(); - - $this->fillEnumRepls($struct, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function fillEnumRepls(mtgMetaEnum $enum, &$repl) - { - $repl['%values%'] = ''; - $repl['%vnames_list%'] = ''; - $repl['%values_list%'] = ''; - - $vnames = array(); - $values = array(); - $txt_values = array(); - $values_map = array(); - $names_map = array(); - $default_value = null; - - $enum_name = $enum->getName(); - foreach($enum->getValues() as $vname => $value) - { - $txt_values[] = "const $vname = $value;"; - $vnames[] = "'$vname'"; - $values[] = $value; - $values_map[] = "'$vname' => $value"; - $names_map[] = "$value => '$vname'"; - if(!$default_value) - $default_value = "$value; // $vname"; - } - - $repl['%values%'] = implode("\n ", $txt_values); - $repl['%vnames_list%'] = implode(',', $vnames); - $repl['%values_list%'] = implode(',', $values); - $repl['%values_map%'] = implode(',', $values_map); - $repl['%names_map%'] = implode(',', $names_map); - $repl['%default_enum_value%'] = $default_value; - } - - function genRPC(mtgMetaRpc $rpc) - { - $req = $this->genRPCPacket($rpc->getReq()); - $rsp = $this->genRPCPacket($rpc->getRsp()); - return $req . str_replace('getName(); - $repl['%code%'] = $packet->getNumericCode(); - $repl['%class%'] = $packet->getName(); - $repl['%class_id%'] = $packet->getClassId(); - $repl['%parent_class%'] = 'extends mtgStrictPropsObject'; - - $tpl = $templater->tpl_packet(); - - $this->fillStructRepls($packet, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function genStruct(mtgMetaStruct $struct) - { - $templater = new mtg_php_templater(); - - $repl = array(); - $repl['%class%'] = $struct->getName(); - $repl['%class_id%'] = $struct->getClassId(); - $repl['%parent_class%'] = $struct->getParent() ? "extends " . $struct->getParent() : "extends mtgStrictPropsObject"; - - $tpl = $templater->tpl_struct(); - - $this->fillStructRepls($struct, $repl); - - return mtg_fill_template($tpl, $repl); - } - - function preprocessField(mtgMetaStruct $struct, mtgMetaField $field) - {} - - function fillStructRepls(mtgMetaStruct $struct, &$repl) - { - foreach($struct->getFields() as $field) - $this->preprocessField($struct, $field); - - $parent = $struct->getParent(); - - $repl['%includes%'] = ''; - $repl['%fields%'] = ''; - $repl['%fields_names%'] = ($parent ? 'array_merge(parent::CLASS_FIELDS(), ' : '') . 'array('; - $repl['%fields_props%'] = ($parent ? 'array_merge(parent::CLASS_FIELDS_PROPS(), ' : '') . 'array('; - $repl['%fields_types%'] = ($parent ? 'array_merge(parent::CLASS_FIELDS_TYPES(), ' : '') . 'array('; - $repl['%fields_init%'] = ''; - $repl['%fill_fields%'] = ''; - $repl['%fill_buffer%'] = ''; - $repl['%total_top_fields%'] = sizeof($struct->getFields()); - $repl["%ext_methods%"] = ""; - - $repl['%class_props%'] = str_replace("\n", "", var_export($struct->getTokens(), true)); - - $deps = array(); - if($parent) - $deps[] = $parent.''; - foreach($struct->getFields() as $field) - { - $type = $field->getType(); - if($type instanceof mtgArrType) - $type = $type->getValue(); - - if($type instanceof mtgUserType) - $deps[] = $type->getName(); - } - $deps = array_unique($deps); - - foreach($deps as $dep) - $repl['%includes%'] .= "require_once(dirname(__FILE__) . '/$dep.class.php');\n"; - - if($parent) - { - $repl['%fields_init%'] .= "parent::__construct();\n"; - $repl['%fill_fields%'] .= "\$IDX = parent::import(\$message, \$assoc, false);\n"; - $repl['%fill_buffer%'] .= "\$__last_var = 'parent';\$__last_val='<>';parent::fill(\$message, \$assoc, false);\n"; - } - - $indent = " "; - $local_indent = " "; - $fill_func_indent = " "; - - foreach($struct->getFields() as $field) - { - $repl['%fields_names%'] .= "'" . $field->getName() . "',"; - $repl['%fields_props%'] .= "'" . $field->getName() . "' => " . str_replace("\n", "", var_export($field->getTokens(), true)) . ","; - $field_type = $field->getType(); - $repl['%fields_types%'] .= "'" . $field->getName() . "' => '" . $field_type . "',"; - - $repl['%fields_init%'] .= $this->genFieldInit($field, ' $this->') . "\n"; - $repl['%fill_fields%'] .= $local_indent.$this->genFieldFill($field, '$message', '$this->', $indent) . $indent."++\$IDX;\n"; - $repl['%fill_buffer%'] .= $this->genBufFill($field, '$message', '$this->', $fill_func_indent) . "\n"; - $repl['%fields%'] .= $this->genFieldDecl($field) . "\n"; - } - - $repl['%fields_names%'] .= ')' . ($parent ? ')' : ''); - $repl['%fields_props%'] .= ')' . ($parent ? ')' : ''); - $repl['%fields_types%'] .= ')' . ($parent ? ')' : ''); - - $this->undoTemp(); - } - - function genFieldInitValue(mtgMetaField $field) - { - $tokens = $field->getTokens(); - $name = $field->getName(); - $type = $field->getType(); - - if($type instanceof mtgMetaStruct) - { - return "new {$type}()"; - } - else if($type instanceof mtgMetaEnum) - { - if(array_key_exists('default', $tokens)) - $default = $this->genDefault($tokens['default']); - else - $default = 'DEFAULT_VALUE'; - - $default = str_replace('"', '', $default); - return "{$type}::$default"; - } - else if($type instanceof mtgArrType) - { - return "array()"; - } - else if($type instanceof mtgBuiltinType) - { - if(array_key_exists('default', $tokens)) - { - $raw_default_value = $this->genDefault($tokens['default']); - $default_value = $this->genApplyFieldFilters($name, $tokens, $raw_default_value, false); - return "mtg_php_val_{$type}($default_value)"; - } - if ($type->isString()) - return "''"; - return '0'; - } - else - throw new Exception("Unable generate field initial value for unknown type '{$type}'"); - } - - function genFieldInit(mtgMetaField $field, $prefix = "") - { - $value = $this->genFieldInitValue($field); - - return $prefix . $field->getName() . " = $value;"; - } - - function genFieldFill(mtgMetaField $field, $buf, $prefix, $indent = "") - { - return $this->genFieldFillEx($field->getName(), $field->getType(), $buf, $prefix, $field->getTokens(), false, "", $indent); - } - - function genFieldFillEx($name, mtgType $type, $buf, $prefix = '', $tokens = array(), $as_is = false, $postfix = '', $indent = "") - { - $str = ''; - $tmp_val = '$tmp_val__'; - $pname = $prefix.$name; - - $cond_indent = $indent." "; - - $default_value_arg = array_key_exists('default', $tokens) ? $this->genDefault($tokens['default']) : 'null'; - if($type instanceof mtgMetaStruct) - { - $default = array_key_exists('default', $tokens) ? $tokens['default'] : null; - if($default) - { - $default = json_decode($default, true); - if(!is_array($default)) - throw new Exception("Bad default struct: " . $tokens['default']); - $default = str_replace("\n", "", var_export($default, true)); - $default_value_arg = "\$assoc ? $default : array_values($default)"; - } - else - $default_value_arg = "null"; - } - - $str .= "\n"; - - if($as_is) - $tmp_val = $buf; - else - $str .= $indent."{$tmp_val} = mtg_php_array_extract_val({$buf}, \$assoc, '{$name}', {$default_value_arg});\n"; - - if($type instanceof mtgBuiltinType) - { - $str .= $cond_indent."{$tmp_val} = " . $this->genApplyFieldFilters($name, $tokens, "{$tmp_val}"). ";\n"; - $str .= $cond_indent."{$pname} = mtg_php_val_{$type}({$tmp_val});\n"; - } - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - { - $str .= $cond_indent."{$tmp_val} = " . $this->genApplyFieldFilters($name, $tokens, "{$tmp_val}"). ";\n"; - $str .= $cond_indent."\$tmp_sub_arr__ = mtg_php_val_arr({$tmp_val});\n"; - $str .= $cond_indent."\$vclass__ = AutogenBundle::getClassName(mtg_php_val_uint32(mtg_php_array_extract_val(\$tmp_sub_arr__, \$assoc, 'vclass__')));\n"; - $str .= $cond_indent."{$pname} = new \$vclass__(\$tmp_sub_arr__, \$assoc);\n"; - } - else - { - $str .= $cond_indent."{$tmp_val} = " . $this->genApplyFieldFilters($name, $tokens, "{$tmp_val}"). ";\n"; - $str .= $cond_indent."\$tmp_sub_arr__ = mtg_php_val_arr({$tmp_val});\n"; - $str .= $cond_indent."{$pname} = new {$type}(\$tmp_sub_arr__, \$assoc);\n"; - } - } - else if($type instanceof mtgArrType) - { - //TODO: maybe filters should be applied to the whole array as well? - $str .= $cond_indent."\$tmp_arr__ = mtg_php_val_arr({$tmp_val});\n"; - $str .= $cond_indent."foreach(\$tmp_arr__ as \$tmp_arr_item__)\n"; - $str .= $cond_indent."{\n"; - //NOTE: удаляем дефолтное значение уровня поля, а не его значений - unset($tokens['default']); - $str .= $this->genFieldFillEx('$tmp__', $type->getValue(), "\$tmp_arr_item__", '', $tokens, true, "{$pname}[] = \$tmp__;", $cond_indent." ") . "\n"; - $str .= $cond_indent."}\n"; - } - else if($type instanceof mtgMetaEnum) - { - $str .= $cond_indent."{$tmp_val} = " . $this->genApplyFieldFilters($name, $tokens, "{$tmp_val}"). ";\n"; - $check_enum_validity = array_key_exists('is_enum_mask', $tokens) ? 'false' : 'true'; - $str .= $cond_indent."{$pname} = mtg_php_val_enum('$type', {$tmp_val}, {$check_enum_validity});\n"; - } - else - throw new Exception("Unknown type '{$type}'"); - - if($postfix) - $str .= $cond_indent.$postfix."\n"; - - return $str; - } - - function genApplyFieldFilters($field_name, array $tokens, $val, $add_assoc_check = true) - { - $str = $val; - foreach($tokens as $token => $args_json) - { - if(isset($this->filter_aliases[$token])) - $token = $this->filter_aliases[$token]; - - if(strpos($token, 'flt_') === false) - continue; - - $filter_func = 'mtg_' . $token; - - if(function_exists($filter_func)) - { - $args = array(); - if($args_json) - { - $args = json_decode($args_json, true); - if(!is_array($args)) - throw new Exception("Bad filter args: $args_json"); - } - if($add_assoc_check) - $str = "(\$assoc ? $filter_func($str, '$field_name', \$this, " . str_replace("\n", "", var_export($args, true)) . ") : $str)"; - else - $str = "$filter_func($str, '$field_name', \$this, " . str_replace("\n", "", var_export($args, true)) . ")"; - } - else - throw new Exception("No such filter '$filter_func'"); - } - - return $str; - } - - function genBufFill(mtgMetaField $field, $buf, $prefix, $indent = "") - { - return $this->genBufFillEx($field->getName(), $field->getType(), $buf, $prefix, $field->getTokens(), $indent); - } - - function genBufFillEx($name, mtgType $type, $buf, $prefix = '', $tokens = array(), $indent = "") - { - $pname = $prefix.$name; - - $str = ''; - $str .= "\$__last_var = '$name';"; - $str .= "\$__last_val = $pname;"; - - if($type instanceof mtgBuiltinType) - { - if($type->isNumeric()) - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', 1*{$pname});"; - else if($type->isString()) - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', ''.{$pname});"; - else if($type->isBool()) - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', (bool){$pname});"; - else if($type->isBlob()) - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', {$pname});"; - else - throw new Exception("Unknown type '$type'"); - } - else if($type instanceof mtgMetaStruct) - { - if(array_key_exists('virtual', $tokens)) - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', is_array({$pname}) ? {$pname} : {$pname}->export(\$assoc, true/*virtual*/));"; - else - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', is_array({$pname}) ? {$pname} : {$pname}->export(\$assoc));"; - } - else if($type instanceof mtgMetaEnum) - { - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', 1*{$pname});"; - } - else if($type instanceof mtgArrType) - { - $str .= $indent."\$arr_tmp__ = array();\n"; - //NOTE: adding optimization, checking if the first item is array - $str .= $indent."if(!\$assoc && {$pname} && is_array(current({$pname})))\n"; - $str .= $indent."{\n"; - //$str .= " mtg_php_debug('BULK:' . get_class(\$this));\n"; - $str .= $indent." \$arr_tmp__ = {$pname};\n"; - $str .= $indent."}\n"; - $str .= $indent."else\n"; - $str .= $indent." foreach({$pname} as \$idx__ => \$arr_tmp_item__)\n"; - $str .= $indent." {\n"; - $str .= $this->genBufFillEx('$arr_tmp_item__', $type->getValue(), "\$arr_tmp__", "", $tokens, $indent." ") . "\n"; - $str .= $indent." if(\$assoc)\n"; - $str .= $indent." {\n"; - $str .= $indent." \$arr_tmp__[] = \$arr_tmp__['\$arr_tmp_item__'];\n"; - $str .= $indent." unset(\$arr_tmp__['\$arr_tmp_item__']);\n"; - $str .= $indent." }\n"; - $str .= $indent." }\n"; - $str .= $indent."mtg_php_array_set_value({$buf}, \$assoc, '$name', \$arr_tmp__);\n"; - } - else - throw new Exception("Unknown type '{$type}'"); - - return $str; - } - - function genDefault($default) - { - if($default == "[]") - return 'array()'; - if(strlen($default) > 2 && strpos($default, '[') === 0 && strpos($default, ']') === strlen($default)-1) - { - $str = trim($default, ']['); - if(strpos($str, "{") !== false ) - $str = var_export(json_decode(trim($default, ']['), true), true); - return 'array(' . $str . ')'; - } - return str_replace('$', '\$', $default); - } - - function genFieldDecl(mtgMetaField $field) - { - $type = $field->getType(); - - $type_comment = "/** @var " . $type ." */\n"; - if($type instanceof mtgBuiltinType && $type->isString()) - return $type_comment."public \$" . $field->getName() . " = '';"; - else if($type instanceof mtgMetaStruct) - return $type_comment."public \$" . $field->getName() . " = null;"; - else if($type instanceof mtgArrType) - return $type_comment."public \$" . $field->getName() . " = array();"; - else - return $type_comment."public \$" . $field->getName() . ";"; - } -} - -class mtgStrictPropsObject -{ - function getTextPropsList() - { - return implode(", ", mtg_get_public_props_names($this)); - } - - function __get($name) - { - throw new Exception("No such property '$name' in class " . get_class($this) . " to get, available properties: " . - $this->getTextPropsList()); - } - - function __set($name, $value) - { - throw new Exception("No such property '$name' in class " . get_class($this) . " to set, available properties: " . - $this->getTextPropsList()); - } -} - -function mtg_get_public_props_names($obj) -{ - static $cache = array(); - $klass = is_string($obj) ? $obj : get_class($obj); - if(!isset($cache[$klass])) - $cache[$klass] = array_keys(get_class_vars($klass)); - return $cache[$klass]; -} - - -//////////////////////////////////////////////////////////////////////// - -function mtg_php_array_extract_val(&$arr, $assoc, $name, $default = null) -{ - if(!is_array($arr)) - throw new Exception("$name: Not an array"); - - if(!$assoc) - { - if(sizeof($arr) == 0) - { - if($default !== null) - return $default; - - throw new Exception("$name: No next array item"); - } - return array_shift($arr); - } - - if(!isset($arr[$name])) - { - if($default !== null) - return $default; - - throw new Exception("$name: No array item"); - } - - $val = $arr[$name]; - unset($arr[$name]); - return $val; -} - -function mtg_php_array_set_value(&$arr, $assoc, $name, $value) -{ - if($assoc) - $arr[$name] = $value; - else - $arr[] = $value; -} - -function mtg_php_val_string($val) -{ - //special case for empty strings - if(is_bool($val) && $val === false) - return ''; - if(!is_string($val)) - throw new Exception("Bad item, not a string(" . serialize($val) . ")"); - return $val; -} - -function mtg_php_val_bool($val) -{ - if(!is_bool($val)) - throw new Exception("Bad item, not a bool(" . serialize($val) . ")"); - return $val; -} - -function mtg_php_val_float($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - return $val; -} - -function mtg_php_val_double($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - return 1*$val; -} - -function mtg_php_val_uint64($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected uint64, float given: $val"); - return $val; -} - -function mtg_php_val_int64($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected int64, float given: $val"); - return $val; -} - -function mtg_php_val_uint32($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected uint32, float given: $val"); - if(($val < 0 && $val < -2147483648) || ($val > 0 && $val > 0xFFFFFFFF)) - throw new Exception("Value not in range: $val"); - return $val; -} - -function mtg_php_val_int32($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected int32, float given: $val"); - if($val > 2147483647 || $val < -2147483648) - throw new Exception("Value not in range: $val"); - return $val; -} - -function mtg_php_val_uint16($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected uint16, float given: $val"); - if($val > 0xFFFF || $val < 0) - throw new Exception("Value not in range: $val"); - return $val; -} - -function mtg_php_val_int16($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected int16, float given: $val"); - if($val > 32767 || $val < -32768) - throw new Exception("Value not in range: $val"); - return $val; -} - -function mtg_php_val_uint8($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected uint8, float given: $val"); - if($val > 0xFF || $val < 0) - throw new Exception("Value not in range: $val"); - return $val; -} - -function mtg_php_val_int8($val) -{ - if(!is_numeric($val)) - throw new Exception("Bad item, not a number(" . serialize($val) . ")"); - $val = 1*$val; - if(is_float($val)) - throw new Exception("Incompatible type, expected int8, float given: $val"); - if($val > 127 || $val < -128) - throw new Exception("Value not in range: $val"); - return $val; -} - -function mtg_php_val_arr($val) -{ - if(!is_array($val)) - throw new Exception("Bad item, not an array(" . serialize($val) . ")"); - return $val; -} - -function mtg_php_val_enum($enum, $val, $check_enum_validity = true) -{ - if(is_string($val)) - return call_user_func_array(array($enum, "getValueByName"), array($val)); - - if(!is_numeric($val)) - throw new Exception("Bad enum value, not a numeric or string(" . serialize($val) . ")"); - - if($check_enum_validity) - call_user_func_array(array($enum, "checkValidity"), array($val)); - return $val; -} - diff --git a/targets/php/php_generator.inc.php b/targets/php/php_generator.inc.php deleted file mode 100644 index c9cf69f..0000000 --- a/targets/php/php_generator.inc.php +++ /dev/null @@ -1,95 +0,0 @@ -setMetaInfo($meta); - - $refl = new ReflectionClass($codegen); - $SHARED_DEPS = array( - dirname(__FILE__) . '/php.inc.php', - dirname(__FILE__) . '/php_tpl.inc.php', - __FILE__, - $refl->getFileName() - ); - - mtg_mkdir(mtg_conf('out-dir')); - - $units = array(); - $rpcs = array(); - $files = array(); - foreach($meta->getUnits() as $unit) - { - if($unit->object instanceof mtgMetaRPC) - { - $rpcs[] = $unit->object; - $files = array_merge($files, mtg_get_file_deps($meta, $unit)); - } - else if($unit->object instanceof mtgMetaEnum || $unit->object instanceof mtgMetaStruct) - { - $files = array_merge($files, mtg_get_file_deps($meta, $unit)); - $units[] = $unit; - } - } - $files = array_unique($files); - - $bundle = mtg_conf("bundle", null); - if($bundle && ($units || $rpcs)) - $targets[] = mtg_new_bundle($bundle, array_merge($SHARED_DEPS, $files), array('gen_php_bundle', $codegen, $units, $rpcs, mtg_conf("inc-dir"))); - - return $targets; - } -} - -function gen_php_struct($OUT, array $DEPS, mtgCodegen $codegen, mtgMetaInfoUnit $unit) -{ - return $codegen->genUnit($unit); -} - -function gen_php_bundle($OUT, array $DEPS, mtgPHPCodegen $codegen, array $units, array $rpcs, $inc_dir) -{ - $bundle = ''; - $class_map = ''; - $packet_map = ''; - $units_src = ''; - - $map = array(); - foreach($units as $unit) - { - $class_id = $unit->object->getClassId(); - $class_name = $unit->object->getName(); - if(isset($map[$class_id])) - throw new Exception("Duplicating class id '$class_id'($class_name vs {$map[$class_id]})"); - $map[$class_id] = $class_name; - - $class_map .= "case " . 1*$class_id . ": return \"$class_name\";\n"; - - if($unit->object instanceof mtgMetaEnum || $unit->object instanceof mtgMetaStruct) - $units_src .= $codegen->genUnit($unit); - } - - foreach($rpcs as $rpc) - { - $code = $rpc->getCode(); - $name = $rpc->getReq()->getName(); - - $packet_map .= "case " . 1*$code . ": return new $name(\$data);\n"; - - $units_src .= $codegen->genRPC($rpc); - } - - $templater = new mtg_php_templater(); - $tpl = $templater->tpl_packet_bundle(); - return mtg_fill_template($tpl, array('%bundle%' => $bundle, - '%units_src%' => $units_src, - '%class_map%' => $class_map, - '%packet_map%' => $packet_map)); -} - diff --git a/targets/php/php_tpl.inc.php b/targets/php/php_tpl.inc.php deleted file mode 100644 index a06b9e3..0000000 --- a/targets/php/php_tpl.inc.php +++ /dev/null @@ -1,347 +0,0 @@ -import(\$message, \$assoc); - } - - function getClassId() - { - return self::CLASS_ID; - } - - %ext_methods% - - function import(&\$message, \$assoc = false, \$root = true) - { - \$IDX = -1; - try - { - if(!is_array(\$message)) - throw new Exception("Bad data: \$message"); - - try - { - \$IDX = 0; - %fill_fields% - } - catch(Exception \$e) - { - if(\$IDX > -1) - { - \$FIELDS = self::CLASS_FIELDS(); - throw new Exception(\$e->getMessage() . " < {\$FIELDS[\$IDX]}"); - } - else - throw \$e; - } - - if(\$root && \$assoc && sizeof(\$message) > 0) - throw new Exception("Junk fields: " . implode(',', array_keys(\$message))); - } - catch(Exception \$e) - { - throw new Exception(\$e->getMessage() . " < (%class%)"); - } - return \$IDX; - } - - function export(\$assoc = false, \$virtual = false) - { - \$message = array(); - \$this->fill(\$message, \$assoc, \$virtual); - return \$message; - } - - function fill(&\$message, \$assoc = false, \$virtual = false) - { - if(\$virtual) - mtg_php_array_set_value(\$message, \$assoc, 'vclass__', \$this->getClassId()); - - try - { - \$__last_var = null; - \$__last_val = null; - %fill_buffer% - } - catch(Exception \$e) - { - throw new Exception("[%class%]\n->\$__last_var\n" . serialize(\$__last_val) . PHP_EOL."\t" . \$e->getMessage()); - } - } -} - -EOD; - return $TPL; - } - - function tpl_enum() - { - $TPL = <<import(\$message, \$assoc); - } - - function getCode() - { - return %code%; - } - - function getType() - { - return "%type%"; - } - - function import(&\$message, \$assoc = false, \$root = true) - { - try - { - if(!\$message || !is_array(\$message)) - throw new Exception("Bad data"); - - \$IDX = -1; - try - { - %fill_fields% - } - catch(Exception \$e) - { - if(\$IDX > -1) - { - \$FIELDS = self::CLASS_FIELDS(); - throw new Exception(\$e->getMessage() . " < {\$FIELDS[\$IDX]}"); - } - else - throw \$e; - } - - if(\$root && \$assoc && sizeof(\$message) > 0) - throw new Exception("Junk fields: " . implode(',', array_keys(\$message))); - } - catch(Exception \$e) - { - throw new Exception(\$e->getMessage() . " < (%class%)"); - } - } - - function export(\$assoc = false) - { - try - { - \$message = array(); - - %fill_buffer% - - return \$message; - } - catch(Exception \$e) - { - throw new Exception(\$e->getMessage() . "\n(%class%)"); - } - } -} - -EOD; - return $TPL; - } - - function tpl_packet_bundle() - { - $TPL = <<findUnit("ConfStock"); assert($u->object instanceof mtgMetaStruct); assert(sizeof($u->object->getFields()) == 1); assert($u->object->getFields()["id"]->getType() == "EnumStock"); - -mtg_run(new mtgCsGenerator(), array( - "meta" => $meta, - "out-dir" => __DIR__ . "/autogen", - "bundle" => __DIR__ . "/autogen/bundle.cs" - )); - -mtg_run(new mtgGoGenerator(), array( - "meta" => $meta, - "out-dir" => __DIR__ . "/autogen", - "bundle" => __DIR__ . "/autogen/bundle.go" - )); - -mtg_run(new mtgPHPGenerator(), array( - "meta" => $meta, - "out-dir" => __DIR__ . "/autogen", - "inc-dir" => __DIR__ . "/autogen", - "bundle" => __DIR__ . "/autogen/bundle.inc.php" - )); - -//TODO: было бы хорошо реализовать -//require_once(__DIR__ . '/../../gme/src/utils.inc.php'); -//require_once(__DIR__ . '/autogen/bundle.inc.php'); -// -//$man = new ProtoMan(); -//assert(count($man->right_hands) == 1); -//assert($man->right_hands[0]->skill == 100); -//assert($man->right_hands[0]->fingers == 1); -//assert($man->right_hands[0]->fingers2 == 77);