parent
7ccdd3add9
commit
d55bb041f6
13 changed files with 571 additions and 0 deletions
@ -0,0 +1,50 @@ |
|||||||
|
--TEST-- |
||||||
|
preprocessor comment condition stack |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function handle_preprocessor_conditions(array &$conds, array $comments): ?string |
||||||
|
{ |
||||||
|
foreach ($comments as $comment) { |
||||||
|
$text = trim($comment); |
||||||
|
if (preg_match('/^#\s*if\s+(.+)$/', $text, $matches)) { |
||||||
|
$conds[] = $matches[1]; |
||||||
|
} elseif (preg_match('/^#\s*ifdef\s+(.+)$/', $text, $matches)) { |
||||||
|
$conds[] = "defined($matches[1])"; |
||||||
|
} elseif (preg_match('/^#\s*ifndef\s+(.+)$/', $text, $matches)) { |
||||||
|
$conds[] = "!defined($matches[1])"; |
||||||
|
} elseif (preg_match('/^#\s*else$/', $text)) { |
||||||
|
if (empty($conds)) { |
||||||
|
return 'else-error'; |
||||||
|
} |
||||||
|
$cond = array_pop($conds); |
||||||
|
$conds[] = "!($cond)"; |
||||||
|
} elseif (preg_match('/^#\s*endif$/', $text)) { |
||||||
|
if (empty($conds)) { |
||||||
|
return 'endif-error'; |
||||||
|
} |
||||||
|
array_pop($conds); |
||||||
|
} elseif ($text !== '' && $text[0] === '#') { |
||||||
|
return "unknown:$text"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return empty($conds) ? null : implode(' && ', $conds); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$conds = []; |
||||||
|
var_dump(handle_preprocessor_conditions($conds, ['#ifdef PHP_WIN32', '#if PHP_VERSION_ID >= 80400'])); |
||||||
|
var_dump(handle_preprocessor_conditions($conds, ['#else'])); |
||||||
|
var_dump(handle_preprocessor_conditions($conds, ['#endif', '#endif'])); |
||||||
|
var_dump(handle_preprocessor_conditions($conds, ['#else'])); |
||||||
|
var_dump(handle_preprocessor_conditions($conds, ['#pragma once'])); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(45) "defined(PHP_WIN32) && PHP_VERSION_ID >= 80400" |
||||||
|
string(48) "defined(PHP_WIN32) && !(PHP_VERSION_ID >= 80400)" |
||||||
|
NULL |
||||||
|
string(10) "else-error" |
||||||
|
string(20) "unknown:#pragma once" |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
--TEST-- |
||||||
|
short option preprocessing splits compact short flag values |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function preprocess_short_options(array $argv): array |
||||||
|
{ |
||||||
|
$processed = [$argv[0]]; |
||||||
|
|
||||||
|
for ($i = 1; $i < count($argv); $i++) { |
||||||
|
$arg = $argv[$i]; |
||||||
|
if (preg_match('/^-([a-zA-Z])(.+)$/', $arg, $matches)) { |
||||||
|
$option = $matches[1]; |
||||||
|
$value = $matches[2]; |
||||||
|
$processed[] = "-{$option}"; |
||||||
|
$processed[] = $value; |
||||||
|
} elseif (preg_match('/^-([a-zA-Z]{2,})$/', $arg, $matches)) { |
||||||
|
$options = str_split($matches[1]); |
||||||
|
foreach ($options as $opt) { |
||||||
|
$processed[] = "-{$opt}"; |
||||||
|
} |
||||||
|
} else { |
||||||
|
$processed[] = $arg; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return $processed; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(preprocess_short_options(['compiler.php', '-Iinclude', '-abc', '--debug', 'project.yml'])); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(7) { |
||||||
|
[0]=> |
||||||
|
string(12) "compiler.php" |
||||||
|
[1]=> |
||||||
|
string(2) "-I" |
||||||
|
[2]=> |
||||||
|
string(7) "include" |
||||||
|
[3]=> |
||||||
|
string(2) "-a" |
||||||
|
[4]=> |
||||||
|
string(2) "bc" |
||||||
|
[5]=> |
||||||
|
string(7) "--debug" |
||||||
|
[6]=> |
||||||
|
string(11) "project.yml" |
||||||
|
} |
||||||
@ -0,0 +1,51 @@ |
|||||||
|
--TEST-- |
||||||
|
target name normalization with path separators and identifier validation |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function normalize_target_name(string $name): array |
||||||
|
{ |
||||||
|
$outputDir = ''; |
||||||
|
if (str_contains($name, '/') || str_contains($name, '\\')) { |
||||||
|
$outputDir = dirname($name); |
||||||
|
$name = basename($name); |
||||||
|
} |
||||||
|
|
||||||
|
$name = str_replace(['-', '*'], '_', $name); |
||||||
|
$valid = preg_match('/^[a-zA-Z0-9_]+$/', $name) === 1; |
||||||
|
|
||||||
|
return [$outputDir, $name, $valid]; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(normalize_target_name('build/my-app')); |
||||||
|
var_dump(normalize_target_name('C:\\tmp\\my*app')); |
||||||
|
var_dump(normalize_target_name('bad.name')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(3) { |
||||||
|
[0]=> |
||||||
|
string(5) "build" |
||||||
|
[1]=> |
||||||
|
string(6) "my_app" |
||||||
|
[2]=> |
||||||
|
bool(true) |
||||||
|
} |
||||||
|
array(3) { |
||||||
|
[0]=> |
||||||
|
string(1) "." |
||||||
|
[1]=> |
||||||
|
string(13) "C:\tmp\my_app" |
||||||
|
[2]=> |
||||||
|
bool(false) |
||||||
|
} |
||||||
|
array(3) { |
||||||
|
[0]=> |
||||||
|
string(0) "" |
||||||
|
[1]=> |
||||||
|
string(8) "bad.name" |
||||||
|
[2]=> |
||||||
|
bool(false) |
||||||
|
} |
||||||
@ -0,0 +1,29 @@ |
|||||||
|
--TEST-- |
||||||
|
compiler command name normalization from command string |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function normalize_compiler_name(string $compilerName): string |
||||||
|
{ |
||||||
|
$firstToken = strtok(trim($compilerName), ' '); |
||||||
|
if ($firstToken === false || $firstToken === '') { |
||||||
|
return ''; |
||||||
|
} |
||||||
|
|
||||||
|
$name = basename(str_replace('\\', '/', $firstToken)); |
||||||
|
$name = strtolower($name); |
||||||
|
|
||||||
|
return preg_replace('/\.exe$/', '', $name); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(normalize_compiler_name(' C:\\LLVM\\bin\\CLANG++.EXE -O2')); |
||||||
|
var_dump(normalize_compiler_name('/usr/bin/g++ -std=c++20')); |
||||||
|
var_dump(normalize_compiler_name('')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(7) "clang++" |
||||||
|
string(3) "g++" |
||||||
|
string(0) "" |
||||||
@ -0,0 +1,102 @@ |
|||||||
|
--TEST-- |
||||||
|
C++ signature parameter splitter with nested templates and defaults |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function split_cpp_parameters(string $paramsStr): array |
||||||
|
{ |
||||||
|
$params = []; |
||||||
|
$current = ''; |
||||||
|
$depth = 0; |
||||||
|
$length = strlen($paramsStr); |
||||||
|
|
||||||
|
for ($i = 0; $i < $length; $i++) { |
||||||
|
$char = $paramsStr[$i]; |
||||||
|
|
||||||
|
if ($char === '<' || $char === '(' || $char === '[') { |
||||||
|
$depth++; |
||||||
|
$current .= $char; |
||||||
|
} elseif ($char === '>' || $char === ')' || $char === ']') { |
||||||
|
$depth--; |
||||||
|
$current .= $char; |
||||||
|
} elseif ($char === ',' && $depth === 0) { |
||||||
|
$params[] = $current; |
||||||
|
$current = ''; |
||||||
|
} else { |
||||||
|
$current .= $char; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
if (!empty($current)) { |
||||||
|
$params[] = $current; |
||||||
|
} |
||||||
|
|
||||||
|
return $params; |
||||||
|
} |
||||||
|
|
||||||
|
function parse_cpp_parameter(string $param): array |
||||||
|
{ |
||||||
|
$param = trim($param); |
||||||
|
$param = preg_replace('/\s*=\s*.*$/', '', $param); |
||||||
|
|
||||||
|
if (preg_match('/^(.+?)\s+(\w+)\s*$/', $param, $matches)) { |
||||||
|
return [ |
||||||
|
'type' => trim($matches[1]), |
||||||
|
'name' => trim($matches[2]), |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
return [ |
||||||
|
'type' => $param, |
||||||
|
'name' => '', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
function parse_cpp_parameters(string $signature, string $funcName): array |
||||||
|
{ |
||||||
|
$pattern = '/' . preg_quote($funcName, '/') . '\s*\((.*?)\)/s'; |
||||||
|
if (!preg_match($pattern, $signature, $matches)) { |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
$paramsStr = trim($matches[1]); |
||||||
|
if (empty($paramsStr) || $paramsStr === 'void') { |
||||||
|
return []; |
||||||
|
} |
||||||
|
|
||||||
|
return array_map('parse_cpp_parameter', split_cpp_parameters($paramsStr)); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$signature = 'static std::vector<std::pair<int, std::string>> build(std::map<int, std::string> values, const char* name = "x", Callback<int,string> cb)'; |
||||||
|
var_dump(parse_cpp_parameters($signature, 'build')); |
||||||
|
var_dump(parse_cpp_parameters('void reset(void)', 'reset')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(3) { |
||||||
|
[0]=> |
||||||
|
array(2) { |
||||||
|
["type"]=> |
||||||
|
string(26) "std::map<int, std::string>" |
||||||
|
["name"]=> |
||||||
|
string(6) "values" |
||||||
|
} |
||||||
|
[1]=> |
||||||
|
array(2) { |
||||||
|
["type"]=> |
||||||
|
string(11) "const char*" |
||||||
|
["name"]=> |
||||||
|
string(4) "name" |
||||||
|
} |
||||||
|
[2]=> |
||||||
|
array(2) { |
||||||
|
["type"]=> |
||||||
|
string(20) "Callback<int,string>" |
||||||
|
["name"]=> |
||||||
|
string(2) "cb" |
||||||
|
} |
||||||
|
} |
||||||
|
array(0) { |
||||||
|
} |
||||||
@ -0,0 +1,48 @@ |
|||||||
|
--TEST-- |
||||||
|
doc comment tag extraction with preg_match_all set order |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function parse_doc_tags(array $comments): array |
||||||
|
{ |
||||||
|
$tags = []; |
||||||
|
|
||||||
|
foreach ($comments as $comment) { |
||||||
|
if (preg_match_all('/@(\w+)\s+(.*)$/m', $comment, $matches, PREG_SET_ORDER)) { |
||||||
|
foreach ($matches as $match) { |
||||||
|
$tagName = $match[1]; |
||||||
|
$tagValue = trim($match[2]); |
||||||
|
|
||||||
|
if (!isset($tags[$tagName])) { |
||||||
|
$tags[$tagName] = []; |
||||||
|
} |
||||||
|
|
||||||
|
$tags[$tagName][] = $tagValue; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return $tags; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$comment = "summary\n@param int \$id\n@param string \$name user name\n@return bool"; |
||||||
|
var_dump(parse_doc_tags([$comment])); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(2) { |
||||||
|
["param"]=> |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
string(7) "int $id" |
||||||
|
[1]=> |
||||||
|
string(22) "string $name user name" |
||||||
|
} |
||||||
|
["return"]=> |
||||||
|
array(1) { |
||||||
|
[0]=> |
||||||
|
string(4) "bool" |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
--TEST-- |
||||||
|
docblock param regex with recursive named groups |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function parse_doc_param_name(string $value): array |
||||||
|
{ |
||||||
|
$matches = []; |
||||||
|
preg_match('/^\s*(?<type>[\w\|\\\\]+(?<parens>\((?<inparens>(?:(?&parens)|[^(){}[\]<>]*+))++\)|\{(?&inparens)\}|\[(?&inparens)\]|<(?&inparens)>)*+(?::(?&type))?)\s*(\.\.\.)?\$(?<name>\w+).*$/', $value, $matches); |
||||||
|
|
||||||
|
return [ |
||||||
|
$matches['type'] ?? '', |
||||||
|
$matches['name'] ?? '', |
||||||
|
]; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(parse_doc_param_name('callable(array<string, int>):mixed $handler callback')); |
||||||
|
var_dump(parse_doc_param_name('int ...$items')); |
||||||
|
var_dump(parse_doc_param_name('$missingType')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
string(34) "callable(array<string, int>):mixed" |
||||||
|
[1]=> |
||||||
|
string(7) "handler" |
||||||
|
} |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
string(3) "int" |
||||||
|
[1]=> |
||||||
|
string(5) "items" |
||||||
|
} |
||||||
|
array(2) { |
||||||
|
[0]=> |
||||||
|
string(0) "" |
||||||
|
[1]=> |
||||||
|
string(0) "" |
||||||
|
} |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
--TEST-- |
||||||
|
file extension classifier with pathinfo and in_array |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function file_name_of(string $path): string |
||||||
|
{ |
||||||
|
return pathinfo($path, PATHINFO_FILENAME); |
||||||
|
} |
||||||
|
|
||||||
|
function file_ext_of(string $path): string |
||||||
|
{ |
||||||
|
return pathinfo($path, PATHINFO_EXTENSION); |
||||||
|
} |
||||||
|
|
||||||
|
function classify_source_file(string $file): string |
||||||
|
{ |
||||||
|
$ext = file_ext_of($file); |
||||||
|
if (in_array($ext, ['php', 'inc', 'phpt'])) { |
||||||
|
return 'php:' . file_name_of($file); |
||||||
|
} |
||||||
|
if (in_array($ext, ['cc', 'cpp', 'cxx'])) { |
||||||
|
return 'cpp:' . file_name_of($file); |
||||||
|
} |
||||||
|
if (in_array($ext, ['c', 'h', 'hpp'])) { |
||||||
|
return 'native:' . file_name_of($file); |
||||||
|
} |
||||||
|
return 'other:' . $ext; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(classify_source_file('/tmp/src/main.php')); |
||||||
|
var_dump(classify_source_file('lib/compiler.cxx')); |
||||||
|
var_dump(classify_source_file('include/aot.hpp')); |
||||||
|
var_dump(classify_source_file('README')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(8) "php:main" |
||||||
|
string(12) "cpp:compiler" |
||||||
|
string(10) "native:aot" |
||||||
|
string(6) "other:" |
||||||
@ -0,0 +1,36 @@ |
|||||||
|
--TEST-- |
||||||
|
resource version normalization with ltrim explode preg_replace and slice |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function normalize_resource_version(string $version): string |
||||||
|
{ |
||||||
|
$version = ltrim($version, 'vV'); |
||||||
|
|
||||||
|
if (str_contains($version, ',')) { |
||||||
|
return $version; |
||||||
|
} |
||||||
|
|
||||||
|
$parts = explode('.', $version); |
||||||
|
foreach ($parts as $i => $part) { |
||||||
|
$parts[$i] = preg_replace('/[^0-9]/', '', $part) ?: '0'; |
||||||
|
} |
||||||
|
|
||||||
|
while (count($parts) < 4) { |
||||||
|
$parts[] = '0'; |
||||||
|
} |
||||||
|
|
||||||
|
return implode(',', array_slice($parts, 0, 4)); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(normalize_resource_version('v1.2.3')); |
||||||
|
var_dump(normalize_resource_version('V10.beta.5-rc1.7.9')); |
||||||
|
var_dump(normalize_resource_version('1,2,3,4')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(7) "1,2,3,0" |
||||||
|
string(9) "10,0,51,7" |
||||||
|
string(7) "1,2,3,4" |
||||||
@ -0,0 +1,30 @@ |
|||||||
|
--TEST-- |
||||||
|
unix library paths normalized into linker flags |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function make_unix_link_lib_flags(array $libraries, string $ext): string |
||||||
|
{ |
||||||
|
$flags = []; |
||||||
|
foreach ($libraries as $lib) { |
||||||
|
$libName = basename($lib); |
||||||
|
if (str_starts_with($libName, 'lib')) { |
||||||
|
$libName = substr($libName, 3); |
||||||
|
} |
||||||
|
$libName = preg_replace('/\.(a|' . $ext . ')$/', '', $libName); |
||||||
|
|
||||||
|
$flags[] = '-l' . $libName; |
||||||
|
} |
||||||
|
|
||||||
|
return implode(' ', $flags); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(make_unix_link_lib_flags(['/usr/lib/libssl.so', 'libcrypto.a', 'z'], 'so')); |
||||||
|
var_dump(make_unix_link_lib_flags(['libcustom.dylib', '/opt/lib/libplain.txt'], 'dylib')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(18) "-lssl -lcrypto -lz" |
||||||
|
string(20) "-lcustom -lplain.txt" |
||||||
@ -0,0 +1,21 @@ |
|||||||
|
--TEST-- |
||||||
|
camel case to snake case with regex replacement |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function camel_to_snake(string $name): string |
||||||
|
{ |
||||||
|
return strtolower(preg_replace('/([a-z])([A-Z])/', '$1_$2', $name)); |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(camel_to_snake('toStdOrderedMap')); |
||||||
|
var_dump(camel_to_snake('HTMLParserValue')); |
||||||
|
var_dump(camel_to_snake('simple')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(18) "to_std_ordered_map" |
||||||
|
string(16) "htmlparser_value" |
||||||
|
string(6) "simple" |
||||||
@ -0,0 +1,26 @@ |
|||||||
|
--TEST-- |
||||||
|
negative string offset read |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function format_kind(string $format): string |
||||||
|
{ |
||||||
|
if ($format[0] == '.' and $format[-1] == 'f') { |
||||||
|
return 'float:' . substr($format, 1, strlen($format) - 2); |
||||||
|
} elseif (str_contains($format, '%')) { |
||||||
|
return 'date:' . $format; |
||||||
|
} |
||||||
|
return 'other:' . $format[-1]; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(format_kind('.3f')); |
||||||
|
var_dump(format_kind('%Y-%m-%d')); |
||||||
|
var_dump(format_kind('abc')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(7) "float:3" |
||||||
|
string(13) "date:%Y-%m-%d" |
||||||
|
string(7) "other:c" |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
--TEST-- |
||||||
|
numeric literal classifier style regex and digit extraction |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
function strip_numeric_underscores(string $value): string |
||||||
|
{ |
||||||
|
return str_replace('_', '', $value); |
||||||
|
} |
||||||
|
|
||||||
|
function is_big_int_literal_string(string $rawValue): bool |
||||||
|
{ |
||||||
|
$clean = strip_numeric_underscores($rawValue); |
||||||
|
if (!preg_match('/^\d+$/', $clean)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return strlen(ltrim($clean, '0')) >= 19; |
||||||
|
} |
||||||
|
|
||||||
|
function is_decimal_literal_string(string $rawValue): bool |
||||||
|
{ |
||||||
|
$clean = strip_numeric_underscores($rawValue); |
||||||
|
if (!preg_match('/[\.eE]/', $clean)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
$digits = preg_replace('/[^0-9]/', '', $clean); |
||||||
|
return strlen(ltrim($digits, '0')) >= 16; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
var_dump(is_big_int_literal_string('9_223_372_036_854_775_808')); |
||||||
|
var_dump(is_big_int_literal_string('0x10000000000000000')); |
||||||
|
var_dump(is_decimal_literal_string('123_456_789_012_345.6')); |
||||||
|
var_dump(is_decimal_literal_string('123.45')); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(true) |
||||||
|
bool(false) |
||||||
|
bool(true) |
||||||
|
bool(false) |
||||||
Loading…
Reference in new issue