2022-12-08 11:40:55 +03:00
|
|
|
<?php
|
|
|
|
namespace metagen_go;
|
2023-06-06 14:37:34 +03:00
|
|
|
|
2022-12-08 11:40:55 +03:00
|
|
|
use Exception;
|
2023-06-06 14:37:34 +03:00
|
|
|
use Twig\{TwigTest, TwigFilter, TwigFunction};
|
2022-12-08 11:40:55 +03:00
|
|
|
|
2023-08-31 10:48:55 +03:00
|
|
|
function get_twig(array $inc_path = []): \Twig\Environment
|
2022-12-08 11:40:55 +03:00
|
|
|
{
|
|
|
|
array_unshift($inc_path, __DIR__ . "/../tpl/");
|
|
|
|
$loader = new \Twig\Loader\FilesystemLoader($inc_path);
|
|
|
|
|
|
|
|
$twig = new \Twig\Environment($loader, [
|
2023-06-06 14:37:34 +03:00
|
|
|
'debug' => true,
|
|
|
|
'autoescape' => false,
|
|
|
|
'strict_variables' => true,
|
|
|
|
]);
|
2022-12-08 11:40:55 +03:00
|
|
|
$twig->addExtension(new \Twig\Extension\DebugExtension());
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
add_twig_tests($twig);
|
|
|
|
add_twig_filters($twig);
|
|
|
|
add_twig_functions($twig);
|
2022-12-08 11:40:55 +03:00
|
|
|
|
|
|
|
return $twig;
|
|
|
|
}
|
|
|
|
|
|
|
|
function supported_tokens()
|
|
|
|
{
|
|
|
|
return [
|
2023-06-06 14:37:34 +03:00
|
|
|
'table',
|
|
|
|
'table_pkey',
|
|
|
|
'table_json_kv',
|
2023-07-31 17:48:54 +03:00
|
|
|
'db_skip',
|
2023-06-06 14:37:34 +03:00
|
|
|
|
2023-07-04 11:05:12 +03:00
|
|
|
'data_root',
|
2023-06-06 14:37:34 +03:00
|
|
|
'bitfields',
|
|
|
|
'diffable',
|
|
|
|
'diff_removed',
|
|
|
|
|
|
|
|
'alias',
|
2022-12-08 11:40:55 +03:00
|
|
|
'default',
|
|
|
|
'virtual',
|
|
|
|
|
|
|
|
'statist',
|
|
|
|
'statist_skip',
|
2022-12-08 16:51:08 +03:00
|
|
|
'statist_alias',
|
2022-12-08 11:40:55 +03:00
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function add_twig_tests(\Twig\Environment $twig)
|
2022-12-08 11:40:55 +03:00
|
|
|
{
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'metaenum',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaInfoUnit $u): bool => $u->object instanceof \mtgMetaEnum,
|
2022-12-08 11:40:55 +03:00
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'metastruct',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaInfoUnit $u): bool => $u->object instanceof \mtgMetaStruct,
|
2022-12-08 11:40:55 +03:00
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'metarpc',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaInfoUnit $u): bool => $u->object instanceof \mtgMetaRPC,
|
2022-12-08 11:40:55 +03:00
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'enum',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgMetaEnum,
|
2022-12-08 11:40:55 +03:00
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'struct',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgMetaStruct,
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'array',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgArrType,
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'builtin',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType,
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'numeric',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isNumeric(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'int',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isInt(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'uint',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isUint(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'bool',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isBool(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'float',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isFloat(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'double',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isDouble(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'string',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isString(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'blob',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgType $t): bool => $t instanceof \mtgBuiltinType && $t->isBlob(),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
|
|
|
|
$twig->addTest(new TwigTest(
|
|
|
|
'instanceof',
|
|
|
|
fn($obj, $class): bool => (new \ReflectionClass($class))->isInstance($obj),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function add_twig_filters(\Twig\Environment $twig)
|
2023-06-06 14:37:34 +03:00
|
|
|
{
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'go_type',
|
2023-09-01 17:45:20 +03:00
|
|
|
fn(\mtgType $t, array $tokens = []): string => go_type($t, $tokens),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'ucfirst',
|
|
|
|
fn(string $str): string => ucfirst($str),
|
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'lcfirst',
|
|
|
|
fn(string $str): string => lcfirst($str),
|
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'camel',
|
|
|
|
fn(string $str): string => snake2camel($str),
|
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'quote',
|
|
|
|
fn(string $str, string $char = '`'): string => "{$char}{$str}{$char}"
|
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'sql_where',
|
|
|
|
function(array $fields): string {
|
|
|
|
$exprs = [];
|
|
|
|
foreach ($fields as $field) {
|
|
|
|
$fieldName = $field->getName();
|
|
|
|
$exprs[] = "`{$fieldName}` = ?";
|
|
|
|
}
|
|
|
|
return implode(' AND ', $exprs);
|
2022-12-08 11:40:55 +03:00
|
|
|
}
|
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'alias',
|
2023-08-10 12:52:45 +03:00
|
|
|
function(\mtgMetaField $field): string {
|
2023-06-06 14:37:34 +03:00
|
|
|
if ($field->hasToken('alias')) {
|
|
|
|
return $field->getToken('alias');
|
|
|
|
}
|
|
|
|
return $field->getName();
|
2022-12-08 11:40:55 +03:00
|
|
|
}
|
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'fname',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaField $field): string => snake2camel($field->getName())
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'varname',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaField $field): string => lcfirst(snake2camel($field->getName()))
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
2023-08-31 10:48:55 +03:00
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'tname',
|
|
|
|
fn(\mtgMetaField $field): string => $field->getType() instanceof \mtgArrType ? $field->getType()->getValue()->getName() : $field->getType()->getName()
|
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'builtin_type_suffix',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn (\mtgBuiltinType $type): string => builtin_type_method_suffix($type),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'default_val',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaField $field) => default_value($field)
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
2023-08-31 10:48:55 +03:00
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'fields',
|
|
|
|
function (\mtgMetaField $field): array {
|
|
|
|
$type = $field->getType();
|
|
|
|
if($type instanceof \mtgArrType)
|
|
|
|
{
|
|
|
|
$type = $type->getValue();
|
|
|
|
}
|
|
|
|
return $type->getFields();
|
|
|
|
}
|
|
|
|
));
|
|
|
|
$twig->addFilter(new TwigFilter(
|
|
|
|
'pk_fields',
|
|
|
|
function (\mtgMetaField $field): array {
|
|
|
|
$type = $field->getType();
|
|
|
|
if($type instanceof \mtgArrType)
|
|
|
|
{
|
|
|
|
$type = $type->getValue();
|
|
|
|
}
|
|
|
|
$pkey = explode(',', $type->getToken('table_pkey'));
|
|
|
|
$fields = [];
|
|
|
|
foreach ($pkey as $fieldName) {
|
|
|
|
$fields[] = $type->getField($fieldName);
|
|
|
|
}
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function add_twig_functions(\Twig\Environment $twig)
|
2023-06-06 14:37:34 +03:00
|
|
|
{
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'Error',
|
|
|
|
function(string $e) {
|
|
|
|
throw new Exception($e);
|
2022-12-08 14:23:55 +03:00
|
|
|
}
|
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'has_token',
|
|
|
|
fn($o, string $token): bool => $o->hasToken($token),
|
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'has_token_in_parent',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaStruct $s, string $token): bool => $s->hasTokenInParent($token),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'token',
|
|
|
|
fn($o, string $name) => $o->getToken($name),
|
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'token_or',
|
|
|
|
fn($o, string $name, $v) => $o->hasToken($name) ? $o->getToken($name) : $v,
|
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'get_all_fields',
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaStruct $s): array => \mtg_get_all_fields($s),
|
2023-06-06 14:37:34 +03:00
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'arr_fill',
|
|
|
|
fn($value, int $count): array => array_fill(0, $count, $value)
|
2022-12-08 14:50:32 +03:00
|
|
|
));
|
2023-06-06 14:37:34 +03:00
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'table_pkey',
|
2023-08-10 12:52:45 +03:00
|
|
|
function(\mtgMetaStruct $struct): array {
|
2023-06-06 14:37:34 +03:00
|
|
|
$pkey = explode(',', $struct->getToken('table_pkey'));
|
|
|
|
$fields = [];
|
|
|
|
foreach ($pkey as $fieldName) {
|
|
|
|
$fields[] = $struct->getField($fieldName);
|
|
|
|
}
|
|
|
|
return $fields;
|
|
|
|
}
|
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'table_fields',
|
2023-08-10 12:52:45 +03:00
|
|
|
function(\mtgMetaStruct $struct): array {
|
2023-06-06 14:37:34 +03:00
|
|
|
$pkey = explode(',', $struct->getToken('table_pkey'));
|
|
|
|
return array_filter(
|
|
|
|
$struct->getFields(),
|
2023-08-10 12:52:45 +03:00
|
|
|
fn(\mtgMetaField $field): bool => !in_array($field->getName(), $pkey),
|
2023-06-06 14:37:34 +03:00
|
|
|
);
|
|
|
|
}
|
|
|
|
));
|
|
|
|
$twig->addFunction(new TwigFunction(
|
|
|
|
'meta_field',
|
2023-08-10 12:52:45 +03:00
|
|
|
function (string $str) use ($twig): \mtgMetaField {
|
2023-06-06 14:37:34 +03:00
|
|
|
$meta = $twig->getGlobals()['meta'];
|
2023-08-10 12:52:45 +03:00
|
|
|
return parse_meta_field($str, $meta);
|
2023-06-06 14:37:34 +03:00
|
|
|
}
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
function snake2camel(string $str): string
|
|
|
|
{
|
|
|
|
return str_replace('_', '', ucwords($str, '_'));
|
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function go_type(\mtgType $type, array $tokens = []): string
|
2023-06-06 14:37:34 +03:00
|
|
|
{
|
2023-08-10 12:52:45 +03:00
|
|
|
if($type instanceof \mtgMetaEnum)
|
2023-09-01 17:45:20 +03:00
|
|
|
{
|
2023-06-06 14:37:34 +03:00
|
|
|
return $type->getName();
|
2023-09-01 17:45:20 +03:00
|
|
|
}
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type instanceof \mtgMetaStruct)
|
2023-09-01 17:45:20 +03:00
|
|
|
{
|
|
|
|
if(array_key_exists('virtual', $tokens)) {
|
|
|
|
return 'I'.$type->getName();
|
|
|
|
}
|
2023-06-06 14:37:34 +03:00
|
|
|
return $type->getName();
|
2023-09-01 17:45:20 +03:00
|
|
|
}
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type instanceof \mtgBuiltinType)
|
|
|
|
{
|
|
|
|
if($type->isFloat())
|
2023-06-06 14:37:34 +03:00
|
|
|
return 'float32';
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type->isDouble())
|
2023-06-06 14:37:34 +03:00
|
|
|
return 'float64';
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type->isBlob())
|
2023-06-06 14:37:34 +03:00
|
|
|
return '[]byte';
|
2023-08-10 12:52:45 +03:00
|
|
|
else
|
2023-06-06 14:37:34 +03:00
|
|
|
return $type->getName();
|
2023-08-10 12:52:45 +03:00
|
|
|
}
|
|
|
|
else if($type instanceof \mtgArrType)
|
|
|
|
{
|
2023-09-01 17:45:20 +03:00
|
|
|
$native = go_type($type->getValue(), $tokens);
|
2023-06-06 14:37:34 +03:00
|
|
|
return "[]$native";
|
2023-09-01 17:45:20 +03:00
|
|
|
}
|
2023-08-10 12:52:45 +03:00
|
|
|
else
|
2023-08-16 14:17:23 +03:00
|
|
|
throw new Exception("Unknown type '{$type->getName()}'");
|
2023-06-06 14:37:34 +03:00
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function builtin_type_method_suffix(\mtgBuiltinType $type): string
|
2023-06-06 14:37:34 +03:00
|
|
|
{
|
2023-08-10 12:52:45 +03:00
|
|
|
if($type->isBlob())
|
2023-06-06 14:37:34 +03:00
|
|
|
return 'Bytes';
|
2023-08-10 12:52:45 +03:00
|
|
|
|
|
|
|
return ucfirst(go_type($type));
|
2023-06-06 14:37:34 +03:00
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function default_value(\mtgMetaField $field)
|
2023-06-06 14:37:34 +03:00
|
|
|
{
|
|
|
|
$type = $field->getType();
|
|
|
|
$tokens = $field->getTokens();
|
|
|
|
$default = $field->getToken('default');
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
if($type instanceof \mtgBuiltinType)
|
|
|
|
{
|
|
|
|
if($type->isNumeric())
|
2023-06-06 14:37:34 +03:00
|
|
|
return $default ?? 0;
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type->isString())
|
2023-06-06 14:37:34 +03:00
|
|
|
return $default ?? '""';
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type->isBool())
|
2023-06-06 14:37:34 +03:00
|
|
|
return $default ?? 'false';
|
2023-08-10 12:52:45 +03:00
|
|
|
else if($type->isBlob())
|
|
|
|
{
|
|
|
|
if($default == 'null')
|
2023-07-04 13:57:39 +03:00
|
|
|
$default = 'nil';
|
2023-08-10 12:52:45 +03:00
|
|
|
|
2023-06-06 14:37:34 +03:00
|
|
|
return $default ?? 'nil';
|
2023-08-10 12:52:45 +03:00
|
|
|
}
|
|
|
|
else
|
2023-06-06 14:37:34 +03:00
|
|
|
throw new Exception("Unknown type '$type'");
|
2023-08-10 12:52:45 +03:00
|
|
|
|
|
|
|
}
|
|
|
|
else if($type instanceof \mtgMetaEnum)
|
|
|
|
return $default ? go_type($type, $tokens)."_".trim($tokens['default'], '"') : 0;
|
|
|
|
else
|
2023-06-06 14:37:34 +03:00
|
|
|
throw new Exception("Unknown type '$type'");
|
|
|
|
}
|
|
|
|
|
2023-08-10 12:52:45 +03:00
|
|
|
function parse_meta_field(string $str, \mtgMetaInfo $meta): \mtgMetaField
|
2023-06-06 14:37:34 +03:00
|
|
|
{
|
|
|
|
list($name, $type) = explode('|', $str);
|
2023-08-10 12:52:45 +03:00
|
|
|
return new \mtgMetaField($name, new \mtgTypeRef(new \mtgBuiltinType($type)));
|
2022-12-08 13:29:16 +03:00
|
|
|
}
|