From 7c57789a504f9d31a333a0a48bda4d25f832f755 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Wed, 22 Jun 2022 17:22:37 +0200 Subject: [PATCH 1/7] Parser: recover on missing first item in tuple expression --- src/Compiler/FSComp.txt | 3 ++- src/Compiler/pars.fsy | 5 +++++ src/Compiler/xlf/FSComp.txt.cs.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.de.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.es.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.fr.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.it.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ja.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ko.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.pl.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.pt-BR.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.ru.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.tr.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.zh-Hans.xlf | 5 +++++ src/Compiler/xlf/FSComp.txt.zh-Hant.xlf | 5 +++++ 15 files changed, 72 insertions(+), 1 deletion(-) diff --git a/src/Compiler/FSComp.txt b/src/Compiler/FSComp.txt index 3cad8590d7f..0b3d9b1f093 100644 --- a/src/Compiler/FSComp.txt +++ b/src/Compiler/FSComp.txt @@ -1644,4 +1644,5 @@ reprStateMachineInvalidForm,"The state machine has an unexpected form" 3520,invalidXmlDocPosition,"XML comment is not placed on a valid language element." 3521,tcInvalidMemberDeclNameMissingOrHasParen,"Invalid member declaration. The name of the member is missing or has parentheses." 3522,tcAnonRecdDuplicateFieldId,"The field '%s' appears multiple times in this record expression." -3523,tcAnonRecdTypeDuplicateFieldId,"The field '%s' appears multiple times in this anonymous record type." \ No newline at end of file +3523,tcAnonRecdTypeDuplicateFieldId,"The field '%s' appears multiple times in this anonymous record type." +3524,parsExpectingExpressionInTuple,"Expecting expression" \ No newline at end of file diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 0269b1b64f7..2f5ab8487d0 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4384,6 +4384,11 @@ tupleExpr: | declExpr COMMA declExpr { [$3 ; $1], [rhs parseState 2] } + | COMMA declExpr + { let commaRange = rhs parseState 1 + reportParseErrorAt commaRange (FSComp.SR.parsExpectingExpressionInTuple()) + [$2; arbExpr ("tupleExpr3", commaRange.StartRange)], [commaRange] } + minusExpr: | MINUS minusExpr %prec expr_prefix_plus_minus { mkSynPrefix (rhs parseState 1) (unionRanges (rhs parseState 1) $2.Range) "~-" $2 } diff --git a/src/Compiler/xlf/FSComp.txt.cs.xlf b/src/Compiler/xlf/FSComp.txt.cs.xlf index 95f1966a336..5daa15e1579 100644 --- a/src/Compiler/xlf/FSComp.txt.cs.xlf +++ b/src/Compiler/xlf/FSComp.txt.cs.xlf @@ -517,6 +517,11 @@ Neočekávaný token v definici typu. Za typem {0} se očekává =. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Tento přístup člena je nejednoznačný. Při vytváření objektu použijte závorky, např. (new SomeType(args)).MemberName' diff --git a/src/Compiler/xlf/FSComp.txt.de.xlf b/src/Compiler/xlf/FSComp.txt.de.xlf index e164dba0f05..bf26b598afa 100644 --- a/src/Compiler/xlf/FSComp.txt.de.xlf +++ b/src/Compiler/xlf/FSComp.txt.de.xlf @@ -517,6 +517,11 @@ Unerwartetes Token in Typdefinition. Nach Typ "{0}" wurde "=" erwartet. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Dieser Memberzugriff ist mehrdeutig. Setzen Sie Klammern um die Objekterstellung, z. B. "(new SomeType(args)). MemberName“ diff --git a/src/Compiler/xlf/FSComp.txt.es.xlf b/src/Compiler/xlf/FSComp.txt.es.xlf index ea1ecde3db6..f11ff17b39e 100644 --- a/src/Compiler/xlf/FSComp.txt.es.xlf +++ b/src/Compiler/xlf/FSComp.txt.es.xlf @@ -517,6 +517,11 @@ Token inesperado en la definición de tipo. Se esperaba "=" después del tipo "{0}". + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Este acceso de miembro es ambiguo. Use paréntesis alrededor de la creación del objeto, por ejemplo, '(nuevo AlgúnTipo(args)).NombreMiembro' diff --git a/src/Compiler/xlf/FSComp.txt.fr.xlf b/src/Compiler/xlf/FSComp.txt.fr.xlf index 648ef9169da..73e9906b74c 100644 --- a/src/Compiler/xlf/FSComp.txt.fr.xlf +++ b/src/Compiler/xlf/FSComp.txt.fr.xlf @@ -517,6 +517,11 @@ Jeton inattendu dans la définition de type. Signe '=' attendu après le type '{0}'. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' L’accès à ce membre est ambigu. Utilisez des parenthèses autour de la création de l’objet, par exemple' (New SomeType (args)). MemberName diff --git a/src/Compiler/xlf/FSComp.txt.it.xlf b/src/Compiler/xlf/FSComp.txt.it.xlf index 1a76a536e19..40599faa5e4 100644 --- a/src/Compiler/xlf/FSComp.txt.it.xlf +++ b/src/Compiler/xlf/FSComp.txt.it.xlf @@ -517,6 +517,11 @@ Token imprevisto nella definizione del tipo. Dopo il tipo '{0}' è previsto '='. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' L'accesso ai membri è ambiguo. Utilizzare le parentesi intorno alla creazione oggetto, ad esempio “(New SomeType (args)). MemberName” diff --git a/src/Compiler/xlf/FSComp.txt.ja.xlf b/src/Compiler/xlf/FSComp.txt.ja.xlf index 6da3c202ac1..5da834773d3 100644 --- a/src/Compiler/xlf/FSComp.txt.ja.xlf +++ b/src/Compiler/xlf/FSComp.txt.ja.xlf @@ -517,6 +517,11 @@ 型定義に予期しないトークンがあります。型 '{0}' の後には '=' が必要です。 + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' このメンバーへのアクセスはあいまいです。オブジェクト作成の前後にはかっこを使用してください。例: '(new SomeType(args)).MemberName' diff --git a/src/Compiler/xlf/FSComp.txt.ko.xlf b/src/Compiler/xlf/FSComp.txt.ko.xlf index 72daec99994..85ff4e40d45 100644 --- a/src/Compiler/xlf/FSComp.txt.ko.xlf +++ b/src/Compiler/xlf/FSComp.txt.ko.xlf @@ -517,6 +517,11 @@ 형식 정의에 예기치 않은 토큰이 있습니다. '{0}' 형식 뒤에 '='가 필요합니다. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' 이 구성원 액세스가 모호합니다. 개체 생성 주위에 괄호를 사용하세요. 예: '(새로운 SomeType(인수)).MemberName' diff --git a/src/Compiler/xlf/FSComp.txt.pl.xlf b/src/Compiler/xlf/FSComp.txt.pl.xlf index 386aacfbc99..5185ed19e81 100644 --- a/src/Compiler/xlf/FSComp.txt.pl.xlf +++ b/src/Compiler/xlf/FSComp.txt.pl.xlf @@ -517,6 +517,11 @@ Nieoczekiwany token w definicji typu. Oczekiwano znaku „=” po typie „{0}”. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Dostęp tego elementu członkowskiego jest niejednoznaczny. W celu utworzenia obiektu użyj nawiasów, na przykład „(nowy SomeType(args)).MemberName” diff --git a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf index 3b581e58c9e..1fff3a0b123 100644 --- a/src/Compiler/xlf/FSComp.txt.pt-BR.xlf +++ b/src/Compiler/xlf/FSComp.txt.pt-BR.xlf @@ -517,6 +517,11 @@ Token inesperado na definição de tipo. Esperava-se '=' após o tipo '{0}'. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Este acesso de membro é ambíguo. Use parênteses em torno da criação do objeto, por exemplo, '(new SomeType(args)).MemberName''. diff --git a/src/Compiler/xlf/FSComp.txt.ru.xlf b/src/Compiler/xlf/FSComp.txt.ru.xlf index 3288b85bc5f..029d14dc67b 100644 --- a/src/Compiler/xlf/FSComp.txt.ru.xlf +++ b/src/Compiler/xlf/FSComp.txt.ru.xlf @@ -517,6 +517,11 @@ Неожиданный токен в определении типа. После типа "{0}" ожидается "=". + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Неоднозначный доступ к этому элементу. Заключите операцию создания объекта в круглые скобки, например (new Объект(аргументы)).Элемент diff --git a/src/Compiler/xlf/FSComp.txt.tr.xlf b/src/Compiler/xlf/FSComp.txt.tr.xlf index cc11f361ba5..2e4179f51f7 100644 --- a/src/Compiler/xlf/FSComp.txt.tr.xlf +++ b/src/Compiler/xlf/FSComp.txt.tr.xlf @@ -517,6 +517,11 @@ Tür tanımında beklenmeyen belirteç var. '{0}' türünden sonra '=' bekleniyordu. + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' Bu üye erişimi belirsiz. Lütfen nesne oluşturma etrafında parantez kullanın, örneğin '(yeni SomeType (args)).MemberName’ diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf index 13a2e6d7300..fa70d217b28 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hans.xlf @@ -517,6 +517,11 @@ 类型定义中出现意外标记。类型“{0}”后应为 "="。 + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' 此成员访问权限不明确。请在对象创建周围使用括号,例如 “(new SomeType(args)).MemberName” diff --git a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf index 314dff132d8..b8aea86c7ce 100644 --- a/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf +++ b/src/Compiler/xlf/FSComp.txt.zh-Hant.xlf @@ -517,6 +517,11 @@ 型別定義中出現非預期的權杖。類型 '{0}' 之後應該要有 '='。 + + Expecting expression + Expecting expression + + This member access is ambiguous. Please use parentheses around the object creation, e.g. '(new SomeType(args)).MemberName' 此成員存取不明確。請在物件建立前後加上括弧,例如「(new SomeType(args)).MemberName」 From 2177e8d91f12c03f4b7f05b71deadce189958cad Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 23 Jun 2022 12:20:33 +0200 Subject: [PATCH 2/7] Fix longer tuples, add test --- src/Compiler/SyntaxTree/SyntaxTreeOps.fs | 7 ++ src/Compiler/SyntaxTree/SyntaxTreeOps.fsi | 2 + src/Compiler/pars.fsy | 7 ++ tests/service/Common.fs | 7 ++ tests/service/ParserTests.fs | 86 +++++++++++++++++++++++ 5 files changed, 109 insertions(+) diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 3af3910f0c9..2be88b2c005 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -985,3 +985,10 @@ let mkDynamicArgExpr expr = SynExpr.Const(con, con.Range ident.idRange) | SynExpr.Paren (expr = e) -> e | e -> e + +let rec normalizeTupleExpr exprs commas : SynExpr list * range list = + match exprs with + | SynExpr.Tuple(false, innerExprs, innerCommas, _) :: rest -> + let innerExprs, innerCommas = normalizeTupleExpr (List.rev innerExprs) (List.rev innerCommas) + innerExprs @ rest, innerCommas @ commas + | _ -> exprs, commas diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi index dfff0392bcf..30035546550 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fsi @@ -340,3 +340,5 @@ val (|SynPipeRight3|_|): SynExpr -> (SynExpr * SynExpr * SynExpr * SynExpr) opti val prependIdentInLongIdentWithTrivia: ident: SynIdent -> dotm: range -> lid: SynLongIdent -> SynLongIdent val mkDynamicArgExpr: expr: SynExpr -> SynExpr + +val normalizeTupleExpr: exprs: SynExpr list -> commas: range list -> SynExpr list * range List diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 2f5ab8487d0..8a3ba216c5b 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4028,6 +4028,13 @@ declExpr: | tupleExpr %prec expr_tuple { let exprs, commas = $1 + let exprs, commas = + // Nested non-struct tuple is only possible during error recovery, + // in other situations there are intermediate nodes. + match exprs with + | SynExpr.Tuple(false, _, _, _) :: _ -> normalizeTupleExpr exprs commas + | _ -> exprs, commas + SynExpr.Tuple (false, List.rev exprs, List.rev commas, (commas.Head, exprs) ||> unionRangeWithListBy (fun e -> e.Range) ) } | declExpr JOIN_IN declExpr diff --git a/tests/service/Common.fs b/tests/service/Common.fs index efc7e115084..b683dd9dce1 100644 --- a/tests/service/Common.fs +++ b/tests/service/Common.fs @@ -226,6 +226,11 @@ let getSingleExprInModule (input: ParsedInput) = | SynModuleDecl.Expr (expr, _) -> expr | _ -> failwith "Unexpected expression" +let getSingleParenInnerExpr expr = + match expr with + | SynModuleDecl.Expr(SynExpr.Paren(expr, _, _, _), _) -> expr + | _ -> failwith "Unexpected tree" + let parseSourceCodeAndGetModule (source: string) = parseSourceCode ("test.fsx", source) |> getSingleModuleLikeDecl @@ -449,6 +454,8 @@ let coreLibAssemblyName = "mscorlib" #endif +let getRange (e: SynExpr) = e.Range + let assertRange (expectedStartLine: int, expectedStartColumn: int) (expectedEndLine: int, expectedEndColumn: int) diff --git a/tests/service/ParserTests.fs b/tests/service/ParserTests.fs index bbfb623aef9..b718f738e87 100644 --- a/tests/service/ParserTests.fs +++ b/tests/service/ParserTests.fs @@ -3,6 +3,7 @@ open FSharp.Compiler.Service.Tests.Common open FSharp.Compiler.Syntax open FSharp.Compiler.Text +open FsUnit open NUnit.Framework [] @@ -187,3 +188,88 @@ let f (x, | SynPat.FromParseError (SynPat.Paren (SynPat.FromParseError (SynPat.Wild _, _), _), _) -> () | _ -> failwith "Unexpected tree" | _ -> failwith "Unexpected tree" + +let assertIsBefore (f: _ -> range) (a, b) = + let r1 = f a + let r2 = f b + Position.posGeq r2.Start r1.End |> shouldEqual true + +let checkExprOrder exprs = + exprs + |> List.pairwise + |> List.iter (assertIsBefore getRange) + +let checkRangeCountAndOrder commas = + commas + |> List.iter (fun (commas, length) -> + List.length commas |> shouldEqual length + + commas + |> List.pairwise + |> List.iter (assertIsBefore id)) + +[] +let ``Expr - Tuple 01`` () = + let parseResults = getParseResults """ +(,) +(,,) +""" + let exprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr + match exprs with + | [ SynExpr.ArbitraryAfterError _ + SynExpr.ArbitraryAfterError _ ] -> () + + | _ -> failwith "Unexpected tree" + +[] +let ``Expr - Tuple 02`` () = + let parseResults = getParseResults """ +(1,) +(,1) +(1,1) +""" + let exprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr + match exprs with + | [ SynExpr.Tuple(_, [SynExpr.Const _ as e11; SynExpr.ArbitraryAfterError _ as e12], c1, _) + SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e21; SynExpr.Const _ as e22], c2, _) + SynExpr.Tuple(_, [SynExpr.Const _ as e31; SynExpr.Const _ as e32], c3, _) ] -> + [ e11; e12; e21; e22; e31; e32 ] |> checkExprOrder + [ c1, 1; c2, 1; c3, 1 ] |> checkRangeCountAndOrder + + | _ -> failwith "Unexpected tree" + +[] +let ``Expr - Tuple 03`` () = + let parseResults = getParseResults """ +(1,,) // two items are produced +(,1,) +(,,1) + +(1,1,) +(,1,1) +(1,,1) + +(1,1,1) +""" + let exprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr + match exprs with + | [ SynExpr.Tuple(_, [SynExpr.Const _ as e11; SynExpr.ArbitraryAfterError _ as e12], c1, _) + SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e21; SynExpr.Const _ as e22; SynExpr.ArbitraryAfterError _ as e23], c2, _) + SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e31; SynExpr.ArbitraryAfterError _ as e32; SynExpr.Const _ as e33], c3, _) + + SynExpr.Tuple(_, [SynExpr.Const _ as e41; SynExpr.Const _ as e42; SynExpr.ArbitraryAfterError _ as e43], c4, _) + SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e51; SynExpr.Const _ as e52; SynExpr.Const _ as e53], c5, _) + SynExpr.Tuple(_, [SynExpr.Const _ as e61; SynExpr.ArbitraryAfterError _ as e62; SynExpr.Const _ as e63], c6, _) + + SynExpr.Tuple(_, [SynExpr.Const _ as e71; SynExpr.Const _ as e72; SynExpr.Const _ as e73], c7, _) ] -> + [ e11; e12; e21; e22; e23; e31; e32; e33 + e41; e42; e43; e51; e52; e53; e61; e62; e63 + e71; e72; e73 ] + |> checkExprOrder + + [ c1, 1; c2, 2; c3, 2 + c4, 2; c5, 2; c6, 2 + c7, 2 ] + |> checkRangeCountAndOrder + + | _ -> failwith "Unexpected tree" From 16d7d58f8055c6f83ac4d959db3dd04e1edc2661 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 23 Jun 2022 13:00:15 +0200 Subject: [PATCH 3/7] Add another test --- tests/service/ParserTests.fs | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/service/ParserTests.fs b/tests/service/ParserTests.fs index b718f738e87..5fae9ad4f84 100644 --- a/tests/service/ParserTests.fs +++ b/tests/service/ParserTests.fs @@ -273,3 +273,26 @@ let ``Expr - Tuple 03`` () = |> checkRangeCountAndOrder | _ -> failwith "Unexpected tree" + + +[] +let ``Expr - Tuple 04`` () = + let parseResults = getParseResults """ +(,1,,2,3,,4,) +""" + let exprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr + match exprs with + | [ SynExpr.Tuple(_, [ SynExpr.ArbitraryAfterError _ as e1 + SynExpr.Const _ as e2 + SynExpr.ArbitraryAfterError _ as e3 + SynExpr.Const _ as e4 + SynExpr.Const _ as e5 + SynExpr.ArbitraryAfterError _ as e6 + SynExpr.Const _ as e7 + SynExpr.ArbitraryAfterError _ as e8 ], c, _) ] -> + [ e1; e2; e3; e4; e5; e6; e7; e8 ] + |> checkExprOrder + + [ c, 7 ] |> checkRangeCountAndOrder + + | _ -> failwith "Unexpected tree" \ No newline at end of file From 8b25d3f9f0e8b3096e69708edbe03a7390e32557 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 23 Jun 2022 13:30:10 +0200 Subject: [PATCH 4/7] Fix perfect formatting * add an extra line break in a line that has less than 120 chars * add an extra space after an capitalized pattern --- src/Compiler/SyntaxTree/SyntaxTreeOps.fs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs index 2be88b2c005..af767c5ac6d 100644 --- a/src/Compiler/SyntaxTree/SyntaxTreeOps.fs +++ b/src/Compiler/SyntaxTree/SyntaxTreeOps.fs @@ -988,7 +988,9 @@ let mkDynamicArgExpr expr = let rec normalizeTupleExpr exprs commas : SynExpr list * range list = match exprs with - | SynExpr.Tuple(false, innerExprs, innerCommas, _) :: rest -> - let innerExprs, innerCommas = normalizeTupleExpr (List.rev innerExprs) (List.rev innerCommas) + | SynExpr.Tuple (false, innerExprs, innerCommas, _) :: rest -> + let innerExprs, innerCommas = + normalizeTupleExpr (List.rev innerExprs) (List.rev innerCommas) + innerExprs @ rest, innerCommas @ commas | _ -> exprs, commas From b7122c69b49ea73fefc3616c7f86e53778c5314e Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Thu, 23 Jun 2022 13:34:07 +0200 Subject: [PATCH 5/7] Add another test --- tests/service/ParserTests.fs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/service/ParserTests.fs b/tests/service/ParserTests.fs index 5fae9ad4f84..c03b9dcaa84 100644 --- a/tests/service/ParserTests.fs +++ b/tests/service/ParserTests.fs @@ -295,4 +295,13 @@ let ``Expr - Tuple 04`` () = [ c, 7 ] |> checkRangeCountAndOrder - | _ -> failwith "Unexpected tree" \ No newline at end of file + | _ -> failwith "Unexpected tree" + +[] +let ``Expr - Tuple 05`` () = + let parseResults = getParseResults """ +(1, +""" + match getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr with + | [ SynExpr.FromParseError(SynExpr.Tuple(_, [SynExpr.Const _; SynExpr.ArbitraryAfterError _], _, _), _) ] -> () + | _ -> failwith "Unexpected tree" From 5650f086264fef08cc72f1be8905aaaba9fdfc37 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Fri, 24 Jun 2022 17:03:02 +0200 Subject: [PATCH 6/7] Another test --- tests/service/ParserTests.fs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/tests/service/ParserTests.fs b/tests/service/ParserTests.fs index c03b9dcaa84..3a6abd4eb72 100644 --- a/tests/service/ParserTests.fs +++ b/tests/service/ParserTests.fs @@ -305,3 +305,16 @@ let ``Expr - Tuple 05`` () = match getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr with | [ SynExpr.FromParseError(SynExpr.Tuple(_, [SynExpr.Const _; SynExpr.ArbitraryAfterError _], _, _), _) ] -> () | _ -> failwith "Unexpected tree" + +[] +let ``Expr - Tuple 06`` () = + let parseResults = getParseResults """ +(1,,,2) +""" + let synExprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr + match synExprs with + | [ SynExpr.Tuple(_, [ SynExpr.Const _ + SynExpr.ArbitraryAfterError _ + SynExpr.ArbitraryAfterError _ + SynExpr.Const _ ], _, _) ] -> () + | _ -> failwith "Unexpected tree" \ No newline at end of file From dab9fb309591348909f4b1fa37470a87a1351476 Mon Sep 17 00:00:00 2001 From: Eugene Auduchinok Date: Fri, 24 Jun 2022 23:31:19 +0200 Subject: [PATCH 7/7] Recover on missing last item --- src/Compiler/pars.fsy | 6 ++++++ tests/service/ParserTests.fs | 18 +++++++++++------- 2 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/Compiler/pars.fsy b/src/Compiler/pars.fsy index 8a3ba216c5b..8db997e9a0b 100644 --- a/src/Compiler/pars.fsy +++ b/src/Compiler/pars.fsy @@ -4396,6 +4396,12 @@ tupleExpr: reportParseErrorAt commaRange (FSComp.SR.parsExpectingExpressionInTuple()) [$2; arbExpr ("tupleExpr3", commaRange.StartRange)], [commaRange] } + | COMMA ends_coming_soon_or_recover + { if not $2 then reportParseErrorAt (rhs parseState 2) (FSComp.SR.parsExpectedExpressionAfterToken()) + let commaRange = rhs parseState 1 + let zeroWidthAtNextToken = (rhs parseState 2).StartRange + [(arbExpr("tupleExpr4", zeroWidthAtNextToken)); arbExpr ("tupleExpr5", commaRange.StartRange)], [commaRange] } + minusExpr: | MINUS minusExpr %prec expr_prefix_plus_minus { mkSynPrefix (rhs parseState 1) (unionRanges (rhs parseState 1) $2.Range) "~-" $2 } diff --git a/tests/service/ParserTests.fs b/tests/service/ParserTests.fs index 3a6abd4eb72..f493fc76816 100644 --- a/tests/service/ParserTests.fs +++ b/tests/service/ParserTests.fs @@ -213,11 +213,15 @@ let ``Expr - Tuple 01`` () = let parseResults = getParseResults """ (,) (,,) +(,,,) """ let exprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr match exprs with - | [ SynExpr.ArbitraryAfterError _ - SynExpr.ArbitraryAfterError _ ] -> () + | [ SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e11; SynExpr.ArbitraryAfterError _ as e12], c1, _) + SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e21; SynExpr.ArbitraryAfterError _ as e22; SynExpr.ArbitraryAfterError _ as e23], c2, _) + SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e31; SynExpr.ArbitraryAfterError _ as e32; SynExpr.ArbitraryAfterError _ as e33; SynExpr.ArbitraryAfterError _ as e34], c3, _) ] -> + [ e11; e12; e21; e22; e23; e31; e32; e33; e34 ] |> checkExprOrder + [ c1, 1; c2, 2; c3, 3 ] |> checkRangeCountAndOrder | _ -> failwith "Unexpected tree" @@ -241,7 +245,7 @@ let ``Expr - Tuple 02`` () = [] let ``Expr - Tuple 03`` () = let parseResults = getParseResults """ -(1,,) // two items are produced +(1,,) (,1,) (,,1) @@ -253,7 +257,7 @@ let ``Expr - Tuple 03`` () = """ let exprs = getSingleModuleMemberDecls parseResults |> List.map getSingleParenInnerExpr match exprs with - | [ SynExpr.Tuple(_, [SynExpr.Const _ as e11; SynExpr.ArbitraryAfterError _ as e12], c1, _) + | [ SynExpr.Tuple(_, [SynExpr.Const _ as e11; SynExpr.ArbitraryAfterError _ as e12; SynExpr.ArbitraryAfterError _ as e13], c1, _) SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e21; SynExpr.Const _ as e22; SynExpr.ArbitraryAfterError _ as e23], c2, _) SynExpr.Tuple(_, [SynExpr.ArbitraryAfterError _ as e31; SynExpr.ArbitraryAfterError _ as e32; SynExpr.Const _ as e33], c3, _) @@ -262,12 +266,12 @@ let ``Expr - Tuple 03`` () = SynExpr.Tuple(_, [SynExpr.Const _ as e61; SynExpr.ArbitraryAfterError _ as e62; SynExpr.Const _ as e63], c6, _) SynExpr.Tuple(_, [SynExpr.Const _ as e71; SynExpr.Const _ as e72; SynExpr.Const _ as e73], c7, _) ] -> - [ e11; e12; e21; e22; e23; e31; e32; e33 + [ e11; e12; e13; e21; e22; e23; e31; e32; e33 e41; e42; e43; e51; e52; e53; e61; e62; e63 e71; e72; e73 ] |> checkExprOrder - [ c1, 1; c2, 2; c3, 2 + [ c1, 2; c2, 2; c3, 2 c4, 2; c5, 2; c6, 2 c7, 2 ] |> checkRangeCountAndOrder @@ -317,4 +321,4 @@ let ``Expr - Tuple 06`` () = SynExpr.ArbitraryAfterError _ SynExpr.ArbitraryAfterError _ SynExpr.Const _ ], _, _) ] -> () - | _ -> failwith "Unexpected tree" \ No newline at end of file + | _ -> failwith "Unexpected tree"