| /* General AST-related method implementations for Rust frontend. |
| Copyright (C) 2009-2023 Free Software Foundation, Inc. |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it under |
| the terms of the GNU General Public License as published by the Free |
| Software Foundation; either version 3, or (at your option) any later |
| version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT ANY |
| WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "rust-system.h" |
| #include "rust-ast-full.h" |
| #include "rust-diagnostics.h" |
| #include "rust-ast-visitor.h" |
| #include "rust-macro.h" |
| #include "rust-session-manager.h" |
| #include "rust-lex.h" |
| #include "rust-parse.h" |
| #include "rust-operators.h" |
| |
| /* Compilation unit used for various AST-related functions that would make |
| * the headers too long if they were defined inline and don't receive any |
| * benefits from being defined inline because they are virtual. Also used |
| * for various other stuff. */ |
| |
| namespace Rust { |
| namespace AST { |
| |
| enum indent_mode |
| { |
| enter, |
| out, |
| stay |
| }; |
| |
| std::string |
| indent_spaces (enum indent_mode mode) |
| { |
| static int indent = 0; |
| std::string str = ""; |
| if (out == mode) |
| indent--; |
| for (int i = 0; i < indent; i++) |
| str += " "; |
| if (enter == mode) |
| indent++; |
| |
| return str; |
| } |
| |
| // Gets a string in a certain delim type. |
| std::string |
| get_string_in_delims (std::string str_input, DelimType delim_type) |
| { |
| switch (delim_type) |
| { |
| case PARENS: |
| return "(" + str_input + ")"; |
| case SQUARE: |
| return "[" + str_input + "]"; |
| case CURLY: |
| return "{" + str_input + "}"; |
| default: |
| return "ERROR-MARK-STRING (delims)"; |
| } |
| gcc_unreachable (); |
| } |
| |
| enum AttrMode |
| { |
| OUTER, |
| INNER |
| }; |
| |
| std::string |
| get_mode_dump_desc (AttrMode mode) |
| { |
| switch (mode) |
| { |
| case OUTER: |
| return "outer attributes"; |
| case INNER: |
| return "inner attributes"; |
| default: |
| gcc_unreachable (); |
| return ""; |
| } |
| } |
| |
| // Adds lines below adding attributes |
| std::string |
| append_attributes (std::vector<Attribute> attrs, AttrMode mode) |
| { |
| indent_spaces (enter); |
| |
| std::string str |
| = "\n" + indent_spaces (stay) + get_mode_dump_desc (mode) + ": "; |
| // str += "\n" + indent_spaces (stay) + "inner attributes: "; |
| if (attrs.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| /* note that this does not print them with outer or "inner attribute" |
| * syntax - just prints the body */ |
| for (const auto &attr : attrs) |
| str += "\n" + indent_spaces (stay) + attr.as_string (); |
| } |
| |
| indent_spaces (out); |
| |
| return str; |
| } |
| |
| // Removes the beginning and end quotes of a quoted string. |
| std::string |
| unquote_string (std::string input) |
| { |
| rust_assert (input.front () == '"'); |
| rust_assert (input.back () == '"'); |
| return input.substr (1, input.length () - 2); |
| } |
| |
| std::string |
| Crate::as_string () const |
| { |
| rust_debug ("beginning crate recursive as-string"); |
| |
| std::string str ("Crate: "); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| // items |
| str += "\n items: "; |
| if (items.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : items) |
| { |
| // DEBUG: null pointer check |
| if (item == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - " |
| "null pointer item in crate."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + item->as_string (); |
| } |
| } |
| |
| return str + "\n"; |
| } |
| |
| std::string |
| Attribute::as_string () const |
| { |
| std::string path_str = path.as_string (); |
| if (attr_input == nullptr) |
| return path_str; |
| else |
| return path_str + attr_input->as_string (); |
| } |
| |
| // Copy constructor must deep copy attr_input as unique pointer |
| Attribute::Attribute (Attribute const &other) |
| : path (other.path), locus (other.locus) |
| { |
| // guard to protect from null pointer dereference |
| if (other.attr_input != nullptr) |
| attr_input = other.attr_input->clone_attr_input (); |
| } |
| |
| // overload assignment operator to use custom clone method |
| Attribute & |
| Attribute::operator= (Attribute const &other) |
| { |
| path = other.path; |
| locus = other.locus; |
| // guard to protect from null pointer dereference |
| if (other.attr_input != nullptr) |
| attr_input = other.attr_input->clone_attr_input (); |
| else |
| attr_input = nullptr; |
| |
| return *this; |
| } |
| |
| std::string |
| DelimTokenTree::as_string () const |
| { |
| std::string start_delim; |
| std::string end_delim; |
| switch (delim_type) |
| { |
| case PARENS: |
| start_delim = "("; |
| end_delim = ")"; |
| break; |
| case SQUARE: |
| start_delim = "["; |
| end_delim = "]"; |
| break; |
| case CURLY: |
| start_delim = "{"; |
| end_delim = "}"; |
| break; |
| default: |
| rust_debug ("Invalid delimiter type, " |
| "Should be PARENS, SQUARE, or CURLY."); |
| return "Invalid delimiter type"; |
| } |
| std::string str = start_delim; |
| if (!token_trees.empty ()) |
| { |
| for (const auto &tree : token_trees) |
| { |
| // DEBUG: null pointer check |
| if (tree == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "token tree in delim token tree."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += tree->as_string (); |
| } |
| } |
| str += end_delim; |
| |
| return str; |
| } |
| |
| std::string |
| Token::as_string () const |
| { |
| if (tok_ref->has_str ()) |
| { |
| std::string str = tok_ref->get_str (); |
| |
| std::string quote = is_string_lit () ? "\"" : ""; |
| return quote + str + quote; |
| } |
| else |
| { |
| return tok_ref->get_token_description (); |
| } |
| } |
| |
| std::string |
| SimplePathSegment::as_string () const |
| { |
| return segment_name; |
| } |
| |
| std::string |
| SimplePath::as_string () const |
| { |
| std::string path; |
| if (has_opening_scope_resolution) |
| path = "::"; |
| |
| // crappy hack because doing proper for loop would be more code |
| bool first_time = true; |
| for (const auto &segment : segments) |
| { |
| if (first_time) |
| { |
| path += segment.as_string (); |
| first_time = false; |
| } |
| else |
| { |
| path += "::" + segment.as_string (); |
| } |
| |
| // DEBUG: remove later. Checks for path error. |
| if (segment.is_error ()) |
| { |
| rust_debug ("segment in path is error - this should've been filtered " |
| "out. first segment " |
| "was '%s'", |
| segments.at (0).as_string ().c_str ()); |
| } |
| } |
| |
| return path; |
| } |
| |
| std::string |
| Visibility::as_string () const |
| { |
| switch (vis_type) |
| { |
| case PRIV: |
| return std::string (""); |
| case PUB: |
| return std::string ("pub"); |
| case PUB_CRATE: |
| return std::string ("pub(crate)"); |
| case PUB_SELF: |
| return std::string ("pub(self)"); |
| case PUB_SUPER: |
| return std::string ("pub(super)"); |
| case PUB_IN_PATH: |
| return std::string ("pub(in ") + in_path.as_string () + std::string (")"); |
| default: |
| gcc_unreachable (); |
| } |
| } |
| |
| // Creates a string that reflects the visibility stored. |
| std::string |
| VisItem::as_string () const |
| { |
| // FIXME: can't do formatting on string to make identation occur. |
| std::string str; |
| |
| if (!outer_attrs.empty ()) |
| { |
| for (const auto &attr : outer_attrs) |
| str += attr.as_string () + "\n"; |
| } |
| |
| if (has_visibility ()) |
| str += visibility.as_string () + " "; |
| |
| return str; |
| } |
| |
| std::string |
| Module::as_string () const |
| { |
| std::string str = VisItem::as_string () + "mod " + module_name; |
| |
| // Return early if we're dealing with an unloaded module as their body resides |
| // in a different file |
| if (kind == ModuleKind::UNLOADED) |
| return str + "\n no body (reference to external file)\n"; |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| // items |
| str += "\n items: "; |
| |
| // This can still happen if the module is loaded but empty, i.e. `mod foo {}` |
| if (items.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : items) |
| { |
| // DEBUG: null pointer check |
| if (item == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - " |
| "null pointer item in crate."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + item->as_string (); |
| } |
| } |
| |
| return str + "\n"; |
| } |
| |
| std::string |
| StaticItem::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += indent_spaces (stay) + "static"; |
| |
| if (has_mut) |
| str += " mut"; |
| |
| str += " " + name; |
| |
| // DEBUG: null pointer check |
| if (type == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - null " |
| "pointer type in static item."); |
| return "NULL_POINTER_MARK"; |
| } |
| str += "\n" + indent_spaces (stay) + "Type: " + type->as_string (); |
| |
| // DEBUG: null pointer check |
| if (expr == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - null " |
| "pointer expr in static item."); |
| return "NULL_POINTER_MARK"; |
| } |
| str += "\n" + indent_spaces (stay) + "Expression: " + expr->as_string (); |
| |
| return str + "\n"; |
| } |
| |
| std::string |
| ExternCrate::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "extern crate " + referenced_crate; |
| |
| if (has_as_clause ()) |
| str += " as " + as_clause_name; |
| |
| return str; |
| } |
| |
| std::string |
| TupleStruct::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "struct " + struct_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in enum."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| // tuple fields |
| str += "\n Tuple fields: "; |
| if (fields.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &field : fields) |
| str += "\n " + field.as_string (); |
| } |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| return str; |
| } |
| |
| std::string |
| ConstantItem::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "const " + identifier; |
| |
| // DEBUG: null pointer check |
| if (type == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - null " |
| "pointer type in const item."); |
| return "NULL_POINTER_MARK"; |
| } |
| str += "\n Type: " + type->as_string (); |
| |
| // DEBUG: null pointer check |
| if (const_expr == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - null " |
| "pointer expr in const item."); |
| return "NULL_POINTER_MARK"; |
| } |
| str += "\n Expression: " + const_expr->as_string (); |
| |
| return str + "\n"; |
| } |
| |
| std::string |
| InherentImpl::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "impl "; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in inherent impl."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Type: " + trait_type->as_string (); |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| // inherent impl items |
| str += "\n Inherent impl items: "; |
| if (!has_impl_items ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : impl_items) |
| str += "\n " + item->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| Method::as_string () const |
| { |
| std::string str ("Method: \n "); |
| |
| str += vis.as_string () + " " + qualifiers.as_string (); |
| |
| str += " fn " + method_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in method."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Self param: " + self_param.as_string (); |
| |
| str += "\n Function params: "; |
| if (function_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : function_params) |
| str += "\n " + param.as_string (); |
| } |
| |
| str += "\n Return type: "; |
| if (has_return_type ()) |
| str += return_type->as_string (); |
| else |
| str += "none (void)"; |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| str += "\n Block expr (body): \n "; |
| str += function_body->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| StructStruct::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "struct " + struct_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in enum."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| // struct fields |
| str += "\n Struct fields: "; |
| if (is_unit) |
| { |
| str += "none (unit)"; |
| } |
| else if (fields.empty ()) |
| { |
| str += "none (non-unit)"; |
| } |
| else |
| { |
| for (const auto &field : fields) |
| str += "\n " + field.as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| UseDeclaration::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| // DEBUG: null pointer check |
| if (use_tree == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer use tree in " |
| "use declaration."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "use " + use_tree->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| UseTreeGlob::as_string () const |
| { |
| switch (glob_type) |
| { |
| case NO_PATH: |
| return "*"; |
| case GLOBAL: |
| return "::*"; |
| case PATH_PREFIXED: { |
| std::string path_str = path.as_string (); |
| return path_str + "::*"; |
| } |
| default: |
| // some kind of error |
| return "ERROR-PATH"; |
| } |
| gcc_unreachable (); |
| } |
| |
| std::string |
| UseTreeList::as_string () const |
| { |
| std::string path_str; |
| switch (path_type) |
| { |
| case NO_PATH: |
| path_str = "{"; |
| break; |
| case GLOBAL: |
| path_str = "::{"; |
| break; |
| case PATH_PREFIXED: { |
| path_str = path.as_string () + "::{"; |
| break; |
| } |
| default: |
| // some kind of error |
| return "ERROR-PATH-LIST"; |
| } |
| |
| if (has_trees ()) |
| { |
| auto i = trees.begin (); |
| auto e = trees.end (); |
| |
| // DEBUG: null pointer check |
| if (*i == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - null pointer " |
| "tree in use tree list."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| for (; i != e; i++) |
| { |
| path_str += (*i)->as_string (); |
| if (e != i + 1) |
| path_str += ", "; |
| } |
| } |
| else |
| { |
| path_str += "none"; |
| } |
| |
| return path_str + "}"; |
| } |
| |
| std::string |
| UseTreeRebind::as_string () const |
| { |
| std::string path_str = path.as_string (); |
| |
| switch (bind_type) |
| { |
| case NONE: |
| // nothing to add, just path |
| break; |
| case IDENTIFIER: |
| path_str += " as " + identifier; |
| break; |
| case WILDCARD: |
| path_str += " as _"; |
| break; |
| default: |
| // error |
| return "ERROR-PATH-REBIND"; |
| } |
| |
| return path_str; |
| } |
| |
| std::string |
| Enum::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| str += enum_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in enum."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| // items |
| str += "\n Items: "; |
| if (items.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : items) |
| { |
| // DEBUG: null pointer check |
| if (item == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "enum item in enum."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + item->as_string (); |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string |
| Trait::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| if (has_unsafe) |
| str += "unsafe "; |
| |
| str += "trait " + name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in trait."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Type param bounds: "; |
| if (!has_type_param_bounds ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &bound : type_param_bounds) |
| { |
| // DEBUG: null pointer check |
| if (bound == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "type param bound in trait."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + bound->as_string (); |
| } |
| } |
| |
| str += "\n Where clause: "; |
| if (!has_where_clause ()) |
| str += "none"; |
| else |
| str += where_clause.as_string (); |
| |
| str += "\n Trait items: "; |
| if (!has_trait_items ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : trait_items) |
| { |
| // DEBUG: null pointer check |
| if (item == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "trait item in trait."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + item->as_string (); |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string |
| Union::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "union " + union_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in union."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| // struct fields |
| str += "\n Struct fields (variants): "; |
| if (variants.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &field : variants) |
| str += "\n " + field.as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| Function::as_string () const |
| { |
| std::string str = VisItem::as_string () + "\n"; |
| std::string qstr = qualifiers.as_string (); |
| if ("" != qstr) |
| str += qstr + " "; |
| |
| if (has_return_type ()) |
| { |
| // DEBUG: null pointer check |
| if (return_type == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer return " |
| "type in function."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += return_type->as_string () + " "; |
| } |
| else |
| { |
| str += "void "; |
| } |
| |
| str += function_name; |
| |
| if (has_generics ()) |
| { |
| str += "<"; |
| |
| auto i = generic_params.begin (); |
| auto e = generic_params.end (); |
| |
| // DEBUG: null pointer check |
| if (i == e) |
| { |
| rust_debug ("something really terrible has gone wrong - null pointer " |
| "generic param in function item."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| for (; i != e; i++) |
| { |
| str += (*i)->as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| str += ">"; |
| } |
| |
| if (has_function_params ()) |
| { |
| auto i = function_params.begin (); |
| auto e = function_params.end (); |
| str += "("; |
| for (; i != e; i++) |
| { |
| str += (*i).as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| str += ")"; |
| } |
| else |
| { |
| str += "()"; |
| } |
| |
| if (has_where_clause ()) |
| str += " where " + where_clause.as_string (); |
| |
| str += "\n"; |
| |
| // DEBUG: null pointer check |
| if (function_body == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer function " |
| "body in function."); |
| return "NULL_POINTER_MARK"; |
| } |
| str += function_body->as_string () + "\n"; |
| |
| return str; |
| } |
| |
| std::string |
| WhereClause::as_string () const |
| { |
| // just print where clause items, don't mention "where" or "where clause" |
| std::string str; |
| |
| if (where_clause_items.empty ()) |
| { |
| str = "none"; |
| } |
| else |
| { |
| for (const auto &item : where_clause_items) |
| str += "\n " + item->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| BlockExpr::as_string () const |
| { |
| std::string istr = indent_spaces (enter); |
| std::string str = istr + "BlockExpr:\n" + istr; |
| |
| // get outer attributes |
| str += append_attributes (outer_attrs, OUTER); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| // statements |
| str += "\n" + indent_spaces (stay) + "statements: "; |
| if (statements.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &stmt : statements) |
| { |
| // DEBUG: null pointer check |
| if (stmt == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "stmt in block expr."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n" + indent_spaces (stay) + stmt->as_string (); |
| } |
| } |
| |
| // final expression |
| str += "\n" + indent_spaces (stay) + "final expression: "; |
| if (expr == nullptr) |
| str += "none"; |
| else |
| str += "\n" + expr->as_string (); |
| |
| str += "\n" + indent_spaces (out); |
| return str; |
| } |
| |
| std::string |
| TraitImpl::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| if (has_unsafe) |
| str += "unsafe "; |
| |
| str += "impl "; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (!has_generics ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| str += "\n " + param->as_string (); |
| } |
| |
| str += "\n Has exclam: "; |
| if (has_exclam) |
| str += "true"; |
| else |
| str += "false"; |
| |
| str += "\n TypePath (to trait): " + trait_path.as_string (); |
| |
| str += "\n Type (struct to impl on): " + trait_type->as_string (); |
| |
| str += "\n Where clause: "; |
| if (!has_where_clause ()) |
| str += "none"; |
| else |
| str += where_clause.as_string (); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| str += "\n trait impl items: "; |
| if (!has_impl_items ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : impl_items) |
| str += "\n " + item->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| TypeAlias::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += " " + new_type_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (!has_generics ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| auto i = generic_params.begin (); |
| auto e = generic_params.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i)->as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| } |
| |
| str += "\n Where clause: "; |
| if (!has_where_clause ()) |
| str += "none"; |
| else |
| str += where_clause.as_string (); |
| |
| str += "\n Type: " + existing_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ExternBlock::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| |
| str += "extern "; |
| if (has_abi ()) |
| str += "\"" + abi + "\" "; |
| |
| str += append_attributes (inner_attrs, INNER); |
| |
| str += "\n external items: "; |
| if (!has_extern_items ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &item : extern_items) |
| str += "\n " + item->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| MacroRule::as_string () const |
| { |
| std::string str ("Macro rule: "); |
| |
| str += "\n Matcher: \n "; |
| str += matcher.as_string (); |
| |
| str += "\n Transcriber: \n "; |
| str += transcriber.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MacroRulesDefinition::as_string () const |
| { |
| std::string str; |
| |
| // get outer attrs |
| str += append_attributes (outer_attrs, OUTER); |
| |
| // TODO: deal with macro_2_0 |
| str += "macro_rules!"; |
| |
| str += rule_name; |
| |
| str += "\n Macro rules: "; |
| if (rules.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &rule : rules) |
| str += "\n " + rule.as_string (); |
| } |
| |
| str += "\n Delim type: "; |
| switch (delim_type) |
| { |
| case PARENS: |
| str += "parentheses"; |
| break; |
| case SQUARE: |
| str += "square"; |
| break; |
| case CURLY: |
| str += "curly"; |
| break; |
| default: |
| return "ERROR_MARK_STRING - delim type in macro invocation"; |
| } |
| |
| return str; |
| } |
| |
| std::string |
| MacroInvocation::as_string () const |
| { |
| std::string str = "MacroInvocation: "; |
| auto is_builtin = kind == InvocKind::Builtin; |
| |
| if (is_builtin) |
| str += "[builtin] "; |
| else |
| str += "[regular] "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n " + invoc_data.as_string (); |
| |
| str += "\n has semicolon: "; |
| str += has_semicolon () ? "true" : "false"; |
| |
| if (is_builtin) |
| { |
| str += "[PENDING EAGER INVOCATIONS]: "; |
| for (auto &pending : pending_eager_invocs) |
| { |
| str += pending->as_string (); |
| str += "\n"; |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string |
| MacroInvocData::as_string () const |
| { |
| return path.as_string () + "!" + token_tree.as_string (); |
| } |
| |
| std::string |
| PathInExpression::as_string () const |
| { |
| std::string str; |
| |
| if (has_opening_scope_resolution) |
| str = "::"; |
| |
| return str + PathPattern::as_string (); |
| } |
| |
| std::string |
| ExprStmtWithBlock::as_string () const |
| { |
| std::string str = indent_spaces (enter) + "ExprStmtWithBlock: \n"; |
| |
| if (expr == nullptr) |
| { |
| str += "none (this should not happen and is an error)"; |
| } |
| else |
| { |
| indent_spaces (enter); |
| str += expr->as_string (); |
| indent_spaces (out); |
| } |
| |
| indent_spaces (out); |
| return str; |
| } |
| |
| std::string |
| ClosureParam::as_string () const |
| { |
| std::string str (pattern->as_string ()); |
| |
| if (has_type_given ()) |
| str += " : " + type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ClosureExpr::as_string () const |
| { |
| std::string str = "ClosureExpr:"; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Has move: "; |
| if (has_move) |
| str += "true"; |
| else |
| str += "false"; |
| |
| str += "\n Params: "; |
| if (params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : params) |
| str += "\n " + param.as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| ClosureExprInnerTyped::as_string () const |
| { |
| std::string str = ClosureExpr::as_string (); |
| |
| str += "\n Return type: " + return_type->as_string (); |
| |
| str += "\n Body: " + expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| PathPattern::as_string () const |
| { |
| std::string str; |
| |
| for (const auto &segment : segments) |
| str += segment.as_string () + "::"; |
| |
| // basically a hack - remove last two characters of string (remove final ::) |
| str.erase (str.length () - 2); |
| |
| return str; |
| } |
| |
| std::string |
| QualifiedPathType::as_string () const |
| { |
| std::string str ("<"); |
| str += type_to_invoke_on->as_string (); |
| |
| if (has_as_clause ()) |
| str += " as " + trait_path.as_string (); |
| |
| return str + ">"; |
| } |
| |
| std::string |
| QualifiedPathInExpression::as_string () const |
| { |
| return path_type.as_string () + "::" + PathPattern::as_string (); |
| } |
| |
| std::string |
| BorrowExpr::as_string () const |
| { |
| /* TODO: find way to incorporate outer attrs - may have to represent in |
| * different style (i.e. something more like BorrowExpr: \n outer attrs) */ |
| |
| std::string str ("&"); |
| |
| if (double_borrow) |
| str += "&"; |
| |
| if (is_mut) |
| str += "mut "; |
| |
| str += main_or_left_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ReturnExpr::as_string () const |
| { |
| /* TODO: find way to incorporate outer attrs - may have to represent in |
| * different style (i.e. something more like BorrowExpr: \n outer attrs) */ |
| |
| std::string str ("return "); |
| |
| if (has_returned_expr ()) |
| str += return_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| GroupedExpr::as_string () const |
| { |
| std::string str ("Grouped expr:"); |
| |
| // outer attrs |
| str += append_attributes (outer_attrs, OUTER); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| str += "\n Expr in parens: " + expr_in_parens->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| RangeToExpr::as_string () const |
| { |
| return ".." + to->as_string (); |
| } |
| |
| std::string |
| ContinueExpr::as_string () const |
| { |
| // TODO: rewrite format to allow outer attributes |
| std::string str ("continue "); |
| |
| if (has_label ()) |
| str += label.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| NegationExpr::as_string () const |
| { |
| // TODO: rewrite formula to allow outer attributes |
| std::string str; |
| |
| switch (expr_type) |
| { |
| case NegationOperator::NEGATE: |
| str = "-"; |
| break; |
| case NegationOperator::NOT: |
| str = "!"; |
| break; |
| default: |
| return "ERROR_MARK_STRING - negation expr"; |
| } |
| |
| str += main_or_left_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| RangeFromExpr::as_string () const |
| { |
| return from->as_string () + ".."; |
| } |
| |
| std::string |
| RangeFullExpr::as_string () const |
| { |
| return ".."; |
| } |
| |
| std::string |
| ArrayIndexExpr::as_string () const |
| { |
| // TODO: rewrite formula to allow outer attributes |
| return array_expr->as_string () + "[" + index_expr->as_string () + "]"; |
| } |
| |
| std::string |
| AssignmentExpr::as_string () const |
| { |
| std::string str ("AssignmentExpr: "); |
| |
| if (main_or_left_expr == nullptr || right_expr == nullptr) |
| { |
| str += "error (either or both expressions are null)"; |
| } |
| else |
| { |
| // left expr |
| str += "\n left: " + main_or_left_expr->as_string (); |
| |
| // right expr |
| str += "\n right: " + right_expr->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| AsyncBlockExpr::as_string () const |
| { |
| std::string str = "AsyncBlockExpr: "; |
| |
| // get outer attributes |
| // str += "\n " + Expr::as_string (); |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Has move: "; |
| str += has_move ? "true" : "false"; |
| |
| return str + "\n" + block_expr->as_string (); |
| } |
| |
| std::string |
| ComparisonExpr::as_string () const |
| { |
| // TODO: rewrite to better reflect non-literal expressions |
| std::string str (main_or_left_expr->as_string ()); |
| |
| switch (expr_type) |
| { |
| case ComparisonOperator::EQUAL: |
| str += " == "; |
| break; |
| case ComparisonOperator::NOT_EQUAL: |
| str += " != "; |
| break; |
| case ComparisonOperator::GREATER_THAN: |
| str += " > "; |
| break; |
| case ComparisonOperator::LESS_THAN: |
| str += " < "; |
| break; |
| case ComparisonOperator::GREATER_OR_EQUAL: |
| str += " >= "; |
| break; |
| case ComparisonOperator::LESS_OR_EQUAL: |
| str += " <= "; |
| break; |
| default: |
| return "ERROR_MARK_STRING - comparison expr"; |
| } |
| |
| str += right_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MethodCallExpr::as_string () const |
| { |
| std::string str = "MethodCallExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Object (receiver) expr: \n"; |
| str += receiver->as_string (); |
| |
| str += "\n Method path segment: \n"; |
| str += method_name.as_string (); |
| |
| str += "\n Call params:"; |
| if (params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : params) |
| { |
| if (param == nullptr) |
| return "ERROR_MARK_STRING - method call expr param is null"; |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string |
| TupleIndexExpr::as_string () const |
| { |
| // TODO: rewrite dump to better reflect non-literal exprs |
| return tuple_expr->as_string () + "." + std::to_string (tuple_index); |
| } |
| |
| std::string |
| DereferenceExpr::as_string () const |
| { |
| // TODO: rewrite dump to better reflect non-literal exprs |
| return "*" + main_or_left_expr->as_string (); |
| } |
| |
| std::string |
| FieldAccessExpr::as_string () const |
| { |
| // TODO: rewrite dump to better reflect non-literal exprs |
| return receiver->as_string () + "." + field; |
| } |
| |
| std::string |
| LazyBooleanExpr::as_string () const |
| { |
| // TODO: rewrite dump to better reflect non-literal exprs |
| std::string str (main_or_left_expr->as_string ()); |
| |
| switch (expr_type) |
| { |
| case LazyBooleanOperator::LOGICAL_OR: |
| str += " || "; |
| break; |
| case LazyBooleanOperator::LOGICAL_AND: |
| str += " && "; |
| break; |
| default: |
| return "ERROR_MARK_STRING - lazy boolean expr out of bounds"; |
| } |
| |
| str += right_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| RangeFromToExpr::as_string () const |
| { |
| // TODO: rewrite dump to better reflect non-literal exprs |
| return from->as_string () + ".." + to->as_string (); |
| } |
| |
| std::string |
| RangeToInclExpr::as_string () const |
| { |
| // TODO: rewrite dump to better reflect non-literal exprs |
| return "..=" + to->as_string (); |
| } |
| |
| std::string |
| UnsafeBlockExpr::as_string () const |
| { |
| std::string str = "UnsafeBlockExpr:" + indent_spaces (enter); |
| |
| // get outer attributes |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += indent_spaces (stay) + expr->as_string () + "\n" + indent_spaces (out); |
| |
| return str; |
| } |
| |
| std::string |
| ClosureExprInner::as_string () const |
| { |
| std::string str = ClosureExpr::as_string (); |
| |
| str += "\n Expression: " + closure_inner->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfExpr::as_string () const |
| { |
| std::string str = "IfExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Condition expr: " + condition->as_string (); |
| |
| str += "\n If block expr: " + if_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfExprConseqElse::as_string () const |
| { |
| std::string str = IfExpr::as_string (); |
| |
| str += "\n Else block expr: " + else_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfExprConseqIf::as_string () const |
| { |
| std::string str = IfExpr::as_string (); |
| |
| str += "\n Else if expr: \n " + conseq_if_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfExprConseqIfLet::as_string () const |
| { |
| std::string str = IfExpr::as_string (); |
| |
| str += "\n Else if let expr: \n " + if_let_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfLetExpr::as_string () const |
| { |
| std::string str = "IfLetExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Condition match arm patterns: "; |
| if (match_arm_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &pattern : match_arm_patterns) |
| str += "\n " + pattern->as_string (); |
| } |
| |
| str += "\n Scrutinee expr: " + value->as_string (); |
| |
| str += "\n If let block expr: " + if_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfLetExprConseqElse::as_string () const |
| { |
| std::string str = IfLetExpr::as_string (); |
| |
| str += "\n Else block expr: " + else_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfLetExprConseqIf::as_string () const |
| { |
| std::string str = IfLetExpr::as_string (); |
| |
| str += "\n Else if expr: \n " + if_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IfLetExprConseqIfLet::as_string () const |
| { |
| std::string str = IfLetExpr::as_string (); |
| |
| str += "\n Else if let expr: \n " + if_let_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| RangeFromToInclExpr::as_string () const |
| { |
| // TODO: rewrite to allow dumps with non-literal exprs |
| return from->as_string () + "..=" + to->as_string (); |
| } |
| |
| std::string |
| ErrorPropagationExpr::as_string () const |
| { |
| // TODO: rewrite to allow dumps with non-literal exprs |
| return main_or_left_expr->as_string () + "?"; |
| } |
| |
| std::string |
| CompoundAssignmentExpr::as_string () const |
| { |
| std::string operator_str; |
| operator_str.reserve (1); |
| |
| // get operator string |
| switch (expr_type) |
| { |
| case CompoundAssignmentOperator::ADD: |
| operator_str = "+"; |
| break; |
| case CompoundAssignmentOperator::SUBTRACT: |
| operator_str = "-"; |
| break; |
| case CompoundAssignmentOperator::MULTIPLY: |
| operator_str = "*"; |
| break; |
| case CompoundAssignmentOperator::DIVIDE: |
| operator_str = "/"; |
| break; |
| case CompoundAssignmentOperator::MODULUS: |
| operator_str = "%"; |
| break; |
| case CompoundAssignmentOperator::BITWISE_AND: |
| operator_str = "&"; |
| break; |
| case CompoundAssignmentOperator::BITWISE_OR: |
| operator_str = "|"; |
| break; |
| case CompoundAssignmentOperator::BITWISE_XOR: |
| operator_str = "^"; |
| break; |
| case CompoundAssignmentOperator::LEFT_SHIFT: |
| operator_str = "<<"; |
| break; |
| case CompoundAssignmentOperator::RIGHT_SHIFT: |
| operator_str = ">>"; |
| break; |
| default: |
| operator_str = "invalid operator. wtf"; |
| break; |
| } |
| |
| operator_str += "="; |
| |
| std::string str ("CompoundAssignmentExpr: "); |
| if (main_or_left_expr == nullptr || right_expr == nullptr) |
| { |
| str += "error. this is probably a parsing failure."; |
| } |
| else |
| { |
| str += "\n left: " + main_or_left_expr->as_string (); |
| str += "\n right: " + right_expr->as_string (); |
| str += "\n operator: " + operator_str; |
| } |
| |
| return str; |
| } |
| |
| std::string |
| ArithmeticOrLogicalExpr::as_string () const |
| { |
| std::string operator_str; |
| operator_str.reserve (1); |
| |
| // get operator string |
| switch (expr_type) |
| { |
| case ArithmeticOrLogicalOperator::ADD: |
| operator_str = "+"; |
| break; |
| case ArithmeticOrLogicalOperator::SUBTRACT: |
| operator_str = "-"; |
| break; |
| case ArithmeticOrLogicalOperator::MULTIPLY: |
| operator_str = "*"; |
| break; |
| case ArithmeticOrLogicalOperator::DIVIDE: |
| operator_str = "/"; |
| break; |
| case ArithmeticOrLogicalOperator::MODULUS: |
| operator_str = "%"; |
| break; |
| case ArithmeticOrLogicalOperator::BITWISE_AND: |
| operator_str = "&"; |
| break; |
| case ArithmeticOrLogicalOperator::BITWISE_OR: |
| operator_str = "|"; |
| break; |
| case ArithmeticOrLogicalOperator::BITWISE_XOR: |
| operator_str = "^"; |
| break; |
| case ArithmeticOrLogicalOperator::LEFT_SHIFT: |
| operator_str = "<<"; |
| break; |
| case ArithmeticOrLogicalOperator::RIGHT_SHIFT: |
| operator_str = ">>"; |
| break; |
| default: |
| operator_str = "invalid operator. wtf"; |
| break; |
| } |
| |
| std::string str ("ArithmeticOrLogicalExpr: "); |
| if (main_or_left_expr == nullptr || right_expr == nullptr) |
| { |
| str += "error. this is probably a parsing failure."; |
| } |
| else |
| { |
| str += main_or_left_expr->as_string () + " "; |
| str += operator_str + " "; |
| str += right_expr->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| CallExpr::as_string () const |
| { |
| std::string str = "CallExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Function expr: "; |
| str += function->as_string (); |
| |
| str += "\n Call params:"; |
| if (!has_params ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : params) |
| { |
| if (param == nullptr) |
| return "ERROR_MARK_STRING - call expr param is null"; |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string |
| WhileLoopExpr::as_string () const |
| { |
| std::string str = "WhileLoopExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Label: "; |
| if (!has_loop_label ()) |
| str += "none"; |
| else |
| str += loop_label.as_string (); |
| |
| str += "\n Conditional expr: " + condition->as_string (); |
| |
| str += "\n Loop block: " + loop_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| WhileLetLoopExpr::as_string () const |
| { |
| std::string str = "WhileLetLoopExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Label: "; |
| if (!has_loop_label ()) |
| str += "none"; |
| else |
| str += loop_label.as_string (); |
| |
| str += "\n Match arm patterns: "; |
| if (match_arm_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &pattern : match_arm_patterns) |
| str += "\n " + pattern->as_string (); |
| } |
| |
| str += "\n Scrutinee expr: " + scrutinee->as_string (); |
| |
| str += "\n Loop block: " + loop_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| LoopExpr::as_string () const |
| { |
| std::string str = "LoopExpr: (infinite loop)"; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Label: "; |
| if (!has_loop_label ()) |
| str += "none"; |
| else |
| str += loop_label.as_string (); |
| |
| str += "\n Loop block: " + loop_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ArrayExpr::as_string () const |
| { |
| std::string str = "ArrayExpr:"; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| str += "\n Array elems: "; |
| str += internal_elements->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| AwaitExpr::as_string () const |
| { |
| // TODO: rewrite dump to allow non-literal exprs |
| return awaited_expr->as_string () + ".await"; |
| } |
| |
| std::string |
| BreakExpr::as_string () const |
| { |
| // TODO: rewrite dump to allow outer attrs, non-literal exprs |
| std::string str ("break "); |
| |
| if (has_label ()) |
| str += label.as_string () + " "; |
| |
| if (has_break_expr ()) |
| str += break_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| LoopLabel::as_string () const |
| { |
| return label.as_string () + ": (label) "; |
| } |
| |
| std::string |
| MatchArm::as_string () const |
| { |
| // outer attributes |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\nPatterns: "; |
| if (match_arm_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &pattern : match_arm_patterns) |
| str += "\n " + pattern->as_string (); |
| } |
| |
| str += "\nGuard expr: "; |
| if (!has_match_arm_guard ()) |
| str += "none"; |
| else |
| str += guard_expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MatchCase::as_string () const |
| { |
| std::string str ("MatchCase: (match arm) "); |
| |
| str += "\n Match arm matcher: \n" + arm.as_string (); |
| str += "\n Expr: " + expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MatchExpr::as_string () const |
| { |
| std::string str ("MatchExpr:"); |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Scrutinee expr: " + branch_value->as_string (); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| // match arms |
| str += "\n Match arms: "; |
| if (match_arms.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &arm : match_arms) |
| str += "\n " + arm.as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| TupleExpr::as_string () const |
| { |
| std::string str ("TupleExpr:"); |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| str += "\n Tuple elements: "; |
| if (tuple_elems.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &elem : tuple_elems) |
| str += "\n " + elem->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| ExprStmtWithoutBlock::as_string () const |
| { |
| std::string str ("ExprStmtWithoutBlock:\n"); |
| indent_spaces (enter); |
| str += indent_spaces (stay); |
| |
| if (expr == nullptr) |
| str += "none (this shouldn't happen and is probably an error)"; |
| else |
| str += expr->as_string (); |
| indent_spaces (out); |
| |
| return str; |
| } |
| |
| std::string |
| FunctionParam::as_string () const |
| { |
| // TODO: rewrite dump to allow non-literal types |
| return param_name->as_string () + " : " + type->as_string (); |
| } |
| |
| std::string |
| FunctionQualifiers::as_string () const |
| { |
| std::string str; |
| |
| switch (const_status) |
| { |
| case NONE: |
| // do nothing |
| break; |
| case CONST_FN: |
| str += "const "; |
| break; |
| case ASYNC_FN: |
| str += "async "; |
| break; |
| default: |
| return "ERROR_MARK_STRING: async-const status failure"; |
| } |
| |
| if (has_unsafe) |
| str += "unsafe "; |
| |
| if (has_extern) |
| { |
| str += "extern"; |
| if (extern_abi != "") |
| str += " \"" + extern_abi + "\""; |
| } |
| |
| return str; |
| } |
| |
| std::string |
| TraitBound::as_string () const |
| { |
| std::string str ("TraitBound:"); |
| |
| str += "\n Has opening question mark: "; |
| if (opening_question_mark) |
| str += "true"; |
| else |
| str += "false"; |
| |
| str += "\n For lifetimes: "; |
| if (!has_for_lifetimes ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &lifetime : for_lifetimes) |
| str += "\n " + lifetime.as_string (); |
| } |
| |
| str += "\n Type path: " + type_path.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MacroMatcher::as_string () const |
| { |
| std::string str ("Macro matcher: "); |
| |
| str += "\n Delim type: "; |
| |
| switch (delim_type) |
| { |
| case PARENS: |
| str += "parentheses"; |
| break; |
| case SQUARE: |
| str += "square"; |
| break; |
| case CURLY: |
| str += "curly"; |
| break; |
| default: |
| return "ERROR_MARK_STRING - macro matcher delim"; |
| } |
| |
| str += "\n Matches: "; |
| |
| if (matches.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &match : matches) |
| str += "\n " + match->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| LifetimeParam::as_string () const |
| { |
| std::string str ("LifetimeParam: "); |
| |
| str += "\n Outer attribute: "; |
| if (!has_outer_attribute ()) |
| str += "none"; |
| else |
| str += outer_attr.as_string (); |
| |
| str += "\n Lifetime: " + lifetime.as_string (); |
| |
| str += "\n Lifetime bounds: "; |
| if (!has_lifetime_bounds ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &bound : lifetime_bounds) |
| str += "\n " + bound.as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| ConstGenericParam::as_string () const |
| { |
| std::string str ("ConstGenericParam: "); |
| str += "const " + name + ": " + type->as_string (); |
| |
| if (has_default_value ()) |
| str += " = " + get_default_value ().as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MacroMatchFragment::as_string () const |
| { |
| return "$" + ident + ": " + frag_spec.as_string (); |
| } |
| |
| std::string |
| QualifiedPathInType::as_string () const |
| { |
| /* TODO: this may need adjusting if segments (e.g. with functions) can't be |
| * literalised */ |
| std::string str = path_type.as_string (); |
| |
| for (const auto &segment : segments) |
| str += "::" + segment->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| MacroMatchRepetition::as_string () const |
| { |
| std::string str ("Macro match repetition: "); |
| |
| str += "\n Matches: "; |
| if (matches.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &match : matches) |
| str += "\n " + match->as_string (); |
| } |
| |
| str += "\n Sep: "; |
| if (!has_sep ()) |
| str += "none"; |
| else |
| str += sep->as_string (); |
| |
| str += "\n Op: "; |
| switch (op) |
| { |
| case ANY: |
| str += "*"; |
| break; |
| case ONE_OR_MORE: |
| str += "+"; |
| break; |
| case ZERO_OR_ONE: |
| str += "?"; |
| break; |
| case NONE: |
| str += "no op? shouldn't be allowed"; |
| break; |
| default: |
| return "ERROR_MARK_STRING - unknown op in macro match repetition"; |
| } |
| |
| return str; |
| } |
| |
| std::string |
| Lifetime::as_string () const |
| { |
| if (is_error ()) |
| return "error lifetime"; |
| |
| switch (lifetime_type) |
| { |
| case NAMED: |
| return "'" + lifetime_name; |
| case STATIC: |
| return "'static"; |
| case WILDCARD: |
| return "'_"; |
| default: |
| return "ERROR-MARK-STRING: lifetime type failure"; |
| } |
| } |
| |
| std::string |
| TypePath::as_string () const |
| { |
| /* TODO: this may need to be rewritten if a segment (e.g. function) can't be |
| * literalised */ |
| std::string str; |
| |
| if (has_opening_scope_resolution) |
| str = "::"; |
| |
| for (const auto &segment : segments) |
| str += segment->as_string () + "::"; |
| |
| // kinda hack - remove last 2 '::' characters |
| str.erase (str.length () - 2); |
| |
| return str; |
| } |
| |
| std::string |
| TypeParam::as_string () const |
| { |
| std::string str ("TypeParam: "); |
| |
| str += "\n Outer attribute: "; |
| if (!has_outer_attribute ()) |
| str += "none"; |
| else |
| str += outer_attr.as_string (); |
| |
| str += "\n Identifier: " + type_representation; |
| |
| str += "\n Type param bounds: "; |
| if (!has_type_param_bounds ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &bound : type_param_bounds) |
| str += "\n " + bound->as_string (); |
| } |
| |
| str += "\n Type: "; |
| if (!has_type ()) |
| str += "none"; |
| else |
| str += type->as_string (); |
| |
| return str; |
| } |
| |
| SimplePath |
| PathPattern::convert_to_simple_path (bool with_opening_scope_resolution) const |
| { |
| if (!has_segments ()) |
| return SimplePath::create_empty (); |
| |
| // create vector of reserved size (to minimise reallocations) |
| std::vector<SimplePathSegment> simple_segments; |
| simple_segments.reserve (segments.size ()); |
| |
| for (const auto &segment : segments) |
| { |
| // return empty path if doesn't meet simple path segment requirements |
| if (segment.is_error () || segment.has_generic_args () |
| || segment.as_string () == "Self") |
| return SimplePath::create_empty (); |
| |
| // create segment and add to vector |
| std::string segment_str = segment.as_string (); |
| simple_segments.push_back ( |
| SimplePathSegment (std::move (segment_str), segment.get_locus ())); |
| } |
| |
| // kind of a HACK to get locus depending on opening scope resolution |
| Location locus = Linemap::unknown_location (); |
| if (with_opening_scope_resolution) |
| locus = simple_segments[0].get_locus () - 2; // minus 2 chars for :: |
| else |
| locus = simple_segments[0].get_locus (); |
| // FIXME: this hack probably doesn't actually work |
| |
| return SimplePath (std::move (simple_segments), with_opening_scope_resolution, |
| locus); |
| } |
| |
| SimplePath |
| TypePath::as_simple_path () const |
| { |
| if (segments.empty ()) |
| return SimplePath::create_empty (); |
| |
| // create vector of reserved size (to minimise reallocations) |
| std::vector<SimplePathSegment> simple_segments; |
| simple_segments.reserve (segments.size ()); |
| |
| for (const auto &segment : segments) |
| { |
| // return empty path if doesn't meet simple path segment requirements |
| if (segment == nullptr || segment->is_error () |
| || !segment->is_ident_only () || segment->as_string () == "Self") |
| return SimplePath::create_empty (); |
| |
| // create segment and add to vector |
| std::string segment_str = segment->as_string (); |
| simple_segments.push_back ( |
| SimplePathSegment (std::move (segment_str), segment->get_locus ())); |
| } |
| |
| return SimplePath (std::move (simple_segments), has_opening_scope_resolution, |
| locus); |
| } |
| |
| std::string |
| PathExprSegment::as_string () const |
| { |
| // TODO: rewrite dump to work with non-literalisable types |
| std::string ident_str = segment_name.as_string (); |
| if (has_generic_args ()) |
| ident_str += "::<" + generic_args.as_string () + ">"; |
| |
| return ident_str; |
| } |
| |
| std::string |
| GenericArgs::as_string () const |
| { |
| std::string args; |
| |
| // lifetime args |
| if (!lifetime_args.empty ()) |
| { |
| auto i = lifetime_args.begin (); |
| auto e = lifetime_args.end (); |
| |
| for (; i != e; i++) |
| { |
| args += (*i).as_string (); |
| if (e != i + 1) |
| args += ", "; |
| } |
| } |
| |
| // type args |
| if (!generic_args.empty ()) |
| { |
| auto i = generic_args.begin (); |
| auto e = generic_args.end (); |
| |
| for (; i != e; i++) |
| { |
| args += (*i).as_string (); |
| if (e != i + 1) |
| args += ", "; |
| } |
| } |
| |
| // binding args |
| if (!binding_args.empty ()) |
| { |
| auto i = binding_args.begin (); |
| auto e = binding_args.end (); |
| |
| for (; i != e; i++) |
| { |
| args += (*i).as_string (); |
| if (e != i + 1) |
| args += ", "; |
| } |
| } |
| |
| return args; |
| } |
| |
| std::string |
| GenericArgsBinding::as_string () const |
| { |
| // TODO: rewrite to work with non-literalisable types |
| return identifier + " = " + type->as_string (); |
| } |
| |
| std::string |
| ForLoopExpr::as_string () const |
| { |
| std::string str = "ForLoopExpr: "; |
| |
| str += append_attributes (outer_attrs, OUTER); |
| |
| str += "\n Label: "; |
| if (!has_loop_label ()) |
| str += "none"; |
| else |
| str += loop_label.as_string (); |
| |
| str += "\n Pattern: " + pattern->as_string (); |
| |
| str += "\n Iterator expr: " + iterator_expr->as_string (); |
| |
| str += "\n Loop block: " + loop_block->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| RangePattern::as_string () const |
| { |
| // TODO: maybe rewrite to work with non-linearisable bounds |
| if (has_ellipsis_syntax) |
| return lower->as_string () + "..." + upper->as_string (); |
| else |
| return lower->as_string () + "..=" + upper->as_string (); |
| } |
| |
| std::string |
| RangePatternBoundLiteral::as_string () const |
| { |
| std::string str; |
| |
| if (has_minus) |
| str += "-"; |
| |
| str += literal.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| SlicePattern::as_string () const |
| { |
| std::string str ("SlicePattern: "); |
| |
| for (const auto &pattern : items) |
| str += "\n " + pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| AltPattern::as_string () const |
| { |
| std::string str ("AltPattern: "); |
| |
| for (const auto &pattern : alts) |
| str += "\n " + pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TuplePatternItemsMultiple::as_string () const |
| { |
| std::string str; |
| |
| for (const auto &pattern : patterns) |
| str += "\n " + pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TuplePatternItemsRanged::as_string () const |
| { |
| std::string str; |
| |
| str += "\n Lower patterns: "; |
| if (lower_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &lower : lower_patterns) |
| str += "\n " + lower->as_string (); |
| } |
| |
| str += "\n Upper patterns: "; |
| if (upper_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &upper : upper_patterns) |
| str += "\n " + upper->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| TuplePattern::as_string () const |
| { |
| return "TuplePattern: " + items->as_string (); |
| } |
| |
| std::string |
| StructPatternField::as_string () const |
| { |
| // outer attributes |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| return str; |
| } |
| |
| std::string |
| StructPatternFieldIdent::as_string () const |
| { |
| std::string str = StructPatternField::as_string (); |
| |
| str += "\n"; |
| |
| if (has_ref) |
| str += "ref "; |
| |
| if (has_mut) |
| str += "mut "; |
| |
| str += ident; |
| |
| return str; |
| } |
| |
| std::string |
| StructPatternFieldTuplePat::as_string () const |
| { |
| // TODO: maybe rewrite to work with non-linearisable patterns |
| std::string str = StructPatternField::as_string (); |
| |
| str += "\n"; |
| |
| str += std::to_string (index) + " : " + tuple_pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| StructPatternFieldIdentPat::as_string () const |
| { |
| // TODO: maybe rewrite to work with non-linearisable patterns |
| std::string str = StructPatternField::as_string (); |
| |
| str += "\n"; |
| |
| str += ident + " : " + ident_pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| StructPatternElements::as_string () const |
| { |
| std::string str ("\n Fields: "); |
| |
| if (!has_struct_pattern_fields ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &field : fields) |
| str += "\n " + field->as_string (); |
| } |
| |
| str += "\n Etc: "; |
| if (has_struct_pattern_etc) |
| str += "true"; |
| else |
| str += "false"; |
| |
| return str; |
| } |
| |
| std::string |
| StructPattern::as_string () const |
| { |
| std::string str ("StructPattern: \n Path: "); |
| |
| str += path.as_string (); |
| |
| str += "\n Struct pattern elems: "; |
| if (!has_struct_pattern_elems ()) |
| str += "none"; |
| else |
| str += elems.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| LiteralPattern::as_string () const |
| { |
| return lit.as_string (); |
| } |
| |
| std::string |
| ReferencePattern::as_string () const |
| { |
| // TODO: maybe rewrite to work with non-linearisable patterns |
| std::string str ("&"); |
| |
| if (has_two_amps) |
| str += "&"; |
| |
| if (is_mut) |
| str += "mut "; |
| |
| str += pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| IdentifierPattern::as_string () const |
| { |
| // TODO: maybe rewrite to work with non-linearisable patterns |
| std::string str; |
| |
| if (is_ref) |
| str += "ref "; |
| |
| if (is_mut) |
| str += "mut "; |
| |
| str += variable_ident; |
| |
| if (has_pattern_to_bind ()) |
| str += " @ " + to_bind->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TupleStructItemsNoRange::as_string () const |
| { |
| std::string str; |
| |
| for (const auto &pattern : patterns) |
| str += "\n " + pattern->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TupleStructItemsRange::as_string () const |
| { |
| std::string str ("\n Lower patterns: "); |
| |
| if (lower_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &lower : lower_patterns) |
| str += "\n " + lower->as_string (); |
| } |
| |
| str += "\n Upper patterns: "; |
| if (upper_patterns.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &upper : upper_patterns) |
| str += "\n " + upper->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| TupleStructPattern::as_string () const |
| { |
| std::string str ("TupleStructPattern: \n Path: "); |
| |
| str += path.as_string (); |
| |
| str += "\n Tuple struct items: " + items->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| LetStmt::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types and exprs |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\n" + indent_spaces (stay) + "let " + variables_pattern->as_string (); |
| |
| if (has_type ()) |
| str += " : " + type->as_string (); |
| |
| if (has_init_expr ()) |
| str += " = " + init_expr->as_string (); |
| |
| return str; |
| } |
| |
| // hopefully definition here will prevent circular dependency issue |
| TraitBound * |
| TypePath::to_trait_bound (bool in_parens) const |
| { |
| return new TraitBound (TypePath (*this), get_locus (), in_parens); |
| } |
| |
| std::string |
| InferredType::as_string () const |
| { |
| return "_ (inferred)"; |
| } |
| |
| std::string |
| TypeCastExpr::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs and types |
| return main_or_left_expr->as_string () + " as " |
| + type_to_convert_to->as_string (); |
| } |
| |
| std::string |
| ImplTraitType::as_string () const |
| { |
| std::string str ("ImplTraitType: \n TypeParamBounds: "); |
| |
| if (type_param_bounds.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &bound : type_param_bounds) |
| str += "\n " + bound->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| ReferenceType::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| std::string str ("&"); |
| |
| if (has_lifetime ()) |
| str += lifetime.as_string () + " "; |
| |
| if (has_mut) |
| str += "mut "; |
| |
| str += type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| RawPointerType::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| std::string str ("*"); |
| |
| switch (pointer_type) |
| { |
| case MUT: |
| str += "mut "; |
| break; |
| case CONST: |
| str += "const "; |
| break; |
| default: |
| return "ERROR_MARK_STRING - unknown pointer type in raw pointer type"; |
| } |
| |
| str += type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TraitObjectType::as_string () const |
| { |
| std::string str ("TraitObjectType: \n Has dyn dispatch: "); |
| |
| if (has_dyn) |
| str += "true"; |
| else |
| str += "false"; |
| |
| str += "\n TypeParamBounds: "; |
| if (type_param_bounds.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &bound : type_param_bounds) |
| str += "\n " + bound->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| BareFunctionType::as_string () const |
| { |
| std::string str ("BareFunctionType: \n For lifetimes: "); |
| |
| if (!has_for_lifetimes ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &for_lifetime : for_lifetimes) |
| str += "\n " + for_lifetime.as_string (); |
| } |
| |
| str += "\n Qualifiers: " + function_qualifiers.as_string (); |
| |
| str += "\n Params: "; |
| if (params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : params) |
| str += "\n " + param.as_string (); |
| } |
| |
| str += "\n Is variadic: "; |
| if (_is_variadic) |
| str += "true"; |
| else |
| str += "false"; |
| |
| str += "\n Return type: "; |
| if (!has_return_type ()) |
| str += "none (void)"; |
| else |
| str += return_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ImplTraitTypeOneBound::as_string () const |
| { |
| std::string str ("ImplTraitTypeOneBound: \n TraitBound: "); |
| |
| return str + trait_bound.as_string (); |
| } |
| |
| std::string |
| TypePathSegmentGeneric::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| return TypePathSegment::as_string () + "<" + generic_args.as_string () + ">"; |
| } |
| |
| std::string |
| TraitObjectTypeOneBound::as_string () const |
| { |
| std::string str ("TraitObjectTypeOneBound: \n Has dyn dispatch: "); |
| |
| if (has_dyn) |
| str += "true"; |
| else |
| str += "false"; |
| |
| str += "\n TraitBound: " + trait_bound.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TypePathFunction::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| std::string str ("("); |
| |
| if (has_inputs ()) |
| { |
| auto i = inputs.begin (); |
| auto e = inputs.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i)->as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| } |
| |
| str += ")"; |
| |
| if (has_return_type ()) |
| str += " -> " + return_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TypePathSegmentFunction::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| return TypePathSegment::as_string () + function_path.as_string (); |
| } |
| |
| std::string |
| ArrayType::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types and exprs |
| return "[" + elem_type->as_string () + "; " + size->as_string () + "]"; |
| } |
| |
| std::string |
| SliceType::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| return "[" + elem_type->as_string () + "]"; |
| } |
| |
| std::string |
| TupleType::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable types |
| std::string str ("("); |
| |
| if (!is_unit_type ()) |
| { |
| auto i = elems.begin (); |
| auto e = elems.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i)->as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| } |
| |
| str += ")"; |
| |
| return str; |
| } |
| |
| std::string |
| StructExpr::as_string () const |
| { |
| std::string str = append_attributes (outer_attrs, OUTER); |
| indent_spaces (enter); |
| str += "\n" + indent_spaces (stay) + "StructExpr:"; |
| indent_spaces (enter); |
| str += "\n" + indent_spaces (stay) + "PathInExpr:\n"; |
| str += indent_spaces (stay) + struct_name.as_string (); |
| indent_spaces (out); |
| indent_spaces (out); |
| return str; |
| } |
| |
| std::string |
| StructExprStruct::as_string () const |
| { |
| // TODO: doesn't this require data from StructExpr? |
| std::string str ("StructExprStruct (or subclass): "); |
| |
| str += "\n Path: " + get_struct_name ().as_string (); |
| |
| // inner attributes |
| str += append_attributes (inner_attrs, INNER); |
| |
| return str; |
| } |
| |
| std::string |
| StructBase::as_string () const |
| { |
| if (base_struct != nullptr) |
| return base_struct->as_string (); |
| else |
| return "ERROR_MARK_STRING - invalid struct base had as string applied"; |
| } |
| |
| std::string |
| StructExprFieldWithVal::as_string () const |
| { |
| // used to get value string |
| return value->as_string (); |
| } |
| |
| std::string |
| StructExprFieldIdentifierValue::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs |
| return field_name + " : " + StructExprFieldWithVal::as_string (); |
| } |
| |
| std::string |
| StructExprFieldIndexValue::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs |
| return std::to_string (index) + " : " + StructExprFieldWithVal::as_string (); |
| } |
| |
| std::string |
| StructExprStructFields::as_string () const |
| { |
| std::string str = StructExprStruct::as_string (); |
| |
| str += "\n Fields: "; |
| if (fields.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &field : fields) |
| str += "\n " + field->as_string (); |
| } |
| |
| str += "\n Struct base: "; |
| if (!has_struct_base ()) |
| str += "none"; |
| else |
| str += struct_base.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| EnumItem::as_string () const |
| { |
| std::string str = VisItem::as_string (); |
| str += variant_name; |
| |
| return str; |
| } |
| |
| std::string |
| EnumItemTuple::as_string () const |
| { |
| std::string str = EnumItem::as_string (); |
| |
| // add tuple opening parens |
| str += "("; |
| |
| // tuple fields |
| if (has_tuple_fields ()) |
| { |
| auto i = tuple_fields.begin (); |
| auto e = tuple_fields.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i).as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| } |
| |
| // add tuple closing parens |
| str += ")"; |
| |
| return str; |
| } |
| |
| std::string |
| TupleField::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs |
| |
| // outer attributes |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| if (has_visibility ()) |
| str += "\n" + visibility.as_string (); |
| |
| str += " " + field_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| EnumItemStruct::as_string () const |
| { |
| std::string str = EnumItem::as_string (); |
| |
| // add struct opening parens |
| str += "{"; |
| |
| // tuple fields |
| if (has_struct_fields ()) |
| { |
| auto i = struct_fields.begin (); |
| auto e = struct_fields.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i).as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| } |
| |
| // add struct closing parens |
| str += "}"; |
| |
| return str; |
| } |
| |
| std::string |
| StructField::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs |
| // outer attributes |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| if (has_visibility ()) |
| str += "\n" + visibility.as_string (); |
| |
| str += " " + field_name + " : " + field_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| EnumItemDiscriminant::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs |
| std::string str = EnumItem::as_string (); |
| |
| // add equal and expression |
| str += " = " + expression->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ExternalStaticItem::as_string () const |
| { |
| // outer attributes |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| // start visibility on new line and with a space |
| str += "\n" + visibility.as_string () + " "; |
| |
| str += "static "; |
| |
| if (has_mut) |
| str += "mut "; |
| |
| // add name |
| str += item_name; |
| |
| // add type on new line |
| str += "\n Type: " + item_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| ExternalFunctionItem::as_string () const |
| { |
| // outer attributes |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| // start visibility on new line and with a space |
| str += "\n" + visibility.as_string () + " "; |
| |
| str += "fn "; |
| |
| // add name |
| str += item_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in external function item."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| // function params |
| str += "\n Function params: "; |
| if (function_params.empty () && !has_variadics) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : function_params) |
| str += "\n " + param.as_string (); |
| |
| if (has_variadics) |
| { |
| str += "\n variadic outer attrs: "; |
| if (has_variadic_outer_attrs ()) |
| { |
| for (const auto &attr : variadic_outer_attrs) |
| str += "\n " + attr.as_string (); |
| } |
| else |
| { |
| str += "none"; |
| } |
| str += "\n ... (variadic)"; |
| } |
| } |
| |
| // add type on new line |
| str += "\n (return) Type: " |
| + (has_return_type () ? return_type->as_string () : "()"); |
| |
| // where clause |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| return str; |
| } |
| |
| std::string |
| NamedFunctionParam::as_string () const |
| { |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\n" + name; |
| |
| str += "\n Type: " + param_type->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TraitItemFunc::as_string () const |
| { |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\n" + decl.as_string (); |
| |
| str += "\n Definition (block expr): "; |
| if (has_definition ()) |
| str += block_expr->as_string (); |
| else |
| str += "none"; |
| |
| return str; |
| } |
| |
| std::string |
| TraitFunctionDecl::as_string () const |
| { |
| std::string str = qualifiers.as_string () + "fn " + function_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in trait function decl."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Function params: "; |
| if (has_params ()) |
| { |
| for (const auto ¶m : function_params) |
| str += "\n " + param.as_string (); |
| } |
| else |
| { |
| str += "none"; |
| } |
| |
| str += "\n Return type: "; |
| if (has_return_type ()) |
| str += return_type->as_string (); |
| else |
| str += "none (void)"; |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| return str; |
| } |
| |
| std::string |
| TraitItemMethod::as_string () const |
| { |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\n" + decl.as_string (); |
| |
| str += "\n Definition (block expr): "; |
| if (has_definition ()) |
| str += block_expr->as_string (); |
| else |
| str += "none"; |
| |
| return str; |
| } |
| |
| std::string |
| TraitMethodDecl::as_string () const |
| { |
| std::string str = qualifiers.as_string () + "fn " + function_name; |
| |
| // generic params |
| str += "\n Generic params: "; |
| if (generic_params.empty ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto ¶m : generic_params) |
| { |
| // DEBUG: null pointer check |
| if (param == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "generic param in trait function decl."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + param->as_string (); |
| } |
| } |
| |
| str += "\n Self param: " + self_param.as_string (); |
| |
| str += "\n Function params: "; |
| if (has_params ()) |
| { |
| for (const auto ¶m : function_params) |
| str += "\n " + param.as_string (); |
| } |
| else |
| { |
| str += "none"; |
| } |
| |
| str += "\n Return type: "; |
| if (has_return_type ()) |
| str += return_type->as_string (); |
| else |
| str += "none (void)"; |
| |
| str += "\n Where clause: "; |
| if (has_where_clause ()) |
| str += where_clause.as_string (); |
| else |
| str += "none"; |
| |
| return str; |
| } |
| |
| std::string |
| TraitItemConst::as_string () const |
| { |
| // TODO: rewrite to work with non-linearisable exprs |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\nconst " + name + " : " + type->as_string (); |
| |
| if (has_expression ()) |
| str += " = " + expr->as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TraitItemType::as_string () const |
| { |
| std::string str = append_attributes (outer_attrs, OUTER); |
| |
| str += "\ntype " + name; |
| |
| str += "\n Type param bounds: "; |
| if (!has_type_param_bounds ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &bound : type_param_bounds) |
| { |
| // DEBUG: null pointer check |
| if (bound == nullptr) |
| { |
| rust_debug ( |
| "something really terrible has gone wrong - null pointer " |
| "type param bound in trait item type."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + bound->as_string (); |
| } |
| } |
| |
| return str; |
| } |
| |
| std::string |
| SelfParam::as_string () const |
| { |
| // TODO: rewrite to allow non-linearisable types |
| if (is_error ()) |
| { |
| return "error"; |
| } |
| else |
| { |
| if (has_type ()) |
| { |
| // type (i.e. not ref, no lifetime) |
| std::string str; |
| |
| if (is_mut) |
| str += "mut "; |
| |
| str += "self : "; |
| |
| str += type->as_string (); |
| |
| return str; |
| } |
| else if (has_lifetime ()) |
| { |
| // ref and lifetime |
| std::string str = "&" + lifetime.as_string () + " "; |
| |
| if (is_mut) |
| str += "mut "; |
| |
| str += "self"; |
| |
| return str; |
| } |
| else if (has_ref) |
| { |
| // ref with no lifetime |
| std::string str = "&"; |
| |
| if (is_mut) |
| str += " mut "; |
| |
| str += "self"; |
| |
| return str; |
| } |
| else |
| { |
| // no ref, no type |
| std::string str; |
| |
| if (is_mut) |
| str += "mut "; |
| |
| str += "self"; |
| |
| return str; |
| } |
| } |
| } |
| |
| std::string |
| ArrayElemsCopied::as_string () const |
| { |
| // TODO: rewrite to allow non-linearisable exprs |
| return elem_to_copy->as_string () + "; " + num_copies->as_string (); |
| } |
| |
| std::string |
| LifetimeWhereClauseItem::as_string () const |
| { |
| std::string str ("Lifetime: "); |
| |
| str += lifetime.as_string (); |
| |
| str += "\nLifetime bounds: "; |
| |
| for (const auto &bound : lifetime_bounds) |
| str += "\n " + bound.as_string (); |
| |
| return str; |
| } |
| |
| std::string |
| TypeBoundWhereClauseItem::as_string () const |
| { |
| std::string str ("For lifetimes: "); |
| |
| if (!has_for_lifetimes ()) |
| { |
| str += "none"; |
| } |
| else |
| { |
| for (const auto &for_lifetime : for_lifetimes) |
| str += "\n " + for_lifetime.as_string (); |
| } |
| |
| str += "\nType: " + bound_type->as_string (); |
| |
| str += "\nType param bounds bounds: "; |
| |
| for (const auto &bound : type_param_bounds) |
| { |
| // debug null pointer check |
| if (bound == nullptr) |
| return "NULL_POINTER_MARK - type param bounds"; |
| |
| str += "\n " + bound->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| ArrayElemsValues::as_string () const |
| { |
| std::string str; |
| |
| for (const auto &expr : values) |
| { |
| // DEBUG: null pointer check |
| if (expr == nullptr) |
| { |
| rust_debug ("something really terrible has gone wrong - null pointer " |
| "expr in array elems values."); |
| return "NULL_POINTER_MARK"; |
| } |
| |
| str += "\n " + expr->as_string (); |
| } |
| |
| return str; |
| } |
| |
| std::string |
| MaybeNamedParam::as_string () const |
| { |
| // TODO: rewrite to allow using non-linearisable types in dump |
| std::string str; |
| |
| switch (param_kind) |
| { |
| case UNNAMED: |
| break; |
| case IDENTIFIER: |
| str = name + " : "; |
| break; |
| case WILDCARD: |
| str = "_ : "; |
| break; |
| default: |
| return "ERROR_MARK_STRING - maybe named param unrecognised param kind"; |
| } |
| |
| str += param_type->as_string (); |
| |
| return str; |
| } |
| |
| MetaItemInner::~MetaItemInner () = default; |
| |
| std::unique_ptr<MetaNameValueStr> |
| MetaItemInner::to_meta_name_value_str () const |
| { |
| if (is_key_value_pair ()) |
| { |
| auto converted_item = static_cast<const MetaNameValueStr *> (this); |
| return converted_item->to_meta_name_value_str (); |
| } |
| // TODO actually parse foo = bar |
| return nullptr; |
| } |
| |
| std::string |
| MetaItemSeq::as_string () const |
| { |
| std::string path_str = path.as_string () + "("; |
| |
| auto i = seq.begin (); |
| auto e = seq.end (); |
| |
| for (; i != e; i++) |
| { |
| path_str += (*i)->as_string (); |
| if (e != i + 1) |
| path_str += ", "; |
| } |
| |
| return path_str + ")"; |
| } |
| |
| std::string |
| MetaListPaths::as_string () const |
| { |
| std::string str = ident + "("; |
| |
| auto i = paths.begin (); |
| auto e = paths.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i).as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| |
| return str + ")"; |
| } |
| |
| std::string |
| MetaListNameValueStr::as_string () const |
| { |
| std::string str = ident + "("; |
| |
| auto i = strs.begin (); |
| auto e = strs.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i).as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| |
| return str + ")"; |
| } |
| |
| std::string |
| AttrInputMetaItemContainer::as_string () const |
| { |
| std::string str = "("; |
| |
| auto i = items.begin (); |
| auto e = items.end (); |
| |
| for (; i != e; i++) |
| { |
| str += (*i)->as_string (); |
| if (e != i + 1) |
| str += ", "; |
| } |
| |
| return str + ")"; |
| } |
| |
| /* Override that calls the function recursively on all items contained within |
| * the module. */ |
| void |
| Module::add_crate_name (std::vector<std::string> &names) const |
| { |
| /* TODO: test whether module has been 'cfg'-ed out to determine whether to |
| * exclude it from search */ |
| |
| for (const auto &item : items) |
| item->add_crate_name (names); |
| } |
| |
| static bool |
| file_exists (const std::string path) |
| { |
| // Simply check if the file exists |
| // FIXME: This does not work on Windows |
| return access (path.c_str (), F_OK) != -1; |
| } |
| |
| static std::string |
| filename_from_path_attribute (std::vector<Attribute> &outer_attrs) |
| { |
| // An out-of-line module cannot have inner attributes. Additionally, the |
| // default name is specified as `""` so that the caller can detect the case |
| // of "no path given" and use the default path logic (`name.rs` or |
| // `name/mod.rs`). |
| return extract_module_path ({}, outer_attrs, ""); |
| } |
| |
| void |
| Module::process_file_path () |
| { |
| rust_assert (kind == Module::ModuleKind::UNLOADED); |
| rust_assert (module_file.empty ()); |
| |
| // This corresponds to the path of the file 'including' the module. So the |
| // file that contains the 'mod <file>;' directive |
| std::string including_fname (outer_filename); |
| |
| std::string expected_file_path = module_name + ".rs"; |
| std::string expected_dir_path = "mod.rs"; |
| |
| auto dir_slash_pos = including_fname.rfind (file_separator); |
| std::string current_directory_name; |
| |
| // If we haven't found a file_separator, then we have to look for files in the |
| // current directory ('.') |
| if (dir_slash_pos == std::string::npos) |
| current_directory_name = std::string (".") + file_separator; |
| else |
| current_directory_name |
| = including_fname.substr (0, dir_slash_pos) + file_separator; |
| |
| // Handle inline module declarations adding path components. |
| for (auto const &name : module_scope) |
| { |
| current_directory_name.append (name); |
| current_directory_name.append (file_separator); |
| } |
| |
| auto path_string = filename_from_path_attribute (get_outer_attrs ()); |
| if (!path_string.empty ()) |
| { |
| module_file = current_directory_name + path_string; |
| return; |
| } |
| |
| // FIXME: We also have to search for |
| // <directory>/<including_fname>/<module_name>.rs In rustc, this is done via |
| // the concept of `DirOwnernship`, which is based on whether or not the |
| // current file is titled `mod.rs`. |
| |
| // First, we search for <directory>/<module_name>.rs |
| std::string file_mod_path = current_directory_name + expected_file_path; |
| bool file_mod_found = file_exists (file_mod_path); |
| |
| // Then, search for <directory>/<module_name>/mod.rs |
| std::string dir_mod_path |
| = current_directory_name + module_name + file_separator + expected_dir_path; |
| bool dir_mod_found = file_exists (dir_mod_path); |
| |
| bool multiple_candidates_found = file_mod_found && dir_mod_found; |
| bool no_candidates_found = !file_mod_found && !dir_mod_found; |
| |
| if (multiple_candidates_found) |
| rust_error_at (locus, |
| "two candidates found for module %s: %s.rs and %s%smod.rs", |
| module_name.c_str (), module_name.c_str (), |
| module_name.c_str (), file_separator); |
| |
| if (no_candidates_found) |
| rust_error_at (locus, "no candidate found for module %s", |
| module_name.c_str ()); |
| |
| if (no_candidates_found || multiple_candidates_found) |
| return; |
| |
| module_file = std::move (file_mod_found ? file_mod_path : dir_mod_path); |
| } |
| |
| void |
| Module::load_items () |
| { |
| process_file_path (); |
| |
| // We will already have errored out appropriately in the process_file_path () |
| // method |
| if (module_file.empty ()) |
| return; |
| |
| RAIIFile file_wrap (module_file.c_str ()); |
| Linemap *linemap = Session::get_instance ().linemap; |
| if (!file_wrap.ok ()) |
| { |
| rust_error_at (get_locus (), "cannot open module file %s: %m", |
| module_file.c_str ()); |
| return; |
| } |
| |
| rust_debug ("Attempting to parse file %s", module_file.c_str ()); |
| |
| Lexer lex (module_file.c_str (), std::move (file_wrap), linemap); |
| Parser<Lexer> parser (lex); |
| |
| // we need to parse any possible inner attributes for this module |
| inner_attrs = parser.parse_inner_attributes (); |
| auto parsed_items = parser.parse_items (); |
| for (const auto &error : parser.get_errors ()) |
| error.emit (); |
| |
| items = std::move (parsed_items); |
| kind = ModuleKind::LOADED; |
| } |
| |
| void |
| Attribute::parse_attr_to_meta_item () |
| { |
| // only parse if has attribute input and not already parsed |
| if (!has_attr_input () || is_parsed_to_meta_item ()) |
| return; |
| |
| auto res = attr_input->parse_to_meta_item (); |
| std::unique_ptr<AttrInput> converted_input (res); |
| |
| if (converted_input != nullptr) |
| attr_input = std::move (converted_input); |
| } |
| |
| AttrInputMetaItemContainer * |
| DelimTokenTree::parse_to_meta_item () const |
| { |
| // must have token trees |
| if (token_trees.empty ()) |
| return nullptr; |
| |
| /* assume top-level delim token tree in attribute - convert all nested ones |
| * to token stream */ |
| std::vector<std::unique_ptr<Token>> token_stream = to_token_stream (); |
| |
| AttributeParser parser (std::move (token_stream)); |
| std::vector<std::unique_ptr<MetaItemInner>> meta_items ( |
| parser.parse_meta_item_seq ()); |
| |
| return new AttrInputMetaItemContainer (std::move (meta_items)); |
| } |
| |
| std::unique_ptr<MetaItemInner> |
| AttributeParser::parse_meta_item_inner () |
| { |
| // if first tok not identifier, not a "special" case one |
| if (peek_token ()->get_id () != IDENTIFIER) |
| { |
| switch (peek_token ()->get_id ()) |
| { |
| case CHAR_LITERAL: |
| case STRING_LITERAL: |
| case BYTE_CHAR_LITERAL: |
| case BYTE_STRING_LITERAL: |
| case INT_LITERAL: |
| case FLOAT_LITERAL: |
| case TRUE_LITERAL: |
| case FALSE_LITERAL: |
| return parse_meta_item_lit (); |
| |
| case SUPER: |
| case SELF: |
| case CRATE: |
| case DOLLAR_SIGN: |
| case SCOPE_RESOLUTION: |
| return parse_path_meta_item (); |
| |
| default: |
| rust_error_at (peek_token ()->get_locus (), |
| "unrecognised token '%s' in meta item", |
| get_token_description (peek_token ()->get_id ())); |
| return nullptr; |
| } |
| } |
| |
| // else, check for path |
| if (peek_token (1)->get_id () == SCOPE_RESOLUTION) |
| { |
| // path |
| return parse_path_meta_item (); |
| } |
| |
| auto ident = peek_token ()->as_string (); |
| auto ident_locus = peek_token ()->get_locus (); |
| |
| if (is_end_meta_item_tok (peek_token (1)->get_id ())) |
| { |
| // meta word syntax |
| skip_token (); |
| return std::unique_ptr<MetaWord> (new MetaWord (ident, ident_locus)); |
| } |
| |
| if (peek_token (1)->get_id () == EQUAL) |
| { |
| // maybe meta name value str syntax - check next 2 tokens |
| if (peek_token (2)->get_id () == STRING_LITERAL |
| && is_end_meta_item_tok (peek_token (3)->get_id ())) |
| { |
| // meta name value str syntax |
| auto &value_tok = peek_token (2); |
| auto value = value_tok->as_string (); |
| auto locus = value_tok->get_locus (); |
| |
| skip_token (2); |
| |
| // remove the quotes from the string value |
| std::string raw_value = unquote_string (std::move (value)); |
| |
| return std::unique_ptr<MetaNameValueStr> ( |
| new MetaNameValueStr (ident, ident_locus, std::move (raw_value), |
| locus)); |
| } |
| else |
| { |
| // just interpret as path-based meta item |
| return parse_path_meta_item (); |
| } |
| } |
| |
| if (peek_token (1)->get_id () != LEFT_PAREN) |
| { |
| rust_error_at (peek_token (1)->get_locus (), |
| "unexpected token '%s' after identifier in attribute", |
| get_token_description (peek_token (1)->get_id ())); |
| return nullptr; |
| } |
| |
| // is it one of those special cases like not? |
| if (peek_token ()->get_id () == IDENTIFIER) |
| { |
| return parse_path_meta_item (); |
| } |
| |
| auto meta_items = parse_meta_item_seq (); |
| |
| // pass for meta name value str |
| std::vector<MetaNameValueStr> meta_name_value_str_items; |
| for (const auto &item : meta_items) |
| { |
| std::unique_ptr<MetaNameValueStr> converted_item |
| = item->to_meta_name_value_str (); |
| if (converted_item == nullptr) |
| { |
| meta_name_value_str_items.clear (); |
| break; |
| } |
| meta_name_value_str_items.push_back (std::move (*converted_item)); |
| } |
| // if valid, return this |
| if (!meta_name_value_str_items.empty ()) |
| { |
| return std::unique_ptr<MetaListNameValueStr> ( |
| new MetaListNameValueStr (ident, ident_locus, |
| std::move (meta_name_value_str_items))); |
| } |
| |
| // // pass for meta list idents |
| // std::vector<Identifier> ident_items; |
| // for (const auto &item : meta_items) |
| // { |
| // std::unique_ptr<Identifier> converted_ident (item->to_ident_item ()); |
| // if (converted_ident == nullptr) |
| // { |
| // ident_items.clear (); |
| // break; |
| // } |
| // ident_items.push_back (std::move (*converted_ident)); |
| // } |
| // // if valid return this |
| // if (!ident_items.empty ()) |
| // { |
| // return std::unique_ptr<MetaListIdents> ( |
| // new MetaListIdents (std::move (ident), std::move (ident_items))); |
| // } |
| // // as currently no meta list ident, currently no path. may change in future |
| |
| // pass for meta list paths |
| std::vector<SimplePath> path_items; |
| for (const auto &item : meta_items) |
| { |
| SimplePath converted_path (item->to_path_item ()); |
| if (converted_path.is_empty ()) |
| { |
| path_items.clear (); |
| break; |
| } |
| path_items.push_back (std::move (converted_path)); |
| } |
| if (!path_items.empty ()) |
| { |
| return std::unique_ptr<MetaListPaths> ( |
| new MetaListPaths (ident, ident_locus, std::move (path_items))); |
| } |
| |
| rust_error_at (Linemap::unknown_location (), |
| "failed to parse any meta item inner"); |
| return nullptr; |
| } |
| |
| bool |
| AttributeParser::is_end_meta_item_tok (TokenId id) const |
| { |
| return id == COMMA || id == RIGHT_PAREN; |
| } |
| |
| std::unique_ptr<MetaItem> |
| AttributeParser::parse_path_meta_item () |
| { |
| SimplePath path = parse_simple_path (); |
| if (path.is_empty ()) |
| { |
| rust_error_at (peek_token ()->get_locus (), |
| "failed to parse simple path in attribute"); |
| return nullptr; |
| } |
| |
| switch (peek_token ()->get_id ()) |
| { |
| case LEFT_PAREN: { |
| std::vector<std::unique_ptr<MetaItemInner>> meta_items |
| = parse_meta_item_seq (); |
| |
| return std::unique_ptr<MetaItemSeq> ( |
| new MetaItemSeq (std::move (path), std::move (meta_items))); |
| } |
| case EQUAL: { |
| skip_token (); |
| |
| Location locus = peek_token ()->get_locus (); |
| Literal lit = parse_literal (); |
| if (lit.is_error ()) |
| { |
| rust_error_at (peek_token ()->get_locus (), |
| "failed to parse literal in attribute"); |
| return nullptr; |
| } |
| LiteralExpr expr (std::move (lit), {}, locus); |
| // stream_pos++; |
| /* shouldn't be required anymore due to parsing literal actually |
| * skipping the token */ |
| return std::unique_ptr<MetaItemPathLit> ( |
| new MetaItemPathLit (std::move (path), std::move (expr))); |
| } |
| case COMMA: |
| // just simple path |
| return std::unique_ptr<MetaItemPath> ( |
| new MetaItemPath (std::move (path))); |
| default: |
| rust_error_at (peek_token ()->get_locus (), |
| "unrecognised token '%s' in meta item", |
| get_token_description (peek_token ()->get_id ())); |
| return nullptr; |
| } |
| } |
| |
| /* Parses a parenthesised sequence of meta item inners. Parentheses are |
| * required here. */ |
| std::vector<std::unique_ptr<MetaItemInner>> |
| AttributeParser::parse_meta_item_seq () |
| { |
| int vec_length = token_stream.size (); |
| std::vector<std::unique_ptr<MetaItemInner>> meta_items; |
| |
| if (peek_token ()->get_id () != LEFT_PAREN) |
| { |
| rust_error_at (peek_token ()->get_locus (), |
| "missing left paren in delim token tree"); |
| return {}; |
| } |
| skip_token (); |
| |
| while (stream_pos < vec_length && peek_token ()->get_id () != RIGHT_PAREN) |
| { |
| std::unique_ptr<MetaItemInner> inner = parse_meta_item_inner (); |
| if (inner == nullptr) |
| { |
| rust_error_at (peek_token ()->get_locus (), |
| "failed to parse inner meta item in attribute"); |
| return {}; |
| } |
| meta_items.push_back (std::move (inner)); |
| |
| if (peek_token ()->get_id () != COMMA) |
| break; |
| |
| skip_token (); |
| } |
| |
| if (peek_token ()->get_id () != RIGHT_PAREN) |
| { |
| rust_error_at (peek_token ()->get_locus (), |
| "missing right paren in delim token tree"); |
| return {}; |
| } |
| skip_token (); |
| |
| return meta_items; |
| } |
| |
| /* Collects any nested token trees into a flat token stream, suitable for |
| * parsing. */ |
| std::vector<std::unique_ptr<Token>> |
| DelimTokenTree::to_token_stream () const |
| { |
| std::vector<std::unique_ptr<Token>> tokens; |
| for (const auto &tree : token_trees) |
| { |
| std::vector<std::unique_ptr<Token>> stream = tree->to_token_stream (); |
| |
| tokens.insert (tokens.end (), std::make_move_iterator (stream.begin ()), |
| std::make_move_iterator (stream.end ())); |
| } |
| |
| tokens.shrink_to_fit (); |
| return tokens; |
| } |
| |
| Literal |
| AttributeParser::parse_literal () |
| { |
| const std::unique_ptr<Token> &tok = peek_token (); |
| switch (tok->get_id ()) |
| { |
| case CHAR_LITERAL: |
| skip_token (); |
| return Literal (tok->as_string (), Literal::CHAR, tok->get_type_hint ()); |
| case STRING_LITERAL: |
| skip_token (); |
| return Literal (tok->as_string (), Literal::STRING, |
| tok->get_type_hint ()); |
| case BYTE_CHAR_LITERAL: |
| skip_token (); |
| return Literal (tok->as_string (), Literal::BYTE, tok->get_type_hint ()); |
| case BYTE_STRING_LITERAL: |
| skip_token (); |
| return Literal (tok->as_string (), Literal::BYTE_STRING, |
| tok->get_type_hint ()); |
| case INT_LITERAL: |
| skip_token (); |
| return Literal (tok->as_string (), Literal::INT, tok->get_type_hint ()); |
| case FLOAT_LITERAL: |
| skip_token (); |
| return Literal (tok->as_string (), Literal::FLOAT, tok->get_type_hint ()); |
| case TRUE_LITERAL: |
| skip_token (); |
| return Literal ("true", Literal::BOOL, tok->get_type_hint ()); |
| case FALSE_LITERAL: |
| skip_token (); |
| return Literal ("false", Literal::BOOL, tok->get_type_hint ()); |
| default: |
| rust_error_at (tok->get_locus (), "expected literal - found '%s'", |
| get_token_description (tok->get_id ())); |
| return Literal::create_error (); |
| } |
| } |
| |
| SimplePath |
| AttributeParser::parse_simple_path () |
| { |
| bool has_opening_scope_res = false; |
| if (peek_token ()->get_id () == SCOPE_RESOLUTION) |
| { |
| has_opening_scope_res = true; |
| skip_token (); |
| } |
| |
| std::vector<SimplePathSegment> segments; |
| |
| SimplePathSegment segment = parse_simple_path_segment (); |
| if (segment.is_error ()) |
| { |
| rust_error_at ( |
| peek_token ()->get_locus (), |
| "failed to parse simple path segment in attribute simple path"); |
| return SimplePath::create_empty (); |
| } |
| segments.push_back (std::move (segment)); |
| |
| while (peek_token ()->get_id () == SCOPE_RESOLUTION) |
| { |
| skip_token (); |
| |
| SimplePathSegment segment = parse_simple_path_segment (); |
| if (segment.is_error ()) |
| { |
| rust_error_at ( |
| peek_token ()->get_locus (), |
| "failed to parse simple path segment in attribute simple path"); |
| return SimplePath::create_empty (); |
| } |
| segments.push_back (std::move (segment)); |
| } |
| segments.shrink_to_fit (); |
| |
| return SimplePath (std::move (segments), has_opening_scope_res); |
| } |
| |
| SimplePathSegment |
| AttributeParser::parse_simple_path_segment () |
| { |
| const std::unique_ptr<Token> &tok = peek_token (); |
| switch (tok->get_id ()) |
| { |
| case IDENTIFIER: |
| skip_token (); |
| return SimplePathSegment (tok->as_string (), tok->get_locus ()); |
| case SUPER: |
| skip_token (); |
| return SimplePathSegment ("super", tok->get_locus ()); |
| case SELF: |
| skip_token (); |
| return SimplePathSegment ("self", tok->get_locus ()); |
| case CRATE: |
| skip_token (); |
| return SimplePathSegment ("crate", tok->get_locus ()); |
| case DOLLAR_SIGN: |
| if (peek_token (1)->get_id () == CRATE) |
| { |
| skip_token (1); |
| return SimplePathSegment ("$crate", tok->get_locus ()); |
| } |
| gcc_fallthrough (); |
| default: |
| rust_error_at (tok->get_locus (), |
| "unexpected token '%s' in simple path segment", |
| get_token_description (tok->get_id ())); |
| return SimplePathSegment::create_error (); |
| } |
| } |
| |
| std::unique_ptr<MetaItemLitExpr> |
| AttributeParser::parse_meta_item_lit () |
| { |
| Location locus = peek_token ()->get_locus (); |
| LiteralExpr lit_expr (parse_literal (), {}, locus); |
| return std::unique_ptr<MetaItemLitExpr> ( |
| new MetaItemLitExpr (std::move (lit_expr))); |
| } |
| |
| bool |
| AttrInputMetaItemContainer::check_cfg_predicate (const Session &session) const |
| { |
| if (items.empty ()) |
| return false; |
| |
| for (const auto &inner_item : items) |
| { |
| if (!inner_item->check_cfg_predicate (session)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool |
| MetaItemLitExpr::check_cfg_predicate (const Session &) const |
| { |
| /* as far as I can tell, a literal expr can never be a valid cfg body, so |
| * false */ |
| return false; |
| } |
| |
| bool |
| MetaListNameValueStr::check_cfg_predicate (const Session &session) const |
| { |
| if (ident == "all") |
| { |
| for (const auto &str : strs) |
| { |
| if (!str.check_cfg_predicate (session)) |
| return false; |
| } |
| return true; |
| } |
| else if (ident == "any") |
| { |
| for (const auto &str : strs) |
| { |
| if (str.check_cfg_predicate (session)) |
| return true; |
| } |
| return false; |
| } |
| else if (ident == "not") |
| { |
| if (strs.size () != 1) |
| { |
| /* HACK: convert vector platform-dependent size_type to string to |
| * use in printf */ |
| rust_error_at (Linemap::unknown_location (), |
| "cfg predicate could not be checked for " |
| "MetaListNameValueStr with ident of " |
| "'not' because there are '%s' elements, not '1'", |
| std::to_string (strs.size ()).c_str ()); |
| return false; |
| } |
| |
| return !strs[0].check_cfg_predicate (session); |
| } |
| else |
| { |
| rust_error_at (Linemap::unknown_location (), |
| "cfg predicate could not be checked for " |
| "MetaListNameValueStr with ident of " |
| "'%s' - ident must be 'all' or 'any'", |
| ident.c_str ()); |
| return false; |
| } |
| } |
| |
| bool |
| MetaListPaths::check_cfg_predicate (const Session &session) const |
| { |
| if (ident == "all") |
| { |
| for (const auto &path : paths) |
| { |
| if (!check_path_exists_in_cfg (session, path)) |
| return false; |
| } |
| return true; |
| } |
| else if (ident == "any") |
| { |
| for (const auto &path : paths) |
| { |
| if (check_path_exists_in_cfg (session, path)) |
| return true; |
| } |
| return false; |
| } |
| else if (ident == "not") |
| { |
| if (paths.size () != 1) |
| { |
| // HACK: convert vector platform-dependent size_type to string to |
| // use in printf |
| rust_error_at (Linemap::unknown_location (), |
| "cfg predicate could not be checked for MetaListPaths " |
| "with ident of 'not' " |
| "because there are '%s' elements, not '1'", |
| std::to_string (paths.size ()).c_str ()); |
| return false; |
| } |
| |
| return !check_path_exists_in_cfg (session, paths[0]); |
| } |
| else |
| { |
| rust_error_at (Linemap::unknown_location (), |
| "cfg predicate could not be checked for " |
| "MetaListNameValueStr with ident of " |
| "'%s' - ident must be 'all' or 'any'", |
| ident.c_str ()); |
| return false; |
| } |
| } |
| |
| bool |
| MetaListPaths::check_path_exists_in_cfg (const Session &session, |
| const SimplePath &path) const |
| { |
| return session.options.target_data.has_key (path.as_string ()); |
| } |
| |
| bool |
| MetaItemSeq::check_cfg_predicate (const Session &session) const |
| { |
| if (path.as_string () == "all") |
| { |
| for (const auto &item : seq) |
| { |
| if (!item->check_cfg_predicate (session)) |
| return false; |
| } |
| return true; |
| } |
| else if (path.as_string () == "any") |
| { |
| for (const auto &item : seq) |
| { |
| if (item->check_cfg_predicate (session)) |
| return true; |
| } |
| return false; |
| } |
| else if (path.as_string () == "not") |
| { |
| if (seq.size () != 1) |
| { |
| /* HACK: convert vector platform-dependent size_type to string to |
| * use in printf */ |
| rust_error_at (Linemap::unknown_location (), |
| "cfg predicate could not be checked for MetaItemSeq " |
| "with ident of 'not' " |
| "because there are '%s' elements, not '1'", |
| std::to_string (seq.size ()).c_str ()); |
| return false; |
| } |
| |
| return !seq[0]->check_cfg_predicate (session); |
| } |
| else |
| { |
| rust_error_at ( |
| Linemap::unknown_location (), |
| "cfg predicate could not be checked for MetaItemSeq with path of " |
| "'%s' - path must be 'all' or 'any'", |
| path.as_string ().c_str ()); |
| return false; |
| } |
| } |
| |
| bool |
| MetaWord::check_cfg_predicate (const Session &session) const |
| { |
| return session.options.target_data.has_key (ident); |
| } |
| |
| bool |
| MetaItemPath::check_cfg_predicate (const Session &session) const |
| { |
| /* Strictly speaking, this should always be false, but maybe do check |
| * relating to SimplePath being identifier. Currently, it would return true |
| * if path as identifier existed, and if the path in string form existed |
| * (though this shouldn't occur). */ |
| return session.options.target_data.has_key (path.as_string ()); |
| } |
| |
| bool |
| MetaNameValueStr::check_cfg_predicate (const Session &session) const |
| { |
| // DEBUG |
| rust_debug ( |
| "checked key-value pair for cfg: '%s', '%s' - is%s in target data", |
| ident.c_str (), str.c_str (), |
| session.options.target_data.has_key_value_pair (ident, str) ? "" : " not"); |
| |
| return session.options.target_data.has_key_value_pair (ident, str); |
| } |
| |
| bool |
| MetaItemPathLit::check_cfg_predicate (const Session &session) const |
| { |
| return session.options.target_data.has_key_value_pair (path.as_string (), |
| lit.as_string ()); |
| } |
| |
| std::vector<std::unique_ptr<Token>> |
| Token::to_token_stream () const |
| { |
| /* initialisation list doesn't work as it needs copy constructor, so have to |
| * do this */ |
| std::vector<std::unique_ptr<Token>> dummy_vector; |
| dummy_vector.reserve (1); |
| dummy_vector.push_back (std::unique_ptr<Token> (clone_token_impl ())); |
| return dummy_vector; |
| } |
| |
| Attribute |
| MetaNameValueStr::to_attribute () const |
| { |
| LiteralExpr lit_expr (str, Literal::LitType::STRING, |
| PrimitiveCoreType::CORETYPE_UNKNOWN, {}, str_locus); |
| // FIXME: What location do we put here? Is the literal above supposed to have |
| // an empty location as well? |
| // Should MetaNameValueStr keep a location? |
| return Attribute (SimplePath::from_str (ident, ident_locus), |
| std::unique_ptr<AttrInputLiteral> ( |
| new AttrInputLiteral (std::move (lit_expr)))); |
| } |
| |
| Attribute |
| MetaItemPath::to_attribute () const |
| { |
| return Attribute (path, nullptr); |
| } |
| |
| Attribute |
| MetaItemSeq::to_attribute () const |
| { |
| std::vector<std::unique_ptr<MetaItemInner>> new_seq; |
| new_seq.reserve (seq.size ()); |
| for (const auto &e : seq) |
| new_seq.push_back (e->clone_meta_item_inner ()); |
| |
| std::unique_ptr<AttrInputMetaItemContainer> new_seq_container ( |
| new AttrInputMetaItemContainer (std::move (new_seq))); |
| return Attribute (path, std::move (new_seq_container)); |
| } |
| |
| Attribute |
| MetaWord::to_attribute () const |
| { |
| return Attribute (SimplePath::from_str (ident, ident_locus), nullptr); |
| } |
| |
| Attribute |
| MetaListPaths::to_attribute () const |
| { |
| /* probably one of the most annoying conversions - have to lose specificity by |
| * turning it into just AttrInputMetaItemContainer (i.e. paths-only nature is |
| * no longer known). If conversions back are required, might have to do a |
| * "check all are paths" pass or something. */ |
| |
| std::vector<std::unique_ptr<MetaItemInner>> new_seq; |
| new_seq.reserve (paths.size ()); |
| for (const auto &e : paths) |
| new_seq.push_back (std::unique_ptr<MetaItemPath> (new MetaItemPath (e))); |
| |
| std::unique_ptr<AttrInputMetaItemContainer> new_seq_container ( |
| new AttrInputMetaItemContainer (std::move (new_seq))); |
| return Attribute (SimplePath::from_str (ident, ident_locus), |
| std::move (new_seq_container)); |
| } |
| |
| Attribute |
| MetaListNameValueStr::to_attribute () const |
| { |
| std::vector<std::unique_ptr<MetaItemInner>> new_seq; |
| new_seq.reserve (strs.size ()); |
| for (const auto &e : strs) |
| new_seq.push_back ( |
| std::unique_ptr<MetaNameValueStr> (new MetaNameValueStr (e))); |
| |
| std::unique_ptr<AttrInputMetaItemContainer> new_seq_container ( |
| new AttrInputMetaItemContainer (std::move (new_seq))); |
| return Attribute (SimplePath::from_str (ident, ident_locus), |
| std::move (new_seq_container)); |
| } |
| |
| Attribute |
| MetaItemPathLit::to_attribute () const |
| { |
| return Attribute (path, std::unique_ptr<AttrInputLiteral> ( |
| new AttrInputLiteral (lit))); |
| } |
| |
| std::vector<Attribute> |
| AttrInputMetaItemContainer::separate_cfg_attrs () const |
| { |
| rust_assert (!items.empty ()); |
| |
| if (items.size () == 1) |
| return {}; |
| |
| std::vector<Attribute> attrs; |
| attrs.reserve (items.size () - 1); |
| |
| for (auto it = items.begin () + 1; it != items.end (); ++it) |
| { |
| Attribute attr = (*it)->to_attribute (); |
| if (attr.is_empty ()) |
| { |
| /* TODO should this be an error that causes us to chuck out |
| * everything? */ |
| continue; |
| } |
| attrs.push_back (std::move (attr)); |
| } |
| |
| attrs.shrink_to_fit (); |
| return attrs; |
| } |
| |
| bool |
| Attribute::check_cfg_predicate (const Session &session) const |
| { |
| /* assume that cfg predicate actually can exist, i.e. attribute has cfg or |
| * cfg_attr path */ |
| if (!has_attr_input () |
| || (path.as_string () != "cfg" && path.as_string () != "cfg_attr")) |
| { |
| // DEBUG message |
| rust_debug ( |
| "tried to check cfg predicate on attr that either has no input " |
| "or invalid path. attr: '%s'", |
| as_string ().c_str ()); |
| |
| return false; |
| } |
| |
| // assume that it has already been parsed |
| if (!is_parsed_to_meta_item ()) |
| return false; |
| |
| return attr_input->check_cfg_predicate (session); |
| } |
| |
| std::vector<Attribute> |
| Attribute::separate_cfg_attrs () const |
| { |
| if (!has_attr_input () || path.as_string () != "cfg_attr") |
| return {}; |
| |
| // assume that it has already been parsed |
| if (!is_parsed_to_meta_item ()) |
| return {}; |
| |
| return attr_input->separate_cfg_attrs (); |
| } |
| |
| bool |
| Attribute::is_parsed_to_meta_item () const |
| { |
| return has_attr_input () && attr_input->is_meta_item (); |
| } |
| |
| /* Visitor implementations - these are short but inlining can't happen anyway |
| * due to virtual functions and I didn't want to make the ast header includes |
| * any longer than they already are. */ |
| |
| void |
| Token::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| DelimTokenTree::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IdentifierExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Lifetime::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LifetimeParam::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ConstGenericParam::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| PathInExpression::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypePathSegment::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypePathSegmentGeneric::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypePathSegmentFunction::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypePath::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| QualifiedPathInExpression::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| QualifiedPathInType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LiteralExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| AttrInputLiteral::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaItemLitExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaItemPathLit::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| BorrowExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| DereferenceExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ErrorPropagationExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| NegationExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ArithmeticOrLogicalExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ComparisonExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LazyBooleanExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypeCastExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| AssignmentExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| CompoundAssignmentExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| GroupedExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ArrayElemsValues::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ArrayElemsCopied::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ArrayExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ArrayIndexExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleIndexExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructExprStruct::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructExprFieldIdentifier::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructExprFieldIdentifierValue::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructExprFieldIndexValue::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructExprStructFields::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructExprStructBase::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| CallExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MethodCallExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| FieldAccessExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ClosureExprInner::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| BlockExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ClosureExprInnerTyped::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ContinueExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| BreakExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangeFromToExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangeFromExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangeToExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangeFullExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangeFromToInclExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangeToInclExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ReturnExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| UnsafeBlockExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LoopExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| WhileLoopExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| WhileLetLoopExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ForLoopExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfExprConseqElse::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfExprConseqIf::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfExprConseqIfLet::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfLetExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfLetExprConseqElse::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfLetExprConseqIf::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IfLetExprConseqIfLet::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MatchExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| AwaitExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| AsyncBlockExpr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypeParam::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LifetimeWhereClauseItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypeBoundWhereClauseItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Method::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Module::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ExternCrate::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| UseTreeGlob::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| UseTreeList::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| UseTreeRebind::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| UseDeclaration::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Function::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TypeAlias::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructStruct::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleStruct::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| EnumItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| EnumItemTuple::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| EnumItemStruct::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| EnumItemDiscriminant::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Enum::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Union::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ConstantItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StaticItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitItemFunc::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitItemMethod::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitItemConst::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitItemType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| Trait::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| InherentImpl::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitImpl::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ExternalStaticItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ExternalFunctionItem::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ExternBlock::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MacroMatchFragment::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MacroMatchRepetition::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MacroMatcher::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MacroRulesDefinition::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MacroInvocation::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LiteralPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| IdentifierPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| WildcardPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangePatternBoundLiteral::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangePatternBoundPath::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangePatternBoundQualPath::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RangePattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ReferencePattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructPatternFieldTuplePat::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructPatternFieldIdentPat::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructPatternFieldIdent::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| StructPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleStructItemsNoRange::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleStructItemsRange::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleStructPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TuplePatternItemsMultiple::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TuplePatternItemsRanged::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TuplePattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| GroupedPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| SlicePattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| AltPattern::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| EmptyStmt::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| LetStmt::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ExprStmtWithoutBlock::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ExprStmtWithBlock::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitBound::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ImplTraitType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitObjectType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ParenthesisedType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ImplTraitTypeOneBound::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TraitObjectTypeOneBound::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| TupleType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| NeverType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| RawPointerType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ReferenceType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| ArrayType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| SliceType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| InferredType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| BareFunctionType::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaItemSeq::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaItemPath::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaListPaths::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaNameValueStr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaListNameValueStr::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| AttrInputMetaItemContainer::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| void |
| MetaWord::accept_vis (ASTVisitor &vis) |
| { |
| vis.visit (*this); |
| } |
| |
| GenericArg |
| GenericArg::disambiguate_to_const () const |
| { |
| rust_assert (get_kind () == Kind::Either); |
| |
| // FIXME: is it fine to have no outer attributes? |
| return GenericArg::create_const ( |
| std::unique_ptr<Expr> (new IdentifierExpr (path, {}, locus))); |
| } |
| |
| GenericArg |
| GenericArg::disambiguate_to_type () const |
| { |
| rust_assert (get_kind () == Kind::Either); |
| |
| auto segment = std::unique_ptr<TypePathSegment> ( |
| new TypePathSegment (path, false, locus)); |
| auto segments = std::vector<std::unique_ptr<TypePathSegment>> (); |
| segments.emplace_back (std::move (segment)); |
| |
| return GenericArg::create_type ( |
| std::unique_ptr<Type> (new TypePath (std::move (segments), locus))); |
| } |
| |
| } // namespace AST |
| } // namespace Rust |