Validate the current attribute type.

@param TokenStream $stream
@param string      $type
@param string[]    $allowed

@throws SyntaxError When the attribute type is not allowed
178315
protected function validateAttributeType(TokenStream $stream, $type, array $allowed): void
    {
        $valid = false;

        foreach ($allowed as $aType) {
            if ($stream->test(\constant(Token::class.'::'.$aType.'_TYPE'))) {
                $valid = true;

                break;
            }
        }

        if (!$valid) {
            $message = 'The attribute %s "%s" must be an %s';

            throw new SyntaxError(sprintf($message, $type, $stream->getCurrent()->getValue(), implode(', ', $allowed)), $stream->getCurrent()->getLine(), $stream->getSourceContext());
        }
    }
292037
public function deserialize($stream, $type = ['type' => ''])
    {
        if (is_string($stream)) {
            $res = fopen('php://memory', 'rw+b');
            fwrite($res, $stream);
            fseek($res, 0);
            $stream = $res;
        } elseif (!is_resource($stream)) {
            throw new Exception(\danog\MadelineProto\Lang::$current_lang['stream_handle_invalid']);
        }
        switch ($type['type']) {
            case 'Bool':
                return $this->deserialize_bool(stream_get_contents($stream, 4));
            case 'int':
                return $this->unpack_signed_int(stream_get_contents($stream, 4));
            case '#':
                return unpack('V', stream_get_contents($stream, 4))[1];
            case 'long':
                if (isset($type['idstrlong'])) {
                    return stream_get_contents($stream, 8);
                }

                return \danog\MadelineProto\Magic::$bigint || isset($type['strlong']) ? stream_get_contents($stream, 8) : $this->unpack_signed_long(stream_get_contents($stream, 8));
            case 'double':
                return $this->unpack_double(stream_get_contents($stream, 8));
            case 'int128':
                return stream_get_contents($stream, 16);
            case 'int256':
                return stream_get_contents($stream, 32);
            case 'int512':
                return stream_get_contents($stream, 64);
            case 'string':
            case 'bytes':
                $l = ord(stream_get_contents($stream, 1));
                if ($l > 254) {
                    throw new Exception(\danog\MadelineProto\Lang::$current_lang['length_too_big']);
                }
                if ($l === 254) {
                    $long_len = unpack('V', stream_get_contents($stream, 3).chr(0))[1];
                    $x = stream_get_contents($stream, $long_len);
                    $resto = $this->posmod(-$long_len, 4);
                    if ($resto > 0) {
                        stream_get_contents($stream, $resto);
                    }
                } else {
                    $x = $l ? stream_get_contents($stream, $l) : '';
                    $resto = $this->posmod(-($l + 1), 4);
                    if ($resto > 0) {
                        stream_get_contents($stream, $resto);
                    }
                }
                if (!is_string($x)) {
                    throw new Exception(\danog\MadelineProto\Lang::$current_lang['deserialize_not_str']);
                }

                return $type['type'] === 'bytes' ? new Types\Bytes($x) : $x;
            case 'Vector t':
                $id = stream_get_contents($stream, 4);
                $constructorData = $this->constructors->find_by_id($id);
                if ($constructorData === false) {
                    $constructorData = $this->methods->find_by_id($id);
                    $constructorData['predicate'] = 'method_'.$constructorData['method'];
                }
                if ($constructorData === false) {
                    throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id))));
                }
                switch ($constructorData['predicate']) {
                    case 'gzip_packed':
                        return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes', 'datacenter' => $type['datacenter']])), ['type' => '', 'datacenter' => $type['datacenter']]);
                    case 'Vector t':
                    case 'vector':
                        break;
                    default:
                        throw new Exception(\danog\MadelineProto\Lang::$current_lang['vector_invalid'].$constructorData['predicate']);
                }
            case 'vector':
                $count = unpack('V', stream_get_contents($stream, 4))[1];
                $result = [];
                $type['type'] = $type['subtype'];
                for ($i = 0; $i < $count; $i++) {
                    $result[] = $this->deserialize($stream, $type);
                }

                return $result;
        }
        if ($type['type'] != '' && $type['type'][0] === '%') {
            $checkType = substr($type['type'], 1);
            $constructorData = $this->constructors->find_by_type($checkType);
            if ($constructorData === false) {
                throw new Exception(\danog\MadelineProto\Lang::$current_lang['constructor_not_found'].$checkType);
            }
        } else {
            $constructorData = $this->constructors->find_by_predicate($type['type']);
            if ($constructorData === false) {
                $id = stream_get_contents($stream, 4);
                $constructorData = $this->constructors->find_by_id($id);
                if ($constructorData === false) {
                    $constructorData = $this->methods->find_by_id($id);
                    if ($constructorData === false) {
                        throw new Exception(sprintf(\danog\MadelineProto\Lang::$current_lang['type_extract_error_id'], $type['type'], bin2hex(strrev($id))));
                    }
                    $constructorData['predicate'] = 'method_'.$constructorData['method'];
                }
            }
        }
        if ($constructorData['predicate'] === 'gzip_packed') {
            if (!isset($type['subtype'])) {
                $type['subtype'] = '';
            }

            return $this->deserialize(gzdecode($this->deserialize($stream, ['type' => 'bytes'])), ['type' => '', 'datacenter' => $type['datacenter'], 'subtype' => $type['subtype']]);
        }
        if ($constructorData['type'] === 'Vector t') {
            $constructorData['datacenter'] = $type['datacenter'];
            $constructorData['subtype'] = isset($type['subtype']) ? $type['subtype'] : '';
            $constructorData['type'] = 'vector';

            return $this->deserialize($stream, $constructorData);
        }
        if ($constructorData['predicate'] === 'boolTrue') {
            return true;
        }
        if ($constructorData['predicate'] === 'boolFalse') {
            return false;
        }
        $x = ['_' => $constructorData['predicate']];
        if (isset($this->tl_callbacks[TLCallback::CONSTRUCTOR_BEFORE_CALLBACK][$x['_']])) {
            foreach ($this->tl_callbacks[TLCallback::CONSTRUCTOR_BEFORE_CALLBACK][$x['_']] as $callback) {
                $callback($x['_']);
            }
        }
        foreach ($constructorData['params'] as $arg) {
            if (isset($arg['pow'])) {
                switch ($arg['type']) {
                    case 'true':
                    case 'false':
                        $x[$arg['name']] = ($x['flags'] & $arg['pow']) !== 0;
                        continue 2;
                    case 'Bool':
                        if (($x['flags'] & $arg['pow']) === 0) {
                            $x[$arg['name']] = false;
                            continue 2;
                        }
                    default:
                        if (($x['flags'] & $arg['pow']) === 0) {
                            continue 2;
                        }
                }
            }
            if (in_array($arg['name'], ['msg_ids', 'msg_id', 'bad_msg_id', 'req_msg_id', 'answer_msg_id', 'first_msg_id'])) {
                $arg['idstrlong'] = true;
            }
            if (in_array($arg['name'], ['key_fingerprint', 'server_salt', 'new_server_salt', 'server_public_key_fingerprints', 'ping_id', 'exchange_id'])) {
                $arg['strlong'] = true;
            }
            if (in_array($arg['name'], ['peer_tag', 'file_token', 'cdn_key', 'cdn_iv'])) {
                $arg['type'] = 'string';
            }
            if ($x['_'] === 'rpc_result' && $arg['name'] === 'result') {
                if (isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_'])
                    && isset($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']])
                ) {
                    foreach ($this->tl_callbacks[TLCallback::METHOD_BEFORE_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']] as $callback) {
                        $callback($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']);
                    }
                }

                if (isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type'])
                    && stripos($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type'], '<') !== false
                ) {
                    $arg['subtype'] = str_replace(['Vector<', '>'], '', $this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['type']);
                }
            }
            if (isset($type['datacenter'])) {
                $arg['datacenter'] = $type['datacenter'];
            }
            $x[$arg['name']] = $this->deserialize($stream, $arg);
            if ($arg['name'] === 'random_bytes') {
                if (strlen($x[$arg['name']]) < 15) {
                    throw new \danog\MadelineProto\SecurityException(\danog\MadelineProto\Lang::$current_lang['rand_bytes_too_small']);
                } else {
                    unset($x[$arg['name']]);
                }
            }
        }
        if (isset($x['flags'])) {
            // I don't think we need this anymore
            unset($x['flags']);
        }
        if ($x['_'] === 'dataJSON') {
            return json_decode($x['data'], true);
        } elseif ($constructorData['type'] === 'JSONValue') {
            switch ($x['_']) {
                case 'jsonNull':
                    return;
                case 'jsonObject':
                    $res = [];
                    foreach ($x['value'] as $pair) {
                        $res[$pair['key']] = $pair['value'];
                    }

                    return $res;
                default:
                    return $x['value'];
            }
        }

        if (isset($this->tl_callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']])) {
            foreach ($this->tl_callbacks[TLCallback::CONSTRUCTOR_CALLBACK][$x['_']] as $callback) {
                $callback($x);
            }
        } elseif ($x['_'] === 'rpc_result'
            && isset($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_'])
            && isset($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']])
        ) {
            foreach ($this->tl_callbacks[TLCallback::METHOD_CALLBACK][$this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']]['_']] as $callback) {
                $callback($this->datacenter->sockets[$type['datacenter']]->outgoing_messages[$x['req_msg_id']], $x['result']);
            }
        }

        if ($x['_'] === 'message' && isset($x['reply_markup']['rows'])) {
            foreach ($x['reply_markup']['rows'] as $key => $row) {
                foreach ($row['buttons'] as $bkey => $button) {
                    $x['reply_markup']['rows'][$key]['buttons'][$bkey] = new Types\Button($this, $x, $button);
                }
            }
        }

        return $x;
    }
517512
public function setAllowedTypes($types)
    {
        $this->allowedTypes = [];
        $token = ' ,;';
        $type = strtok($types, $token);
        while ($type !== false) {
            $this->allowedTypes[] = $type;
            $type = strtok($token);
        }
    }
1275831
protected function parseBody(TokenStream $stream)
    {
        $visibility = $this->skip($stream)->expect(array(Lexer::TOKEN_PUBL, Lexer::TOKEN_PROT, Lexer::TOKEN_PRIV));
        $name = $this->skip($stream)->expect(array(Lexer::TOKEN_NODE));

        if ($this->skip($stream)->is(Lexer::TOKEN_METO)) {
            $this->parseMethod($stream, $visibility, $name);
        } else {
            $this->parseProperty($stream, $visibility, $name);
        }
    }
244919
private function parseSimpleSelector(TokenStream $stream, bool $insideNegation = false): array
    {
        $stream->skipWhitespace();

        $selectorStart = \count($stream->getUsed());
        $result = $this->parseElementNode($stream);
        $pseudoElement = null;

        while (true) {
            $peek = $stream->getPeek();
            if ($peek->isWhitespace()
                || $peek->isFileEnd()
                || $peek->isDelimiter([',', '+', '>', '~'])
                || ($insideNegation && $peek->isDelimiter([')']))
            ) {
                break;
            }

            if (null !== $pseudoElement) {
                throw SyntaxErrorException::pseudoElementFound($pseudoElement, 'not at the end of a selector');
            }

            if ($peek->isHash()) {
                $result = new Node\HashNode($result, $stream->getNext()->getValue());
            } elseif ($peek->isDelimiter(['.'])) {
                $stream->getNext();
                $result = new Node\ClassNode($result, $stream->getNextIdentifier());
            } elseif ($peek->isDelimiter(['['])) {
                $stream->getNext();
                $result = $this->parseAttributeNode($result, $stream);
            } elseif ($peek->isDelimiter([':'])) {
                $stream->getNext();

                if ($stream->getPeek()->isDelimiter([':'])) {
                    $stream->getNext();
                    $pseudoElement = $stream->getNextIdentifier();

                    continue;
                }

                $identifier = $stream->getNextIdentifier();
                if (\in_array(strtolower($identifier), ['first-line', 'first-letter', 'before', 'after'])) {
                    // Special case: CSS 2.1 pseudo-elements can have a single ':'.
                    // Any new pseudo-element must have two.
                    $pseudoElement = $identifier;

                    continue;
                }

                if (!$stream->getPeek()->isDelimiter(['('])) {
                    $result = new Node\PseudoNode($result, $identifier);

                    continue;
                }

                $stream->getNext();
                $stream->skipWhitespace();

                if ('not' === strtolower($identifier)) {
                    if ($insideNegation) {
                        throw SyntaxErrorException::nestedNot();
                    }

                    list($argument, $argumentPseudoElement) = $this->parseSimpleSelector($stream, true);
                    $next = $stream->getNext();

                    if (null !== $argumentPseudoElement) {
                        throw SyntaxErrorException::pseudoElementFound($argumentPseudoElement, 'inside ::not()');
                    }

                    if (!$next->isDelimiter([')'])) {
                        throw SyntaxErrorException::unexpectedToken('")"', $next);
                    }

                    $result = new Node\NegationNode($result, $argument);
                } else {
                    $arguments = [];
                    $next = null;

                    while (true) {
                        $stream->skipWhitespace();
                        $next = $stream->getNext();

                        if ($next->isIdentifier()
                            || $next->isString()
                            || $next->isNumber()
                            || $next->isDelimiter(['+', '-'])
                        ) {
                            $arguments[] = $next;
                        } elseif ($next->isDelimiter([')'])) {
                            break;
                        } else {
                            throw SyntaxErrorException::unexpectedToken('an argument', $next);
                        }
                    }

                    if (empty($arguments)) {
                        throw SyntaxErrorException::unexpectedToken('at least one argument', $next);
                    }

                    $result = new Node\FunctionNode($result, $identifier, $arguments);
                }
            } else {
                throw SyntaxErrorException::unexpectedToken('selector', $peek);
            }
        }

        if (\count($stream->getUsed()) === $selectorStart) {
            throw SyntaxErrorException::unexpectedToken('selector', $stream->getPeek());
        }

        return [$result, $pseudoElement];
    }
1209200
protected function parseLinenosOption(\Twig_Token $token, \Twig_TokenStream $stream)
    {
        $this->testToken('linenos', $token, $stream);

        return $this->getNextExpectedBoolValueFromStream($stream, 'linenos');
    }
142239
public AttributeDataset parse(InputStream stream) throws IOException, ParseException {
        try (Reader r = new BufferedReader(new InputStreamReader(stream))) {
            StreamTokenizer tokenizer = new StreamTokenizer(r);
            initTokenizer(tokenizer);

            List<Attribute> attributes = new ArrayList<>();
            String relationName = readHeader(tokenizer, attributes);

            if (attributes.isEmpty()) {
                throw new IOException("no header information available");
            }
        
            Attribute response = null;
            Attribute[] attr = new Attribute[attributes.size()];
            attributes.toArray(attr);
        
            for (int i = 0; i < attributes.size(); i++) {
                if (responseIndex == i) {
                    response = attributes.remove(i);
                    break;
                }
            }
        
            AttributeDataset data = new AttributeDataset(relationName, attributes.toArray(new Attribute[attributes.size()]), response);
        
            while (true) {
                // Check if end of file reached.
                getFirstToken(tokenizer);
                if (tokenizer.ttype == StreamTokenizer.TT_EOF) {
                    break;
                }

                // Parse instance
                if (tokenizer.ttype == '{') {
                    readSparseInstance(tokenizer, data, attr);
                } else {
                    readInstance(tokenizer, data, attr);
                }
            }
        
            for (Attribute attribute : attributes) {
                if (attribute instanceof NominalAttribute) {
                    NominalAttribute a = (NominalAttribute) attribute;
                    a.setOpen(false);
                }
            
                if (attribute instanceof StringAttribute) {
                    StringAttribute a = (StringAttribute) attribute;
                    a.setOpen(false);
                }
            }
        
            return data;
        }
    }
655885
private function parseIdentifier(Stream $stream)
    {
        if ($stream->current()->is(Token::TYPE_IDENTIFIER)) {
            return $stream->expects(Token::TYPE_IDENTIFIER)->getValue();
        } else {
            return $stream->expects(Token::TYPE_STRING | Token::TYPE_DOUBLE_QUOTED)->getValue();
        }
    }
862348
protected function isNotSpecialToken(\Twig_TokenStream $stream)
    {
        return !$stream->test(\Twig_Token::NAME_TYPE, 'with')
            && !$stream->test(\Twig_Token::NAME_TYPE, 'sfor')
            && !$stream->test(\Twig_Token::PUNCTUATION_TYPE, ':')
            && !$stream->test(\Twig_Token::BLOCK_END_TYPE);
    }
990660
public function allow($type)
    {
        if (!is_array($type)) {
            $type = func_get_args();
        }
        $this->allowedTypes = implode(',', $type);

        return $this;
    }
760111
protected function parseComment(TokenStream $stream, $type)
    {
        while ($stream->skipType(array(Lexer::TOKEN_EOL, Lexer::TOKEN_WTSP))->is(Lexer::TOKEN_CMNT)) {
            $this->nodes[] = new Node($type, $stream->current()->getValue());
            $stream->next();
        }
    }
654564
protected function parseClass(ClassBuilder $builder, NodeStream $stream)
    {
        $node = $stream->expect(TokenParser::NODE_CLASS);
        $docblock = array();
        $builder->setClass($node->getValue());
        if ($stream->is(TokenParser::NODE_EXTENDS)) {
            $builder->setExtends($stream->current()->getValue());
            $stream->next();
        }
        while ($stream->is(TokenParser::NODE_IMPLEMENTS)) {
            $builder->addInterface($stream->current()->getValue());
            $stream->next();
        }
        while ($stream->is(TokenParser::NODE_CLASS_COMMENT)) {
            $docblock[] = $stream->current()->getValue();
            $stream->next();
        }

        if (count($docblock) > 0) {
            $builder->setDocblock($docblock);
        }

        $this->status = self::STAT_BODY;
    }
671097
public static function invalidParameterType($actualType, array $allowedTypes, $keyword, $pointer)
    {
        $message = sprintf(
            'Value has type "%s" but must be one of: "%s"',
            $actualType,
            implode(', ', $allowedTypes)
        );

        return new self($message, $keyword, $pointer);
    }
834218
public function validateProperty(string $property, $allowed): bool
    {
        if (is_string($allowed)) {
            $allowed = explode('|', $allowed);
        }

        if (!is_array($allowed)) {
            throw new InvalidTypeException('$allowed must be a string or array');
        }

        $valid = false;
        $optional = in_array('optional', $allowed);

        if ($optional && (!isset($this->{$property}) || $this->{$property} === null)) {
            return true;
        }

        foreach ($allowed as $index => $type) {
            if ($type === 'optional') {
                continue;
            }

            if ($valid = $this->validatePropertyType($property, $type)) {
                break;
            }
        }

        if (!$valid) {
            $this->throwInvalidTypeException($property, $allowed, $optional);
        }

        return true;
    }
492939
protected function validateType(string $attribute, Type $type, $value, string $format = null)
    {
        $builtinType = $type->getBuiltinType();
        if (Type::BUILTIN_TYPE_FLOAT === $builtinType && null !== $format && false !== strpos($format, 'json')) {
            $isValid = \is_float($value) || \is_int($value);
        } else {
            $isValid = \call_user_func('is_'.$builtinType, $value);
        }

        if (!$isValid) {
            throw new InvalidArgumentException(sprintf(
                'The type of the "%s" attribute must be "%s", "%s" given.', $attribute, $builtinType, \gettype($value)
            ));
        }
    }
909235
private static void validateTypes(byte[] types) {
        if (types == null) {
            throw new IllegalArgumentException("types is null");
        }
        for (int i = 0; i < types.length; ++i) {
            if (types[i] < TYPE_MIN || types[i] > TYPE_MAX) {
                throw new IllegalArgumentException("illegal type value at " + i + ": " + types[i]);
            }
        }
        for (int i = 0; i < types.length - 1; ++i) {
            if (types[i] == B) {
                throw new IllegalArgumentException("B type before end of paragraph at index: " + i);
            }
        }
    }
891155
function (streamer, token) {
	var character = streamer.next(true),
		attrs  = token.attrs,
		events = token.events,
		i, key, value;

	while (character && character !== ']') {
		if (character === '(') {
			streamer.next(true);
			key = parse_identifier(streamer);
			character = streamer.next(true);

			if (character !== ')') {
				throw new SyntaxError("[JeefoTemplate]: Invalid syntax error.");
			}

			character = streamer.next(true);
			if (character === '=') {
				streamer.next(true);
				value = parse_value(streamer);
				character = streamer.next(true);
			} else {
				throw new SyntaxError("[JeefoTemplate]: Invalid syntax error, empty event.");
			}

			events.set(key, value);
		} else {
			key = dash_case(parse_identifier(streamer));

			character = streamer.next(true);

			if (character === '=') {
				streamer.next(true);
				value = parse_value(streamer);
				character = streamer.next(true);
			} else if (key === "class") {
				throw new SyntaxError("[JeefoTemplate]: Expected class value.");
			} else {
				value = null;
			}

			if (key === "class") {
				key   = token.class_list.list;
				value = new ClassList(value.split(WHITESPACE_REGEX));

				for (i = 0; i < key.length; ++i) {
					value.add(key[i]);
				}

				token.class_list = value;
			} else {
				attrs.set(key, value);
			}
		}

		while (character === ',') {
			character = streamer.next(true);
		}
	}
}