Skip to content
This repository has been archived by the owner on Apr 13, 2019. It is now read-only.

Commit

Permalink
req projections syntax: allow references on model tails
Browse files Browse the repository at this point in the history
  • Loading branch information
Konstantin Sobolev committed Nov 6, 2017
1 parent 2eb9699 commit 89d96b6
Show file tree
Hide file tree
Showing 19 changed files with 502 additions and 162 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -386,17 +386,7 @@ private static void supportedEntityTailTypes(@NotNull GenVarProjection<?, ?, ?>
@NotNull TextLocation location,
@NotNull PsiProcessingContext ctx) throws PsiProcessingException {

@Nullable DatumTypeApi targetType = getDatumType(tailTypeRef, true, resolver, location, ctx);

if (targetType == null) {
throw new PsiProcessingException(
String.format(
"Unknown tail type '%s'. Supported tail types: {%s}",
tailTypeRef.toString(),
String.join(", ", supportedModelTailTypes(mp))
), location, ctx
);
}
@Nullable DatumTypeApi targetType = getModelTailType(mp, tailTypeRef, resolver, location, ctx);

if (targetType.equals(mp.type())) return mp;

Expand All @@ -414,6 +404,27 @@ private static void supportedEntityTailTypes(@NotNull GenVarProjection<?, ?, ?>
return (MP) mp.normalizedForType(targetType);
}

public static @NotNull <MP extends GenModelProjection<?, ?, ?, ?>> DatumTypeApi getModelTailType(
final @NotNull MP mp,
final @NotNull TypeRef tailTypeRef,
final @NotNull TypesResolver resolver,
final @NotNull TextLocation location,
final @NotNull PsiProcessingContext ctx) throws PsiProcessingException {

@Nullable DatumTypeApi targetType = getDatumType(tailTypeRef, true, resolver, location, ctx);

if (targetType == null) {
throw new PsiProcessingException(
String.format(
"Unknown tail type '%s'. Supported tail types: {%s}",
tailTypeRef.toString(),
String.join(", ", supportedModelTailTypes(mp))
), location, ctx
);
}
return targetType;
}

@SuppressWarnings("unchecked")
public static <MP extends GenModelProjection<?, ?, ?, ?>> boolean hasModelTail(
@NotNull MP mp,
Expand All @@ -424,10 +435,10 @@ private static void supportedEntityTailTypes(@NotNull GenVarProjection<?, ?, ?>
return tails != null && tails.stream().anyMatch(t -> hasModelTail((MP) t, tailType));
}

public static @NotNull List<String> supportedModelTailTypes(@NotNull GenModelProjection<?, ?, ?, ?> vp) {
if (vp.polymorphicTails() == null) return Collections.emptyList();
public static @NotNull List<String> supportedModelTailTypes(@NotNull GenModelProjection<?, ?, ?, ?> mp) {
if (mp.polymorphicTails() == null) return Collections.emptyList();
Set<String> acc = new HashSet<>();
supportedModelTailTypes(vp, acc);
supportedModelTailTypes(mp, acc);
List<String> res = new ArrayList<>(acc);
Collections.sort(res);
return res;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -753,7 +753,8 @@ private ReqEntityProjection buildEntityTailProjection(
@NotNull TypesResolver typesResolver) throws PsiProcessingException {

@NotNull TypeRef tailTypeRef = TypeRefs.fromPsi(tailTypeRefPsi, context);
@NotNull OpEntityProjection opTail = ProjectionsParsingUtil.getEntityTail(op,
@NotNull OpEntityProjection opTail = ProjectionsParsingUtil.getEntityTail(
op,
tailTypeRef,
typesResolver,
EpigraphPsiUtil.getLocation(tailTypeRefPsi),
Expand Down Expand Up @@ -1071,11 +1072,7 @@ private void checkModelPsi(@NotNull UrlReqComaModelProjection psi, @NotNull Type
op,
tailItemPsi.getPlus() != null,
tailItemPsi.getTypeRef(),
tailItemPsi.getReqComaModelProjection(),
tailItemPsi,
tailItemPsi.getReqParamList(),
tailItemPsi.getReqAnnotationList(),
tailItemPsi.getReqModelMeta(),
tailItemPsi.getReqUnnamedOrRefComaModelProjection(),
typesResolver
)
);
Expand All @@ -1088,11 +1085,7 @@ private void checkModelPsi(@NotNull UrlReqComaModelProjection psi, @NotNull Type
op,
singleTailPsi.getPlus() != null,
singleTailPsi.getTypeRef(),
singleTailPsi.getReqComaModelProjection(),
singleTailPsi,
singleTailPsi.getReqParamList(),
singleTailPsi.getReqAnnotationList(),
singleTailPsi.getReqModelMeta(),
singleTailPsi.getReqUnnamedOrRefComaModelProjection(),
typesResolver
)
);
Expand All @@ -1101,6 +1094,73 @@ private void checkModelPsi(@NotNull UrlReqComaModelProjection psi, @NotNull Type
}
}

@SuppressWarnings("unchecked")
private <MP extends ReqModelProjection<?, ?, ?>>
@NotNull MP buildModelTailProjection(
@NotNull Class<MP> modelClass,
@NotNull OpModelProjection<?, ?, ?, ?> op,
boolean flag,
@NotNull UrlTypeRef tailTypeRefPsi,
@NotNull UrlReqUnnamedOrRefComaModelProjection unnamedOrRefModelProjectionPsi,
@NotNull TypesResolver typesResolver) throws PsiProcessingException {

UrlReqComaModelProjectionRef refPsi = unnamedOrRefModelProjectionPsi.getReqComaModelProjectionRef();

if (refPsi == null) {
UrlReqComaModelProjection modelProjectionPsi = unnamedOrRefModelProjectionPsi.getReqComaModelProjection();

if (modelProjectionPsi == null)
throw new PsiProcessingException("Incomplete model tail expression", unnamedOrRefModelProjectionPsi, context);

return buildModelTailProjection(
modelClass,
op,
flag,
tailTypeRefPsi,
modelProjectionPsi,
unnamedOrRefModelProjectionPsi,
unnamedOrRefModelProjectionPsi.getReqParamList(),
unnamedOrRefModelProjectionPsi.getReqAnnotationList(),
unnamedOrRefModelProjectionPsi.getReqModelMeta(),
typesResolver
);
} else {
@Nullable UrlQid namePsi = refPsi.getQid();
if (namePsi == null)
throw new PsiProcessingException("Model tail reference name missing", refPsi, context);
@NotNull String referenceName = namePsi.getCanonicalName();

@NotNull TypeRef tailTypeRef = TypeRefs.fromPsi(tailTypeRefPsi, context);
@NotNull DatumTypeApi tailType = ProjectionsParsingUtil.getModelTailType(
op,
tailTypeRef,
typesResolver,
EpigraphPsiUtil.getLocation(tailTypeRefPsi),
context
);

ReqReferenceContext referenceContext = this.context.referenceContext();
ReqModelProjection<?, ?, ?> tailProjectionReference =
referenceContext.modelReference(tailType, referenceName, true, EpigraphPsiUtil.getLocation(refPsi));

tailProjectionReference.runOnResolved(() -> {
try {
checkModelTailType(
op.type(),
tailType,
tailProjectionReference.type(),
EpigraphPsiUtil.getLocation(unnamedOrRefModelProjectionPsi),
context
);
} catch (PsiProcessingException e) {
context.addException(e);
}
});

return (MP) tailProjectionReference;
}
}

private <MP extends ReqModelProjection<?, ?, ?>>
@NotNull MP buildModelTailProjection(
@NotNull Class<MP> modelClass,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@
import ws.epigraph.lang.MessagesContext;
import ws.epigraph.projections.StepsAndProjection;
import ws.epigraph.projections.gen.ProjectionReferenceName;
import ws.epigraph.projections.op.OpEntityProjection;
import ws.epigraph.projections.op.OpProjectionPsiParser;
import ws.epigraph.projections.op.OpPsiProcessingContext;
import ws.epigraph.projections.op.OpReferenceContext;
import ws.epigraph.projections.op.*;
import ws.epigraph.projections.op.delete.OpDeleteProjectionsPsiParser;
import ws.epigraph.projections.op.input.OpInputProjectionsPsiParser;
import ws.epigraph.projections.op.output.OpOutputProjectionsPsiParser;
Expand All @@ -36,8 +33,10 @@
import ws.epigraph.schema.parser.SchemaSubParserDefinitions;
import ws.epigraph.schema.parser.psi.SchemaOpEntityPath;
import ws.epigraph.schema.parser.psi.SchemaOpEntityProjection;
import ws.epigraph.schema.parser.psi.SchemaOpModelProjection;
import ws.epigraph.test.TestUtil;
import ws.epigraph.types.DataType;
import ws.epigraph.types.DatumTypeApi;
import ws.epigraph.url.parser.UrlSubParserDefinitions;
import ws.epigraph.url.parser.psi.UrlReqTrunkEntityProjection;
import ws.epigraph.url.projections.req.delete.ReqDeleteProjectionPsiParser;
Expand All @@ -59,11 +58,19 @@ public final class ReqTestUtil {
private ReqTestUtil() {}

public static @NotNull OpEntityProjection parseOpOutputEntityProjection(
@NotNull DataType varDataType,
@NotNull DataType entityDataType,
@NotNull String projectionString,
@NotNull TypesResolver resolver) {

return parseOpEntityProjection(OpOutputProjectionsPsiParser::new, entityDataType, projectionString, resolver);
}

public static @NotNull OpModelProjection<?,?,?,?> parseOpOutputModelProjection(
@NotNull DatumTypeApi type,
@NotNull String projectionString,
@NotNull TypesResolver resolver) {

return parseOpEntityProjection(OpOutputProjectionsPsiParser::new, varDataType, projectionString, resolver);
return parseOpModelProjection(OpOutputProjectionsPsiParser::new, type, projectionString, resolver);
}

public static @NotNull OpEntityProjection parseOpInputEntityProjection(
Expand Down Expand Up @@ -93,19 +100,19 @@ private ReqTestUtil() {}

private static @NotNull OpEntityProjection parseOpEntityProjection(
@NotNull Function<MessagesContext, OpProjectionPsiParser> parserFactory,
@NotNull DataType varDataType,
@NotNull DataType entityDataType,
@NotNull String projectionString,
@NotNull TypesResolver resolver) {

EpigraphPsiUtil.ErrorsAccumulator errorsAccumulator = new EpigraphPsiUtil.ErrorsAccumulator();

SchemaOpEntityProjection psiVarProjection = EpigraphPsiUtil.parseText(
SchemaOpEntityProjection entityProjectionPsi = EpigraphPsiUtil.parseText(
projectionString,
SchemaSubParserDefinitions.OP_ENTITY_PROJECTION,
errorsAccumulator
);

failIfHasErrors(psiVarProjection, errorsAccumulator);
failIfHasErrors(entityProjectionPsi, errorsAccumulator);

return runPsiParser(true, context -> {
OpReferenceContext opOutputReferenceContext =
Expand All @@ -116,17 +123,57 @@ private ReqTestUtil() {}
opOutputReferenceContext
);
OpProjectionPsiParser parser = parserFactory.apply(context);
OpEntityProjection vp = parser.parseEntityProjection(
varDataType,
OpEntityProjection ep = parser.parseEntityProjection(
entityDataType,
false,
psiVarProjection,
entityProjectionPsi,
resolver,
opPsiProcessingContext
);

opOutputReferenceContext.ensureAllReferencesResolved();

return vp;
return ep;
});

}

private static @NotNull OpModelProjection<?,?,?,?> parseOpModelProjection(
@NotNull Function<MessagesContext, OpProjectionPsiParser> parserFactory,
@NotNull DatumTypeApi type,
@NotNull String projectionString,
@NotNull TypesResolver resolver) {

EpigraphPsiUtil.ErrorsAccumulator errorsAccumulator = new EpigraphPsiUtil.ErrorsAccumulator();

SchemaOpModelProjection modelProjectionPsi = EpigraphPsiUtil.parseText(
projectionString,
SchemaSubParserDefinitions.OP_MODEL_PROJECTION,
errorsAccumulator
);

failIfHasErrors(modelProjectionPsi, errorsAccumulator);

return runPsiParser(true, context -> {
OpReferenceContext opOutputReferenceContext =
new OpReferenceContext(ProjectionReferenceName.EMPTY, null, context);

OpPsiProcessingContext opPsiProcessingContext = new OpPsiProcessingContext(
context,
opOutputReferenceContext
);
OpProjectionPsiParser parser = parserFactory.apply(context);
OpModelProjection<?,?,?,?> mp = parser.parseModelProjection(
type,
false,
modelProjectionPsi,
resolver,
opPsiProcessingContext
);

opOutputReferenceContext.ensureAllReferencesResolved();

return mp;
});

}
Expand Down
Loading

0 comments on commit 89d96b6

Please sign in to comment.