metagen_cs/tpl/macro.twig

670 lines
16 KiB
Twig
Raw Normal View History

2022-12-06 19:16:13 +03:00
{% macro decl_units(meta) %}
{%- for u in meta.getunits ~%}
{%- if u.object is instanceof('\\mtgMetaStruct') -%}
{{ _self.decl_struct(u.object) }}
{%- elseif u.object is instanceof('\\mtgMetaEnum') -%}
{{ _self.decl_enum(u.object) }}
{%- elseif u.object is instanceof('\\mtgMetaRPC') -%}
{{ _self.decl_rpc(u.object) }}
{%- endif ~%}
2022-12-06 19:16:13 +03:00
{%- endfor ~%}
{%- for ai in get_all_declarable_accessor_interfaces(meta) ~%}
{{ _self.decl_accessor_interface(ai) }}
{%- endfor ~%}
2022-12-06 19:16:13 +03:00
{% endmacro %}
{% macro decl_struct(o, extra = '') %}
{% set pkey_fields = token(o, 'table_pkey')|split(',') %}
{% set pkey = pkey_fields|filter(f => f|length > 0)|map(f => o.getField(f)) %}
{%- 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 -%}
2022-12-06 19:16:13 +03:00
{{_self.attributes(o)}}
public {{_self.struct_type(o)}} {{o.name}} {{_self.base_struct_class(o)}}
2022-12-06 19:16:13 +03:00
{
{{_self.decl_struct_fields(o)}}
public {{o.parent ? 'new'}} const uint STATIC_CLASS_ID = {{o.classid}};
public {{_self.override(o)}} uint CLASS_ID()
{
return {{o.classid}};
}
{{_self.comment_POD_begin(o)}}
public {{o.name}}()
{
2023-08-16 14:19:28 +03:00
Reset();
2022-12-06 19:16:13 +03:00
}
{{_self.comment_POD_end(o)}}
2023-08-16 14:19:28 +03:00
public {{_self.override(o)}} void Reset()
2022-12-06 19:16:13 +03:00
{
{{_self.struct_fields_reset(o)}}
}
{{_self.comment_non_cloneable_begin(o)}}
2023-08-01 12:40:27 +03:00
public void CloneTo(ref {{o.name}} dst)
{
2023-08-16 14:19:28 +03:00
MetaIO.Clone(this, ref dst, AutogenBundle.createById);
2023-08-01 12:40:27 +03:00
}
2023-08-16 14:19:28 +03:00
public {{_self.virtual_clone(o)}} IMetaStruct Clone()
2022-12-06 19:16:13 +03:00
{
2023-08-01 12:40:27 +03:00
var dst = new {{o.name}}();
CloneTo(ref dst);
return dst;
2022-12-06 19:16:13 +03:00
}
{{_self.comment_non_cloneable_end(o)}}
2023-08-16 14:19:28 +03:00
public {{_self.override(o)}} void SyncFields(MetaSyncContext ctx)
2022-12-06 19:16:13 +03:00
{
2022-12-07 11:49:34 +03:00
{{_self.sync_fields(o)}}
2022-12-06 19:16:13 +03:00
}
2023-08-16 14:19:28 +03:00
public {{_self.override(o)}} int GetFieldsCount()
2022-12-06 19:16:13 +03:00
{
2022-12-07 11:49:34 +03:00
return {{fields_count(o)}};
2022-12-06 19:16:13 +03:00
}
2023-08-16 14:19:28 +03:00
public {{_self.override(o)}} int GetDirtyFieldsCount()
2022-12-06 19:16:13 +03:00
{
2022-12-07 12:54:56 +03:00
{%~ if has_token(o, 'bitfields') ~%}
2023-07-26 18:00:39 +03:00
return fields_mask.GetDirtyFieldsCount();
2022-12-07 12:54:56 +03:00
{% else %}
2023-08-16 14:19:28 +03:00
return GetFieldsCount();
2022-12-07 11:49:34 +03:00
{%- endif ~%}
2022-12-06 19:16:13 +03:00
}
2022-12-07 11:49:34 +03:00
{%- if has_token(o, 'bitfields') ~%}
{{_self.bitmask_helpers(o)}}
{%- endif -%}
2022-12-06 19:16:13 +03:00
{%- if has_token(o, 'table') ~%}
public static bool operator <({{o.name}} o1, {{o.name}} o2)
{
return {{o.name}}Comparer.self.Compare(o1, o2) < 0;
}
public static bool operator >({{o.name}} o1, {{o.name}} o2)
{
return {{o.name}}Comparer.self.Compare(o1, o2) > 0;
}
public {{o.name}}Id MakeId()
{
return new {{o.name}}Id{
{% for f in pkey %}
{{f.name}} = {{f.name}},
{% endfor %}
};
}
{%- endif -%}
{%- if has_token(o, 'diffable') ~%}
{{_self.diffable_support(o)}}
{%- endif -%}
{{_self.decl_struct_accessor_implements(o)}}
2022-12-06 19:16:13 +03:00
{{extra}}
}
{%- if has_token(o, 'table') ~%}
public class {{o.name}}Comparer : IComparer<{{o.name}}>
{
public readonly static {{o.name}}Comparer self = new {{o.name}}Comparer();
public int Compare({{o.name}} o1, {{o.name}} o2)
{
int result;
{% set comparable = pkey %}
{% if comparable|length > 1 %}
{% set comparable = comparable [1:] %}
{% endif %}
{% for f in comparable %}
{% if not loop.first %}
if(result == 0)
{% endif %}
result = o1.{{f.name}}.CompareTo(o2.{{f.name}});
{% endfor %}
return result;
}
}
{%- endif ~%}
2022-12-06 19:16:13 +03:00
{% endmacro %}
{%- macro decl_struct_fields(o) -%}
{%- if has_token(o, 'bitfields') ~%}
public FieldsMask fields_mask;
2022-12-06 19:16:13 +03:00
{%- endif -%}
{%- for f in o.fields ~%}
{{_self.decl_struct_field(o, f)}}
{%- endfor -%}
{%- endmacro -%}
{%- macro decl_struct_field(o, f) -%}
{{_self.attributes(f)}}
public {{f.type|cs_type|obscure_type(f)}} {{f.name}} {% if not has_token(o, 'POD') -%} {{_self.decl_init_value(f)}} {%- endif -%};
2022-12-06 19:16:13 +03:00
{%- endmacro -%}
{% macro decl_init_value(f) %}
{%- if f.type is instanceof('\\mtgBuiltinType') -%}
{%- if f.type.isstring -%} = ""{%- endif -%}
2022-12-06 19:16:13 +03:00
{%- else -%}
{%- if has_token(f, 'default') and token(f, 'default') == 'null' -%}
/*null*/
{%- else -%}
= new {{f.type|cs_type}}()
{%- endif -%}
2022-12-06 19:16:13 +03:00
{%- endif -%}
{% endmacro %}
{% macro struct_fields_reset(o) %}
{%- if o.parent ~%}
2023-08-16 14:19:28 +03:00
base.Reset();
2022-12-06 19:16:13 +03:00
{%- endif -%}
{%- for f in o.fields ~%}
{{var_reset(f.name, f.type, token_or(f, 'default', null))}}
{%- endfor -%}
{%- if has_token(o, 'bitfields') ~%}
ResetFieldMask();
2022-12-06 19:16:13 +03:00
{%- endif -%}
{% endmacro %}
{%- macro attributes(o) %}
{%- if has_token(o, 'cs_attributes') -%}
{%- for attr in token(o, 'cs_attributes')|split(',') -%}
[{{attr}}]
{%- endfor -%}
{%- endif -%}
{%- endmacro %}
{%- macro struct_type(o) -%}
{{has_token(o, 'POD') ? 'struct' : 'class'}}
{%- endmacro -%}
{%- macro base_struct_class(o) -%}
{%- if has_token(o, 'POD') -%}
: IMetaStruct
{%- else -%}
: {{o.parent ? o.parent.name : 'BaseMetaStruct'}}
{{- has_token(o, 'cloneable') and not o.parent ? ', IMetaCloneable' -}}
2022-12-06 19:16:13 +03:00
{%- endif -%}
{%- for ifs in token(o, "cs_implements", "")|split(',') -%}
, {{ifs}}
{%- endfor -%}
{%- for ai in get_accessor_interfaces(o) -%}
, {{ai.interfacename}}
{%- endfor -%}
2022-12-06 19:16:13 +03:00
{%- endmacro -%}
{%- macro override(o) -%}
{%- if not has_token(o, 'POD') -%}
override
{%- endif -%}
{%- endmacro -%}
{%- macro virtual(o) -%}
{%- if not has_token(o, 'POD') -%}
{{o.parent ? 'override' : 'virtual'}}
{%- endif -%}
{%- endmacro -%}
2022-12-06 19:16:13 +03:00
{%- macro comment_POD_begin(o) -%}
{%- if has_token(o, 'POD') -%}
2022-12-07 11:49:34 +03:00
/* commented in POD
2022-12-06 19:16:13 +03:00
{%- endif -%}
{%- endmacro -%}
{%- macro comment_POD_end(o) -%}
{%- if has_token(o, 'POD') -%}
*/
{%- endif -%}
{%- endmacro -%}
{%- macro comment_non_cloneable_begin(o) -%}
{%- if not has_token(o, 'cloneable') -%}
2022-12-07 11:49:34 +03:00
/* commented in non-cloneable
2022-12-06 19:16:13 +03:00
{%- endif -%}
{%- endmacro -%}
{%- macro comment_non_cloneable_end(o) -%}
{%- if not has_token(o, 'cloneable') -%}
*/
{%- endif -%}
{%- endmacro -%}
{%- macro virtual_clone(o) -%}
{%- if has_token(o, 'cloneable') -%}
{%- if has_token(o, 'POD') -%}
{%- elseif o.parent and has_token_in_parent(o.parent, 'cloneable') -%}
override
{%- else -%}
virtual
{%- endif -%}
2022-12-06 19:16:13 +03:00
{%- endif -%}
{%- endmacro -%}
2022-12-07 11:49:34 +03:00
{%- macro sync_fields(o) -%}
{%- if has_token(o, 'bitfields') ~%}
2023-08-16 14:19:28 +03:00
var bitctx = new MetaIO.BitfieldsContext(ctx, fields_mask);
2022-12-07 11:49:34 +03:00
bitctx.SyncMaskHeader();
{%- endif -%}
{%- if o.parent ~%}
2023-08-16 14:19:28 +03:00
base.SyncFields(ctx);
2022-12-07 11:49:34 +03:00
{%- 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 = FieldsMask.MakeClean(fields_amount: {{fields_count(o)}});
2022-12-07 11:49:34 +03:00
}
public void SetPrimaryFieldsChanged()
{
SetPrimaryFieldsChanged(ref this.fields_mask);
}
static void SetPrimaryFieldsChanged(ref FieldsMask mask)
2022-12-07 11:49:34 +03:00
{
{%- for f in o.fields ~%}
{%- if is_primary_field(o, f) ~%}
MetaIO.SetFieldDirty(ref mask, {{loop.index0}});
2022-12-07 11:49:34 +03:00
{%- endif -%}
{%- endfor ~%}
}
public bool IsContentDirty()
{
int fields_amount = {{fields_count(o)}};
var primary_id_mask = FieldsMask.MakeClean(fields_amount);
SetPrimaryFieldsChanged(ref primary_id_mask);
for(int i = 0; i < fields_amount; i++)
{
bool is_primary_id = primary_id_mask.IsDirty(i);
if(!is_primary_id && fields_mask.IsDirty(i))
return true;
}
return false;
}
2022-12-07 12:54:56 +03:00
public void SetDirtyMask()
{
fields_mask = FieldsMask.MakeDirty(fields_amount: {{fields_count(o)}});
2022-12-07 12:54:56 +03:00
}
public void SetDirtyMaskDeep()
{
SetDirtyMask();
2022-12-07 12:54:56 +03:00
{%- for f in o.fields ~%}
{%- if f.type is instanceof('\\mtgMetaStruct') and has_token(f.type, 'bitfields') ~%}
{{f.name}}.SetDirtyMaskDeep();
2022-12-07 12:54:56 +03:00
{%- elseif f.type is instanceof('\\mtgArrType') and f.type.value is instanceof('\\mtgMetaStruct') and has_token(f.type.value, "bitfields") ~%}
{
for(int i=0;i<{{f.name}}.Count;++i)
2022-12-07 12:54:56 +03:00
{
var __tmp = {{f.name}}[i];
__tmp.SetDirtyMaskDeep();
{{f.name}}[i] = __tmp;
2022-12-07 12:54:56 +03:00
}
}
2022-12-07 12:54:56 +03:00
{%- endif -%}
{%- endfor ~%}
}
2022-12-07 12:54:56 +03:00
2022-12-07 11:49:34 +03:00
{%- endmacro -%}
2022-12-06 19:16:13 +03:00
{% macro decl_enum(o) %}
2022-12-07 12:54:56 +03:00
{{_self.attributes(o)}}
public enum {{o.name}}
{
{%- for n,v in o.values ~%}
{{n}} = {{v}},
{%- endfor ~%}
}
2022-12-06 19:16:13 +03:00
{% endmacro %}
{% macro decl_rpc(o) %}
2022-12-07 12:54:56 +03:00
{{_self.decl_struct(o.req)}}
{{_self.decl_struct(o.rsp)}}
2022-12-07 12:54:56 +03:00
public class {{o.name}} : IRpc
{
public IRpcError error = null;
public {{o.req.name}} req = new {{o.req.name}}();
public {{o.rsp.name}} rsp = new {{o.rsp.name}}();
2023-08-16 14:19:28 +03:00
public int GetCode()
2022-12-07 12:54:56 +03:00
{
return {{o.code}};
}
2023-08-16 14:19:28 +03:00
public void SetError(IRpcError error)
2022-12-07 12:54:56 +03:00
{
this.error = error;
}
2023-08-16 14:19:28 +03:00
public IRpcError GetError()
2022-12-07 12:54:56 +03:00
{
return error;
}
2023-08-16 14:19:28 +03:00
public IMetaStruct GetRequest()
2022-12-07 12:54:56 +03:00
{
return req as IMetaStruct;
}
2023-08-16 14:19:28 +03:00
public IMetaStruct GetResponse()
2022-12-07 12:54:56 +03:00
{
return rsp as IMetaStruct;
}
}
{% endmacro %}
{%- macro diffable_support(o) -%}
public bool GetDiff({{o.name}} old, {{o.name}} diff = null, {{o.name}}RemovedIds removed = null)
{
if(diff != null)
2023-08-16 14:19:28 +03:00
diff.Reset();
if(removed != null)
2023-08-16 14:19:28 +03:00
removed.Reset();
bool no_changes = true;
{% set field_idx = -1 %}
{%- for f in o.fields ~%}
{% set field_idx = field_idx + 1 %}
{%- if not has_token(f, 'nodiff') -%}
{{_self.field_diff(f, field_idx, o)}}
{%- endif -%}
{% endfor %}
return !no_changes;
}
{% set unique_diff_units = [] %}
{% for u in get_diff_related_units(o) %}
{% if u not in unique_diff_units %}
{{_self.diff_methods_for(u)}}
{% set unique_diff_units = unique_diff_units|merge([u]) %}
{% endif %}
{% endfor %}
{% endmacro %}
{%- macro diff_methods_for(u) -%}
static public bool DiffOne(ref {{u.name}} curr, {{u.name}} old)
{
return !{{_self.compare_func_name(u)}}(ref curr, old);
}
static public bool DiffCollection(List<{{u.name}}> items, List<{{u.name}}> old_items, List<{{u.name}}> changed, List<{{u.name}}Id> removed)
{
bool has_diff = false;
if(changed != null)
changed.Clear();
items.Sort({{u.name}}Comparer.self);
old_items.Sort({{u.name}}Comparer.self);
int i = 0;
int old_i = 0;
for(; i < items.Count && old_i < old_items.Count;)
{
var old = old_items[old_i];
var item = items[i];
if(old < item)
{
2023-10-20 08:26:40 +03:00
if(removed != null)
removed.Add(old.MakeId());
old_i++;
has_diff = true;
}
else if(old > item)
{
item.SetDirtyMask();
if(changed != null)
changed.Add(item);
i++;
has_diff = true;
}
else
{
if(!{{_self.compare_func_name(u)}}(ref item, old) && item.IsContentDirty())
{
if(changed != null)
changed.Add(item);
has_diff = true;
}
i++;
old_i++;
}
}
//items leftovers are considered changed
for(; i < items.Count; i++)
{
var item = items[i];
item.SetDirtyMask();
if(changed != null)
changed.Add(item);
has_diff = true;
}
//old items leftovers are considered removed
for(; old_i < old_items.Count; old_i++)
{
2023-09-11 11:14:55 +03:00
if(removed != null)
removed.Add(old_items[old_i].MakeId());
has_diff = true;
}
//if(changed.Count > 0)
2023-08-16 14:19:28 +03:00
// MetaIO.LogDebug("Changed in collection {{u.name}}");
//if(removed_ids.Count > 0)
2023-08-16 14:19:28 +03:00
// MetaIO.LogDebug("Removed in collection {{u.name}}");
return has_diff;
}
public static bool {{_self.compare_func_name(u)}}(ref {{u.name}} a, {{u.name}} b)
{
bool is_equal = true;
2023-03-22 15:54:53 +03:00
{%- if has_token(u, 'bitfields') ~%}
a.ResetFieldMask();
{%- endif -%}
2023-03-22 15:54:53 +03:00
{%- for f in u.fields ~%}
{{_self.field_compare(u, f, loop.index0)}}
{%- endfor -%}
2023-03-22 15:54:53 +03:00
{%- if has_token(u, 'bitfields') ~%}
if(!is_equal)
a.SetPrimaryFieldsChanged();
{%- endif -%}
return is_equal;
}
{% endmacro %}
{% macro compare_func_name(o) %}
2023-03-22 15:54:53 +03:00
{{has_token(o, 'bitfields')?'CompareAndMarkFields':'IsEqual'}}
{%- endmacro %}
{%- macro field_compare(o, f, field_idx) -%}
{% if f.type is instanceof('\\mtgArrType') ~%}
if(a.{{f.name}} == null ||
b.{{f.name}} == null ||
a.{{f.name}}.Count != b.{{f.name}}.Count)
return false;
for(int i=0;i<a.{{f.name}}.Count;++i)
{
{%- if f.type.value is instanceof('\\mtgMetaStruct') ~%}
if(!IsEqual(ref a.{{f.name}}[i], b.{{f.name}}[i]))
return false;
{%- else -%}
if(a.{{f.name}}[i] != b.{{f.name}}[i])
return false;
{%- endif -%}
}
{% elseif f.type is instanceof('\\mtgMetaStruct') ~%}
if(!IsEqual(ref a.{{f.name}}, b.{{f.name}}))
return false;
{% elseif f.type is instanceof('\\mtgBuiltinType') and f.type.isstring ~%}
if((a.{{f.name}} == null ? "" : a.{{f.name}})
!= (b.{{f.name}} == null ? "" : b.{{f.name}}))
{% if has_token(o, 'bitfields') ~%}
{
2023-08-16 14:19:28 +03:00
MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
is_equal = false;
}
{% else ~%}
return false;
{%- endif -%}
{% else ~%}
2023-03-22 16:10:06 +03:00
if(a.{{f.name}} != b.{{f.name}})
{% if has_token(o, 'bitfields') ~%}
{
2023-08-16 14:19:28 +03:00
MetaIO.SetFieldDirty(ref a.fields_mask, {{field_idx}});
is_equal = false;
}
{% else ~%}
return false;
{%- endif -%}
{%- endif -%}
{% endmacro %}
{%- macro field_diff(f, field_idx, o) -%}
{% if f.type is instanceof('\\mtgMetaStruct') %}
{%- if not has_token(f.type, 'POD') -%}
2023-08-23 14:38:05 +03:00
{{Error("Diffable struct '" ~ f.type ~ "' must be POD")}}
{%- endif -%}
{
var __tmp = {{f.name}};
if(DiffOne(ref __tmp, old.{{f.name}}))
{
no_changes &= false;
if(diff != null)
{
diff.{{f.name}} = __tmp;
2023-08-16 14:19:28 +03:00
MetaIO.SetFieldDirty(ref diff.fields_mask, {{field_idx}});
}
}
}
{% elseif f.type is instanceof('\\mtgArrType') %}
{%- if not has_token(f.type.value, 'POD') -%}
2023-08-23 14:38:05 +03:00
{{Error("Diffable struct '" ~ f.type.value ~ "' must be POD")}}
{%- endif -%}
if(DiffCollection({{f.name}}, old.{{f.name}},
diff == null ? null : diff.{{f.name}},
removed == null ? null : removed.{{f.name}}
))
{
no_changes &= false;
if(diff != null)
2023-08-16 14:19:28 +03:00
MetaIO.SetFieldDirty(ref diff.fields_mask, {{field_idx}});
2023-07-25 19:02:52 +03:00
if(removed != null && removed.{{f.name}}.Count > 0)
MetaIO.SetFieldDirty(ref removed.fields_mask, {{ field_index(find_struct(o.name ~ 'RemovedIds'), f.name) }});
}
{% elseif f.type is instanceof('\\mtgBuiltinType') %}
if(diff != null)
diff.{{f.name}} = {{f.name}};
if({{f.name}} != old.{{f.name}})
{
no_changes &= false;
if(diff != null)
2023-08-16 14:19:28 +03:00
MetaIO.SetFieldDirty(ref diff.fields_mask, {{field_idx}});
}
{% else %}
2023-08-23 14:38:05 +03:00
{{Error("Diff for field '"~ f.name ~"' is not supported") }}
{% endif %}
{% endmacro %}
{% macro decl_accessor_interface(ai) ~%}
public interface {{ai.interfacename}}
{
2023-04-26 13:14:18 +03:00
{%- for aif in ai.fields ~%}
{% if aif.is_accessor -%}
{{aif.field.type|cs_type}} Get{{aif.camelfieldname}}();
void Set{{aif.camelfieldname}}({{aif.field.type|cs_type}} v);
{% endif -%}
{%- if aif.is_propget -%}
{{aif.field.type|cs_type}} {{aif.camelfieldname}} {
{%- if aif.is_propget -%}
get;
{%- endif %}
{%- if aif.is_propset -%}
set;
{%- endif -%}
}
{%- endif ~%}
{%- endfor ~%}
}
{% endmacro %}
{%- macro decl_struct_accessor_implements(o) -%}
{%- for ai in get_accessor_interfaces(o) ~%}
2023-04-26 13:14:18 +03:00
{%- for aif in ai.fields ~%}
{% if aif.is_accessor %}
public {{aif.field.type|cs_type}} Get{{aif.camelfieldname}}()
{
return {{aif.field.name}};
}
public void Set{{aif.camelfieldname}}({{aif.field.type|cs_type}} v)
{
this.{{aif.field.name}} = v;
}
{% endif %}
{% if aif.is_propget or aif.is_propset %}
public {{aif.field.type|cs_type}} {{aif.camelfieldname}} {
{%- if aif.is_propget -%}
get => this.{{aif.field.name}};
{%- endif -%}
{%- if aif.is_propset -%}
set => this.{{aif.field.name}} = value;
{%- endif -%}
}
{%- endif ~%}
{% endfor %}
{%- endfor ~%}
{% endmacro %}