Compare commits

...

11 Commits

Author SHA1 Message Date
madpwnhammer da88e6b8db Better check for null default values
Publish PHP Package / docker (push) Successful in 6s Details
2025-03-25 16:02:41 +03:00
Alexey Chubar 1ae22cb86d Removed redundant accessor interface declarations in generated slices
Publish PHP Package / docker (push) Successful in 7s Details
2025-03-25 19:54:33 +07:00
wrenge 1fe32aecb3 blob as ArraySegment<byte>
Publish PHP Package / docker (push) Successful in 7s Details
2025-01-20 15:18:12 +03:00
Pavel Shevaev 5cca57b440 Обновить CHANGELOG.md 2024-12-18 18:41:45 +03:00
Pavel Shevaev 32bfa591d7 Обновить README.md 2024-12-18 18:38:43 +03:00
Pavel Shevaev 02a5871f89 Splitting codegen output to many files assumed to be stored under non VCS directory
Publish PHP Package / docker (push) Successful in 6s Details
2024-12-17 23:14:49 +03:00
wrenge d083ee09bc cs_simple_type filter
Publish PHP Package / docker (push) Successful in 6s Details
2024-11-27 10:31:30 +03:00
n.pankin 6146771ce7 Обновить CHANGELOG.md 2024-08-12 12:10:44 +03:00
n.pankin 8a1fb3126e added implementation of flt_i18n getter setter generation
Publish PHP Package / docker (push) Successful in 6s Details
2024-08-12 12:05:17 +03:00
madpwnhammer 06a96bfdca Added: cs_obsolete changelog 2024-08-08 12:10:43 +03:00
Madpwnhammer 6630a1a3ee Added: cs_obsolete token
Publish PHP Package / docker (push) Successful in 6s Details
2024-07-31 17:01:07 +03:00
6 changed files with 138 additions and 22 deletions

View File

@ -1,3 +1,15 @@
## v6.1.0
- Removed redundant accessor interface declarations in generated slices
## v5.0.0
- Splitting one huge codegenerated file into multiple ones
## v4.10.0
- Added @flt_i18n token to support translations
## v4.9.2
- Added @cs_obsolete token, that mark fields with [Obsolete]. @cs_obsolete:"Comment" will add summary with "Comment" to field
## v4.9.1
- Fixing nested diffable POD structs being incorrectly marked as clean in GetDiff

View File

@ -2,9 +2,10 @@ This package is used for code generation of C# meta structs using Twig templates
Usage example:
$code = \metagen_cs\codegen(null, get_meta(),
$output = \metagen_cs\codegen(null, get_meta(),
[
'namespace' => 'BitGames.Autogen'
]);
file_put_contents('bundle.cs', $code);
foreach($output as $name => $text)
file_put_contents($name, $text);

View File

@ -2,7 +2,7 @@
namespace metagen_cs;
use Exception;
function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) : string
function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) : array
{
$twig = get_twig();
@ -15,7 +15,21 @@ function codegen(?string $cache_dir, \mtgMetaInfo $meta, array $options = []) :
if(!isset($options['namespace']))
$options['namespace'] = 'BitGames.Autogen';
return $twig->render('codegen_bundle.twig', $options);
$sliced_units = slice_units($meta->getUnits(), 50);
$output = array();
foreach($sliced_units as $slice_idx => $slice_units)
{
$slice_options = $options;
$slice_options['slice_idx'] = $slice_idx;
$slice_options['slice_units'] = $slice_units;
$output['types_'.$slice_idx.'.cs'] = $twig->render('codegen_types_slice.twig', $slice_options);
}
$output['factory.cs'] = $twig->render('codegen_factory.twig', $options);
return $output;
}
function get_twig(array $inc_path = []) : \Twig\Environment
@ -55,6 +69,7 @@ function supported_tokens() : array
'cs_propget_interface',
'cs_propset_interface',
'cs_propgetset_interface',
'cs_obsolete',
//TODO:
//'i18n'
];
@ -127,6 +142,15 @@ function _add_twig_support(\Twig\Environment $twig)
return cs_type($type);
}
));
$twig->addFilter(new \Twig\TwigFilter('cs_simple_type',
function($type)
{
if($type instanceof \mtgArrType)
return cs_simple_type($type->getValue());
else
return cs_simple_type($type);
}
));
$twig->addFilter(new \Twig\TwigFilter('cs_type_prefix',
function($type)
{
@ -232,7 +256,7 @@ function cs_simple_type(\mtgType $type)
case "bool":
return "bool";
case "blob":
return "byte[]";
return "ArraySegment<byte>";
}
throw new Exception("Unknown type '{$type}'");
}
@ -343,7 +367,7 @@ function var_reset($name, \mtgType $type, $default = null)
$str .= " = ".trim($default, '"').";";
}
else
$str .= ' = null;';
$str .= ' = default;';
}
else
throw new Exception("Unknown type '$type'");
@ -395,16 +419,16 @@ function var_reset($name, \mtgType $type, $default = null)
if($default)
{
$default = is_array($default) ? $default : json_decode($default, true);
if(is_array($default))
$default_val = is_array($default) ? $default : json_decode($default, true);
if(is_array($default_val))
{
foreach($default as $k => $v)
foreach($default_val as $k => $v)
{
$kf = $type->getField($k);
$str .= var_reset("$name." . $kf->getName(), $kf->getType(), $v);
}
}
else if($default === null)
else if(is_null_str($default))
$str .= "$name = null; ";
else
throw new Exception("Bad default value for struct: " . var_export($default, true));
@ -417,7 +441,7 @@ function var_reset($name, \mtgType $type, $default = null)
function is_null_str($default)
{
return is_string($default) && json_decode($default, true) === null;
return is_string($default) && strtolower($default) === 'null';
}
function var_sync($fname, \mtgType $type, $buf, array $tokens, $opts)
@ -703,3 +727,41 @@ function get_field_index(\mtgMetaStruct $struct, string $field_name): int
}
return -1;
}
function 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;
}
//slices array like this: [[idx0,[..]], [idx1,[..]], ...]
function slice_units(array $units, $max)
{
$pages = paginate(sizeof($units), $max);
$sliced = array();
$units_keys = array_keys($units);
foreach($pages as $idx => $page)
{
$slice = array();
for($i = $page[0];$i<$page[1];++$i)
{
$slice[] = $units[$units_keys[$i]];
}
$sliced[$idx] = $slice;
}
return $sliced;
}

