287 lines
6.2 KiB
PHP
287 lines
6.2 KiB
PHP
|
<?php
|
||
|
namespace metagen_cs;
|
||
|
use Exception;
|
||
|
|
||
|
function get_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());
|
||
|
|
||
|
_add_twig_support($twig);
|
||
|
|
||
|
return $twig;
|
||
|
}
|
||
|
|
||
|
function _add_twig_support(\Twig\Environment $twig)
|
||
|
{
|
||
|
$twig->addTest(new \Twig\TwigTest('instanceof',
|
||
|
function($obj, $class)
|
||
|
{
|
||
|
return (new \ReflectionClass($class))->isInstance($obj);
|
||
|
}
|
||
|
));
|
||
|
$twig->addFunction(new \Twig\TwigFunction('Error',
|
||
|
function($e)
|
||
|
{
|
||
|
throw new Exception($e);
|
||
|
}
|
||
|
));
|
||
|
$twig->addFunction(new \Twig\TwigFunction('has_token',
|
||
|
function($o, $token)
|
||
|
{
|
||
|
return $o->hasToken($token);
|
||
|
}
|
||
|
));
|
||
|
$twig->addFunction(new \Twig\TwigFunction('has_token_in_parent',
|
||
|
function($o, $token)
|
||
|
{
|
||
|
return $o->hasTokenInParent($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->addFilter(new \Twig\TwigFilter('cs_type',
|
||
|
function($type)
|
||
|
{
|
||
|
return cs_type($type);
|
||
|
}
|
||
|
));
|
||
|
$twig->addFilter(new \Twig\TwigFilter('cs_type_prefix',
|
||
|
function($type)
|
||
|
{
|
||
|
return cs_type_prefix($type);
|
||
|
}
|
||
|
));
|
||
|
$twig->addFunction(new \Twig\TwigFunction('var_reset',
|
||
|
function($name, $type, $default)
|
||
|
{
|
||
|
return var_reset($name, $type, $default);
|
||
|
}
|
||
|
));
|
||
|
}
|
||
|
|
||
|
function cs_type(\mtgType $type)
|
||
|
{
|
||
|
if($type instanceof \mtgBuiltinType || $type instanceof \mtgUserType)
|
||
|
return cs_simple_type($type);
|
||
|
else if($type instanceof \mtgArrType)
|
||
|
return "List<" . cs_simple_type($type->getValue()) . ">";
|
||
|
else
|
||
|
throw new Exception("Unknown type '{$type}'");
|
||
|
}
|
||
|
|
||
|
function cs_simple_type(\mtgType $type)
|
||
|
{
|
||
|
if($type instanceof \mtgBuiltinType)
|
||
|
{
|
||
|
switch($type->getName())
|
||
|
{
|
||
|
case "int8":
|
||
|
return "sbyte";
|
||
|
case "uint8":
|
||
|
return "byte";
|
||
|
case "int16":
|
||
|
return "short";
|
||
|
case "uint16":
|
||
|
return "ushort";
|
||
|
case "int32":
|
||
|
case "int":
|
||
|
return "int";
|
||
|
case "uint32":
|
||
|
case "uint":
|
||
|
return "uint";
|
||
|
case "float":
|
||
|
return "float";
|
||
|
case "double":
|
||
|
return "double";
|
||
|
case "uint64":
|
||
|
return "ulong";
|
||
|
case "int64":
|
||
|
return "long";
|
||
|
case "string":
|
||
|
return "string";
|
||
|
case "bool":
|
||
|
return "bool";
|
||
|
case "blob":
|
||
|
return "byte[]";
|
||
|
}
|
||
|
throw new Exception("Unknown type '{$type}'");
|
||
|
}
|
||
|
return $type->getName();
|
||
|
}
|
||
|
|
||
|
function cs_type_prefix(\mtgType $type)
|
||
|
{
|
||
|
switch($type->getName())
|
||
|
{
|
||
|
case "float":
|
||
|
return "Float";
|
||
|
case "double":
|
||
|
return "Double";
|
||
|
case "uint64":
|
||
|
return "U64";
|
||
|
case "int64":
|
||
|
return "I64";
|
||
|
case "uint":
|
||
|
case "uint32":
|
||
|
return "U32";
|
||
|
case "uint16":
|
||
|
return "U16";
|
||
|
case "uint8":
|
||
|
return "U8";
|
||
|
case "int":
|
||
|
case "int32":
|
||
|
return "I32";
|
||
|
case "int16":
|
||
|
return "I16";
|
||
|
case "int8":
|
||
|
return "I8";
|
||
|
case "string":
|
||
|
return "String";
|
||
|
case "bool":
|
||
|
return "Bool";
|
||
|
case "blob":
|
||
|
return "Blob";
|
||
|
default:
|
||
|
throw new Exception("Unknown type '{$type}'");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function var_reset($name, \mtgType $type, $default = null)
|
||
|
{
|
||
|
$str = '';
|
||
|
if($type instanceof \mtgBuiltinType)
|
||
|
{
|
||
|
if($type->isNumeric())
|
||
|
{
|
||
|
$str = $name;
|
||
|
//NOTE: numeric check is against str2num
|
||
|
if($default && is_numeric($default))
|
||
|
{
|
||
|
if($type->isFloat())
|
||
|
$default .= "f";
|
||
|
$str .= " = $default;";
|
||
|
}
|
||
|
else
|
||
|
$str .= " = 0;";
|
||
|
}
|
||
|
else if($type->isString())
|
||
|
{
|
||
|
$str = $name;
|
||
|
if($default)
|
||
|
{
|
||
|
$str .= " = \"".trim($default, '"')."\";";
|
||
|
}
|
||
|
else
|
||
|
$str .= ' = "";';
|
||
|
}
|
||
|
else if($type->isBool())
|
||
|
{
|
||
|
$str = $name;
|
||
|
if($default)
|
||
|
{
|
||
|
$str .= " = ".trim($default, '"').";";
|
||
|
}
|
||
|
else
|
||
|
$str .= ' = false;';
|
||
|
}
|
||
|
else if($type->isBlob())
|
||
|
{
|
||
|
$str = $name;
|
||
|
if($default)
|
||
|
{
|
||
|
$str .= " = ".trim($default, '"').";";
|
||
|
}
|
||
|
else
|
||
|
$str .= ' = null;';
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Unknown type '$type'");
|
||
|
}
|
||
|
else if($type instanceof \mtgArrType)
|
||
|
{
|
||
|
$str = "Meta.ClearList(ref $name);";
|
||
|
|
||
|
if($default)
|
||
|
{
|
||
|
$default_arr = is_array($default) ? $default : json_decode($default, true);
|
||
|
if(!is_array($default_arr))
|
||
|
throw new Exception("Bad default value for array: '$default'");
|
||
|
|
||
|
if($default_arr)
|
||
|
{
|
||
|
$type_str = cs_type($type->getValue());
|
||
|
$str .= "{ $type_str tmp__";
|
||
|
if(is_nullable_type($type->getValue()))
|
||
|
$str .= " = null";
|
||
|
$str .= ";";
|
||
|
foreach($default_arr as $v)
|
||
|
{
|
||
|
$str .= var_reset("tmp__", $type->getValue(), $v);
|
||
|
$str .= "$name.Add(tmp__);";
|
||
|
}
|
||
|
$str .= "}";
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else if($type instanceof \mtgMetaEnum)
|
||
|
{
|
||
|
if($default)
|
||
|
$str = "$name = ".cs_type($type).".".trim($default,'"')."; ";
|
||
|
else
|
||
|
$str = "$name = new ".cs_type($type)."(); ";
|
||
|
}
|
||
|
else if($type instanceof \mtgMetaStruct)
|
||
|
{
|
||
|
$str = "";
|
||
|
$is_pod = $type->hasToken('POD');
|
||
|
if($is_pod)
|
||
|
$str .= "$name.reset(); ";
|
||
|
else
|
||
|
$str .= "Meta.Reset(ref $name); ";
|
||
|
|
||
|
if($default)
|
||
|
{
|
||
|
$default = is_array($default) ? $default : json_decode($default, true);
|
||
|
if(!is_array($default))
|
||
|
throw new Exception("Bad default value for struct: $default");
|
||
|
|
||
|
foreach($default as $k => $v)
|
||
|
{
|
||
|
$kf = $type->getField($k);
|
||
|
$str .= var_reset("$name." . $kf->name, $kf->getType(), $v);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
throw new Exception("Bad type '$type'");
|
||
|
return $str;
|
||
|
}
|
||
|
|
||
|
function is_nullable_type(\mtgType $type)
|
||
|
{
|
||
|
return $type instanceof \mtgArrType ||
|
||
|
($type instanceof \mtgMetaStruct && !$type->hasToken('POD'));
|
||
|
}
|
||
|
|