예제 #1
0
파일: ExpLexer.php 프로젝트: emma5021/toba
 private static function evaluateLiterals(&$tokenStream)
 {
     for ($i = 0; $i < count($tokenStream); $i++) {
         $node = $tokenStream[$i];
         if ($node->type != ExpType::$RAW) {
             continue;
         }
         $str = strtolower($node->value);
         if ($str == 'true' || $str == 'false') {
             $tokenStream[$i] = ExpType::coerceToBool($node);
         } elseif ($str == 'null') {
             $tokenStream[$i] = ExpType::coerceToNull($node);
         } elseif (preg_match(ExpLexer::$NUMBER_PATTERN, $str) == 1) {
             $tokenStream[$i] = ExpType::coerceToNumber($node);
         } elseif (preg_match(ExpLexer::$IDENTITY_PATTERN, $str) == 1) {
             // is identity
             $tokenStream[$i]->type = ExpType::$IDENTITY;
         } else {
             // mal-format
             throw new ExpLexerException("Mal-format expression segment: " . $node->value);
         }
     }
 }
예제 #2
0
 /**
  * Tests ExpType::coerce
  */
 public function testCoerce()
 {
     // coerce number
     $this->assertEquals($this->tokens['int'], ExpType::coerceToNumber($this->tokens['int']));
     $this->assertEquals($this->tokens['float'], ExpType::coerceToNumber($this->tokens['float']));
     $this->assertEquals(new Token(ExpType::$INT, 2), ExpType::coerceToNumber(new Token(ExpType::$RAW, '2')));
     $this->assertEquals(new Token(ExpType::$INT, 2), ExpType::coerceToNumber(new Token(ExpType::$STRING, '2')));
     $this->assertEquals(new Token(ExpType::$INT, 1), ExpType::coerceToNumber(new Token(ExpType::$BOOL, true)));
     $this->assertEquals(new Token(ExpType::$INT, 0), ExpType::coerceToNumber(new Token(ExpType::$BOOL, false)));
     $this->assertEquals(new Token(ExpType::$INT, 0), ExpType::coerceToNumber(new Token(ExpType::$NULL, null)));
     $this->assertEquals(new Token(ExpType::$FLOAT, 1.0), ExpType::coerceToNumber(new Token(ExpType::$RAW, '1.0')));
     $this->assertEquals(new Token(ExpType::$FLOAT, 1.0), ExpType::coerceToNumber(new Token(ExpType::$STRING, '1.0')));
     // coerce string
     $this->assertEquals($this->tokens['string'], ExpType::coerceToString($this->tokens['string']));
     $this->assertEquals(new Token(ExpType::$STRING, '2'), ExpType::coerceToString(new Token(ExpType::$RAW, '2')));
     $this->assertEquals(new Token(ExpType::$STRING, '2'), ExpType::coerceToString(new Token(ExpType::$INT, 2)));
     $this->assertEquals(new Token(ExpType::$STRING, '2'), ExpType::coerceToString(new Token(ExpType::$FLOAT, 2.0)));
     $this->assertEquals(new Token(ExpType::$STRING, '2.5'), ExpType::coerceToString(new Token(ExpType::$FLOAT, 2.5)));
     $this->assertEquals(new Token(ExpType::$STRING, 'true'), ExpType::coerceToString(new Token(ExpType::$BOOL, true)));
     $this->assertEquals(new Token(ExpType::$STRING, 'false'), ExpType::coerceToString(new Token(ExpType::$BOOL, false)));
     $this->assertEquals(new Token(ExpType::$STRING, 'null'), ExpType::coerceToString(new Token(ExpType::$NULL, null)));
     // coerce bool
     $this->assertEquals($this->tokens['bool'], ExpType::coerceToBool($this->tokens['bool']));
     $this->assertEquals(new Token(ExpType::$BOOL, true), ExpType::coerceToBool(new Token(ExpType::$RAW, 'True')));
     $this->assertEquals(new Token(ExpType::$BOOL, true), ExpType::coerceToBool(new Token(ExpType::$RAW, 'true')));
     $this->assertEquals(new Token(ExpType::$BOOL, false), ExpType::coerceToBool(new Token(ExpType::$RAW, 'False')));
     $this->assertEquals(new Token(ExpType::$BOOL, false), ExpType::coerceToBool(new Token(ExpType::$RAW, 'false')));
     $this->assertEquals(new Token(ExpType::$BOOL, true), ExpType::coerceToBool(new Token(ExpType::$STRING, 'false')));
     $this->assertEquals(new Token(ExpType::$BOOL, false), ExpType::coerceToBool(new Token(ExpType::$STRING, '')));
     $this->assertEquals(new Token(ExpType::$BOOL, true), ExpType::coerceToBool(new Token(ExpType::$INT, 2)));
     $this->assertEquals(new Token(ExpType::$BOOL, false), ExpType::coerceToBool(new Token(ExpType::$INT, 0)));
     $this->assertEquals(new Token(ExpType::$BOOL, true), ExpType::coerceToBool(new Token(ExpType::$FLOAT, 2.0)));
     $this->assertEquals(new Token(ExpType::$BOOL, false), ExpType::coerceToBool(new Token(ExpType::$FLOAT, 0.0)));
     $this->assertEquals(new Token(ExpType::$BOOL, false), ExpType::coerceToBool(new Token(ExpType::$NULL, null)));
     // coerce null
     $this->assertEquals($this->tokens['null'], ExpType::coerceToNull($this->tokens['null']));
     $this->assertEquals($this->tokens['null'], ExpType::coerceToNull(new Token(ExpType::$RAW, 'null')));
 }
