예제 #1
0
파일: PrefixExpr.php 프로젝트: quack/quack
 public function getType()
 {
     $right_type = $this->right->getType();
     $op_name = Tag::getOperatorLexeme($this->operator);
     $type_error = new ScopeError(['message' => "No type overload for operator `{$op_name}' for `{$right_type}'"]);
     switch ($this->operator) {
         case '+':
         case '-':
             if ($right_type->isString() || $right_type->isNumber()) {
                 return clone $right_type;
             }
             throw $type_error;
         case '~':
             if ($right_type->isNumber()) {
                 return clone $right_type;
             }
             throw $type_error;
         case Tag::T_NOT:
             if ($right_type->isBoolean()) {
                 return clone $right_type;
             }
             throw $type_error;
         case '^^':
         case '*':
             return clone $right_type;
     }
 }
예제 #2
0
 public function format(Parser $parser)
 {
     $source = '&(';
     $source .= Tag::getOperatorLexeme($this->operator);
     if (null !== $this->right) {
         $source .= ' ';
         $source .= $this->right->format($parser);
     }
     $source .= ')';
     return $this->parenthesize($source);
 }
예제 #3
0
 public function parse(Grammar $grammar, Token $token)
 {
     $op_table =& Tag::getPartialOperators();
     $next_op = $grammar->parser->lookahead->getTag();
     $right = null;
     if (in_array($next_op, $op_table, true)) {
         $grammar->parser->match($next_op);
         // Faster than _optExpr
         if (!$grammar->parser->is(')')) {
             $right = $grammar->_expr();
         }
         $grammar->parser->match(')');
     } else {
         $grammar->parser->match('operator');
     }
     return new PartialFuncExpr($next_op, $right);
 }
예제 #4
0
파일: PostfixExpr.php 프로젝트: quack/quack
 public function format(Parser $parser)
 {
     $source = $this->left->format($parser);
     $source .= Tag::getOperatorLexeme($this->operator);
     return $this->parenthesize($source);
 }
예제 #5
0
 public function getType()
 {
     $type = (object) ['left' => $this->left->getType(), 'right' => 'string' === gettype($this->right) ? null : $this->right->getType()];
     $op_name = Tag::getOperatorLexeme($this->operator);
     $member_access = ['.', '?.'];
     if (in_array($this->operator, $member_access, true)) {
         // When member access and the property exists on the left type
         if (is_array($type->left->props) && array_key_exists($this->right, $type->left->props)) {
             return $type->left->props[$this->right];
         }
         throw new ScopeError(['message' => "Expression of type `{$type->left}' has no property `{$this->right}'"]);
     }
     // Type-checking for assignment. Don't worry. Left-hand assignment was handled on
     // scope injection
     if (':-' === $this->operator) {
         // When right side cannot be attributed to left side
         if (!$type->right->isExactlySameAs($type->left)) {
             $target = $this->left instanceof NameExpr ? "variable `{$this->left->name}' :: {$type->left}" : (string) $type->right;
             throw new ScopeError(['message' => "Trying to set value of type `{$type->right}` to {$target}"]);
         }
         // We've just removed covariance and contravariance :)
         return $type->right;
     }
     // Type checking for numeric and string concat operations
     $numeric_op = ['+', '-', '*', '**', '/', '>>', '<<', '^', '&', '|', Tag::T_MOD];
     if (in_array($this->operator, $numeric_op, true)) {
         if ('+' === $this->operator && $type->left->isString() && $type->right->isString()) {
             return new Type(NativeQuackType::T_STR);
         }
         if ($type->left->isNumber() && $type->right->isNumber()) {
             return Type::getBaseType([$type->left, $type->right]);
         }
         throw new ScopeError(['message' => "No type overload found for operator `{$op_name}' at " . "{{$type->left} {$op_name} {$type->right}}"]);
     }
     // Type checking for equality operators and coalescence
     $eq_op = ['=', '<>', '??', '>', '>=', '<', '<='];
     if (in_array($this->operator, $eq_op, true)) {
         if ($type->left->isExactlySameAs($type->right)) {
             return '??' === $this->operator ? $type->left : new Type(NativeQuackType::T_BOOL);
         }
         throw new ScopeError(['message' => "Why in the world are you trying to compare two expressions of different types? at " . "{{$type->left} {$op_name} {$type->right}}"]);
     }
     // Type checking for string matched by regex
     if ('=~' === $this->operator) {
         if (!$type->left->isString() || !$type->right->isRegex()) {
             throw new ScopeError(['message' => "No type overload found for operator `=~' at " . "{{$type->left} =~ {$type->right}}"]);
         }
         return new Type(NativeQuackType::T_BOOL);
     }
     // Boolean algebra
     $bool_op = [Tag::T_AND, Tag::T_OR, Tag::T_XOR];
     if (in_array($this->operator, $bool_op, true)) {
         if (!$type->left->isBoolean() || !$type->right->isBoolean()) {
             throw new ScopeError(['message' => "No type overload found for operator `{$op_name}' " . "{{$type->left} {$op_name} {$type->right}}"]);
         }
         return new Type(NativeQuackType::T_BOOL);
     }
 }
예제 #6
0
파일: SyntaxError.php 프로젝트: quack/quack
 private function getFoundTokenName()
 {
     $found_tag = $this->found->getTag();
     return 0 === $found_tag ? "end of the source" : Tag::getName($found_tag) ?: $found_tag;
 }