Initial commit

This commit is contained in:
Pavel Shevaev 2022-12-02 16:21:57 +03:00
commit cbd01c39da
5 changed files with 1271 additions and 0 deletions

14
composer.json Normal file
View File

@ -0,0 +1,14 @@
{
"name": "bit/metagen_bhl_bind",
"description": "bhl bindings code generation utils",
"homepage": "https://git.bit5.ru/bit/metagen_bhl_bind",
"require": {
"php": ">=7.4",
"twig/twig" : "v3.4.3"
},
"autoload": {
"files": [
"src/bind.inc.php"
]
}
}

263
src/bind.inc.php Normal file
View File

@ -0,0 +1,263 @@
<?php
namespace bhl_bind;
use Exception;
function bhl_twig(array $inc_path = [])
{
array_unshift($inc_path, __DIR__ . "/../tpl/");
$loader = new \Twig\Loader\FilesystemLoader($inc_path);
$twig = new \Twig\Environment($loader, [
'debug' => true,
'autoescape' => false,
'strict_variables' => true]
);
$twig->addExtension(new \Twig\Extension\DebugExtension());
bhl_add_twig_support($twig);
return $twig;
}
function bhl_add_twig_support(\Twig\Environment $twig)
{
$twig->addTest(new \Twig\TwigTest('instanceof',
function($obj, $class)
{
return (new \ReflectionClass($class))->isInstance($obj);
}
));
$twig->addFilter(new \Twig\TwigFilter('ns_last',
function($str)
{
return bhl_get_last_name($str);
}
));
$twig->addFilter(new \Twig\TwigFilter('ns_prefix',
function($str)
{
return bhl_get_ns_prefix($str);
}
));
$twig->addFilter(new \Twig\TwigFilter('bhl_type',
function($type)
{
return bhl_gen_type($type);
}
));
$twig->addFilter(new \Twig\TwigFilter('bhl_type_ref',
function($type)
{
return bhl_type_ref(is_string($type) ? $type : bhl_gen_type($type));
}
));
$twig->addFilter(new \Twig\TwigFilter('native_type',
function($type)
{
//TODO: mtgCSCodegen instance is not really needed
return bhl_gen_native_type(new \mtgCSCodegen(), $type);
}
));
$twig->addFilter(new \Twig\TwigFilter('norm_name',
function($name)
{
return bhl_normalize_name($name);
}
));
$twig->addFilter(new \Twig\TwigFilter('rtrim_comma',
function($str)
{
return rtrim(rtrim($str), ',');
}
));
$twig->addFilter(new \Twig\TwigFilter('replace_in',
function($txt, array $args = [])
{
return str_replace($args[1], $txt, $args[0]);
},
['is_variadic' => true]
));
$twig->addFunction(new \Twig\TwigFunction('Error',
function($e)
{
throw new Exception($e);
}
));
$twig->addFunction(new \Twig\TwigFunction('Warn',
function($e)
{
echo "WARN: $e\n";
}
));
$twig->addFunction(new \Twig\TwigFunction('has_token',
function($o, $token)
{
return $o->hasToken($token);
}
));
$twig->addFunction(new \Twig\TwigFunction('token',
function($o, $name)
{
return $o->getToken($name);
}
));
$twig->addFunction(new \Twig\TwigFunction('token_or',
function($o, $name, $v)
{
if($o->hasToken($name))
return $o->getToken($name);
else
return $v;
}
));
$twig->addFunction(new \Twig\TwigFunction('count_required_args',
function(\mtgMetaFunc $fn)
{
$req_args_num = 0;
foreach($fn->getArgs() as $arg)
{
if($arg->hasToken('default'))
break;
++$req_args_num;
}
return $req_args_num;
}
));
$twig->addFunction(new \Twig\TwigFunction('count_default_args',
function(\mtgMetaFunc $fn)
{
$def_args_num = 0;
foreach($fn->getArgs() as $arg)
{
if($arg->hasToken('default'))
++$def_args_num;
else if($def_args_num > 0)
throw new Exception("Field '{$name}' in {$fn->getName()} is expected to be tagged with @default");
}
return $def_args_num;
}
));
$twig->addFunction(new \Twig\TwigFunction('types_array',
function(\mtgType $type)
{
$arr = array();
if($type instanceof \mtgMultiType)
$arr = $type->getValues();
else
$arr[] = $type;
return $arr;
}
));
}
function bhl_get_last_name($name)
{
$items = explode('.', $name);
return end($items);
}
function bhl_normalize_name($name)
{
return str_replace('.', '__', $name);
}
function bhl_get_ns_prefix($name)
{
$items = explode('.', $name);
if(sizeof($items) == 1)
return '';
$prefix = '';
for($i=0;$i<sizeof($items)-1;++$i)
$prefix .= 'Nest("'.$items[$i].'").';
return $prefix;
}
function bhl_type_ref($type_str)
{
if(preg_match('~((\w|\.)+)\[\]~', $type_str, $ms))
return "types.TArr(\"{$ms[1]}\")";
else if(preg_match('~func\s+((\w|\.)+)\s+\(\)~', $type_str, $ms))
return "types.TFunc(\"{$ms[1]}\")";
else if(preg_match('~func\s+((\w|\.)+)\s+\(((\w|\.)+)\)~', $type_str, $ms))
return "types.TFunc(\"{$ms[1]}\", \"{$ms[3]}\")";
else if(preg_match('~((\w|\.)+)\,((\w|\.)+)~', $type_str, $ms))
return "types.T(\"{$ms[1]}\", \"{$ms[3]}\")";
else
return "types.T(\"$type_str\")";
}
function bhl_gen_type(\mtgType $type = null)
{
if($type === null)
return "void";
if($type instanceof \mtgBuiltinType)
{
if($type->isFloat() || $type->isDouble())
return "float";
else if($type->isInt() || $type->isUint())
return "int";
}
else if($type instanceof \mtgMetaFunc)
{
$ret_type = $type->getReturnType() ? bhl_gen_type($type->getReturnType()) : 'void';
$str = "func $ret_type(";
foreach($type->getArgs() as $arg)
$str .= bhl_gen_type($arg->getType()) . ",";
$str = rtrim($str, ',');
$str .= ")";
return $str;
}
else if($type instanceof \mtgMultiType)
{
$str = '';
foreach($type->getValues() as $sub_type)
$str .= bhl_gen_type($sub_type) . ",";
return rtrim($str, ",");
}
else if($type instanceof \mtgArrType)
return bhl_gen_type($type->getValue()) . "[]";
return ''.$type;
}
function bhl_gen_native_type(\mtgCSCodegen $gen, \mtgType $type)
{
//any special case
if($type == "any")
return "bhl.Val";
if($type instanceof \mtgArrType)
{
if($type->getValue()->getName() == "any")
return "bhl.ValList";
else
return "HList<".bhl_gen_native_type($gen, $type->getValue()).">";
}
//func special case
if($type instanceof \mtgMetaFunc)
return "VM.FuncPtr";
$alias = null;
if($type instanceof \mtgUserType)
$alias = $type->getToken('bhl_native_class');
if($type instanceof \mtgArrType)
$orig_name = $type->getValue()->getName();
else
$orig_name = $type->getName();
if($alias)
$type->setName($alias);
$ntype = $gen->genNativeType($type);
if($alias)
$type->setName($orig_name);
return $ntype;
}

