Base

This section contains a selection of the definitions declared in the chpl namespace. The entries may not be exhaustive.

class chpl::Context

This class stores the compilation-wide context. Another name for this compilation-wide context is program database. It handles unique’d strings and also stores the results of queries (so that they are are memoized). It tracks dependencies of queries in order to update them appropriately when a dependency changes.

Queries are functions that are written in a stylized manner to interact with the context (aka program database). For example, a parse query might accept as an argument a UniqueString path and return a vector of owned AST nodes. Another example is a query to determine the location of an AST node; it would accept as an argument a BaseAST* and it would return a Location.

When running a query, the query system will manage:
  • checking to see if the query result is already saved and available for reuse

  • recording the queries called by that query as dependencies

To write a query, create a function that uses the QUERY_ macros defined in query-impl.h. The arguments to the function need to be efficient to copy (so UniqueString, ID, Location, and pointers are OK, but e.g. std::vector is not). The function will return a result, which need not be POD and can include AST pointers (but see below). The function needs to be written in a stylized way to interact with the context.

Queries should not have side effects. They should not manipulate global state. Instead, they should return a result that includes all of the output.

For example, here is a query that computes MyResultType from myArg1 and myArg2:

#include "chpl/queries/query-impl.h"

const MyResultType& myQueryFunction(Context* context,
                                    MyArgType MyArg1,
                                    MyOtherArgType MyArg2) {
  QUERY_BEGIN(myQueryFunction, context, myKey1, myKey2)

  // do steps to compute the result
  MyResultType result = ...;
  // if an error is encountered, it can be saved with QUERY_ERROR(error)

  return QUERY_END(result);
}

To call the query, just write e.g. myQueryFunction(context, arg1, arg2).

The query function will check for a result already stored in the program database that can be reused. If a result is reused, QUERY_BEGIN will return that result. If not, the query proceeds to compute the result. When doing so, any queries called will be automatically recorded as dependencies. It will then compare the computed result with the saved result, if any, and in some cases combine the results. Finally, the saved result (which might have been updated) is returned.

Note that a query must currently return a const-reference to the result to be stored in the program database.

There are some requirements on query argument/key types and on result types:

  • argument/key types must have std::hash<KeyType>

  • argument/key types must have std::equal_to<KeyType>

  • result types must have chpl::update<MyResultType> implemented

  • result types must be default constructable

  • If the result contains or refers to any UniqueString, the result type must have chpl::mark<MyResultType> implemented to call mark on the UniqueString(s).

namespace std {
  template<> struct hash<chpl::MyArgType> {
    size_t operator()(const chpl::MyArgType key) const {
      return doSomethingToComputeHash...;
    }
  };
  template<> struct equal_to<chpl::MyArgType> {
    bool operator()(const chpl::MyArgType lhs,
                    const chpl::MyArgType rhs) const {
      return doSomethingToCheckIfEqual...;
    }
  };
}

The process of computing a query and checking to see if it matches a saved result requires that the result type implement chpl::update and possible chpl::mark:

namespace chpl {
  template<> struct update<MyResultType> {
    bool operator()(chpl::MyResultType& keep,
                    chpl::MyResultType& addin) const {
      return doSomethingToCombine...;
    }
    template<> struct mark<MyResultType> {
    void operator()(Context* context,
                    chpl::MyResultType& keep) const {
      keep.markUniqueStrings(context);
    }
  };

On entry to the update function, keep is the current value in the program database and addin is the newly computed value. The update function needs to:

  • store the current, updated result in keep

  • store the unused result in addin

  • return false if keep matched addin – that is, keep did not need to be updated; and true otherwise.

For most result types, return defaultCombine(keep, addin); should be sufficient. In the event that a result is actually a collection of results that owns the elements (for example, when parsing, the result is conceptually a vector of top-level symbol), the combine function should try to update only those elements of keep that changed by swapping in the appropriate elements from addin. This strategy allows later queries that depend on such a result to use pointers to the owned elements and to avoid updating everything if just one element changed.

Queries can return results that contain non-owning pointers to owned results from other queries. However, it is not sufficient to simply use the address of the const & result of the query - that is a location in the map that will not change as the result is updated. Instead, such patterns should use owned to make sure a new heap-allocated value is created.

When working with results containing pointers, the update function should not rely on the contents of these pointers from the keep value. The system will make sure that they refer to valid memory but they might be a combination of old results. Additionally, the system will ensure that any old results being replaced will remain allocated until the garbage collection runs outside of any query.

For example, a parse query might result in a list of owned AST element pointers. A follow-on query, listSymbols, can result in something containing these AST element pointers, but not owning them. In that event, the listSymbols query needs to use a update function that does not look into the AST element pointers. However it can compare the pointers themselves because the parse query will update the pointer if the contents change.

In some situations, the query framework can reuse a result without running the update function for it. That can happen when all dependencies have been checked in this revision and the dependencies are all reused. In that event, the UniqueStrings that are contianed in or referred to by the result need to be marked so that any UniqueStrings not used can be garbage collected. This is accomplished by calling the mark function.

Public Types

enum QueryStatus

Values:

enumerator NOT_CHECKED_NOT_CHANGED
enumerator REUSED
enumerator CHANGED

Public Functions

Context() = default

Create a new AST Context.

~Context()
inline void setErrorHandler(void (*reportError)(const ErrorMessage &err))

Set the error handling function

const char *uniqueCString(const char *s, size_t len)

Get or create a unique string and return it as a C string. If the passed string is NULL, this function will return an empty string.

Unique strings are limited to 2**31 bytes.

The returned string will store len bytes, even if there are interior NULL bytes. It will be NULL terminated either way.

Strings returned by this function will always be aligned to 2 bytes.

The function UniqueString::build returns such a string with a wrapper type. It should be preferred for type safety and to reduce redundant checks.

const char *uniqueCString(const char *s)

Calls uniqueCString with len=strlen(s). This simpler call can be used for C strings that don’t contain zero bytes other than the terminator.

const char *uniqueCStringConcatLen(const char *s1, size_t len1, const char *s2, size_t len2, const char *s3 = nullptr, size_t len3 = 0, const char *s4 = nullptr, size_t len4 = 0, const char *s5 = nullptr, size_t len5 = 0, const char *s6 = nullptr, size_t len6 = 0, const char *s7 = nullptr, size_t len7 = 0, const char *s8 = nullptr, size_t len8 = 0, const char *s9 = nullptr, size_t len9 = 0)

Get or create a unique string by concatenating up to 9 strings with lengths.

const char *uniqueCStringConcat(const char *s1, const char *s2, const char *s3 = nullptr, const char *s4 = nullptr, const char *s5 = nullptr, const char *s6 = nullptr, const char *s7 = nullptr, const char *s8 = nullptr, const char *s9 = nullptr)

Get or create a unique string by concatenating up to 9 strings.

void markUniqueCString(const char *s)

When the context is configured to run with garbage collection enabled, unique strings that are reused need to be marked. This function does that for a C string stored in the map. It will cause program crashes if called on a string that is not the result of one of the uniqueCString calls.

UniqueString filePathForId(ID id)

Return the file path for the file containing this ID.

bool hasFilePathForId(ID id)

Returns true if filePathForId is already populated for this ID.

void advanceToNextRevision(bool prepareToGC)

This function increments the current revision number stored in the context. After it is called, the setters below can be used to provide the input at that revision.

If the prepareToGC argument is true, when processing queries in that revision, will prepare to garbage collect UniqueStrings (by marking elements appropriately).

inline int numQueriesRunThisRevision() const

Returns the number of query bodies executed in this revision.

void collectGarbage()

This function runs garbage collection. It will collect UniqueStrings if the last call to advanceToNextRevision passed prepareToGC=true.

It is an implementation error to call this function while a query is running.

void setFilePathForModuleID(ID moduleID, UniqueString path)

Sets the file path for the given module ID. This is suitable to call from a parse query.

void error(ErrorMessage error)

Note an error for the currently running query and report it with the error handler set by setErrorHandler.

If no query is currently running, it just reports the error.

void error(Location loc, const char *fmt, ...)

Note an error for the currently running query. This is a convenience overload. This version takes in a Location and a printf-style format string.

void error(ID id, const char *fmt, ...)

Note an error for the currently running query. This is a convenience overload. This version takes in an ID and a printf-style format string. The ID is used to compute a Location using parsing::locateId.

void error(const uast::ASTNode *ast, const char *fmt, ...)

Note an error for the currently running query. This is a convenience overload. This version takes in an AST node and a printf-style format string. The AST node is used to compute a Location by using a parsing::locateAst.

void error(const resolution::TypedFnSignature *inFn, const uast::ASTNode *ast, const char *fmt, ...)

Note an error for the currently running query. This is a convenience overload. This version takes in a TypedFnSignature and an AST node and a printf-style format string. The AST node is used to compute a Location by using a parsing::locateAst. The TypedFnSignature is used to print out instantiation information.

template<typename ResultType, typename ...ArgTs>
QueryStatus queryStatus(const ResultType &(*queryFunction)(Context *context, ArgTs...), const std::tuple<ArgTs...> &tupleOfArgs)

Returns: 0 if the query was not checked or changed in this revision 1 if the query was checked but not changed in this revision 2 if the query was changed in this revision

This is intended only as a debugging aid.

Public Static Functions

static size_t lengthForUniqueString(const char *s)

For a unique string, return the length of the string when it was created. It will cause program crashes if called on a string that is not the result of one of the uniqueCString calls.

class chpl::ErrorMessage

This class represents an error/warning message. The message is saved (in the event it needs to be reported again).

Public Functions

ErrorMessage()
ErrorMessage(Location location, std::string message)
ErrorMessage(Location location, const char *message)
void addDetail(ErrorMessage err)
inline bool isEmpty() const
inline Location location() const
inline UniqueString path() const
inline int firstLine() const
inline int firstColumn() const
inline int lastLine() const
inline int lastColumn() const
inline int line() const
inline const std::string &message() const
inline const std::vector<ErrorMessage> &details() const
inline bool operator==(const ErrorMessage &other) const
inline bool operator!=(const ErrorMessage &other) const
void swap(ErrorMessage &other)
void markUniqueStrings(Context *context) const

Public Static Functions

static ErrorMessage vbuild(Location loc, const char *fmt, va_list vl)
static ErrorMessage build(Location loc, const char *fmt, ...)
class chpl::ID

This class represents an ID for an AST node. AST element IDs can be helpful for creating maps with AST elements as keys. All AST nodes have IDs.

Public Functions

ID() = default

Construct an empty ID

inline ID(UniqueString symbolPath, int postOrderId, int numChildIds)

Construct an ID with a symbol path and postorder traversal number

inline UniqueString symbolPath() const

Return a path to the ID symbol scope. For example, a function ‘foo’ declared in a module M would have symbolPath M.foo.

Functions, class/record/union/enum declarations, and modules create new ID symbol scopes.

inline int postOrderId() const

Returns the numbering of this node in a postorder traversal of a symbol’s nodes. When the AST node defines a new ID symbol scope, (as with Function or Module) this will return -1.

inline int numContainedChildren() const

Return the number of ids contained in this node, not including itself. In the postorder traversal numbering, the ids contained appear before the node.

The node with postorder traversal ID postOrderId(Node) - numChildIds() is the first node contained within this node.

E.g. in this notional AST: Node(LeafA LeafB)

LeafA has id 0 and numContainedIds 0 LeafB has id 1 and numContainedIds 0 Node has id 2 and numContainedIds 2

Note that the number of contained children does not include contained IDs with a different symbol scope. So, for example, a module consisting only of a function declaration would have numContainedChildren() == 0.

ID parentSymbolId(Context *context) const

Returns a new ID for the parent symbol ID.

if postOrderId is >= 0, returns the id with postOrderId == -1 if postOrderId is -1, returns the id from removing the last ‘.bla’ part from the symbolPath.

If this ID has no parent, returns an empty ID.

The returned ID always has numContainedChildren() of 0 and it cannot be used with contains(). However it is suitable for use in looking up an ID in a map.

bool contains(const ID &other) const

returns ‘true’ if the AST node with this ID contains the AST node with the other ID, including if they refer to the same AST node.

int compare(const ID &other) const

compare this ID with another ID result < 0 if this < other result == 0 if this == other result > 0 if this > other

inline bool operator==(const ID &other) const
inline bool operator!=(const ID &other) const
inline bool operator<(const ID &other) const
inline bool operator<=(const ID &other) const
inline bool operator>(const ID &other) const
inline bool operator>=(const ID &other) const
inline bool isEmpty() const
inline size_t hash() const
inline void swap(ID &other)
inline void markUniqueStrings(Context *context) const
std::string toString() const
class chpl::Location

This class represents a source location.

Public Functions

Location() = default
inline explicit Location(UniqueString path, int firstLine = -1, int firstColumn = -1, int lastLine = -1, int lastColumn = -1)
inline bool isEmpty() const
inline UniqueString path() const
inline int firstLine() const
inline int firstColumn() const
inline int lastLine() const
inline int lastColumn() const
inline int line() const
inline bool operator==(const Location &other) const
inline bool operator!=(const Location &other) const
inline size_t hash() const
inline void swap(Location &other)
inline void markUniqueStrings(Context *context) const
class chpl::UniqueString

This class represents a unique’d string. Unique’d strings allow: fast == and != not worrying about freeing them

Public Functions

inline UniqueString()

create a UniqueString storing the empty string

inline UniqueString(detail::PODUniqueString s)

create a UniqueString from a PODUniqueString. this constructor intentionally allows implicit conversion.

inline const char *c_str() const

Return the null-terminated string. The returned pointer may refer to invalid memory if the UniqueString goes out of scope.

inline size_t length() const

Return the length of the unique string.

inline const char *astr(Context *context) const

Return the null-terminated string as a pointer to an entry in Context’s string table. This pointer is safe to use after this UniqueString goes out of scope.

inline std::string toString() const

return a std::string containing the string

inline bool isEmpty() const
inline detail::PODUniqueString podUniqueString() const
inline bool startsWith(const char *prefix) const

Checks to see if the string starts with another string.

Note

will not handle prefix strings with embedded '\0' bytes

inline bool startsWith(const UniqueString prefix) const

Checks to see if the string starts with another string.

Note

will not handle prefix strings with embedded '\0' bytes

inline bool startsWith(const std::string &prefix) const

Checks to see if the string starts with another string.

Note

will not handle prefix strings with embedded '\0' bytes

inline bool operator==(const UniqueString other) const
inline bool operator==(const char *other) const

Checks to see if the string contents match a C string.

Note

will only compare up to the first null byte.

inline bool operator!=(const UniqueString other) const
inline bool operator!=(const char *other) const
inline int compare(const UniqueString other) const

Returns: -1 if this string is less than the passed string 0 if they are the same 1 if this string is greater

Note

will only compare up to the first null byte.

inline int compare(const char *other) const
inline size_t hash() const
inline void swap(UniqueString &other)
inline void mark(Context *context) const

Public Static Functions

static inline UniqueString build(Context *context, const char *s)

Get or create a unique string for a NULL-terminated C string. If NULL is provided, this function will return the UniqueString representing “”.

static inline UniqueString buildConcat(Context *context, const char *s1, const char *s2, const char *s3 = nullptr, const char *s4 = nullptr, const char *s5 = nullptr, const char *s6 = nullptr, const char *s7 = nullptr, const char *s8 = nullptr, const char *s9 = nullptr)

Get or create a unique string by concatenating up to 9 input C strings. These input strings cannot contain null bytes other than the null terminator.

static UniqueString build(Context *context, const char *s, size_t len)

Get or create a unique string for a string from a pointer and a length. If the length is 0, this function will return the UniqueString representing “”. The length can be passed to truncate a string. The string can contain zero bytes.

static inline UniqueString build(Context *context, const std::string &s)

Get or create a unique string for a C++ string.

template<typename C>
class chpl::Iterable

Defines a read-only iterator over elements of a container type C

Public Functions

inline Iterable(const C &c)
inline C::const_iterator begin() const
inline C::const_iterator end() const
template<typename T>
using chpl::owned = std::unique_ptr<T>

owned<T> is just a synonym for ‘std::unique_ptr<T>’. It is shorter and uses the Chapel term for it.