//===--- ParserResult.h - Parser Result Wrapper -----------------*- C++ -*-===// // // This source file is part of the Swift.org open source project // // Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors // Licensed under Apache License v2.0 with Runtime Library Exception // // See https://swift.org/LICENSE.txt for license information // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors // //===----------------------------------------------------------------------===// #ifndef SWIFT_PARSER_PARSER_RESULT_H #define SWIFT_PARSER_PARSER_RESULT_H #include "llvm/ADT/PointerIntPair.h" #include "swift/AST/ParameterList.h" #include namespace swift { class ParserStatus; /// A wrapper for a parser AST node result (Decl, Stmt, Expr, Pattern, /// etc.) /// /// Contains the pointer to the AST node itself (or null) and additional bits /// that indicate: /// \li if there was a parse error; /// \li if there was a code completion token. /// /// If you want to return an AST node pointer in the Parser, consider using /// ParserResult instead. template class ParserResult { llvm::PointerIntPair PtrAndBits; enum { IsError = 0x1, IsCodeCompletion = 0x2, }; template friend class ParserResult; template friend inline ParserResult makeParserResult(ParserStatus Status, U *Result); public: /// Construct a null result with error bit set. ParserResult(std::nullptr_t = nullptr) { setIsParseError(); } /// Construct a null result with specified error bits set. ParserResult(ParserStatus Status); /// Construct a successful parser result. explicit ParserResult(T *Result) : PtrAndBits(Result) { assert(Result && "a successful parser result cannot be null"); } /// Convert from a different but compatible parser result. template ::value>::type> ParserResult(ParserResult Other) : PtrAndBits(Other.PtrAndBits.getPointer(), Other.PtrAndBits.getInt()) {} /// Return true if this result does not have an AST node. /// /// If returns true, then error bit is set. bool isNull() const { return getPtrOrNull() == nullptr; } /// Return true if this result has an AST node. /// /// Note that this does not tell us if there was a parse error or not. bool isNonNull() const { return getPtrOrNull() != nullptr; } /// Return the AST node if non-null. T *get() const { assert(getPtrOrNull() && "not checked for nullptr"); return getPtrOrNull(); } /// Return the AST node or a null pointer. T *getPtrOrNull() const { return PtrAndBits.getPointer(); } /// Return true if there was a parse error that the parser has not yet /// recovered from. /// /// Note that we can still have an AST node which was constructed during /// recovery. bool isParseError() const { return PtrAndBits.getInt() & IsError; } /// Return true if there was a parse error that the parser has not yet /// recovered from, or if we found a code completion token while parsing. /// /// Note that we can still have an AST node which was constructed during /// recovery. bool isParseErrorOrHasCompletion() const { return PtrAndBits.getInt() & (IsError | IsCodeCompletion); } /// Return true if we found a code completion token while parsing this. bool hasCodeCompletion() const { return PtrAndBits.getInt() & IsCodeCompletion; } void setIsParseError() { PtrAndBits.setInt(PtrAndBits.getInt() | IsError); } void setHasCodeCompletionAndIsError() { PtrAndBits.setInt(PtrAndBits.getInt() | IsError | IsCodeCompletion); } private: void setHasCodeCompletion() { PtrAndBits.setInt(PtrAndBits.getInt() | IsCodeCompletion); } }; /// Create a successful parser result. template static inline ParserResult makeParserResult(T *Result) { return ParserResult(Result); } /// Create a result (null or non-null) with error bit set. template static inline ParserResult makeParserErrorResult(T *Result = nullptr) { ParserResult PR; if (Result) PR = ParserResult(Result); PR.setIsParseError(); return PR; } /// Create a result (null or non-null) with error and code completion bits set. template static inline ParserResult makeParserCodeCompletionResult(T *Result = nullptr) { ParserResult PR; if (Result) PR = ParserResult(Result); PR.setHasCodeCompletionAndIsError(); return PR; } /// Same as \c ParserResult, but just the status bits without the AST /// node. /// /// Useful when the AST node is returned by some other means (for example, in /// a vector out parameter). /// /// If you want to use 'bool' as a result type in the Parser, consider using /// ParserStatus instead. class ParserStatus { unsigned IsError : 1; unsigned IsCodeCompletion : 1; public: /// Construct a successful parser status. ParserStatus() : IsError(0), IsCodeCompletion(0) {} /// Construct a parser status with specified bits. template ParserStatus(ParserResult Result) : IsError(0), IsCodeCompletion(0) { if (Result.isParseError()) setIsParseError(); if (Result.hasCodeCompletion()) IsCodeCompletion = true; } /// Return true if either 1) no errors were encountered while parsing this, /// or 2) there were errors but the parser already recovered from them. bool isSuccess() const { return !isError(); } bool isErrorOrHasCompletion() const { return IsError || IsCodeCompletion; } /// Return true if we found a code completion token while parsing this. bool hasCodeCompletion() const { return IsCodeCompletion; } /// Return true if we encountered any errors while parsing this that the /// parser hasn't yet recovered from. bool isError() const { return IsError; } void setIsParseError() { IsError = true; } void setHasCodeCompletion() { IsCodeCompletion = true; } void clearIsError() { IsError = false; } void setHasCodeCompletionAndIsError() { IsError = true; IsCodeCompletion = true; } ParserStatus &operator|=(ParserStatus RHS) { IsError |= RHS.IsError; IsCodeCompletion |= RHS.IsCodeCompletion; return *this; } friend ParserStatus operator|(ParserStatus LHS, ParserStatus RHS) { ParserStatus Result = LHS; Result |= RHS; return Result; } }; /// Create a successful parser status. static inline ParserStatus makeParserSuccess() { return ParserStatus(); } /// Create a status with error bit set. static inline ParserStatus makeParserError() { ParserStatus Status; Status.setIsParseError(); return Status; } /// Create a status with error and code completion bits set. static inline ParserStatus makeParserCodeCompletionStatus() { ParserStatus Status; Status.setHasCodeCompletionAndIsError(); return Status; } /// Create a parser result with specified bits. template static inline ParserResult makeParserResult(ParserStatus Status, T *Result) { ParserResult PR = Status.isError() ? makeParserErrorResult(Result) : makeParserResult(Result); if (Status.hasCodeCompletion()) PR.setHasCodeCompletion(); return PR; } template ParserResult::ParserResult(ParserStatus Status) { assert(Status.isError()); setIsParseError(); if (Status.hasCodeCompletion()) setHasCodeCompletion(); } } // namespace swift #endif // LLVM_SWIFT_PARSER_PARSER_RESULT_H