mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Swift will use the basename + argument names formulation for names. Update the DeclName interfaces, printing, and __FUNCTION__ to use the method syntax. We'll still need to rework the "x.foo:bar:wibble:" syntax; that will come (significantly) later. Swift SVN r15763
338 lines
11 KiB
C++
338 lines
11 KiB
C++
//===--- Identifier.h - Uniqued Identifier ----------------------*- C++ -*-===//
|
|
//
|
|
// This source file is part of the Swift.org open source project
|
|
//
|
|
// Copyright (c) 2014 - 2015 Apple Inc. and the Swift project authors
|
|
// Licensed under Apache License v2.0 with Runtime Library Exception
|
|
//
|
|
// See http://swift.org/LICENSE.txt for license information
|
|
// See http://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This file defines the Identifier interface.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#ifndef SWIFT_AST_IDENTIFIER_H
|
|
#define SWIFT_AST_IDENTIFIER_H
|
|
|
|
#include "swift/Basic/LLVM.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/ADT/DenseMapInfo.h"
|
|
#include "llvm/ADT/FoldingSet.h"
|
|
#include "llvm/ADT/PointerUnion.h"
|
|
#include "llvm/ADT/StringRef.h"
|
|
#include <cstring>
|
|
|
|
namespace llvm {
|
|
class raw_ostream;
|
|
}
|
|
|
|
namespace swift {
|
|
class ASTContext;
|
|
|
|
/// DeclRefKind - The kind of reference to an identifier.
|
|
enum class DeclRefKind {
|
|
/// An ordinary reference to an identifier, e.g. 'foo'.
|
|
Ordinary,
|
|
|
|
/// A reference to an identifier as a binary operator, e.g. '+' in 'a+b'.
|
|
BinaryOperator,
|
|
|
|
/// A reference to an identifier as a postfix unary operator, e.g. '++' in
|
|
/// 'a++'.
|
|
PostfixOperator,
|
|
|
|
/// A reference to an identifier as a prefix unary operator, e.g. '--' in
|
|
/// '--a'.
|
|
PrefixOperator
|
|
};
|
|
|
|
/// Identifier - This is an instance of a uniqued identifier created by
|
|
/// ASTContext. It just wraps a nul-terminated "const char*".
|
|
class Identifier {
|
|
friend class ASTContext;
|
|
const char *Pointer;
|
|
|
|
/// Constructor, only accessible by ASTContext, which handles the uniquing.
|
|
explicit Identifier(const char *Ptr) : Pointer(Ptr) {}
|
|
public:
|
|
explicit Identifier() : Pointer(nullptr) {}
|
|
|
|
const char *get() const { return Pointer; }
|
|
|
|
StringRef str() const { return Pointer; }
|
|
|
|
unsigned getLength() const {
|
|
return ::strlen(Pointer);
|
|
}
|
|
|
|
bool empty() const { return Pointer == 0; }
|
|
|
|
/// isOperator - Return true if this identifier is an operator, false if it is
|
|
/// a normal identifier.
|
|
/// FIXME: We should maybe cache this.
|
|
bool isOperator() const {
|
|
if (empty())
|
|
return false;
|
|
if ((unsigned char)Pointer[0] < 0x80)
|
|
return isOperatorStartCodePoint((unsigned char)Pointer[0]);
|
|
|
|
// Handle the high unicode case out of line.
|
|
return isOperatorSlow();
|
|
}
|
|
|
|
/// isOperatorStartCodePoint - Return true if the specified code point is a
|
|
/// valid start of an operator.
|
|
static bool isOperatorStartCodePoint(uint32_t C) {
|
|
// ASCII operator chars.
|
|
static const char OpChars[] = "/=-+*%<>!&|^~.";
|
|
if (C < 0x80)
|
|
return memchr(OpChars, C, sizeof(OpChars) - 1) != 0;
|
|
|
|
// Unicode math, symbol, arrow, dingbat, and line/box drawing chars.
|
|
return (C >= 0x00A1 && C <= 0x00A7)
|
|
|| C == 0x00A9 || C == 0x00AB || C == 0x00AC || C == 0x00AE
|
|
|| C == 0x00B0 || C == 0x00B1 || C == 0x00B6 || C == 0x00BB
|
|
|| C == 0x00BF || C == 0x00D7 || C == 0x00F7
|
|
|| C == 0x2016 || C == 0x2017 || (C >= 0x2020 && C <= 0x2027)
|
|
|| (C >= 0x2030 && C <= 0x203E) || (C >= 0x2041 && C <= 0x2053)
|
|
|| (C >= 0x2055 && C <= 0x205E) || (C >= 0x2190 && C <= 0x23FF)
|
|
|| (C >= 0x2500 && C <= 0x2775) || (C >= 0x2794 && C <= 0x2BFF)
|
|
|| (C >= 0x2E00 && C <= 0x2E7F) || (C >= 0x3001 && C <= 0x3003)
|
|
|| (C >= 0x3008 && C <= 0x3030);
|
|
}
|
|
|
|
/// isOperatorContinuationCodePoint - Return true if the specified code point
|
|
/// is a valid operator code point.
|
|
static bool isOperatorContinuationCodePoint(uint32_t C) {
|
|
// '.' is a special case. It can only appear in '..'.
|
|
if (C == '.')
|
|
return false;
|
|
if (isOperatorStartCodePoint(C))
|
|
return true;
|
|
|
|
// Unicode combining characters.
|
|
return (C >= 0x0300 && C <= 0x036F)
|
|
|| (C >= 0x1DC0 && C <= 0x1DFF)
|
|
|| (C >= 0x20D0 && C <= 0x20FF)
|
|
|| (C >= 0xFE20 && C <= 0xFE2F);
|
|
}
|
|
|
|
void *getAsOpaquePointer() const { return (void *)Pointer; }
|
|
|
|
static Identifier getFromOpaquePointer(void *P) {
|
|
return Identifier((const char*)P);
|
|
}
|
|
|
|
bool operator==(Identifier RHS) const { return Pointer == RHS.Pointer; }
|
|
bool operator!=(Identifier RHS) const { return Pointer != RHS.Pointer; }
|
|
|
|
bool operator<(Identifier RHS) const { return Pointer < RHS.Pointer; }
|
|
|
|
static Identifier getEmptyKey() {
|
|
return Identifier((const char*)
|
|
llvm::DenseMapInfo<const void*>::getEmptyKey());
|
|
}
|
|
static Identifier getTombstoneKey() {
|
|
return Identifier((const char*)
|
|
llvm::DenseMapInfo<const void*>::getTombstoneKey());
|
|
}
|
|
|
|
private:
|
|
bool isOperatorSlow() const;
|
|
};
|
|
|
|
class DeclName;
|
|
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
raw_ostream &operator<<(raw_ostream &OS, swift::Identifier I);
|
|
raw_ostream &operator<<(raw_ostream &OS, swift::DeclName I);
|
|
|
|
// Identifiers hash just like pointers.
|
|
template<> struct DenseMapInfo<swift::Identifier> {
|
|
static swift::Identifier getEmptyKey() {
|
|
return swift::Identifier::getEmptyKey();
|
|
}
|
|
static swift::Identifier getTombstoneKey() {
|
|
return swift::Identifier::getTombstoneKey();
|
|
}
|
|
static unsigned getHashValue(swift::Identifier Val) {
|
|
return DenseMapInfo<const void*>::getHashValue(Val.get());
|
|
}
|
|
static bool isEqual(swift::Identifier LHS, swift::Identifier RHS) {
|
|
return LHS == RHS;
|
|
}
|
|
};
|
|
|
|
// An Identifier is "pointer like".
|
|
template<typename T> class PointerLikeTypeTraits;
|
|
template<>
|
|
class PointerLikeTypeTraits<swift::Identifier> {
|
|
public:
|
|
static inline void *getAsVoidPointer(swift::Identifier I) {
|
|
return (void*)I.get();
|
|
}
|
|
static inline swift::Identifier getFromVoidPointer(void *P) {
|
|
return swift::Identifier::getFromOpaquePointer(P);
|
|
}
|
|
enum { NumLowBitsAvailable = 2 };
|
|
};
|
|
|
|
} // end namespace llvm
|
|
|
|
namespace swift {
|
|
|
|
/// A declaration name, which may comprise one or more identifier pieces.
|
|
class DeclName {
|
|
friend class ASTContext;
|
|
|
|
struct alignas(Identifier*) CompoundDeclName : llvm::FoldingSetNode {
|
|
Identifier BaseName;
|
|
size_t NumArgs;
|
|
|
|
explicit CompoundDeclName(Identifier BaseName, size_t NumArgs)
|
|
: BaseName(BaseName), NumArgs(NumArgs) {}
|
|
|
|
ArrayRef<Identifier> getArgumentNames() const {
|
|
return {reinterpret_cast<const Identifier*>(this + 1), NumArgs};
|
|
}
|
|
MutableArrayRef<Identifier> getArgumentNames() {
|
|
return {reinterpret_cast<Identifier*>(this + 1), NumArgs};
|
|
}
|
|
|
|
/// Uniquing for the ASTContext.
|
|
static void Profile(llvm::FoldingSetNodeID &id,
|
|
Identifier baseName,
|
|
ArrayRef<Identifier> argumentNames);
|
|
|
|
void Profile(llvm::FoldingSetNodeID &id) {
|
|
Profile(id, BaseName, getArgumentNames());
|
|
}
|
|
};
|
|
|
|
// Either a single identifier piece stored inline, or a reference to a
|
|
// compound declaration name.
|
|
llvm::PointerUnion<Identifier, CompoundDeclName*> SimpleOrCompound;
|
|
|
|
DeclName(void *Opaque)
|
|
: SimpleOrCompound(decltype(SimpleOrCompound)::getFromOpaqueValue(Opaque))
|
|
{}
|
|
|
|
public:
|
|
/// Build a null name.
|
|
DeclName() : SimpleOrCompound(Identifier()) {}
|
|
|
|
/// Build a simple value name with one component.
|
|
/*implicit*/ DeclName(Identifier simpleName)
|
|
: SimpleOrCompound(simpleName) {}
|
|
|
|
/// Build a compound value name given a base name and a set of argument names.
|
|
DeclName(ASTContext &C, Identifier baseName,
|
|
ArrayRef<Identifier> argumentNames);
|
|
|
|
/// Retrive the 'base' name, i.e., the name that follows the introducer,
|
|
/// such as the 'foo' in 'func foo(x:Int, y:Int)' or the 'bar' in
|
|
/// 'var bar: Int'.
|
|
Identifier getBaseName() const {
|
|
if (auto compound = SimpleOrCompound.dyn_cast<CompoundDeclName*>())
|
|
return compound->BaseName;
|
|
|
|
return SimpleOrCompound.get<Identifier>();
|
|
}
|
|
|
|
/// Retrieve the names of the arguments, if there are any.
|
|
ArrayRef<Identifier> getArgumentNames() const {
|
|
if (auto compound = SimpleOrCompound.dyn_cast<CompoundDeclName*>())
|
|
return compound->getArgumentNames();
|
|
|
|
return { };
|
|
}
|
|
|
|
explicit operator bool() const {
|
|
if (SimpleOrCompound.dyn_cast<CompoundDeclName*>())
|
|
return true;
|
|
return SimpleOrCompound.get<Identifier>().get();
|
|
}
|
|
|
|
/// True if this is a simple one-component name.
|
|
bool isSimpleName() const {
|
|
return !SimpleOrCompound.dyn_cast<CompoundDeclName*>();
|
|
}
|
|
|
|
/// True if this name is a simple one-component name identical to the
|
|
/// given identifier.
|
|
bool isSimpleName(Identifier name) const {
|
|
return isSimpleName() && getBaseName() == name;
|
|
}
|
|
|
|
/// True if this name is a simple one-component name equal to the
|
|
/// given string.
|
|
bool isSimpleName(StringRef name) const {
|
|
return isSimpleName() && getBaseName().str().equals(name);
|
|
}
|
|
|
|
/// True if this name is an operator.
|
|
bool isOperator() const {
|
|
return isSimpleName() && getBaseName().isOperator();
|
|
}
|
|
|
|
/// True if this name should be found by a decl ref or member ref under the
|
|
/// name specified by 'refName'.
|
|
///
|
|
/// We currently match compound names either when their first component
|
|
/// matches a simple name lookup or when the full compound name matches.
|
|
bool matchesRef(DeclName refName) const {
|
|
// Identical names always match.
|
|
if (SimpleOrCompound == refName.SimpleOrCompound)
|
|
return true;
|
|
// If the reference is a simple name, try simple name matching.
|
|
if (refName.isSimpleName())
|
|
return refName.getBaseName() == getBaseName();
|
|
// The names don't match.
|
|
return false;
|
|
}
|
|
|
|
/// Add a DeclName to a lookup table so that it can be found by its simple
|
|
/// name or its compound name.
|
|
template<typename LookupTable, typename Element>
|
|
void addToLookupTable(LookupTable &table, const Element &elt) {
|
|
table[*this].push_back(elt);
|
|
if (!isSimpleName()) {
|
|
table[getBaseName()].push_back(elt);
|
|
}
|
|
}
|
|
|
|
void *getOpaqueValue() const { return SimpleOrCompound.getOpaqueValue(); }
|
|
static DeclName getFromOpaqueValue(void *p) { return DeclName(p); }
|
|
|
|
/// Dump this name to standard error.
|
|
LLVM_ATTRIBUTE_DEPRECATED(void dump(),
|
|
"only for use within the debugger");
|
|
};
|
|
|
|
} // end namespace swift
|
|
|
|
namespace llvm {
|
|
// DeclNames hash just like pointers.
|
|
template<> struct DenseMapInfo<swift::DeclName> {
|
|
static swift::DeclName getEmptyKey() {
|
|
return swift::Identifier::getEmptyKey();
|
|
}
|
|
static swift::DeclName getTombstoneKey() {
|
|
return swift::Identifier::getTombstoneKey();
|
|
}
|
|
static unsigned getHashValue(swift::DeclName Val) {
|
|
return DenseMapInfo<void*>::getHashValue(Val.getOpaqueValue());
|
|
}
|
|
static bool isEqual(swift::DeclName LHS, swift::DeclName RHS) {
|
|
return LHS.getOpaqueValue() == RHS.getOpaqueValue();
|
|
}
|
|
};
|
|
} // end namespace llvm
|
|
|
|
#endif
|