Skip to content

Commit

Permalink
Incorrect ternary parsing in rescript when using newline (rescript) #424
Browse files Browse the repository at this point in the history
  • Loading branch information
giraud committed Aug 30, 2023
1 parent 9161ab0 commit c1adcae
Show file tree
Hide file tree
Showing 10 changed files with 68 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ public ORASTFactory(T types) {
if (type == myTypes.C_FUNCTION_EXPR) {
return new RPsiFunction(myTypes, type);
}
if (type == myTypes.C_CUSTOM_OPERATOR || type == myTypes.C_SCOPED_EXPR || type == myTypes.C_IF_THEN_SCOPE || type == myTypes.C_DO_LOOP) {
if (type == myTypes.C_CUSTOM_OPERATOR || type == myTypes.C_SCOPED_EXPR || type == myTypes.C_IF_THEN_ELSE || type == myTypes.C_DO_LOOP) {
return new RPsiScopedExpr(myTypes, type);
}
if (type == myTypes.C_FOR_LOOP) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ public RPsiBinaryCondition getCondition() {

@Override
public @Nullable PsiElement getThenExpression() {
return ORUtil.findImmediateFirstChildOfType(this, myTypes.C_IF_THEN_SCOPE);
return ORUtil.findImmediateFirstChildOfType(this, myTypes.C_IF_THEN_ELSE);
}

@Override
public @Nullable PsiElement getElseExpression() {
return ORUtil.findImmediateLastChildOfType(this, myTypes.C_IF_THEN_SCOPE);
return ORUtil.findImmediateLastChildOfType(this, myTypes.C_IF_THEN_ELSE);
}
}
2 changes: 1 addition & 1 deletion src/main/java/com/reason/lang/core/type/ORLangTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public abstract class ORLangTypes extends ORTypes {
public ORCompositeType C_FUNCTOR_RESULT;
public ORCompositeType C_GUARD;
public ORCompositeType C_IF;
public ORCompositeType C_IF_THEN_SCOPE;
public ORCompositeType C_IF_THEN_ELSE;
public ORCompositeType C_LET_ATTR;
public ORCompositeType C_LET_BINDING;
public ORCompositeType C_LOCAL_OPEN;
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/reason/lang/ocaml/OclParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -531,14 +531,14 @@ private void parseThen() {
if (!in(myTypes.C_DIRECTIVE)) {
// if ... |>then<| ...
popEndUntil(myTypes.C_IF).advance()
.mark(myTypes.C_IF_THEN_SCOPE);
.mark(myTypes.C_IF_THEN_ELSE);
}
}

private void parseElse() {
// if ... then ... |>else<| ...
popEndUntil(myTypes.C_IF).advance()
.mark(myTypes.C_IF_THEN_SCOPE);
.mark(myTypes.C_IF_THEN_ELSE);
}

private void parseStruct() {
Expand Down Expand Up @@ -669,7 +669,7 @@ private void parseColon() {
if (isFound(myTypes.C_TERNARY)) {
// x ? y |> :<| ...
popEndUntilFoundIndex()
.advance().mark(myTypes.C_IF_THEN_SCOPE).markHolder(myTypes.H_PLACE_HOLDER);
.advance().mark(myTypes.C_IF_THEN_ELSE).markHolder(myTypes.H_PLACE_HOLDER);
} else {
// external x |> : <| ... OR val x |> : <| ... OR let x |> : <| ...
advance();
Expand Down Expand Up @@ -711,7 +711,7 @@ private void parseQuestionMark() {
markBefore(nextPos, myTypes.C_TERNARY)
.updateCompositeAt(nextPos, myTypes.C_BINARY_CONDITION)
.popEndUntilIndex(nextPos).end()
.advance().mark(myTypes.C_IF_THEN_SCOPE);
.advance().mark(myTypes.C_IF_THEN_ELSE);
markHolder(myTypes.H_PLACE_HOLDER);
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/reason/lang/ocaml/OclTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private OclTypes() {
C_FUNCTOR_RESULT = new ORCompositeElementType("C_FUNCTOR_RESULT", OclLanguage.INSTANCE);
C_GUARD = new ORCompositeElementType("C_GUARD", OclLanguage.INSTANCE);
C_IF = new ORCompositeElementType("C_IF", OclLanguage.INSTANCE);
C_IF_THEN_SCOPE = new ORCompositeElementType("C_IF_THEN_SCOPE", OclLanguage.INSTANCE);
C_IF_THEN_ELSE = new ORCompositeElementType("C_IF_THEN_ELSE", OclLanguage.INSTANCE);
C_INTERPOLATION_EXPR = new ORCompositeElementType("C_INTERPOLATION_EXPR", OclLanguage.INSTANCE);
C_INTERPOLATION_PART = new ORCompositeElementType("C_INTERPOLATION_PART", OclLanguage.INSTANCE);
C_INTERPOLATION_REF = new ORCompositeElementType("C_INTERPOLATION_REF", OclLanguage.INSTANCE);
Expand Down
18 changes: 9 additions & 9 deletions src/main/java/com/reason/lang/reason/RmlParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -280,12 +280,12 @@ private void parseQuestionMark() {
.setWhitespaceSkippedCallback(endJsxPropertyIfWhitespace())
.advance()
.remapCurrentToken(myTypes.PROPERTY_NAME);
} else if (strictlyIn(myTypes.C_IF_THEN_SCOPE)) {
} else if (strictlyIn(myTypes.C_IF_THEN_ELSE)) {
// if_then_scope can be inside a ternary
parseTernary();
} else if (!strictlyInAny(myTypes.C_TERNARY) && previousElementType(1) != myTypes.EQ /*default optional value*/) {
if (inScopeOrAny(myTypes.C_LET_BINDING, myTypes.C_FIELD_VALUE, myTypes.C_PARAM_DECLARATION, myTypes.C_PARAM,
myTypes.C_PATTERN_MATCH_BODY, myTypes.C_IF_THEN_SCOPE, myTypes.C_FUNCTION_BODY, myTypes.H_COLLECTION_ITEM,
myTypes.C_PATTERN_MATCH_BODY, myTypes.C_IF_THEN_ELSE, myTypes.C_FUNCTION_BODY, myTypes.H_COLLECTION_ITEM,
myTypes.C_DEFAULT_VALUE)) {
// a new ternary
parseTernary();
Expand All @@ -301,14 +301,14 @@ private void parseTernary() {
markBefore(nextPos, myTypes.C_TERNARY)
.updateCompositeAt(nextPos, myTypes.C_BINARY_CONDITION)
.popEndUntilIndex(nextPos).end()
.advance().mark(myTypes.C_IF_THEN_SCOPE);
.advance().mark(myTypes.C_IF_THEN_ELSE);
markHolder(myTypes.H_PLACE_HOLDER);
} else if (isAtIndex(foundPos, myTypes.H_COLLECTION_ITEM)) {
markHolderBefore(foundPos, myTypes.H_COLLECTION_ITEM)
.markBefore(foundPos, myTypes.C_TERNARY)
.updateCompositeAt(foundPos, myTypes.C_BINARY_CONDITION)
.popEndUntilIndex(foundPos).end()
.advance().mark(myTypes.C_IF_THEN_SCOPE);
.advance().mark(myTypes.C_IF_THEN_ELSE);
}
}

Expand Down Expand Up @@ -355,13 +355,13 @@ private void parseIf() {
private void parseThen() {
// if ... |>then<| ...
popEndUntil(myTypes.C_IF).advance()
.mark(myTypes.C_IF_THEN_SCOPE);
.mark(myTypes.C_IF_THEN_ELSE);
}

private void parseElse() {
// if ... then ... |>else<| ...
popEndUntil(myTypes.C_IF).advance()
.mark(myTypes.C_IF_THEN_SCOPE);
.mark(myTypes.C_IF_THEN_ELSE);
}

private void parseDot() {
Expand Down Expand Up @@ -724,7 +724,7 @@ else if (inScopeOrAny(
} else if (isFound(myTypes.C_TERNARY)) {
// x ? y |> :<| ...
popEndUntilFoundIndex()
.advance().mark(myTypes.C_IF_THEN_SCOPE);
.advance().mark(myTypes.C_IF_THEN_ELSE);
markHolder(myTypes.H_PLACE_HOLDER);
}
}
Expand Down Expand Up @@ -943,7 +943,7 @@ private void parseLBrace() {
// module M = (...) => |>{<| ...
updateScopeToken(myTypes.LBRACE);
} else if (isCurrent(myTypes.C_IF)) {
markScope(myTypes.C_IF_THEN_SCOPE, myTypes.LBRACE);
markScope(myTypes.C_IF_THEN_ELSE, myTypes.LBRACE);
} else if (is(myTypes.C_MODULE_SIGNATURE)) {
// module M : |>{<| ...
updateScopeToken(myTypes.LBRACE);
Expand Down Expand Up @@ -1079,7 +1079,7 @@ private void parseRParen() {
// if ( x |>)<| ...
end();
if (getTokenType() != myTypes.LBRACE) {
mark(myTypes.C_IF_THEN_SCOPE);
mark(myTypes.C_IF_THEN_ELSE);
}
} else if (lParen != null) {
IElementType nextTokenType = getTokenType();
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/reason/lang/reason/RmlTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private RmlTypes() {
C_FUNCTOR_RESULT = new ORCompositeElementType("C_FUNCTOR_RESULT", RmlLanguage.INSTANCE);
C_GUARD = new ORCompositeElementType("C_GUARD", RmlLanguage.INSTANCE);
C_IF = new ORCompositeElementType("C_IF", RmlLanguage.INSTANCE);
C_IF_THEN_SCOPE = new ORCompositeElementType("C_IF_THEN_SCOPE", RmlLanguage.INSTANCE);
C_IF_THEN_ELSE = new ORCompositeElementType("C_IF_THEN_ELSE", RmlLanguage.INSTANCE);
C_INTERPOLATION_EXPR = new ORCompositeElementType("C_INTERPOLATION_EXPR", RmlLanguage.INSTANCE);
C_INTERPOLATION_PART = new ORCompositeElementType("C_INTERPOLATION_PART", RmlLanguage.INSTANCE);
C_INTERPOLATION_REF = new ORCompositeElementType("C_INTERPOLATION_REF", RmlLanguage.INSTANCE);
Expand Down
48 changes: 35 additions & 13 deletions src/main/java/com/reason/lang/rescript/ResParser.java
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void parse() {
popIfHold();
markHolder(myTypes.H_PLACE_HOLDER);
}
} else if (isCurrent(myTypes.C_IF_THEN_SCOPE) && !currentHasScope()) {
} else if (isCurrent(myTypes.C_IF_THEN_ELSE) && !currentHasScope()) {
endLikeSemi2();
}
}
Expand Down Expand Up @@ -337,7 +337,7 @@ private void parseIf() {
private void parseElse() {
// if ... |>else<| ...
popEndUntil(myTypes.C_IF)
.advance().mark(myTypes.C_IF_THEN_SCOPE);
.advance().mark(myTypes.C_IF_THEN_ELSE);
}

private void parseDotDotDot() {
Expand All @@ -361,7 +361,7 @@ private void parseQuestionMark() {
// ... |>?<| ...
popEndUntilFoundIndex().end()
.advance()
.mark(myTypes.C_IF_THEN_SCOPE);
.mark(myTypes.C_IF_THEN_ELSE);
} else if (!inAny(myTypes.C_TERNARY) && previousElementType(1) != myTypes.EQ) {
if (inScopeOrAny(myTypes.H_PLACE_HOLDER, myTypes.H_COLLECTION_ITEM)) { // a new ternary
parseTernary();
Expand All @@ -376,14 +376,14 @@ private void parseTernary() {
markBefore(foundPos, myTypes.C_TERNARY)
.updateCompositeAt(foundPos, myTypes.C_BINARY_CONDITION)
.popEndUntilIndex(foundPos).end()
.advance().mark(myTypes.C_IF_THEN_SCOPE)
.advance().mark(myTypes.C_IF_THEN_ELSE)
.markHolder(myTypes.H_PLACE_HOLDER);
} else if (isAtIndex(foundPos, myTypes.H_COLLECTION_ITEM)) {
markHolderBefore(foundPos, myTypes.H_COLLECTION_ITEM)
.markBefore(foundPos, myTypes.C_TERNARY)
.updateCompositeAt(foundPos, myTypes.C_BINARY_CONDITION)
.popEndUntilIndex(foundPos).end()
.advance().mark(myTypes.C_IF_THEN_SCOPE);
.advance().mark(myTypes.C_IF_THEN_ELSE);
}
}

Expand Down Expand Up @@ -587,7 +587,7 @@ private void parseColon() {
if (strictlyInAny(
myTypes.C_MODULE_DECLARATION, myTypes.C_LET_DECLARATION, myTypes.C_EXTERNAL_DECLARATION,
myTypes.C_PARAM_DECLARATION, myTypes.C_RECORD_FIELD, myTypes.C_OBJECT_FIELD, myTypes.H_NAMED_PARAM_DECLARATION,
myTypes.C_IF_THEN_SCOPE)) {
myTypes.C_IF_THEN_ELSE)) {

if (isFound(myTypes.C_PARAM_DECLARATION) || isFound(myTypes.H_NAMED_PARAM_DECLARATION)) {
// let x = (y |> :<| ...
Expand Down Expand Up @@ -621,10 +621,11 @@ private void parseColon() {
mark(myTypes.C_FIELD_VALUE)
.markHolder(myTypes.H_PLACE_HOLDER);
}
} else if (isFound(myTypes.C_IF_THEN_SCOPE)) {
} else if (isFound(myTypes.C_IF_THEN_ELSE)) {
// ternary :: cond ? x |> :<| ...
popEndUntilFoundIndex().popEnd()
.advance()
.mark(myTypes.C_IF_THEN_SCOPE);
.mark(myTypes.C_IF_THEN_ELSE);
}

}
Expand Down Expand Up @@ -878,7 +879,7 @@ private void parseLBrace() {
markScope(myTypes.C_TRY_HANDLERS, myTypes.LBRACE);
} else if (isDone(myTypes.C_BINARY_CONDITION) && isRawParent(myTypes.C_IF)) {
// if x |>{<| ... }
markScope(myTypes.C_IF_THEN_SCOPE, myTypes.LBRACE);
markScope(myTypes.C_IF_THEN_ELSE, myTypes.LBRACE);
} else if (isDone(myTypes.C_BINARY_CONDITION) && isRawParent(myTypes.C_SWITCH_EXPR)) {
// switch (x) |>{<| ... }
markScope(myTypes.C_SWITCH_BODY, myTypes.LBRACE);
Expand All @@ -887,7 +888,7 @@ private void parseLBrace() {
if (isCurrent(myTypes.C_IF)) {
// if ... |>{<|
pop();
markScope(myTypes.C_IF_THEN_SCOPE, myTypes.LBRACE);
markScope(myTypes.C_IF_THEN_ELSE, myTypes.LBRACE);
} else if (strictlyIn(myTypes.C_SWITCH_EXPR)) {
// switch x |>{<| ... }
markScope(myTypes.C_SWITCH_BODY, myTypes.LBRACE);
Expand Down Expand Up @@ -1031,7 +1032,7 @@ private void parseRParen() {
end();
if (isRawParent(myTypes.C_IF) && nextTokenType != myTypes.LBRACE) {
// if ( x ) |><| ...
mark(myTypes.C_IF_THEN_SCOPE);
mark(myTypes.C_IF_THEN_ELSE);
}
} else if (lParen != null) {
if (isRawParent(myTypes.C_FUNCTOR_DECLARATION)) {
Expand Down Expand Up @@ -1238,7 +1239,7 @@ private void parseUIdent() {
.markHolder(myTypes.H_COLLECTION_ITEM);
}
} else {
if (!isCurrent(myTypes.C_IF_THEN_SCOPE) || rawHasScope()) { // a block less if then else
if (!isCurrent(myTypes.C_IF_THEN_ELSE) || rawHasScope()) { // a block less if then else
endLikeSemi2();
}
remapCurrentToken(nextToken == myTypes.RIGHT_ARROW ? myTypes.A_VARIANT_NAME : myTypes.A_MODULE_NAME)
Expand Down Expand Up @@ -1367,7 +1368,28 @@ private void endLikeSemi2() {
Marker marker = getActiveMarker();
boolean end = marker == null || !(marker.isCompositeType(myTypes.C_BINARY_CONDITION) || marker.isCompositeType(myTypes.C_PARAM));
if (end) {
popEndUntilScope();
// popEndUntilScope();
if (!myMarkers.isEmpty()) {
Marker latestMarker = myMarkers.peek();
while (latestMarker != null && !latestMarker.hasScope()) {
// A return inside a if/then without scope has no effect
if (latestMarker.isCompositeType(myTypes.C_IF_THEN_ELSE)) {
Marker ifType = find(2);
if (ifType != null && ifType.isCompositeType(myTypes.C_TERNARY)) {
IElementType nextELement = lookAheadSkipEOL(1);
if (nextELement == myTypes.COLON) {
break;
}
}
}

latestMarker = pop();
if (latestMarker != null) {
latestMarker.end();
}
latestMarker = getLatestMarker();
}
}
}
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/reason/lang/rescript/ResTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ private ResTypes() {
C_FUNCTOR_RESULT = new ORCompositeElementType("C_FUNCTOR_RESULT", ResLanguage.INSTANCE);
C_GUARD = new ORCompositeElementType("C_GUARD", ResLanguage.INSTANCE);
C_IF = new ORCompositeElementType("C_IF", ResLanguage.INSTANCE);
C_IF_THEN_SCOPE = new ORCompositeElementType("C_IF_THEN_SCOPE", ResLanguage.INSTANCE);
C_IF_THEN_ELSE = new ORCompositeElementType("C_IF_THEN_ELSE", ResLanguage.INSTANCE);
C_INTERPOLATION_EXPR = new ORCompositeElementType("C_INTERPOLATION_EXPR", ResLanguage.INSTANCE);
C_INTERPOLATION_PART = new ORCompositeElementType("C_INTERPOLATION_PART", ResLanguage.INSTANCE);
C_INTERPOLATION_REF = new ORCompositeElementType("C_INTERPOLATION_REF", ResLanguage.INSTANCE);
Expand Down
13 changes: 13 additions & 0 deletions src/test/java/com/reason/lang/rescript/IfParsingTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -176,4 +176,17 @@ public void test_ternary_fun() {
List<RPsiTernary> ts = new ArrayList<>(PsiTreeUtil.findChildrenOfType(e, RPsiTernary.class));
assertEquals("x ? Some(x) : None", ts.get(0).getText());
}

// https://github.com/giraud/reasonml-idea-plugin/issues/424
@Test
public void test_ternary_new_line() {
RPsiLet e = firstOfType(parseCode("""
let fn = x => x
? true
: false
"""), RPsiLet.class);

RPsiTernary t = PsiTreeUtil.findChildOfType(e, RPsiTernary.class);
assertEquals("x\n ? true\n : false", t.getText());
}
}

0 comments on commit c1adcae

Please sign in to comment.