diff --git a/src/codegen.inc.php b/src/codegen.inc.php index c700130..9453924 100644 --- a/src/codegen.inc.php +++ b/src/codegen.inc.php @@ -78,6 +78,30 @@ function _add_twig_support(\Twig\Environment $twig) return var_reset($name, $type, $default); } )); + $twig->addFunction(new \Twig\TwigFunction('var_sync', + function($name, $type, $buf, $tokens, $opts) + { + return var_sync($name, $type, $buf, $tokens, $opts); + } + )); + $twig->addFunction(new \Twig\TwigFunction('get_sync_opts', + function($o, $name) + { + return get_sync_opts($o, $name); + } + )); + $twig->addFunction(new \Twig\TwigFunction('fields_count', + function($o) + { + return fields_count($o); + } + )); + $twig->addFunction(new \Twig\TwigFunction('is_primary_field', + function($o, $f) + { + return is_primary_field($o, $f); + } + )); } function cs_type(\mtgType $type) @@ -278,6 +302,112 @@ function var_reset($name, \mtgType $type, $default = null) return $str; } +function var_sync($fname, \mtgType $type, $buf, array $tokens, $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 get_sync_opts(\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 fields_count(\mtgMetaStruct $struct) +{ + //NOTE: why not using fields_count(..) here as well? + // (becase they include i18n fields already?) + $count = count($struct->getFields()); + $curr = $struct->getParent(); + while($curr) + { + $count += fields_count_self($curr); + $curr = $curr->getParent(); + } + return $count; +} + +function fields_count_self(\mtgMetaStruct $struct) +{ + $fields = $struct->getFields(); + $count = 0; + foreach($fields as $field) + { + //TODO: do we still need this + if($field->hasToken('i18n')) + $count += 2; + else + $count += 1; + } + + return $count; +} + +function is_primary_field(\mtgMetaStruct $struct, $fld) +{ + $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; + } + + return in_array($fld->getName(), $primary_fields); +} + function is_nullable_type(\mtgType $type) { return $type instanceof \mtgArrType || diff --git a/tpl/macro.twig b/tpl/macro.twig index b9026a0..1f616ba 100644 --- a/tpl/macro.twig +++ b/tpl/macro.twig @@ -12,6 +12,9 @@ {% endmacro %} {% macro decl_struct(o, extra = '') %} +{%- if o.parent and has_token(o, 'POD') -%} +{{Error("@POD structs can't have a parent: " ~ o.name)}} +{%- endif -%} {%- if o.parent and has_token(o, 'bitfields') -%} {{Error("@bitfields structs can't have a parent: " ~ o.name)}} {%- endif -%} @@ -54,6 +57,7 @@ public {{_self.struct_type(o)}} {{o.name}} {{_self.base_class(o)}} reset(); syncFields(ctx); ctx.reader.EndContainer(); + {{_self.copy_fields(o)}} } @@ -67,19 +71,27 @@ public {{_self.struct_type(o)}} {{o.name}} {{_self.base_class(o)}} public {{_self.override(o)}} void syncFields(MetaSyncContext ctx) { - %bitfields_sync_context% - %sync_buffer% + {{_self.sync_fields(o)}} } public {{_self.override(o)}} int getFieldsCount() { - return %fields_count%; + return {{fields_count(o)}}; } public {{_self.override(o)}} int getWritableFieldsCount() { - return %dirty_fields_count%; +{%- if has_token(o, 'bitfields') ~%} + return Meta.GetDirtyFieldsCount(fields_mask, fields_count: {{fields_count(o)}}) + + Meta.MASK_HEADER_FIELDS_COUNT; +{%- else -%} + return {{fields_count(o)}}; +{%- endif ~%} } + +{%- if has_token(o, 'bitfields') ~%} + {{_self.bitmask_helpers(o)}} +{%- endif -%} {{extra}} } @@ -146,7 +158,7 @@ override {%- macro comment_POD_begin(o) -%} {%- if has_token(o, 'POD') -%} -/* +/* commented in POD {%- endif -%} {%- endmacro -%} @@ -158,7 +170,7 @@ override {%- macro comment_non_cloneable_begin(o) -%} {%- if not has_token(o, 'cloneable') -%} -/* +/* commented in non-cloneable {%- endif -%} {%- endmacro -%} @@ -184,6 +196,37 @@ fields_mask = other.fields_mask; {%- endif -%} {%- endmacro -%} +{%- macro sync_fields(o) -%} +{%- if has_token(o, 'bitfields') ~%} +var bitctx = new Meta.BitfieldsContext(ctx, fields_mask); +bitctx.SyncMaskHeader(); +{%- endif -%} +{%- if o.parent ~%} +base.syncFields(ctx); +{%- endif -%} +{%- for f in o.fields ~%} +{{var_sync(f.name, f.type, 'ctx', f.tokens, get_sync_opts(o, 'bitctx'))}} +{%- endfor -%} +{%- endmacro -%} + +{%- macro bitmask_helpers(o) ~%} + + public void ResetFieldMask() + { + fields_mask = 0L; + } + + public void SetPrimaryFieldsChanged() + { +{%- for f in o.fields ~%} +{%- if is_primary_field(o, f) ~%} + Meta.SetFieldDirty(ref fields_mask, {{loop.index0}}); +{%- endif -%} +{%- endfor ~%} + } + +{%- endmacro -%} + {% macro decl_enum(o) %} {% endmacro %}