Example #1
0
 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');
 }