예제 #3
0
 public static function parse($tokenStream, $dataContext)
 {
     $scopes = array();
     $expression = new PrimitiveExp(new Token('final'));
     while ($token = array_shift($tokenStream)) {
         // split non-primitive expression into primitive ones
         switch ($token->type) {
             case ExpType::$PAREN:
                 switch ($token->value) {
                     case '[':
                         $expression->append(new Token(ExpType::$DOT, '.'));
                         // drop through
                     // drop through
                     case '(':
                         ExpParser::scopePush($expression, $scopes, $token);
                         break;
                     case ']':
                         if ($expression->reason->value != '[') {
                             throw new ExpParserException("Unbalanced [], should be detected in Lexer");
                         }
                         ExpParser::scopePop($expression, $scopes, $dataContext);
                         break;
                     case ')':
                         if ($expression->reason->value != '(') {
                             throw new ExpParserException("Unbalanced (), should be detected in Lexer");
                         }
                         ExpParser::scopePop($expression, $scopes, $dataContext);
                         // close if it's a function
                         if ($expression->reason->type == ExpType::$FUNCTION) {
                             ExpParser::scopePop($expression, $scopes, $dataContext);
                         }
                         break;
                     default:
                         throw new ExpParserException("Token error: " . print_r($token, true));
                 }
                 break;
             case ExpType::$FUNCTION:
                 ExpParser::scopePush($expression, $scopes, $token);
                 break;
             case ExpType::$TERNARY:
                 if ($token->value != '?') {
                     throw new ExpParserException("Ternary token error");
                 }
                 $nextTernary = ExpParser::findNextTernary($tokenStream, 1);
                 $indicator = ExpType::coerceToBool($expression->evaluate($dataContext));
                 if ($indicator->value) {
                     // parsed?todo:skip
                     $nextCloseSymbol = ExpParser::findNextCloseSymbol($tokenStream, $nextTernary + 1);
                     array_splice($tokenStream, $nextTernary, $nextCloseSymbol - $nextTernary);
                 } else {
                     // parsed?skip:todo
                     $tokenStream = array_slice($tokenStream, $nextTernary + 1);
                 }
                 $expression = new PrimitiveExp($expression->reason);
                 break;
             case ExpType::$COMMA:
                 if ($expression->reason->value != '(') {
                     throw new ExpParserException("Unbalanced (), should be detected in Lexer");
                 }
                 ExpParser::scopePop($expression, $scopes, $dataContext);
                 ExpParser::scopePush($expression, $scopes, new Token(ExpType::$PAREN, '('));
                 break;
             default:
                 $expression->append($token);
         }
     }
     if ($expression->reason->type != 'final') {
         throw new ExpParserException("Gramma error on the non-primitive expression");
     }
     return $expression->evaluate($dataContext);
 }