private function reduce(Context $ctx, $model = null) { $this->reset(); $this->stack = array(); $len = 0; // While there are input tokens left // Read the next token from input. while ($t = array_shift($this->queue)) { //var_dump ($t->type); switch ($t->type) { case self::OP_FIELD: // If the token is a value or identifier // Push it onto the stack. $this->stack[] = $t; ++$len; break; case self::OP_EQUALS: case self::OP_CONTAINS: case self::OP_AND: case self::OP_OR: case self::OP_NOT: // It is known a priori that the operator takes n arguments. $na = $this->argc($t); // If there are fewer than n values on the stack if ($len < $na) { throw new RuntimeError('run-time error: too few paramter for operator "' . $t->value . '" (' . $na . ' -> ' . $len . ')'); } $rhs = array_pop($this->stack); $lhs = null; if ($na > 1) { $lhs = array_pop($this->stack); } // Values! if ($ctx->hasField($rhs->value)) { $rhs = new Token(self::OP_FIELD, $ctx->getField($rhs->value)); } if ($na > 1 && $ctx->hasField($lhs->value)) { $lhs = new Token(self::OP_FIELD, $ctx->getField($lhs->value)); } // if ($lhs) print "{$lhs->value} {$t->value} {$rhs->value}\n"; // else print "{$t->value} {$rhs->value}\n"; $len -= $na - 1; // Push the returned results, if any, back onto the stack. $this->stack[] = new Token(self::OP_FIELD, $this->op($t->type, $lhs, $rhs, $model)); break; /* case self::OP_FUNCTION: // function $argc = $t->argc; $argv = array(); $len -= $argc - 1; for (; $argc > 0; --$argc) array_unshift($argv, array_pop($this->stack)->value); // Push the returned results, if any, back onto the stack. $this->stack[] = new Token(self::OP_FIELD, $ctx->fn($t->value, $argv)); break; */ /* case self::OP_FUNCTION: // function $argc = $t->argc; $argv = array(); $len -= $argc - 1; for (; $argc > 0; --$argc) array_unshift($argv, array_pop($this->stack)->value); // Push the returned results, if any, back onto the stack. $this->stack[] = new Token(self::OP_FIELD, $ctx->fn($t->value, $argv)); break; */ default: throw new RuntimeError('run-time error: unexpected token`' . $t->value . '`'); } } // If there is only one value in the stack // That value is the result of the calculation. if (count($this->stack) === 1) { return array_pop($this->stack)->value; } // If there are more values in the stack // (Error) The user input has too many values. throw new RuntimeError('run-time error: too many values in the stack'); }
public function testContextModelsCallback() { $context = new Context(); $field = new Field('body'); $field->setCallback(function (FilterTestFieldWeirdGetter $model) { return $model->getWeirdBody(); }); $context->setField($field); $filter = new Parser(new Scanner("body contains midget"), $context); // Models with public attributes $this->assertTrue($filter->validate(new FilterTestFieldWeirdGetter("This object contains a midget in the body."))); $this->assertFalse($filter->validate(new FilterTestFieldWeirdGetter("This object contains a giant in the body."))); $filter = new Parser(new Scanner("body contains body"), $context); // Models with public attributes $this->assertTrue($filter->validate(new FilterTestFieldWeirdGetter("Cuz theze are my united states of whatever"))); }