View File

@ -1,6 +1,7 @@
//THIS FILE IS GENERATED AUTOMATICALLY, DO NOT TOUCH IT!
using System.Collections.Generic;
using metagen;
using System;
{%- import "macro.twig" as macro -%}
@ -8,7 +9,9 @@ using metagen;
namespace {{namespace}} {
{% endif %}
{{ macro.decl_units(meta) }}
{%- for ai in get_all_declarable_accessor_interfaces(meta) ~%}
{{ macro.decl_accessor_interface(ai) }}
{%- endfor ~%}
static public class AutogenBundle
{

View File

@ -0,0 +1,16 @@
//THIS FILE IS GENERATED AUTOMATICALLY, DO NOT TOUCH IT!
using System.Collections.Generic;
using metagen;
using System;
{%- import "macro.twig" as macro -%}
{% if namespace is defined ~%}
namespace {{namespace}} {
{% endif %}
{{ macro.decl_units(slice_units) }}
{% if namespace is defined ~%}
} //namespace {{namespace}}
{% endif %}

View File

@ -1,6 +1,6 @@
{% macro decl_units(meta) %}
{% macro decl_units(units) %}
{%- for u in meta.getunits ~%}
{%- for u in units ~%}
{%- if u.object is instanceof('\\mtgMetaStruct') -%}
{{ _self.decl_struct(u.object) }}
{%- elseif u.object is instanceof('\\mtgMetaEnum') -%}
@ -10,10 +10,6 @@
{%- endif ~%}
{%- endfor ~%}
{%- for ai in get_all_declarable_accessor_interfaces(meta) ~%}
{{ _self.decl_accessor_interface(ai) }}
{%- endfor ~%}
{% endmacro %}
{% macro decl_struct(o, extra = '') %}
@ -160,12 +156,23 @@ public FieldsMask fields_mask;
{%- 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 -%};
{% if has_token(f, 'flt_i18n') -%}
{{f.type}} _{{f.name}} = "";
List<{{f.type}}> __{{f.name}} = new List<{{f.type}}>();
{%- endif ~%}
public {{f.type|cs_type|obscure_type(f)}} {{f.name}} {% if not has_token(o, 'POD') -%} {{_self.decl_init_value(f)}} {%- endif -%} {% if not has_token(f, 'flt_i18n') -%};{%- endif -%}
{%- endmacro -%}
{% macro decl_init_value(f) %}
{%- if f.type is instanceof('\\mtgBuiltinType') -%}
{%- if f.type.isstring -%} = ""{%- endif -%}
{%- if f.type.isstring -%}
{% if has_token(f, 'flt_i18n') -%}
{get{return plural_{{f.name}}(double.NaN);}set{_{{f.name}}=value;}}
{{f.type}} plural_{{f.name}}(double force_n){return MetaI18N.I18NPick(_{{f.name}},__{{f.name}},"#",force_n);}
{%- else -%}
= ""
{%- endif ~%}
{%- endif -%}
{%- else -%}
{%- if has_token(f, 'default') and token(f, 'default') == 'null' -%}
/*null*/
@ -180,7 +187,12 @@ public {{f.type|cs_type|obscure_type(f)}} {{f.name}} {% if not has_token(o, 'POD
base.Reset();
{%- endif -%}
{%- for f in o.fields ~%}
{{var_reset(f.name, f.type, token_or(f, 'default', null))}}
{% set fname = f.name %}
{% if has_token(f, 'flt_i18n') -%}
{% set fname = '_' ~ f.name %}
if(_{{fname}} == null) _{{fname}} = new(); else _{{fname}}.Clear();
{%- endif ~%}
{{var_reset(fname, f.type, token_or(f, 'default', null))}}
{%- endfor -%}
{%- if has_token(o, 'bitfields') ~%}
ResetFieldMask();
@ -188,6 +200,12 @@ ResetFieldMask();
{% endmacro %}
{%- macro attributes(o) %}
{% if has_token(o, "cs_obsolete") %}
/// <summary>
/// {{token(o, "cs_obsolete")}}
/// </summary>
[Obsolete]
{% endif %}
{%- if has_token(o, 'cs_attributes') -%}
{%- for attr in token(o, 'cs_attributes')|split(',') -%}
[{{attr}}]
@ -273,7 +291,11 @@ bitctx.SyncMaskHeader();
base.SyncFields(ctx);
{%- endif -%}
{%- for f in o.fields ~%}
{{var_sync(f.name, f.type, 'ctx', f.tokens, get_sync_opts(o, 'bitctx'))}}
{% set fname = f.name %}
{% if has_token(f, 'flt_i18n') -%}
{% set fname = '_' ~ f.name %}
{%- endif -%}
{{var_sync(fname, f.type, 'ctx', f.tokens, get_sync_opts(o, 'bitctx'))}}
{%- endfor -%}
{%- endmacro -%}