diff --git a/src/main/java/com/reason/lang/core/psi/impl/ORASTFactory.java b/src/main/java/com/reason/lang/core/psi/impl/ORASTFactory.java index fd25fc260..5c76d1e82 100644 --- a/src/main/java/com/reason/lang/core/psi/impl/ORASTFactory.java +++ b/src/main/java/com/reason/lang/core/psi/impl/ORASTFactory.java @@ -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) { diff --git a/src/main/java/com/reason/lang/core/psi/impl/RPsiIfStatement.java b/src/main/java/com/reason/lang/core/psi/impl/RPsiIfStatement.java index ec911c3f9..2647b23bc 100644 --- a/src/main/java/com/reason/lang/core/psi/impl/RPsiIfStatement.java +++ b/src/main/java/com/reason/lang/core/psi/impl/RPsiIfStatement.java @@ -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); } } diff --git a/src/main/java/com/reason/lang/core/type/ORLangTypes.java b/src/main/java/com/reason/lang/core/type/ORLangTypes.java index e12f2d8e1..f4e73d337 100644 --- a/src/main/java/com/reason/lang/core/type/ORLangTypes.java +++ b/src/main/java/com/reason/lang/core/type/ORLangTypes.java @@ -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; diff --git a/src/main/java/com/reason/lang/ocaml/OclParser.java b/src/main/java/com/reason/lang/ocaml/OclParser.java index 73d7be35a..7e98b2d90 100644 --- a/src/main/java/com/reason/lang/ocaml/OclParser.java +++ b/src/main/java/com/reason/lang/ocaml/OclParser.java @@ -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() { @@ -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(); @@ -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); } } diff --git a/src/main/java/com/reason/lang/ocaml/OclTypes.java b/src/main/java/com/reason/lang/ocaml/OclTypes.java index 5d2de5714..b32a63e3d 100644 --- a/src/main/java/com/reason/lang/ocaml/OclTypes.java +++ b/src/main/java/com/reason/lang/ocaml/OclTypes.java @@ -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); diff --git a/src/main/java/com/reason/lang/reason/RmlParser.java b/src/main/java/com/reason/lang/reason/RmlParser.java index ccd4f0138..d26224f18 100644 --- a/src/main/java/com/reason/lang/reason/RmlParser.java +++ b/src/main/java/com/reason/lang/reason/RmlParser.java @@ -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(); @@ -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); } } @@ -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() { @@ -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); } } @@ -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); @@ -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(); diff --git a/src/main/java/com/reason/lang/reason/RmlTypes.java b/src/main/java/com/reason/lang/reason/RmlTypes.java index bf058c4e7..8d5393924 100644 --- a/src/main/java/com/reason/lang/reason/RmlTypes.java +++ b/src/main/java/com/reason/lang/reason/RmlTypes.java @@ -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); diff --git a/src/main/java/com/reason/lang/rescript/ResParser.java b/src/main/java/com/reason/lang/rescript/ResParser.java index abd7ec7d9..326b6ab4a 100644 --- a/src/main/java/com/reason/lang/rescript/ResParser.java +++ b/src/main/java/com/reason/lang/rescript/ResParser.java @@ -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(); } } @@ -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() { @@ -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(); @@ -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); } } @@ -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 |> :<| ... @@ -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); } } @@ -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); @@ -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); @@ -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)) { @@ -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) @@ -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(); + } + } } } } diff --git a/src/main/java/com/reason/lang/rescript/ResTypes.java b/src/main/java/com/reason/lang/rescript/ResTypes.java index 8f3ac2081..76335bcd4 100644 --- a/src/main/java/com/reason/lang/rescript/ResTypes.java +++ b/src/main/java/com/reason/lang/rescript/ResTypes.java @@ -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); diff --git a/src/test/java/com/reason/lang/rescript/IfParsingTest.java b/src/test/java/com/reason/lang/rescript/IfParsingTest.java index abab8585f..28b3ff487 100644 --- a/src/test/java/com/reason/lang/rescript/IfParsingTest.java +++ b/src/test/java/com/reason/lang/rescript/IfParsingTest.java @@ -176,4 +176,17 @@ public void test_ternary_fun() { List 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()); + } }