38
tpl/codegen_register.twig Normal file
View File

@ -0,0 +1,38 @@
using System;
using System.Collections;
using System.Collections.Generic;
#if !BHL_FRONT
using BitGames;
using BitGames.Autogen;
using UnityEngine;
using Leopotam.Ecs;
using bhl;
#endif
{%- import "macro.twig" as macro -%}
{% block extra %}
{% endblock %}
namespace bhl {
{% block declare %}
#if !BHL_FRONT
{{ macro.decl_units(units) }}
#endif
{% endblock %}
static public class BHL_AutoBindings {
public static void Register(Types types)
{
BHL_Types.Type_GenericArray = new GenericArrayTypeSymbol(new Proxy<IType>());
{% block register %}
{{ macro.reg_units(units) }}
{% endblock %}
}
}
} //namespace bhl

15
tpl/codegen_types.twig Normal file
View File

@ -0,0 +1,15 @@
namespace bhl {
static public class BHL_Types
{
static public IType Type_GenericArray;
{%- for u in units ~%}
{%- if u.object is instanceof('\\mtgMetaStruct') ~%}
static public IType Type_{{u.object.name|norm_name}};
{%- endif ~%}
{%- endfor -%}
}
} //namespace bhl

941
tpl/macro.twig Normal file
View File

