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; } }