protected function patternMatch($block, $orderedArgs, $keywordArgs)
{
// match the guards if it has them
// any one of the groups must have all its guards pass for a match
if (!empty($block->guards)) {
$groupPassed = false;
foreach ($block->guards as $guardGroup) {
foreach ($guardGroup as $guard) {
$this->pushEnv();
$this->zipSetArgs($block->args, $orderedArgs, $keywordArgs);
$negate = false;
if ($guard[0] == "negate") {
$guard = $guard[1];
$negate = true;
}
$passed = $this->reduce($guard) == self::$TRUE;
if ($negate) {
$passed = !$passed;
}
$this->popEnv();
if ($passed) {
$groupPassed = true;
} else {
$groupPassed = false;
break;
}
}
if ($groupPassed) {
break;
}
}
if (!$groupPassed) {
return false;
}
}
if (empty($block->args)) {
return $block->isVararg || empty($orderedArgs) && empty($keywordArgs);
}
$remainingArgs = $block->args;
if ($keywordArgs) {
$remainingArgs = array();
foreach ($block->args as $arg) {
if ($arg[0] == "arg" && isset($keywordArgs[$arg[1]])) {
continue;
}
$remainingArgs[] = $arg;
}
}
$i = -1;
// no args
// try to match by arity or by argument literal
foreach ($remainingArgs as $i => $arg) {
switch ($arg[0]) {
case "lit":
if (empty($orderedArgs[$i]) || !$this->eq($arg[1], $orderedArgs[$i])) {
return false;
}
break;
case "arg":
// no arg and no default value
if (!isset($orderedArgs[$i]) && !isset($arg[2])) {
return false;
}
break;
case "rest":
$i--;
// rest can be empty
break 2;
}
}
if ($block->isVararg) {
return true;
// not having enough is handled above
} else {
$numMatched = $i + 1;
// greater than becuase default values always match
return $numMatched >= count($orderedArgs);
}
}