diff --git a/CHANGELOG.md b/CHANGELOG.md index 308d216..e6d1397 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,9 @@ +## v19.0.0 +- Streamline generated code: + - Less inlining in enum bindings + - Functions returning a single value will share code for `ReturnValue` in common cases + - `IDisposable` boilerplate code will be generated only when `Args` actually need disposing + ## v17.1.0 - Splitting one huge codegenerated file into multiple ones @@ -21,4 +27,4 @@ - Always adding `using bhl` directive to generated code ## v13.0.0 -- Migrating to new BHL2-beta123 efficient native array wrappers \ No newline at end of file +- Migrating to new BHL2-beta123 efficient native array wrappers diff --git a/src/bind.inc.php b/src/bind.inc.php index 939ea87..a8550c4 100644 --- a/src/bind.inc.php +++ b/src/bind.inc.php @@ -370,6 +370,26 @@ function add_twig_support(\Twig\Environment $twig) return "Module".module_name($m).".ns"; } )); + + $twig->addFunction(new \Twig\TwigFunction('has_disposable_args', + function(\mtgMetaFunc $fn) + { + foreach($fn->getArgs() as $arg) + { + $type = $arg->getType(); + if( + $type instanceof \mtgArrType || + $type instanceof \mtgMetaFunc || + $type->getName() == "any" + ) + { + return true; + } + } + + return false;; + } + )); } function Warn($msg) diff --git a/tpl/bhl_bind_macro.twig b/tpl/bhl_bind_macro.twig index b5913e7..03bd469 100644 --- a/tpl/bhl_bind_macro.twig +++ b/tpl/bhl_bind_macro.twig @@ -93,7 +93,9 @@ {%- if o.args -%} var args = Script_{{o.name|norm_name}}.ReadArgs(frm, stack, args_info); Script_{{o.name|norm_name}}.Exec(frm, args {{_self.out_results(o)}}); + {% if has_disposable_args(o) ~%} args.Dispose(); + {%- endif ~%} {%- else ~%} Script_{{o.name|norm_name}}.Exec(frm {{_self.out_results(o)}}); {%- endif ~%} @@ -129,24 +131,60 @@ {%- endif -%} {%- endmacro -%} +{%- macro return_out_results_single_common(type, var_name = 'result0') -%} +{%- if type == 'any' -%} +FuncRetValUtil.FuncReturnSingleValueRaw(frm, stack, {{ var_name }}); +{%- else -%} + {%- if type is instanceof('\\mtgBuiltinType') -%} + {%- if type.isfloat -%} + FuncRetValUtil.FuncReturnSingleValueFloat(frm, stack, (double){{ var_name }}); + {%- elseif type.isdouble -%} + FuncRetValUtil.FuncReturnSingleValueFloat(frm, stack, (double){{ var_name }}); + {%- elseif type.isuint8 -%} + FuncRetValUtil.FuncReturnSingleValueInt(frm, stack, (double){{ var_name }}); + {%- elseif type.isuint16 or type.isuint32 -%} + FuncRetValUtil.FuncReturnSingleValueInt(frm, stack, (double){{ var_name }}); + {%- elseif type.isuint64 -%} + FuncRetValUtil.FuncReturnSingleValueInt(frm, stack, (double){{ var_name }}); + {%- elseif type.isstring -%} + FuncRetValUtil.FuncReturnSingleValueString(frm, stack, (string){{ var_name }}); + {%- elseif type.isbool -%} + FuncRetValUtil.FuncReturnSingleValueBool(frm, stack, (bool){{ var_name }}); + {%- else -%} + FuncRetValUtil.FuncReturnSingleValueInt(frm, stack, (double){{ var_name }}); + {%- endif -%} + {%- else -%} + {{Error('Unexpected type for single-value return optimization: ' ~ type)}} + {%- endif -%} +{%- endif -%} +{%- endmacro -%} + {%- macro return_out_results(o) -%} {%- if o.returntype -%} +{%if not has_token(o, 'bhl_coroutine') and (o.returntype == 'any' or o.returntype is instanceof('\\mtgBuiltinType')) %} +{{ _self.return_out_results_single_common(o.returntype) }} +{%- else ~%} Script_{{o.name|norm_name}}.ReturnValue(frm, stack {%- for idx, type_item in types_array(o.returntype) -%} , result{{idx}} {%- endfor -%} ); {%- endif -%} +{%- endif -%} {%- endmacro -%} {%- macro return_method_out_results(o, m) -%} {%- if m.returntype -%} +{%if not has_token(m, 'bhl_coroutine') and (m.returntype == 'any' or m.returntype is instanceof('\\mtgBuiltinType')) %} +{{ _self.return_out_results_single_common(m.returntype) }} +{%- else ~%} Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {%- for idx, type_item in types_array(m.returntype) -%} , result{{idx}} {%- endfor -%} ); {%- endif -%} +{%- endif -%} {%- endmacro -%} {%- macro decl_func_partial_class(o, prefix, this_type = null) ~%} @@ -189,7 +227,9 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {%- else ~%} var args = Script_{{o.name|norm_name}}.Method_{{m.name}}.ReadArgs(frm, stack, args_info); Script_{{o.name|norm_name}}.Method_{{m.name}}.Exec(frm, args {{_self.out_results(m)}}); + {% if has_disposable_args(m) ~%} args.Dispose(); + {%- endif ~%} {{_self.return_method_out_results(o, m)}} return null; {%- endif ~%} @@ -225,7 +265,9 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack var args = Script_{{o.name|norm_name}}.Method_{{m.name}}.ReadArgs(frm, stack, args_info); Script_{{o.name|norm_name}}.Method_{{m.name}}.Exec(frm, args {{_self.out_results(m)}}); + {% if has_disposable_args(m) ~%} args.Dispose(); + {% endif ~%} {{_self.return_method_out_results(o, m)}} return null; @@ -271,7 +313,9 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack public override void Cleanup(VM.Frame frm, bhl.VM.ExecState exec) { Cleanup(frm); {% if o.args or this_type ~%} + {% if has_disposable_args(o) ~%} args.Dispose(); + {% endif %} args = default; {% endif %} } @@ -279,7 +323,11 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {%- endmacro -%} {%- macro Args(o, this_type) ~%} - public struct Args : IDisposable { + public struct Args + {% if has_disposable_args(o) ~%} + : IDisposable + {% endif %} + { {% if this_type and not has_token(o, 'bhl_static') ~%} public {{this_type|native_type}} self; {% endif %} @@ -289,10 +337,12 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {% endfor %} + {% if has_disposable_args(o) ~%} public void Dispose() { {{ _self.dispose_args(o) }} } + {% endif %} } {%- endmacro -%} @@ -305,10 +355,8 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {%- endmacro -%} {%- macro ReturnValue(o) -%} - {%if o.returntype == 'any' %} - static public void ReturnValue(VM.Frame frm, ValStack stack, bhl.Val dv) { - stack.Push(dv); - } + {%if not has_token(o, 'bhl_coroutine') and (o.returntype == 'any' or o.returntype is instanceof('\\mtgBuiltinType')) %} + //Will use shared return function {{_self.return_out_results_single_common(o.returntype)}} {% else ~%} static public void ReturnValue(VM.Frame frm, ValStack stack, {%- for idx, type_item in types_array(o.returntype) -%} @@ -657,7 +705,8 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {%- macro reg_enum(o, scope = 'types.ns') ~%} { - var en = new EnumSymbolNative(new Origin(), "{{o.name|ns_last}}" + const string enumName = "{{o.name|ns_last}}"; + var en = new EnumSymbolNative(new Origin(), enumName #if !BHL_FRONT , typeof({{o|native_class_name}}) #else @@ -665,17 +714,16 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack #endif ); + System.Type nativeType = null; +#if !BHL_FRONT + nativeType = en.GetNativeType(); +#endif + + {{scope}}.{{o.name|ns_prefix}}Define(en); {%- for fname,v in o.values ~%} - { -#if !BHL_FRONT - if(Enum.GetName(en.GetNativeType(), {{v}}) != "{{fname}}") - throw new Exception("Enum '{{o.name}}' names don't match at value " + {{v}}); -#endif - - en.Define(new EnumItemSymbol(new Origin(), "{{fname}}", (int){{v}})); - } + RegisterEnumValue(en, nativeType, enumName, "{{fname}}", (int){{v}}); {%~ endfor -%} } @@ -889,11 +937,15 @@ Script_{{o.name|norm_name}}.Method_{{m.name}}.ReturnValue(frm, stack {{Error('Not implemented for multipled returns')}} {%- endif ~%} + {%if not has_token(f, 'bhl_coroutine') and (f.returntype == 'any' or f.returntype is instanceof('\\mtgBuiltinType')) %} + {{ _self.return_out_results_single_common(f.returntype, 'return_val') }}; + {%- else -%} { var dv = bhl.Val.New(frm.vm); {{ _self.native2val(f.returntype, return_var, 'dv') }}; stack.Push(dv); } + {%- endif ~%} {%- endif ~%} {%- endmacro -%} diff --git a/tpl/codegen_register.twig b/tpl/codegen_register.twig index 3a34d69..088aa3d 100644 --- a/tpl/codegen_register.twig +++ b/tpl/codegen_register.twig @@ -64,6 +64,55 @@ public static void RegisterEnd(Types types) {{ macro.setup_global_types(meta.units) }} } +static void RegisterEnumValue(EnumSymbolNative en, System.Type nativeType, string enumName, string valName, int val) +{ + { +#if !BHL_FRONT + if(Enum.GetName(nativeType, val) != valName) + throw new Exception($"Enum '{enumName}' names don't match at value {val}"); +#endif + + en.Define(new EnumItemSymbol(new Origin(), valName, val)); + } +} + +} + +static public class FuncRetValUtil { + +public static void FuncReturnSingleValueInt(VM.Frame frm, ValStack stack, double v0) +{ + var dv0 = bhl.Val.New(frm.vm); + dv0.SetInt(v0); + stack.Push(dv0); +} + +public static void FuncReturnSingleValueBool(VM.Frame frm, ValStack stack, bool v0) +{ + var dv0 = bhl.Val.New(frm.vm); + dv0.SetBool(v0); + stack.Push(dv0); +} + +public static void FuncReturnSingleValueFloat(VM.Frame frm, ValStack stack, double v0) +{ + var dv0 = bhl.Val.New(frm.vm); + dv0.SetFlt(v0); + stack.Push(dv0); +} + +public static void FuncReturnSingleValueString(VM.Frame frm, ValStack stack, string v0) +{ + var dv0 = bhl.Val.New(frm.vm); + dv0.SetStr(v0); + stack.Push(dv0); +} + +public static void FuncReturnSingleValueRaw(VM.Frame frm, ValStack stack, bhl.Val dv0) +{ + stack.Push(dv0); +} + } }