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')); }