From 7d0687dd40b6c8dc1a1ff27fc18e8d28585f3dcf Mon Sep 17 00:00:00 2001 From: Jens Johansen Date: Wed, 9 Jun 2021 10:07:31 +0000 Subject: [PATCH] [CFE] Fix parsing generics with generics in binary.md Change-Id: Ia09730f08b28e715b4c536c35a53c93bc4dbf8b5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/202922 Reviewed-by: Dmitry Stefantsov Commit-Queue: Jens Johansen --- pkg/front_end/test/binary_md_dill_reader.dart | 121 +++++++++++++++--- 1 file changed, 103 insertions(+), 18 deletions(-) diff --git a/pkg/front_end/test/binary_md_dill_reader.dart b/pkg/front_end/test/binary_md_dill_reader.dart index d9a3d0e3a11..7894e3c0b86 100644 --- a/pkg/front_end/test/binary_md_dill_reader.dart +++ b/pkg/front_end/test/binary_md_dill_reader.dart @@ -6,6 +6,74 @@ import "dart:math" as math; +main() { + List test = BinaryMdDillReader._getGenerics("Pair"); + if (test.length != 2 || test[0] != "A" || test[1] != "B") { + throw "Expected [A, B] got $test"; + } + + test = BinaryMdDillReader._getGenerics("List"); + if (test.length != 1 || test[0] != "Expression") { + throw "Expected [Expression] got $test"; + } + + test = BinaryMdDillReader._getGenerics("List>"); + if (test.length != 1 || test[0] != "Pair") { + throw "Expected [Pair] got $test"; + } + + test = BinaryMdDillReader._getGenerics("RList>"); + if (test.length != 1 || test[0] != "Pair") { + throw "Expected [Pair] got $test"; + } + + test = + BinaryMdDillReader._getGenerics("List>"); + if (test.length != 1 || test[0] != "Pair") { + throw "Expected [Pair] got $test"; + } + + test = BinaryMdDillReader._getGenerics( + "List>"); + if (test.length != 1 || + test[0] != "Pair") { + throw "Expected [Pair] got $test"; + } + + test = BinaryMdDillReader._getGenerics( + "List>"); + if (test.length != 1 || + test[0] != "Pair") { + throw "Expected [Pair] got $test"; + } + + test = BinaryMdDillReader._getGenerics("Option>"); + if (test.length != 1 || test[0] != "List") { + throw "Expected [List] got $test"; + } + + test = BinaryMdDillReader._getGenerics("Foo>"); + if (test.length != 1 || test[0] != "Bar") { + throw "Expected [Bar] got $test"; + } + + test = BinaryMdDillReader._getGenerics("Foo, E>"); + if (test.length != 3 || + test[0] != "A" || + test[1] != "B" || + test[2] != "E") { + throw "Expected [A, B, E] got $test"; + } + + test = BinaryMdDillReader._getGenerics("Foo>>>, H>"); + if (test.length != 3 || + test[0] != "A" || + test[1] != "B>>>" || + test[2] != "H") { + throw "Expected [A, B>>>, H] got $test"; + } +} + class BinaryMdDillReader { final String _binaryMdContent; @@ -236,33 +304,50 @@ class BinaryMdDillReader { return result; } + static const int $COMMA = 44; + static const int $LT = 60; + static const int $GT = 62; + /// Extract the generics used in an input type, e.g. turns /// - /// * "Pair" into ["A", "B"] - /// * "List" into ["Expression"] + /// * "Pair" into ["A", "B"]. + /// * "List" into ["Expression"]. + /// * "Foo>" into ["Bar"]. + /// * "Foo, E>" into ["A", "B", "E"]. /// /// Note that the input string *has* to use generics, i.e. have '<' and '>' /// in it. - /// Also note that nested generics isn't really supported - /// (e.g. Foo>). - List _getGenerics(String s) { + static List _getGenerics(String s) { s = s.substring(s.indexOf("<") + 1, s.lastIndexOf(">")); - if (s.contains("<")) { - if (s == "Pair") { - return ["Pair"]; - } else if (s == "Pair") { - return ["Pair"]; - } else if (s == "Pair") { - return ["Pair"]; - } else if (s == "Pair") { - return ["Pair"]; - } else if (s == "Pair") { - return ["Pair"]; + // Check that any '<' and '>' are balanced and split entries on comma for + // the outermost parameters. + int ltCount = 0; + int gtCount = 0; + int depth = 0; + int lastPos = 0; + + List codeUnits = s.codeUnits; + List result = []; + for (int i = 0; i < codeUnits.length; i++) { + int codeUnit = codeUnits[i]; + if (codeUnit == $LT) { + ltCount++; + depth++; + } else if (codeUnit == $GT) { + gtCount++; + depth--; + } else if (codeUnit == $COMMA && depth == 0) { + result.add(s.substring(lastPos, i).trim()); + lastPos = i + 1; } - throw "Doesn't supported nested generics (input: $s)."; } - return s.split(",").map((untrimmed) => untrimmed.trim()).toList(); + if (ltCount != gtCount) { + throw "Unbalanced '<' and '>': $s"; + } + assert(depth == 0); + result.add(s.substring(lastPos, codeUnits.length).trim()); + return result; } /// Parses a line of binary.md content for a "current class" into the