@ -0,0 +1,941 @@
{%- macro func_native(o, scope = 'types.ns', this_prefix = '') ~%}
{
var fn = new FuncSymbolNative("{{o.name|ns_last}}",
{%- if has_token(o, 'bhl_coroutine') -%}
FuncAttrib.Async,
{%- endif ~%}
{{ o.returntype|bhl_type_ref }},
{{ count_default_args(o) }},
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
{{ _self.read_args2natives(o, '__') }}
{%~ if o.returntype %}
var return_val =
{%- endif ~%}
{{this_prefix}}{{ _self.call_native_prefix_func(o, '__') }}
{# pass back and release ref args #}
{%- for arg in o.args -%}
{%- if has_token(arg, 'bhl_ref_arg') ~%}
{{ _self.native2val(arg.type, '__ref_' ~ arg.name, '__' ~ arg.name) }};
__{{arg.name}}.Release();
{%- endif -%}
{%- endfor -%}
{{ _self.return_val(o, 'return_val') }}
return null;
}
#else
null
#endif
{% if o.args %},{% endif %}
{{ _self.func_decl_args(o) }}
);
{{scope}}.{{o.name|ns_prefix}}Define(fn);
}
{%- endmacro -%}
{%- macro func_partial(o, scope = 'types.ns') ~%}
{
var fn = new FuncSymbolNative("{{o.name|ns_last}}",
{%- if has_token(o, 'bhl_coroutine') -%}
FuncAttrib.Async,
{%- endif ~%}
{{o.returntype|bhl_type_ref}},
{{ count_default_args(o) }},
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
#if !BHL_FRONT
{% if has_token(o, 'bhl_coroutine') -%}
var coro = CoroutinePool.New<Script_{{o.name|norm_name}}>(frm.vm);
coro.Init(frm, args_info);
return coro;
{%- else -%}
{%- if o.args -%}
var args = Script_{{o.name|norm_name}}.ReadArgs(frm, args_info);
Script_{{o.name|norm_name}}.Exec(frm, stack, args);
{%- else ~%}
Script_{{o.name|norm_name}}.Exec(frm, stack);
{%- endif ~%}
return null;
{%- endif ~%}
#else
return null;
#endif
}
{% if o.args %},{% endif %}
{{ _self.func_decl_args(o) }}
);
{{scope}}.{{o.name|ns_prefix}}Define(fn)
}
{%- endmacro -%}
{%- macro func_partial_class(o, prefix, this_type = null) ~%}
public partial class {{prefix}}{{o.name|norm_name}} {% if has_token(o, 'bhl_coroutine') %}: bhl.ICoroutine {% endif %} {
{% if o.args or this_type ~%}
{{ _self.Args(o, this_type) }}
{{ _self.Args_ReadArgs(o, this_type) }}
{% endif %}
{%-if o.returntype ~%}
{{ _self.ReturnValue(o) }}
{% endif %}
{% if has_token(o, 'bhl_coroutine') %}
{{ _self.coroutine_state(o, this_type) }}
{% endif ~%}
} //{{prefix}}{{o.name|norm_name}}
{%~ endmacro -%}
{%- macro method_partial(o, m, class_container) ~%}
{
var fn = new FuncSymbolNative("{{m.name|norm_name}}",
{{ m.returntype|bhl_type_ref }},
{{ count_default_args(m) }},
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
Script_{{o.name|norm_name}}.Method_{{m.name}}.Exec(
frm,
stack,
Script_{{o.name|norm_name}}.Method_{{m.name}}.ReadArgs(frm, args_info)
);
return null
}
#else
null
#endif
{% if m.args %},{% endif %}
{{ _self.func_decl_args(m) }}
);
{{class_container}}.Define(fn);
}
{%if has_token(m, 'bin_op') ~%}
{
var fn = new FuncSymbolNative("{{token(m, 'bin_op')}}",
{{ m.returntype|bhl_type_ref }},
{{ count_default_args(m) }},
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
Script_{{o.name|norm_name}}.Method_{{m.name}}.Exec(
frm,
stack,
Script_{{o.name|norm_name}}.Method_{{m.name}}.ReadArgs(frm, args_info)
);
return null
}
#else
null
#endif
{% if m.args %},{% endif %}
{{ _self.func_decl_args(m) }}
);
{{class_container}}.OverloadBinaryOperator(fn);
{{class_container}}.Define(fn);
}
{% endif ~%}
{%- endmacro -%}
{%- macro coroutine_state(o, this_type) -%}
{% if o.args or this_type ~%}
Args args;
{% endif %}
public void Init(VM.Frame frm, ValStack stack, FuncArgsInfo args_info) {
{% if o.args or this_type ~%}
args = ReadArgs(frm, args_info);
{% endif %}
Init(frm);
}
public void Tick(VM.Frame frm, bhl.VM.ExecState exec, ref BHS status) {
Exec(frm, exec.stack, ref status);
}
public void Cleanup(VM.Frame frm, bhl.VM.ExecState exec) {
Cleanup(frm);
{% if o.args or this_type ~%}
args = default;
{% endif %}
}
{%- endmacro -%}
{%- macro Args(o, this_type) ~%}
public struct Args {
{% if this_type ~%}
public {{this_type|native_type}} self;
{% endif %}
{% for arg in o.args ~%}
{#attribute declaration#}
public {% if has_token(arg, 'bhl_ref_arg') %} bhl.Val {% else %} {{arg.type|native_type}} {% endif %} {{arg.name}};
{% endfor %}
}
{%- endmacro -%}
{%- macro Args_ReadArgs(o, this_type) -%}
static public Args ReadArgs(VM.Frame frm, ValStack stack, FuncArgsInfo args_info) {
var args = new Args();
{#any array special handling#}
{% for arg in o.args %}
{% if arg.type is instanceof('\\mtgArrType') and arg.type.value.name == 'any' %}
args.{{arg.name}} = ValList.New(frm.vm);
{% endif %}
{% endfor %}
{{ _self.read_args2natives(o, 'args.', this_type) }}
return args;
}
{%- endmacro -%}
{%- macro ReturnValue(o) -%}
{%if o.returntype == 'any' %}
static void ReturnValue(VM.Frame frm, ValStack stack, bhl.Val dv) {
stack.Push(dv);
}
{% else ~%}
static void ReturnValue(VM.Frame frm, ValStack stack,
{%- for idx, type_item in types_array(o.returntype) -%}
{{type_item|native_type}} v{{idx}}{% if not loop.last %},{% endif %}
{%- endfor -%}
)
{
{% set ret_types = types_array(o.returntype) %}
{%- for idx, type_item in ret_types -%}
{% set ridx = ret_types|length - idx - 1 ~%}
{
var dv{{ridx}} = bhl.Val.New(frm.vm);
{{ _self.native2val(ret_types[ridx], 'v'~ridx, 'dv'~ridx) }};
stack.Push(dv{{ridx}});
}
{%- endfor ~%}
}
{% endif %}
{%- endmacro -%}
{%- macro local_native_vars(vars, prefix) -%}
{%- for v in vars -%}
{%- if has_token(v, 'bhl_ref_arg') -%}
bhl.Val {{prefix}}{{v.name}} = default;
{{v.type|native_type}} {{prefix}}ref_{{v.name}} = default;
{%- else -%}
{{v.type|native_type}} {{prefix}}{{v.name}} = default;
{%- endif -%}
{%- endfor ~%}
{%- endmacro -%}
{%- macro read_args2natives(o, arg_prefix, this_type = null) -%}
{{ _self.local_native_vars(o.args, arg_prefix) }}
{# traversing args in reverse order #}
{%- set default_counter = 0 -%}
{%- for arg in o.args|reverse ~%}
{#default arg condition#}
{%- if has_token(arg, 'default') -%}
{%- if has_token(arg, 'bhl_ref_arg') -%}
{{Error("ref argument is not allowed to have a default value: " ~ o.name ~ '.' ~ arg.name)}}
{%- endif ~%}
{%- do ++default_counter -%}
if(!args_info.IsDefaultArgUsed({{o.args|length - count_required_args(o) - default_counter}}))
{%- endif ~%}
{
{%- if has_token(arg, 'bhl_ref_arg') ~%}
var dv = stack.Pop();
{{arg_prefix}}{{arg.name}} = dv;
{{ _self.val2native(arg.type, 'dv', arg_prefix ~ 'ref_' ~ arg.name) }};
{%- else ~%}
var dv = stack.Pop();
{{ _self.val2native(arg.type, 'dv', arg_prefix ~ arg.name) }};
dv.Release();
{%- endif ~%}
}
{#-default arg value-#}
{%- if has_token(arg, 'default') ~%}
else
{
{{_self.default_value(arg_prefix ~ arg.name, token(arg, 'default'))}};
}
{%- endif ~%}
{%- endfor ~%}
{%- if this_type ~%}
{
var dv = stack.Pop();
{{ _self.val2native(this_type, 'dv', arg_prefix ~ '.self') }};
dv.Release();
}
{%- endif ~%}
{%- endmacro -%}
{%- macro default_value(dst, value) -%}
{{dst}} = {{value|replace({'%self%': dst})}}
{%- endmacro -%}
{%- macro call_native_prefix_func(o, args_prefix = '') -%}
{# replaces '..' contents of 'bhl_native_prefix' with args #}
{%- apply replace_in(token(o, 'bhl_native_prefix'), '..') -%}
{%- for arg in o.args -%}
{%- if has_token(arg, 'bhl_ref_arg') -%}
ref {{args_prefix}}ref_{{arg.name}}
{%- else -%}
{{args_prefix}}{{arg.name}}
{%- endif -%}{% if not loop.last %},{% endif %}
{%- endfor -%}
{%- endapply -%};
{%- endmacro -%}
{%- macro func_decl_args(fn) -%}
{%- for arg in fn.args -%}
new FuncArgSymbol("{{arg.name}}", {{arg.type|bhl_type_ref}},
{%-if has_token(arg, 'bhl_ref_arg') -%}
true
{%-else-%}
false
{%-endif-%}
){% if not loop.last %},{% endif %}
{%- endfor -%}
{%- endmacro -%}
{%- macro val2native(type, value, native) -%}
{# any special case #}
{%- if type == 'any' -%}
{{native}} = {{value}}
{# bhl functor special case #}
{%- elseif type == "ConfScript" -%}
{{native}}.fct.obj = {{value}}.obj
{%- else -%}
{%- if type is instanceof('\\mtgMetaFunc') -%}
{{native}} = (VM.FuncPtr){{value}}.obj;{{native}}.Retain()
{%- endif -%}
{%- if type is instanceof('\\mtgArrType') -%}
var dvl = (ValList){{value}}._obj;
{{native}}.Clear();
for(int i=0;i<dvl.Count;++i)
{
var tdv = dvl[i];
var {{_self.val2native(type.value, 'tdv', 'tmp')}};
{{native}}.Add(tmp);
}
{%- endif -%}
{%- if type is instanceof('\\mtgBuiltinType') -%}
{%- if type.isfloat -%}
{{native}} = (float){{value}}._num
{%- elseif type.isdouble -%}
{{native}} = {{value}}._num
{%- elseif type.isuint8 -%}
{{native}} = (byte){{value}}._num
{%- elseif type.isuint16 or type.isuint32 -%}
{{native}} = (uint){{value}}._num
{%- elseif type.isuint64 -%}
{{native}} = (ulong){{value}}._num
{%- elseif type.isstring -%}
{{native}} = {{value}}.str
{%- elseif type.isbool -%}
{{native}} = {{value}}.bval
{%- else -%}
{{native}} = (int){{value}}._num
{%- endif -%}
{%- endif -%}
{%- if type is instanceof('\\mtgUserType') -%}
{%- if type is instanceof('\\mtgMetaEnum') -%}
{{value}}.SetInt((int){{native}})
{{native}} = ({{token_or(type, 'bhl_native_class', type.name)}})((int){{value}}._num)
{%- else -%}
{%- if has_token(type, 'bhl_custom_rw') -%}
var tmp = new {{token_or(type, 'bhl_native_class', type.name)}}; {{value}}.Decode(ref tmp); {{native}} = tmp
{%- else -%}
{{native}} = ({{token_or(type, 'bhl_native_class', type.name)}}){{value}}._obj
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endmacro -%}
{%- macro native2val(type, native, value) -%}
{# any special case #}
{%- if type == 'any' -%}
{{value}} = {{native}}
{# bhl functor special case #}
{%- elseif type == "ConfScript" -%}
{{value}}.obj = {{native}}.fct.obj
{%- else -%}
{%- if type is instanceof('\\mtgMetaFunc') -%}
{{value}}.SetObj({{native}}, fld.Type)
{%- endif -%}
{%- if type is instanceof('\\mtgArrType') -%}
var dvl = ValList.New(frm.vm);
for(int i=0;i<{{native}}.Count;++i)
{
var tmp = {{native}}[i];
var tdv = bhl.Val.New(frm.vm);
{{_self.native2val(type.value, 'tmp', 'tdv')}};
dvl.lst.Add(tdv);
}
{{value}}.SetObj(dvl, BHL_Types.Type_GenericArray);
{%- endif -%}
{%- if type is instanceof('\\mtgBuiltinType') -%}
{%- if type.isfloat -%}
{{value}}.SetFlt({{native}})
{%- elseif type.isdouble -%}
{{value}}.SetFlt({{native}})
{%- elseif type.isuint8 -%}
(byte){{value}}._num
{{value}}.SetInt({{native}})
{%- elseif type.isuint16 or type.isuint32 -%}
{{value}}.SetInt({{native}})
{%- elseif type.isuint64 -%}
{{value}}.SetInt({{native}})
{%- elseif type.isstring -%}
{{value}}.SetStr({{native}})
{%- elseif type.isbool -%}
{{value}}.SetBool({{native}})
{%- else -%}
{{value}}.SetInt({{native}})
{%- endif -%}
{%- endif -%}
{%- if type is instanceof('\\mtgUserType') -%}
{%- if type is instanceof('\\mtgMetaEnum') -%}
{{value}}.SetInt((int){{native}})
{%- else -%}
{%- if has_token(type, 'bhl_custom_rw') -%}
{{value}}.Encode({{native}})
{%- else -%}
{%if not has_token(type, "bhl_no_itype") and
not has_token(type, "bhl_ecs_component") and
not has_token(type, "POD") -%}
{{value}}.SetObj({{native}}, {{native}}?.GetIType())
{%- else -%}
{{value}}.SetObj({{native}}, BHL_Types.Type_{{type.name|norm_name}})
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endif -%}
{%- endmacro -%}
{%- macro enum(o, scope = 'types.ns') ~%}
{
var en = new EnumSymbol("{{o.name|ns_last}}");
{{scope}}.{{o.name|ns_prefix}}Define(en);
{%- for fname,v in o.values ~%}
{
en.Define(new EnumItemSymbol("{{fname}}" ,(int){{v}}));
}
{%~ endfor -%}
}
{%- endmacro -%}
{%- macro class(o, scope = 'types.ns') ~%}
{# ignore special case any #}
{% if o.name == 'any' %}
{% else %}
{
var cl = new ClassSymbolNative("{{o.name|ns_last}}",
{% if o.parent %}
(ClassSymbol)types.T("{{o.parent}}").Get(),
{% else ~%}
//no parent
null,
{% endif %}
{% if has_token(o, 'bhl_no_new') ~%}
//constructor is not allowed
null
{% else ~%}
delegate(VM.Frame frm, ref Val v, IType type) {
#if !BHL_FRONT
var o = new {{token_or(o, 'bhl_native_class', o.name)}}({{token_or(o, 'bhl_native_class_params', '')}});
{%if has_token(o, 'bhl_custom_rw') %}
v.Encode(o);
{% else %}
{% if has_token(o, 'POD') %}
o.reset();
{% endif %}
v.SetObj(o, type);
{% endif %}
#endif
}
{% endif ~%}
);
{% if has_token(o, 'POD') and not has_token(o, 'bhl_custom_rw') %}
{{Warn("bhl POD boxing '" ~ o.name ~ "'")}}
{% endif %}
{% for f in o.getfields %}
{{ _self.class_field(o, f) }}
{% endfor %}
{% for m in o.getfuncs %}
{% if has_token(m, 'bhl_native_prefix') %}
{{ _self.func_native(m, 'cl', '(('~token_or(o, 'bhl_native_class', o.name)~')stack.Pop()._obj).') }}
{% else %}
{{ _self.method_partial(o, m, 'cl') }}
{% endif %}
{% endfor %}
{{scope}}.{{o.name|ns_prefix}}Define(cl);
cl.Setup();
}
{% endif %}
{%- endmacro -%}
{%- macro class_field(o, f) -%}
{% set class = token_or(o, 'bhl_native_class', o.name) %}
{
cl.Define(new FieldSymbol("{{f.name}}", {{f.type|bhl_type_ref}},
{% if token_or(f, 'bhl_get', 1) != 0 ~%}
//getter
delegate(VM.Frame frm, Val ctx, ref Val v, FieldSymbol fld) {
#if !BHL_FRONT
{%~ if has_token(o, 'bhl_custom_rw') ~%}
{{class}} f = new {{class}}(); ctx.Decode(ref f);
{%- else ~%}
var f = ({{class}})ctx.obj;
{%- endif ~%}
{% if token(f, 'bhl_get') == 2 %}
{{f.type|native_type}} nv = Script_{{o.name|norm_name}}.Get_{{f.name}}(f);
{{_self.native2val(f.type, 'nv', 'v')}};
{% else %}
{{_self.native2val(f.type, 'f.' ~ f.name, 'v')}};
{%- endif ~%}
#endif
}
{%- else ~%}
//getter not allowed
null
{%- endif ~%}
,
{% if token_or(f, 'bhl_set', 1) != 0 ~%}
//setter
delegate(VM.Frame frm, ref Val ctx, Val v, FieldSymbol fld) {
#if !BHL_FRONT
{%~ if has_token(o, 'bhl_custom_rw') ~%}
{{class}} f = new {{class}}(); ctx.Decode(ref f);
{%- else ~%}
var f = ({{class}})ctx.obj;
{%- endif ~%}
{% if token(f, 'bhl_set') == 2 %}
{{_self.val2native(f.type, 'v', 'var nv')}};
Script_{{o.name|norm_name}}.Set_{{f.name}}(ref f, nv);
{% else %}
{{_self.val2native(f.type, 'v', 'f.' ~ f.name)}};
{%- endif ~%}
{%~ if has_token(o, 'bhl_custom_rw') ~%}
ctx.Encode(f);
{%- elseif has_token(o, 'POD') ~%}
ctx.SetObj(f, ctx.type);
{%- endif ~%}
#endif
}
{%- else ~%}
//setter not allowed
null
{%- endif ~%}
);
}
{%- endmacro -%}
{%- macro interface(o, scope = 'types.ns') ~%}
{
var ifs = new InterfaceSymbolNative("{{o.name|ns_last}}", null
{% for m in o.getfuncs %}
, new FuncSymbolNative("{{m.name}}", {{m.returntype|bhl_type_ref}}, 0, null)
{% endfor %}
);
{{scope}}.{{o.name|ns_prefix}}Define(ifs);
}
{%- endmacro -%}
{%- macro ecs_component(o) ~%}
{
var fn = new FuncSymbolNative("{{o.name}}_Ensure", Types.Void,
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
EcsEntity e = default;
stack.PopRelease().Decode(ref e);
ref var cmp = ref e.Ensure<ecs.{{o.name}}>();
return null;
}
#else
null
#endif
,
new FuncArgSymbol("__self", types.T("ecs.Entity"))
);
types.ns.Define(fn);
}
{
var fn = new FuncSymbolNative("{{o.name}}_Del", Types.Void,
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
EcsEntity e = default;
stack.PopRelease().Decode(ref e);
e.Del<{{o.name}}>();
return null;
}
#else
null
#endif
,
new FuncArgSymbol("__self", types.T("ecs.Entity"))
);
types.ns.Define(fn);
}
{
var fn = new FuncSymbolNative("{{o.name}}_Exists", Types.Bool,
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
EcsEntity e = default;
stack.PopRelease().Decode(ref e);
var dv = bhl.Val.New(frm.vm);
dv.SetBool(e.Has<ecs.{{o.name}}>());
stack.Push(dv);
return null;
}
#else
null
#endif
,
new FuncArgSymbol("__self", types.T("ecs.Entity"))
);
types.ns.Define(fn);
}
{% for f in o.getfields %}
{{ _self.ecs_component_field(o, f) }}
{% endfor %}
{% for m in o.getfuncs %}
{{ _self.ecs_component_func(o, m) }}
{% endfor %}
{% if has_token(o, 'bhl_ecs_component_ref') %}
{
var cl = new ClassSymbolNative("{{o.name}}__Ref", null, null);
{% for f in o.getfields %}
{{ _self.ecs_component_field_ref(o, f) }}
{% endfor %}
types.ns.Define(cl);
cl.Setup();
}
{
var fn = new FuncSymbolNative("{{o.name}}_Ref", {{(o.name ~ '__Ref') | bhl_type_ref}},
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
EcsEntity e = default;
var ev = stack.Pop();
ev.Decode(ref e);
ev.Release();
ref var cmp = ref e.Ensure<ecs.{{o.name}}>();
var dv = bhl.Val.New(frm.vm);
dv._obj = e.GetInternalWorld();
dv._num = e.GetInternalId();
dv.type = cl;
stack.Push(dv);
return null;
}
#else
null
#endif
,
new FuncArgSymbol("__self", types.T("ecs.Entity"))
);
types.ns.Define(fn);
}
{% endif %}
{%- endmacro -%}
{%- macro ecs_component_field(o, f) ~%}
{
var fn = new FuncSymbolNative("{{f.name}}", {{o|bhl_type_ref}},
{%- if token_or(f, 'bhl_set', 1) != 0 ~%}
1,
{%- endif ~%}
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
#if !BHL_FRONT
Val dv = null;
{%- if token_or(f, 'bhl_set', 1) != 0 ~%}
if(args_info.CountArgs() > 1) {
dv = stack.Pop();
}
{%- endif ~%}
EcsEntity e = default;
stack.PopRelease().Decode(ref e);
ref var cmp = ref e.Ensure<ecs.{{o.name}}>();
var v = cmp.{{f.name}};
{%- if token_or(f, 'bhl_set', 1) != 0 ~%}
if(dv != null) {
{{ _self.val2native(f.type, 'v', 'dv') }};
cmp.{{f.name}} = v;
dv.Release();
}
{%- endif ~%}
dv = Val.New(frm.vm);
{
{{ _self.native2val(f.type, 'v', 'dv') }};
}
stack.Push(dv);
#endif
return null;
},
new FuncArgSymbol("e", types.T("ecs.Entity"))
{%- if token_or(f, 'bhl_set', 1) != 0 ~%}
, new FuncArgSymbol("v", {{o|bhl_type_ref}})
{%- endif ~%}
);
types.ns.Define(fn);
}
{%- endmacro -%}
{%- macro ecs_component_func(o, m) ~%}
{
var fn = new FuncSymbolNative("{{o.name}}_{{m.name}}",
{{m.returntype|bhl_type_ref}},
{{ count_default_args(m) }},
#if !BHL_FRONT
delegate(VM.Frame frm, ValStack stack, FuncArgsInfo args_info, ref BHS status) {
EcsEntity e = default;
{{ _self.read_args2natives(m, '__') }}
stack.PopRelease().Decode(ref e);
ref var cmp = ref e.Ensure<ecs.{{o.name}}>();
{%~ if m.returntype %}
var return_val =
{%- endif ~%}
cmp.{{m.name}}(
{%- for arg in m.args ~%} __{{arg.name}}{% if not loop.last %},{% endif %} {%- endfor ~%}
);
{{ _self.return_val(m, 'return_val') }}
return null;
}
#else
null
#endif
, new FuncArgSymbol("__self", types.T("ecs.Entity"))
{%- if m.args %},{% endif ~%}
{{ _self.func_decl_args(m) }}
);
types.ns.Define(fn);
}
{%- endmacro -%}
{%- macro return_val(f, return_var) -%}
{%- if f.returntype -%}
{%- if f.returntype is instanceof('\\mtgMultiType') -%}
{{Error('Not implemented for multipled returns')}}
{%- endif ~%}
{
var dv = bhl.Val.New(frm.vm);
{{ _self.native2val(f.returntype, return_var, 'dv') }};
stack.Push(dv);
}
{%- endif ~%}
{%- endmacro -%}
{%- macro ecs_component_field_ref(o, f) ~%}
{
cl.Define(new FieldSymbol("{{f.name}}", {{f.type|bhl_type_ref}},
//getter
{%- if token_or(f, 'bhl_get', 1) != 0 ~%}
delegate(VM.Frame frm, Val ctx, ref Val v, FieldSymbol fld) {
#if !BHL_FRONT
var pool = ((Leopotam.Ecs.EcsWorld)ctx.obj).GetPool<ecs.{{o.name}}>();
int idx = (int)ctx._num;
ref var f = ref pool.GetItem(idx);
{{ _self.native2val(f.type, 'f.' ~ f.name, 'v') }};
#endif
},
{% else %}
null,
{% endif %}
//setter
{%- if token_or(f, 'bhl_set', 1) != 0 ~%}
delegate(VM.Frame frm, ref Val ctx, Val v, FieldSymbol fld) {
#if !BHL_FRONT
var pool = ((Leopotam.Ecs.EcsWorld)ctx.obj).GetPool<ecs.{{o.name}}>();
int idx = (int)ctx._num;
ref var f = ref pool.GetItem(idx);
{{ _self.val2native(f.type, 'v', 'f.' ~ f.name) }};
#endif
}
{% else %}
null,
{% endif %}
));
}
{%- endmacro -%}
{%- macro decl_units(units) ~%}
{%- for u in units -%}
{%- if u.object is instanceof('\\mtgMetaFunc') -%}
{%- if not has_token(u.object, 'bhl_native_prefix') -%}
{{ _self.func_partial_class(u.object, 'Script_') }}
{%- endif -%}
{%- endif -%}
{%- if u.object is instanceof('\\mtgMetaStruct') -%}
{%- if u.object.getfuncs or u.object.getfields ~%}
public partial class Script_{{u.object.name}} {
{%- endif -%}
{% for m in u.object.getfuncs %}
{%- if not has_token(m, 'bhl_native_prefix') ~%}
{{ _self.func_partial_class(m, 'Method_') }}
{%- endif -%}
{% endfor %}
{%- if u.object.getfuncs or u.object.getfields ~%}
} //Script_{{u.object.name}}
{%- endif -%}
{%- endif -%}
{%- endfor -%}
{%- endmacro -%}
{%- macro reg_units(units) ~%}
{%- for u in units -%}
{%- if u.object is instanceof('\\mtgMetaFunc') -%}
{%- if has_token(u.object, 'bhl_native_prefix') -%}
{{ _self.func_native(u.object) }}
{%- else -%}
{{ _self.func_partial(u.object) }}
{%- endif -%}
{%- elseif u.object is instanceof('\\mtgMetaStruct') -%}
{%- if has_token(u.object, 'bhl_ecs_component') -%}
{{ _self.ecs_component(u.object) }}
{%- else -%}
{{ _self.class(u.object) }}
{%- endif -%}
{%- elseif u.object is instanceof('\\mtgMetaInterface') -%}
{{ _self.interface(u.object) }}
{%- elseif u.object is instanceof('\\mtgMetaEnum') -%}
{{ _self.enum(u.object) }}
{%- else -%}
{{Error('Not supported type: ' ~ u.object)}}
{%- endif -%}
{%- endfor -%}
{%- for u in units -%}
{%- if u.object is instanceof('\\mtgMetaStruct') ~%}
{%- if not has_token(u.object, 'bhl_ecs_component') ~%}
{
var tmp = types.T("{{u.object.name}}").Get();
if(tmp == null)
throw new System.Exception("Type '{{u.object.name}}' not resolved");
BHL_Types.Type_{{u.object.name|norm_name}} = tmp;
}
{%~ endif ~%}
{%- endif -%}
{%- endfor -%}
{%- endmacro -%}