| 1992 | } |
| 1993 | |
| 1994 | Result<FieldRef> FieldRef::FromDotPath(const std::string& dot_path_arg) { |
| 1995 | if (dot_path_arg.empty()) { |
| 1996 | return FieldRef(); |
| 1997 | } |
| 1998 | |
| 1999 | std::vector<FieldRef> children; |
| 2000 | |
| 2001 | std::string_view dot_path = dot_path_arg; |
| 2002 | |
| 2003 | auto parse_name = [&] { |
| 2004 | std::string name; |
| 2005 | for (;;) { |
| 2006 | auto segment_end = dot_path.find_first_of("\\[."); |
| 2007 | if (segment_end == std::string_view::npos) { |
| 2008 | // dot_path doesn't contain any other special characters; consume all |
| 2009 | name.append(dot_path.data(), dot_path.length()); |
| 2010 | dot_path = ""; |
| 2011 | break; |
| 2012 | } |
| 2013 | |
| 2014 | if (dot_path[segment_end] != '\\') { |
| 2015 | // segment_end points to a subscript for a new FieldRef |
| 2016 | name.append(dot_path.data(), segment_end); |
| 2017 | dot_path = dot_path.substr(segment_end); |
| 2018 | break; |
| 2019 | } |
| 2020 | |
| 2021 | if (dot_path.size() == segment_end + 1) { |
| 2022 | // dot_path ends with backslash; consume it all |
| 2023 | name.append(dot_path.data(), dot_path.length()); |
| 2024 | dot_path = ""; |
| 2025 | break; |
| 2026 | } |
| 2027 | |
| 2028 | // append all characters before backslash, then the character which follows it |
| 2029 | name.append(dot_path.data(), segment_end); |
| 2030 | name.push_back(dot_path[segment_end + 1]); |
| 2031 | dot_path = dot_path.substr(segment_end + 2); |
| 2032 | } |
| 2033 | return name; |
| 2034 | }; |
| 2035 | |
| 2036 | while (!dot_path.empty()) { |
| 2037 | auto subscript = dot_path[0]; |
| 2038 | dot_path = dot_path.substr(1); |
| 2039 | switch (subscript) { |
| 2040 | case '.': { |
| 2041 | // next element is a name |
| 2042 | children.emplace_back(parse_name()); |
| 2043 | continue; |
| 2044 | } |
| 2045 | case '[': { |
| 2046 | auto subscript_end = dot_path.find_first_not_of("0123456789"); |
| 2047 | if (subscript_end == std::string_view::npos || dot_path[subscript_end] != ']') { |
| 2048 | return Status::Invalid("Dot path '", dot_path_arg, |
| 2049 | "' contained an unterminated index"); |
| 2050 | } |
| 2051 | children.emplace_back(std::atoi(dot_path.data())); |