#ifndef RUST_AST_BASE_H #define RUST_AST_BASE_H // Base for AST used in gccrs, basically required by all specific ast things // GCC imports #include "config.h" //#define INCLUDE_UNIQUE_PTR // should allow including the gcc emulation of std::unique_ptr #include "system.h" #include "coretypes.h" // order: config, INCLUDE, system, coretypes #include "rust-system.h" // STL imports // with C++11, now can use actual std::unique_ptr #include #include #include // gccrs imports // required for AST::Token #include "rust-token.h" #include "rust-location.h" namespace Rust { // TODO: remove typedefs and make actual types for these // typedef int Location; // typedef ::std::string SimplePath; typedef ::std::string Identifier; typedef int TupleIndex; struct Session; namespace AST { // foward decl: ast visitor class ASTVisitor; // Delimiter types - used in macros and whatever. enum DelimType { PARENS, SQUARE, CURLY }; // Base AST node object - TODO is this really required or useful? Where to draw // line? /*class Node { public: // Gets node's Location. Location get_locus() const { return loc; } // Sets node's Location. void set_locus(Location loc_) { loc = loc_; } // Get node output as a string. Pure virtual. virtual ::std::string as_string() const = 0; virtual ~Node() {} // TODO: constructor including Location? Make all derived classes have Location? private: // The node's location. Location loc; };*/ // decided to not have node as a "node" would never need to be stored // Attribute body - abstract base class class AttrInput { public: virtual ~AttrInput () {} // Unique pointer custom clone function ::std::unique_ptr clone_attr_input () const { return ::std::unique_ptr (clone_attr_input_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; virtual bool check_cfg_predicate (const Session &session) const = 0; // Parse attribute input to meta item, if possible virtual AttrInput *parse_to_meta_item () const { return NULL; } protected: // pure virtual clone implementation virtual AttrInput *clone_attr_input_impl () const = 0; }; // forward decl for use in token tree method class Token; // A tree of tokens (or a single token) - abstract base class class TokenTree { public: virtual ~TokenTree () {} // Unique pointer custom clone function ::std::unique_ptr clone_token_tree () const { return ::std::unique_ptr (clone_token_tree_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; /* Converts token tree to a flat token stream. Tokens must be pointer to avoid * mutual dependency with Token. */ virtual ::std::vector< ::std::unique_ptr > to_token_stream () const = 0; protected: // pure virtual clone implementation virtual TokenTree *clone_token_tree_impl () const = 0; }; // Abstract base class for a macro match class MacroMatch { public: virtual ~MacroMatch () {} virtual ::std::string as_string () const = 0; // Unique pointer custom clone function ::std::unique_ptr clone_macro_match () const { return ::std::unique_ptr (clone_macro_match_impl ()); } virtual void accept_vis (ASTVisitor &vis) = 0; protected: // pure virtual clone implementation virtual MacroMatch *clone_macro_match_impl () const = 0; }; // A token is a kind of token tree (except delimiter tokens) class Token : public TokenTree, public MacroMatch { // A token is a kind of token tree (except delimiter tokens) // A token is a kind of MacroMatch (except $ and delimiter tokens) // TODO: improve member variables - current ones are the same as lexer token // Token kind. TokenId token_id; // Token location. Location locus; // Associated text (if any) of token. std::string str; // Token type hint (if any). PrimitiveCoreType type_hint; public: // Unique pointer custom clone function ::std::unique_ptr clone_token () const { return ::std::unique_ptr (clone_token_impl ()); } // constructor from general text - avoid using if lexer const_TokenPtr is // available Token (TokenId token_id, Location locus, ::std::string str, PrimitiveCoreType type_hint) : token_id (token_id), locus (locus), str (::std::move (str)), type_hint (type_hint) {} // Constructor from lexer const_TokenPtr /* TODO: find workaround for std::string being NULL - probably have to * introduce new method in lexer Token, or maybe make conversion method * there*/ Token (const_TokenPtr lexer_token_ptr) : token_id (lexer_token_ptr->get_id ()), locus (lexer_token_ptr->get_locus ()), str (""), type_hint (lexer_token_ptr->get_type_hint ()) { // FIXME: change to "should have str" later? if (lexer_token_ptr->has_str ()) { str = lexer_token_ptr->get_str (); // DEBUG fprintf (stderr, "ast token created with str '%s'\n", str.c_str ()); } else { // FIXME: is this returning correct thing? str = lexer_token_ptr->get_token_description (); // DEBUG fprintf (stderr, "ast token created with string '%s'\n", str.c_str ()); } // DEBUG if (lexer_token_ptr->should_have_str () && !lexer_token_ptr->has_str ()) { fprintf (stderr, "BAD: for token '%s', should have string but does not!\n", lexer_token_ptr->get_token_description ()); } } inline bool is_string_lit () const { switch (token_id) { case STRING_LITERAL: case BYTE_STRING_LITERAL: return true; default: return false; } } ::std::string as_string () const; virtual void accept_vis (ASTVisitor &vis) OVERRIDE; // Return copy of itself but in token stream form. virtual ::std::vector< ::std::unique_ptr > to_token_stream () const OVERRIDE; TokenId get_id () const { return token_id; } Location get_locus () const { return locus; } protected: // No virtual for now as not polymorphic but can be in future /*virtual*/ Token *clone_token_impl () const { return new Token (*this); } // Use covariance to implement clone function as returning this object rather // than base virtual Token *clone_token_tree_impl () const OVERRIDE { return new Token (*this); } // Use covariance to implement clone function as returning this object rather // than base virtual Token *clone_macro_match_impl () const OVERRIDE { return new Token (*this); } }; // A literal - value with a type. Used in LiteralExpr and LiteralPattern. struct Literal { public: enum LitType { CHAR, STRING, RAW_STRING, BYTE, BYTE_STRING, RAW_BYTE_STRING, INT, FLOAT, BOOL }; private: // TODO: maybe make subclasses of each type of literal with their typed values // (or generics) ::std::string value_as_string; LitType type; public: ::std::string as_string () const { return value_as_string; } inline LitType get_lit_type () const { return type; } Literal (::std::string value_as_string, LitType type) : value_as_string (::std::move (value_as_string)), type (type) {} static Literal create_error () { return Literal ("", CHAR); } // Returns whether literal is in an invalid state. bool is_error () const { return value_as_string == ""; } }; // A token tree with delimiters class DelimTokenTree : public TokenTree, public AttrInput { DelimType delim_type; ::std::vector< ::std::unique_ptr > token_trees; Location locus; // TODO: move all the "parse" functions into a separate class that has the // token stream reference - will be cleaner Parse a meta item inner. //::std::unique_ptr parse_meta_item_inner(const ::std::vector< //::std::unique_ptr >& token_stream, int& i) const; SimplePath // parse_simple_path(const ::std::vector< ::std::unique_ptr >& // token_stream, int& i) const; SimplePathSegment // parse_simple_path_segment(const ::std::vector< // ::std::unique_ptr >& token_stream, int& i) const; //::std::unique_ptr parse_meta_item_lit(const //::std::unique_ptr& // tok) const; //::std::vector< ::std::unique_ptr > parse_meta_item_seq(const //::std::vector< ::std::unique_ptr >& token_stream, int& i) const; // Literal // parse_literal(const ::std::unique_ptr& tok) const; //::std::unique_ptr parse_path_meta_item(const ::std::vector< //::std::unique_ptr >& token_stream, int& i) const; bool // is_end_meta_item_tok(TokenId tok) const; protected: // Use covariance to implement clone function as returning a DelimTokenTree // object virtual DelimTokenTree *clone_attr_input_impl () const OVERRIDE { return new DelimTokenTree (*this); } // Use covariance to implement clone function as returning this object rather // than base virtual DelimTokenTree *clone_token_tree_impl () const OVERRIDE { return new DelimTokenTree (*this); } public: DelimTokenTree (DelimType delim_type, ::std::vector< ::std::unique_ptr > token_trees = ::std::vector< ::std::unique_ptr > (), Location locus = Location ()) : delim_type (delim_type), token_trees (::std::move (token_trees)), locus (locus) {} // Copy constructor with vector clone DelimTokenTree (DelimTokenTree const &other) : delim_type (other.delim_type), locus (other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing // this? token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) { token_trees.push_back (e->clone_token_tree ()); } } // overloaded assignment operator with vector clone DelimTokenTree &operator= (DelimTokenTree const &other) { delim_type = other.delim_type; locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing // this? token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) { token_trees.push_back (e->clone_token_tree ()); } return *this; } // move constructors DelimTokenTree (DelimTokenTree &&other) = default; DelimTokenTree &operator= (DelimTokenTree &&other) = default; static DelimTokenTree create_empty () { return DelimTokenTree (PARENS); } ::std::string as_string () const; virtual void accept_vis (ASTVisitor &vis) OVERRIDE; virtual bool check_cfg_predicate (const Session &session ATTRIBUTE_UNUSED) const OVERRIDE { // this should never be called - should be converted first return false; } virtual AttrInput *parse_to_meta_item () const OVERRIDE; virtual ::std::vector< ::std::unique_ptr > to_token_stream () const OVERRIDE; }; // Forward decl - definition moved to rust-expr.h as it requires LiteralExpr to // be defined class AttrInputLiteral; // TODO: move applicable stuff into here or just don't include it because // nothing uses it A segment of a path (maybe) class PathSegment { public: virtual ~PathSegment () {} virtual ::std::string as_string () const = 0; // TODO: add visitor here? }; // A segment of a simple path without generic or type arguments class SimplePathSegment : public PathSegment { ::std::string segment_name; Location locus; // only allow identifiers, "super", "self", "crate", or "$crate" public: // TODO: put checks in constructor to enforce this rule? SimplePathSegment (::std::string segment_name, Location locus = Location ()) : segment_name (::std::move (segment_name)), locus (locus) {} // Returns whether simple path segment is in an invalid state (currently, if // empty). inline bool is_error () const { return segment_name.empty (); } // Creates an error SimplePathSegment static SimplePathSegment create_error () { return SimplePathSegment (::std::string ("")); } ::std::string as_string () const; inline Location get_locus () const { return locus; } // TODO: visitor pattern? }; // A simple path without generic or type arguments class SimplePath { bool has_opening_scope_resolution; ::std::vector segments; Location locus; public: // Constructor SimplePath (::std::vector path_segments, bool has_opening_scope_resolution = false, Location locus = Location ()) : has_opening_scope_resolution (has_opening_scope_resolution), segments (::std::move (path_segments)), locus (locus) {} // Creates an empty SimplePath. static SimplePath create_empty () { return SimplePath (::std::vector ()); } // Returns whether the SimplePath is empty, i.e. has path segments. inline bool is_empty () const { return segments.empty (); } ::std::string as_string () const; Location get_locus () const { return locus; } // does this need visitor if not polymorphic? probably not // path-to-string comparison operator bool operator== (const ::std::string &rhs) { return !has_opening_scope_resolution && segments.size () == 1 && segments[0].as_string () == rhs; } /* Creates a single-segment SimplePath from a string. This will not check to * ensure that this is a valid identifier in path, so be careful. Also, this * will have no location data. * TODO have checks? */ static SimplePath from_str (::std::string str) { ::std::vector single_segments = {AST::SimplePathSegment (::std::move (str))}; return SimplePath (::std::move (single_segments)); } }; // aka Attr // Attribute AST representation struct Attribute { private: SimplePath path; // bool has_attr_input; // AttrInput* attr_input; ::std::unique_ptr attr_input; Location locus; // TODO: maybe a variable storing whether attr input is parsed or not public: // Returns whether Attribute has AttrInput inline bool has_attr_input () const { return attr_input != NULL; } // Constructor has pointer AttrInput for polymorphism reasons Attribute (SimplePath path, ::std::unique_ptr input, Location locus = Location ()) : path (::std::move (path)), attr_input (::std::move (input)), locus (locus) {} // Copy constructor must deep copy attr_input as unique pointer Attribute (Attribute const &other) : path (other.path), locus (other.locus) { // guard to protect from null pointer dereference if (other.attr_input != NULL) { attr_input = other.attr_input->clone_attr_input (); } } // default destructor ~Attribute () = default; // overload assignment operator to use custom clone method Attribute &operator= (Attribute const &other) { path = other.path; locus = other.locus; // guard to protect from null pointer dereference if (other.attr_input != NULL) { attr_input = other.attr_input->clone_attr_input (); } return *this; } // default move semantics Attribute (Attribute &&other) = default; Attribute &operator= (Attribute &&other) = default; // Unique pointer custom clone function ::std::unique_ptr clone_attribute () const { return ::std::unique_ptr (clone_attribute_impl ()); } /*~Attribute() { delete attr_input; }*/ // Creates an empty attribute (which is invalid) static Attribute create_empty () { return Attribute (SimplePath::create_empty (), NULL); } // Returns whether the attribute is considered an "empty" attribute. inline bool is_empty () const { return attr_input == NULL && path.is_empty (); } /* e.g.: #![crate_type = "lib"] #[test] #[cfg(target_os = "linux")] #[allow(non_camel_case_types)] #![allow(unused_variables)] */ // Full built-in attribute list: /* cfg * cfg_attr * test * ignore * should_panic * derive * macro_export * macro_use * proc_macro * proc_macro_derive * proc_macro_attribute * allow * warn * deny * forbid * deprecated * must_use * link * link_name * no_link * repr * crate_type * no_main * export_name * link_section * no_mangle * used * crate_name * inline * cold * no_builtins * target_feature * doc * no_std * no_implicit_prelude * path * recursion_limit * type_length_limit * panic_handler * global_allocator * windows_subsystem * feature */ ::std::string as_string () const; // TODO: does this require visitor pattern as not polymorphic? // Maybe change to const-reference in future SimplePath get_path () const { return path; } // Call to parse attribute body to meta item syntax. void parse_attr_to_meta_item (); // Determines whether cfg predicate is true and item with attribute should not // be stripped. bool check_cfg_predicate (const Session &session) { // assume that cfg predicate actually can exist, i.e. attribute has cfg or // cfg_attr path if (!has_attr_input ()) { return false; } // TODO: maybe replace with storing a "has been parsed" variable? parse_attr_to_meta_item (); // can't be const because of this anyway return attr_input->check_cfg_predicate (session); } protected: // not virtual as currently no subclasses of Attribute, but could be in future /*virtual*/ Attribute *clone_attribute_impl () const { return new Attribute (*this); } }; // Forward decl - defined in rust-macro.h class MetaNameValueStr; // abstract base meta item inner class class MetaItemInner { protected: // pure virtual as MetaItemInner virtual MetaItemInner *clone_meta_item_inner_impl () const = 0; public: // Unique pointer custom clone function ::std::unique_ptr clone_meta_item_inner () const { return ::std::unique_ptr (clone_meta_item_inner_impl ()); } virtual ~MetaItemInner () {} virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; // HACK: used to simplify parsing - creates a copy of that type, or returns // null virtual MetaNameValueStr *to_meta_name_value_str () const { return NULL; } // HACK: used to simplify parsing - same thing virtual SimplePath to_path_item () const { return SimplePath::create_empty (); } virtual bool check_cfg_predicate (const Session &session) const = 0; }; // Container used to store MetaItems as AttrInput (bridge-ish kinda thing) class AttrInputMetaItemContainer : public AttrInput { ::std::vector< ::std::unique_ptr > items; public: AttrInputMetaItemContainer ( ::std::vector< ::std::unique_ptr > items) : items (::std::move (items)) {} // copy constructor with vector clone AttrInputMetaItemContainer (const AttrInputMetaItemContainer &other) { // crappy vector unique pointer clone - TODO is there a better way of doing // this? items.reserve (other.items.size ()); for (const auto &e : other.items) { items.push_back (e->clone_meta_item_inner ()); } } // no destructor definition required // copy assignment operator with vector clone AttrInputMetaItemContainer & operator= (const AttrInputMetaItemContainer &other) { AttrInput::operator= (other); // crappy vector unique pointer clone - TODO is there a better way of doing // this? items.reserve (other.items.size ()); for (const auto &e : other.items) { items.push_back (e->clone_meta_item_inner ()); } return *this; } // default move constructors AttrInputMetaItemContainer (AttrInputMetaItemContainer &&other) = default; AttrInputMetaItemContainer &operator= (AttrInputMetaItemContainer &&other) = default; ::std::string as_string () const OVERRIDE; virtual void accept_vis (ASTVisitor &vis) OVERRIDE; virtual bool check_cfg_predicate (const Session &session) const OVERRIDE; protected: // Use covariance to implement clone function as returning this type virtual AttrInputMetaItemContainer *clone_attr_input_impl () const OVERRIDE { return new AttrInputMetaItemContainer (*this); } }; // abstract base meta item class class MetaItem : public MetaItemInner { }; // Forward decl - defined in rust-expr.h class MetaItemLitExpr; // Forward decl - defined in rust-expr.h class MetaItemPathLit; // Forward decl - defined in rust-macro.h class MetaItemPath; // Forward decl - defined in rust-macro.h class MetaItemSeq; // Forward decl - defined in rust-macro.h class MetaWord; // Forward decl - defined in rust-macro.h class MetaListPaths; // Forward decl - defined in rust-macro.h struct MetaListNameValueStr; /* Base statement abstract class. Note that most "statements" are not allowed in * top-level module scope - only a subclass of statements called "items" are. */ class Stmt { public: // Unique pointer custom clone function ::std::unique_ptr clone_stmt () const { return ::std::unique_ptr (clone_stmt_impl ()); } virtual ~Stmt () {} virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; // HACK: slow way of getting location from base expression through virtual // methods. virtual Location get_locus_slow () const { return Location (); } protected: // Clone function implementation as pure virtual method virtual Stmt *clone_stmt_impl () const = 0; }; // Rust "item" AST node (declaration of top-level/module-level allowed stuff) class Item : public Stmt { ::std::vector outer_attrs; // TODO: should outer attrs be defined here or in each derived class? public: // Unique pointer custom clone function ::std::unique_ptr clone_item () const { return ::std::unique_ptr (clone_item_impl ()); } ::std::string as_string () const; // Adds crate names to the vector passed by reference, if it can // (polymorphism). virtual void add_crate_name (::std::vector< ::std::string> &names ATTRIBUTE_UNUSED) const {} virtual void accept_vis (ASTVisitor &vis ATTRIBUTE_UNUSED) {} protected: // Constructor Item (::std::vector outer_attribs = ::std::vector ()) : outer_attrs (::std::move (outer_attribs)) {} // Clone function implementation as pure virtual method virtual Item *clone_item_impl () const = 0; /* Save having to specify two clone methods in derived classes by making * statement clone return item clone. Hopefully won't affect performance too * much. */ virtual Item *clone_stmt_impl () const OVERRIDE { return clone_item_impl (); } }; // forward decl of ExprWithoutBlock class ExprWithoutBlock; // Base expression AST node - abstract class Expr { // TODO: move outer attribute data to derived classes? ::std::vector outer_attrs; public: inline const ::std::vector &get_outer_attrs () const { return outer_attrs; } // Unique pointer custom clone function ::std::unique_ptr clone_expr () const { return ::std::unique_ptr (clone_expr_impl ()); } /* TODO: public methods that could be useful: * - get_type() - returns type of expression. set_type() may also be useful * for some? * - evaluate() - evaluates expression if constant? can_evaluate()? */ // HACK: downcasting without dynamic_cast (if possible) via polymorphism - // overrided in subclasses of ExprWithoutBlock virtual ExprWithoutBlock *as_expr_without_block () const { // DEBUG fprintf ( stderr, "clone expr without block returns null and has not been overriden\n"); return NULL; } // TODO: make pure virtual if move out outer attributes to derived classes virtual ::std::string as_string () const; virtual ~Expr () {} // HACK: slow way of getting location from base expression through virtual // methods. virtual Location get_locus_slow () const { return Location (); } virtual void accept_vis (ASTVisitor &vis) = 0; protected: // Constructor Expr (::std::vector outer_attribs = ::std::vector ()) : outer_attrs (::std::move (outer_attribs)) {} // Clone function implementation as pure virtual method virtual Expr *clone_expr_impl () const = 0; // TODO: think of less hacky way to implement this kind of thing // Sets outer attributes. void set_outer_attrs (::std::vector outer_attrs_to_set) { outer_attrs = ::std::move (outer_attrs_to_set); } }; // AST node for an expression without an accompanying block - abstract class ExprWithoutBlock : public Expr { protected: // Constructor ExprWithoutBlock (::std::vector outer_attribs = ::std::vector ()) : Expr (::std::move (outer_attribs)) {} // pure virtual clone implementation virtual ExprWithoutBlock *clone_expr_without_block_impl () const = 0; /* Save having to specify two clone methods in derived classes by making expr * clone * return exprwithoutblock clone. Hopefully won't affect performance too much. */ virtual ExprWithoutBlock *clone_expr_impl () const OVERRIDE { return clone_expr_without_block_impl (); } public: // Unique pointer custom clone function ::std::unique_ptr clone_expr_without_block () const { return ::std::unique_ptr ( clone_expr_without_block_impl ()); } // downcasting hack from expr to use pratt parsing with // parse_expr_without_block virtual ExprWithoutBlock *as_expr_without_block () const OVERRIDE { // DEBUG fprintf (stderr, "about to call the impl for clone expr without block\n"); return clone_expr_without_block_impl (); } }; // HACK: IdentifierExpr, delete when figure out identifier vs expr problem in // Pratt parser Alternatively, identifiers could just be represented as // single-segment paths class IdentifierExpr : public ExprWithoutBlock { public: Identifier ident; Location locus; IdentifierExpr (Identifier ident, Location locus = Location (), ::std::vector outer_attrs = ::std::vector ()) : ExprWithoutBlock (::std::move (outer_attrs)), ident (::std::move (ident)), locus (locus) {} ::std::string as_string () const OVERRIDE { return ident; } Location get_locus () const { return locus; } Location get_locus_slow () const OVERRIDE { return get_locus (); } virtual void accept_vis (ASTVisitor &vis) OVERRIDE; protected: // Clone method implementation virtual IdentifierExpr *clone_expr_without_block_impl () const OVERRIDE { return new IdentifierExpr (*this); } }; // Pattern base AST node class Pattern { public: // Unique pointer custom clone function ::std::unique_ptr clone_pattern () const { return ::std::unique_ptr (clone_pattern_impl ()); } // possible virtual methods: is_refutable() virtual ~Pattern () {} virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; protected: // Clone pattern implementation as pure virtual method virtual Pattern *clone_pattern_impl () const = 0; }; // forward decl for Type class TraitBound; // Base class for types as represented in AST - abstract class Type { public: // Unique pointer custom clone function ::std::unique_ptr clone_type () const { return ::std::unique_ptr (clone_type_impl ()); } // virtual destructor virtual ~Type () {} virtual ::std::string as_string () const = 0; // HACK: convert to trait bound. Virtual method overriden by classes that // enable this. virtual TraitBound *to_trait_bound (bool in_parens ATTRIBUTE_UNUSED) const { return NULL; } // as pointer, shouldn't require definition beforehand, only forward // declaration. virtual void accept_vis (ASTVisitor &vis) = 0; protected: // Clone function implementation as pure virtual method virtual Type *clone_type_impl () const = 0; }; // A type without parentheses? - abstract class TypeNoBounds : public Type { public: // Unique pointer custom clone function ::std::unique_ptr clone_type_no_bounds () const { return ::std::unique_ptr (clone_type_no_bounds_impl ()); } protected: // Clone function implementation as pure virtual method virtual TypeNoBounds *clone_type_no_bounds_impl () const = 0; /* Save having to specify two clone methods in derived classes by making type * clone return typenobounds clone. Hopefully won't affect performance too * much. */ virtual TypeNoBounds *clone_type_impl () const OVERRIDE { return clone_type_no_bounds_impl (); } }; // Abstract base class representing a type param bound - Lifetime and TraitBound // extends it class TypeParamBound { public: virtual ~TypeParamBound () {} // Unique pointer custom clone function ::std::unique_ptr clone_type_param_bound () const { return ::std::unique_ptr (clone_type_param_bound_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; protected: // Clone function implementation as pure virtual method virtual TypeParamBound *clone_type_param_bound_impl () const = 0; }; // Represents a lifetime (and is also a kind of type param bound) class Lifetime : public TypeParamBound { public: enum LifetimeType { NAMED, // corresponds to LIFETIME_OR_LABEL STATIC, // corresponds to 'static WILDCARD // corresponds to '_ }; private: LifetimeType lifetime_type; // TODO: LIFETIME_OR_LABEL (aka lifetime token) is only field // find way of enclosing token or something ::std::string lifetime_name; // only applies for NAMED lifetime_type Location locus; public: // Constructor Lifetime (LifetimeType type, ::std::string name = ::std::string (), Location locus = Location ()) : lifetime_type (type), lifetime_name (::std::move (name)), locus (locus) {} // Creates an "error" lifetime. static Lifetime error () { return Lifetime (NAMED, ::std::string ("")); } // Returns true if the lifetime is in an error state. inline bool is_error () const { return lifetime_type == NAMED && lifetime_name.empty (); } ::std::string as_string () const; virtual void accept_vis (ASTVisitor &vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather // than base virtual Lifetime *clone_type_param_bound_impl () const OVERRIDE { return new Lifetime (*this); } }; // Base generic parameter in AST. Abstract - can be represented by a Lifetime or // Type param class GenericParam { public: virtual ~GenericParam () {} // Unique pointer custom clone function ::std::unique_ptr clone_generic_param () const { return ::std::unique_ptr (clone_generic_param_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; protected: // Clone function implementation as pure virtual method virtual GenericParam *clone_generic_param_impl () const = 0; }; // A lifetime generic parameter (as opposed to a type generic parameter) class LifetimeParam : public GenericParam { Lifetime lifetime; // bool has_lifetime_bounds; // LifetimeBounds lifetime_bounds; ::std::vector lifetime_bounds; // inlined LifetimeBounds // bool has_outer_attribute; //::std::unique_ptr outer_attr; Attribute outer_attr; Location locus; public: // Returns whether the lifetime param has any lifetime bounds. inline bool has_lifetime_bounds () const { return !lifetime_bounds.empty (); } // Returns whether the lifetime param has an outer attribute. inline bool has_outer_attribute () const { return !outer_attr.is_empty (); } // Creates an error state lifetime param. static LifetimeParam create_error () { return LifetimeParam (Lifetime::error ()); } // Returns whether the lifetime param is in an error state. inline bool is_error () const { return lifetime.is_error (); } // Constructor LifetimeParam (Lifetime lifetime, Location locus = Location (), ::std::vector lifetime_bounds = ::std::vector (), Attribute outer_attr = Attribute::create_empty ()) : lifetime (::std::move (lifetime)), lifetime_bounds (::std::move (lifetime_bounds)), outer_attr (::std::move (outer_attr)), locus (locus) {} // TODO: remove copy and assignment operator definitions - not required // Copy constructor with clone LifetimeParam (LifetimeParam const &other) : lifetime (other.lifetime), lifetime_bounds (other.lifetime_bounds), outer_attr (other.outer_attr), locus (other.locus) {} // Destructor - define here if required // Overloaded assignment operator to clone attribute LifetimeParam &operator= (LifetimeParam const &other) { lifetime = other.lifetime; lifetime_bounds = other.lifetime_bounds; outer_attr = other.outer_attr; locus = other.locus; return *this; } // move constructors LifetimeParam (LifetimeParam &&other) = default; LifetimeParam &operator= (LifetimeParam &&other) = default; ::std::string as_string () const; virtual void accept_vis (ASTVisitor &vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather // than base virtual LifetimeParam *clone_generic_param_impl () const OVERRIDE { return new LifetimeParam (*this); } }; // A macro item AST node - potentially abstract base class class MacroItem : public Item { /*public: ::std::string as_string() const;*/ protected: MacroItem (::std::vector outer_attribs) : Item (::std::move (outer_attribs)) {} }; // Item used in trait declarations - abstract base class class TraitItem { // bool has_outer_attrs; // TODO: remove and rely on virtual functions and VisItem-derived attributes? //::std::vector outer_attrs; // NOTE: all children should have outer attributes protected: // Constructor /*TraitItem(::std::vector outer_attrs = ::std::vector()) : outer_attrs(::std::move(outer_attrs)) {}*/ // Clone function implementation as pure virtual method virtual TraitItem *clone_trait_item_impl () const = 0; public: virtual ~TraitItem () {} // Returns whether TraitItem has outer attributes. /*inline bool has_outer_attrs() const { return !outer_attrs.empty(); }*/ // Unique pointer custom clone function ::std::unique_ptr clone_trait_item () const { return ::std::unique_ptr (clone_trait_item_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; }; // Abstract base class for items used within an inherent impl block (the impl // name {} one) class InherentImplItem { protected: // Clone function implementation as pure virtual method virtual InherentImplItem *clone_inherent_impl_item_impl () const = 0; public: virtual ~InherentImplItem () {} // Unique pointer custom clone function ::std::unique_ptr clone_inherent_impl_item () const { return ::std::unique_ptr ( clone_inherent_impl_item_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; }; // Abstract base class for items used in a trait impl class TraitImplItem { protected: virtual TraitImplItem *clone_trait_impl_item_impl () const = 0; public: virtual ~TraitImplItem (){}; // Unique pointer custom clone function ::std::unique_ptr clone_trait_impl_item () const { return ::std::unique_ptr (clone_trait_impl_item_impl ()); } virtual ::std::string as_string () const = 0; virtual void accept_vis (ASTVisitor &vis) = 0; }; // A macro invocation item (or statement) AST node (i.e. semi-coloned macro // invocation) class MacroInvocationSemi : public MacroItem, public TraitItem, public InherentImplItem, public TraitImplItem /*, public Statement*/ { // already inherits from statement indirectly via item as item is a subclass // of statement SimplePath path; // all delim types except curly must have invocation end with a semicolon DelimType delim_type; //::std::vector token_trees; ::std::vector< ::std::unique_ptr > token_trees; Location locus; public: ::std::string as_string () const; MacroInvocationSemi ( SimplePath macro_path, DelimType delim_type, ::std::vector< ::std::unique_ptr > token_trees, ::std::vector outer_attribs, Location locus) : MacroItem (::std::move (outer_attribs)), path (::std::move (macro_path)), delim_type (delim_type), token_trees (::std::move (token_trees)), locus (locus) {} /* TODO: possible issue with Item and TraitItem hierarchies both having outer * attributes * - storage inefficiency at least. * Best current idea is to make Item preferred and have TraitItem get virtual * functions for attributes or something. Or just redo the "composition" * approach, but then this prevents polymorphism and would entail redoing * quite a bit of the parser. */ // Copy constructor with vector clone MacroInvocationSemi (MacroInvocationSemi const &other) : MacroItem (other), TraitItem (other), InherentImplItem (other), TraitImplItem (other), path (other.path), delim_type (other.delim_type), locus (other.locus) { // crappy vector unique pointer clone - TODO is there a better way of doing // this? token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) { token_trees.push_back (e->clone_token_tree ()); } } // Overloaded assignment operator to vector clone MacroInvocationSemi &operator= (MacroInvocationSemi const &other) { MacroItem::operator= (other); TraitItem::operator= (other); InherentImplItem::operator= (other); TraitImplItem::operator= (other); path = other.path; delim_type = other.delim_type; locus = other.locus; // crappy vector unique pointer clone - TODO is there a better way of doing // this? token_trees.reserve (other.token_trees.size ()); for (const auto &e : other.token_trees) { token_trees.push_back (e->clone_token_tree ()); } return *this; } // Move constructors MacroInvocationSemi (MacroInvocationSemi &&other) = default; MacroInvocationSemi &operator= (MacroInvocationSemi &&other) = default; virtual void accept_vis (ASTVisitor &vis) OVERRIDE; protected: // Use covariance to implement clone function as returning this object rather // than base virtual MacroInvocationSemi *clone_item_impl () const OVERRIDE { return new MacroInvocationSemi (*this); } // Use covariance to implement clone function as returning this object rather // than base virtual MacroInvocationSemi *clone_inherent_impl_item_impl () const OVERRIDE { return new MacroInvocationSemi (*this); } // Use covariance to implement clone function as returning this object rather // than base virtual MacroInvocationSemi *clone_trait_impl_item_impl () const OVERRIDE { return new MacroInvocationSemi (*this); } // FIXME: remove if item impl virtual override works properly // Use covariance to implement clone function as returning this object rather // than base /*virtual MacroInvocationSemi* clone_statement_impl() const OVERRIDE { return new MacroInvocationSemi(*this); }*/ // Use covariance to implement clone function as returning this object rather // than base virtual MacroInvocationSemi *clone_trait_item_impl () const OVERRIDE { return new MacroInvocationSemi (*this); } }; // A crate AST object - holds all the data for a single compilation unit struct Crate { bool has_utf8bom; bool has_shebang; ::std::vector inner_attrs; //::std::vector items; // dodgy spacing required here // TODO: is it better to have a vector of items here or a module (implicit // top-level one)? ::std::vector< ::std::unique_ptr > items; public: // Constructor Crate (::std::vector< ::std::unique_ptr > items, ::std::vector inner_attrs, bool has_utf8bom = false, bool has_shebang = false) : has_utf8bom (has_utf8bom), has_shebang (has_shebang), inner_attrs (::std::move (inner_attrs)), items (::std::move (items)) {} // Copy constructor with vector clone Crate (Crate const &other) : has_utf8bom (other.has_utf8bom), has_shebang (other.has_shebang), inner_attrs (other.inner_attrs) { // crappy vector unique pointer clone - TODO is there a better way of doing // this? items.reserve (other.items.size ()); for (const auto &e : other.items) { items.push_back (e->clone_item ()); } } ~Crate () = default; // Overloaded assignment operator with vector clone Crate &operator= (Crate const &other) { inner_attrs = other.inner_attrs; has_shebang = other.has_shebang; has_utf8bom = other.has_utf8bom; // crappy vector unique pointer clone - TODO is there a better way of doing // this? items.reserve (other.items.size ()); for (const auto &e : other.items) { items.push_back (e->clone_item ()); } return *this; } // Move constructors Crate (Crate &&other) = default; Crate &operator= (Crate &&other) = default; // Get crate representation as string (e.g. for debugging). ::std::string as_string () const; }; // Base path expression AST node - abstract class PathExpr : public ExprWithoutBlock { protected: PathExpr (::std::vector outer_attribs) : ExprWithoutBlock (::std::move (outer_attribs)) {} public: // TODO: think of a better and less hacky way to allow this // Replaces the outer attributes of this path expression with the given outer // attributes. void replace_outer_attrs (::std::vector outer_attrs) { set_outer_attrs (::std::move (outer_attrs)); } }; } // namespace AST } // namespace Rust #endif