ParseResult (@NotNull PsiElement anchor, @NotNull String type, @NotNull TypeEvalContext context) { PyPsiUtils.assertValid(anchor); final ForwardDeclaration<ParseResult, PyElementType> typeExpr = ForwardDeclaration.create(); final FunctionalParser<ParseResult, PyElementType> classType = token(IDENTIFIER).then(many(op(".").skipThen(token(IDENTIFIER)))) .map(new MakeSimpleType(anchor, context)) .cached() .named("class-type"); final FunctionalParser<ParseResult, PyElementType> tupleType = op("(").skipThen(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op(")")) .map(value -> { ParseResult result = value.getFirst(); final List<ParseResult> rest = value.getSecond(); if (rest.isEmpty()) { return result; } final List<PyType> types = new ArrayList<>(); types.add(result.getType()); for (ParseResult r : rest) { result = result.merge(r); types.add(r.getType()); } return result.withType(PyTupleType.create(anchor, types)); }) .named("tuple-type"); final FunctionalParser<ParseResult, PyElementType> typeParameter = token(PARAMETER).then(maybe(op("<=").skipThen(typeExpr))) .map(value -> { final Token<PyElementType> token = value.getFirst(); final String name = token.getText().toString(); final TextRange range = token.getRange(); final ParseResult boundResult = value.getSecond(); if (boundResult != null) { final PyTypeVarType type1 = new PyTypeVarTypeImpl(name, boundResult.getType()); final ParseResult result = new ParseResult(type1, range); return result.merge(boundResult).withType(type1); } return new ParseResult(new PyTypeVarTypeImpl(name, null), range); }) .named("type-parameter"); final FunctionalParser<ParseResult, PyElementType> simpleExpr = classType .or(tupleType) .or(typeParameter) .named("simple-expr"); final FunctionalParser<ParseResult, PyElementType> paramExpr = classType.thenSkip(op("[")).then(typeExpr).then(many(op(",").skipThen(typeExpr))).thenSkip(op("]")) .map(value -> { final Pair<ParseResult, ParseResult> firstPair = value.getFirst(); final ParseResult first = firstPair.getFirst(); final ParseResult second = firstPair.getSecond(); final List<ParseResult> third = value.getSecond(); final PyType firstType = first.getType(); final List<PyType> typesInBrackets = new ArrayList<>(); typesInBrackets.add(second.getType()); ParseResult result = first; result = result.merge(second); for (ParseResult r : third) { typesInBrackets.add(r.getType()); result = result.merge(r); } final List<PyType> elementTypes = third.isEmpty() ? Collections.singletonList(second.getType()) : typesInBrackets; if (firstType instanceof PyClassType) { final PyType type1 = new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, elementTypes); return result.withType(type1); } return EMPTY_RESULT; }) .or(classType.thenSkip(op("of")).then(simpleExpr) .map(value -> { final ParseResult firstResult = value.getFirst(); final ParseResult secondResult = value.getSecond(); final ParseResult result = firstResult.merge(secondResult); final PyType firstType = firstResult.getType(); final PyType secondType = secondResult.getType(); if (firstType != null) { if (firstType instanceof PyClassType && secondType != null) { return result.withType(new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, Collections.singletonList(secondType))); } return result.withType(firstType); } return EMPTY_RESULT; })) .or(classType.thenSkip(op("from")).then(simpleExpr).thenSkip(op("to")).then(simpleExpr) .map(value -> { final Pair<ParseResult, ParseResult> firstPair = value.getFirst(); final ParseResult first = firstPair.getFirst(); final ParseResult second = firstPair.getSecond(); final ParseResult third = value.getSecond(); final PyType firstType = first.getType(); if (firstType instanceof PyClassType) { final List<PyType> elementTypes = Arrays.asList(second.getType(), third.getType()); final PyCollectionTypeImpl type1 = new PyCollectionTypeImpl(((PyClassType)firstType).getPyClass(), false, elementTypes); return first.merge(second).merge(third).withType(type1); } return EMPTY_RESULT; })) .named("param-expr"); final FunctionalParser<ParseResult, PyElementType> callableExpr = op("(").skipThen(maybe(typeExpr.then(many(op(",").skipThen(typeExpr))))).thenSkip(op(")")).thenSkip(op("->")).then(typeExpr) .map( value -> { final List<PyCallableParameter> parameters = new ArrayList<>(); final ParseResult returnResult = value.getSecond(); ParseResult result; final Pair<ParseResult, List<ParseResult>> firstPair = value.getFirst(); if (firstPair != null) { final ParseResult first = firstPair.getFirst(); final List<ParseResult> second = firstPair.getSecond(); result = first; parameters.add(PyCallableParameterImpl.nonPsi(first.getType())); for (ParseResult r : second) { result = result.merge(r); parameters.add(PyCallableParameterImpl.nonPsi(r.getType())); } result = result.merge(returnResult); } else { result = returnResult; } return result.withType(new PyCallableTypeImpl(parameters, returnResult.getType())); }) .named("callable-expr"); final FunctionalParser<ParseResult, PyElementType> singleExpr = paramExpr .or(callableExpr) .or(simpleExpr) .named("single-expr"); final FunctionalParser<ParseResult, PyElementType> unionExpr = singleExpr.then(many(op("or").or(op("|")).skipThen(singleExpr))) .map(value -> { final ParseResult first = value.getFirst(); final List<ParseResult> rest = value.getSecond(); if (rest.isEmpty()) { return first; } final List<PyType> types = new ArrayList<>(); types.add(first.getType()); ParseResult result = first; for (ParseResult r : rest) { types.add(r.getType()); result = result.merge(r); } return result.withType(PyUnionType.union(types)); }) .named("union-expr"); typeExpr .define(unionExpr) .named("type-expr"); final FunctionalParser<ParseResult, PyElementType> typeFile = typeExpr .endOfInput() .named("type-file"); try { return typeFile.parse(tokenize(type)); } catch (ParserException e) { return EMPTY_RESULT; } }