You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
593 lines
21 KiB
593 lines
21 KiB
/*
|
|
* Copyright 2010, The Android Open Source Project
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#include "slang_rs_pragma_handler.h"
|
|
|
|
#include <map>
|
|
#include <sstream>
|
|
#include <string>
|
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/Basic/TokenKinds.h"
|
|
|
|
#include "clang/Lex/LiteralSupport.h"
|
|
#include "clang/Lex/Preprocessor.h"
|
|
#include "clang/Lex/Token.h"
|
|
|
|
#include "slang_assert.h"
|
|
#include "slang_rs_context.h"
|
|
#include "slang_rs_export_reduce.h"
|
|
#include "slang_version.h"
|
|
|
|
namespace slang {
|
|
|
|
namespace { // Anonymous namespace
|
|
|
|
class RSExportTypePragmaHandler : public RSPragmaHandler {
|
|
private:
|
|
void handleItem(const std::string &Item) {
|
|
mContext->addPragma(this->getName(), Item);
|
|
mContext->addExportType(Item);
|
|
}
|
|
|
|
public:
|
|
RSExportTypePragmaHandler(llvm::StringRef Name, RSContext *Context)
|
|
: RSPragmaHandler(Name, Context) { }
|
|
|
|
void HandlePragma(clang::Preprocessor &PP,
|
|
clang::PragmaIntroducerKind Introducer,
|
|
clang::Token &FirstToken) {
|
|
this->handleItemListPragma(PP, FirstToken);
|
|
}
|
|
};
|
|
|
|
class RSJavaPackageNamePragmaHandler : public RSPragmaHandler {
|
|
public:
|
|
RSJavaPackageNamePragmaHandler(llvm::StringRef Name, RSContext *Context)
|
|
: RSPragmaHandler(Name, Context) { }
|
|
|
|
void HandlePragma(clang::Preprocessor &PP,
|
|
clang::PragmaIntroducerKind Introducer,
|
|
clang::Token &FirstToken) {
|
|
// FIXME: Need to validate the extracted package name from pragma.
|
|
// Currently "all chars" specified in pragma will be treated as package
|
|
// name.
|
|
//
|
|
// 18.1 The Grammar of the Java Programming Language
|
|
// (http://java.sun.com/docs/books/jls/third_edition/html/syntax.html#18.1)
|
|
//
|
|
// CompilationUnit:
|
|
// [[Annotations] package QualifiedIdentifier ; ] {ImportDeclaration}
|
|
// {TypeDeclaration}
|
|
//
|
|
// QualifiedIdentifier:
|
|
// Identifier { . Identifier }
|
|
//
|
|
// Identifier:
|
|
// IDENTIFIER
|
|
//
|
|
// 3.8 Identifiers
|
|
// (http://java.sun.com/docs/books/jls/third_edition/html/lexical.html#3.8)
|
|
//
|
|
//
|
|
|
|
clang::Token &PragmaToken = FirstToken;
|
|
std::string PackageName;
|
|
|
|
// Skip first token, "java_package_name"
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// Now, the current token must be clang::tok::lpara
|
|
if (PragmaToken.isNot(clang::tok::l_paren))
|
|
return;
|
|
|
|
while (PragmaToken.isNot(clang::tok::eod)) {
|
|
// Lex package name
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
bool Invalid;
|
|
std::string Spelling = PP.getSpelling(PragmaToken, &Invalid);
|
|
if (!Invalid)
|
|
PackageName.append(Spelling);
|
|
|
|
// Pre-mature end (syntax error will be triggered by preprocessor later)
|
|
if (PragmaToken.is(clang::tok::eod) || PragmaToken.is(clang::tok::eof)) {
|
|
break;
|
|
} else {
|
|
// Next token is ')' (end of pragma)
|
|
const clang::Token &NextTok = PP.LookAhead(0);
|
|
if (NextTok.is(clang::tok::r_paren)) {
|
|
mContext->addPragma(this->getName(), PackageName);
|
|
mContext->setReflectJavaPackageName(PackageName);
|
|
// Lex until meets clang::tok::eod
|
|
do {
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
} while (PragmaToken.isNot(clang::tok::eod));
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
class RSReducePragmaHandler : public RSPragmaHandler {
|
|
public:
|
|
RSReducePragmaHandler(llvm::StringRef Name, RSContext *Context)
|
|
: RSPragmaHandler(Name, Context) { }
|
|
|
|
void HandlePragma(clang::Preprocessor &PP,
|
|
clang::PragmaIntroducerKind Introducer,
|
|
clang::Token &FirstToken) override {
|
|
// #pragma rs reduce(name)
|
|
// initializer(initializename)
|
|
// accumulator(accumulatename)
|
|
// combiner(combinename)
|
|
// outconverter(outconvertname)
|
|
// halter(haltname)
|
|
|
|
const clang::SourceLocation PragmaLocation = FirstToken.getLocation();
|
|
|
|
clang::Token &PragmaToken = FirstToken;
|
|
|
|
// Grab "reduce(name)" ("reduce" is already known to be the first
|
|
// token) and all the "keyword(value)" contributions
|
|
KeywordValueMapType KeywordValueMap({std::make_pair(RSExportReduce::KeyReduce, ""),
|
|
std::make_pair(RSExportReduce::KeyInitializer, ""),
|
|
std::make_pair(RSExportReduce::KeyAccumulator, ""),
|
|
std::make_pair(RSExportReduce::KeyCombiner, ""),
|
|
std::make_pair(RSExportReduce::KeyOutConverter, "")});
|
|
if (mContext->getTargetAPI() >= SLANG_FEATURE_GENERAL_REDUCTION_HALTER_API) {
|
|
// Halter functionality has not been released, nor has its
|
|
// specification been finalized with partners. We do not have a
|
|
// specification that extends through the full RenderScript
|
|
// software stack, either.
|
|
KeywordValueMap.insert(std::make_pair(RSExportReduce::KeyHalter, ""));
|
|
}
|
|
while (PragmaToken.is(clang::tok::identifier)) {
|
|
if (!ProcessKeywordAndValue(PP, PragmaToken, KeywordValueMap))
|
|
return;
|
|
}
|
|
|
|
// Make sure there's no end-of-line garbage
|
|
if (PragmaToken.isNot(clang::tok::eod)) {
|
|
PP.Diag(PragmaToken.getLocation(),
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"did not expect '%0' here for '#pragma rs %1'"))
|
|
<< PP.getSpelling(PragmaToken) << getName();
|
|
return;
|
|
}
|
|
|
|
// Make sure we have an accumulator
|
|
if (KeywordValueMap[RSExportReduce::KeyAccumulator].empty()) {
|
|
PP.Diag(PragmaLocation, PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"missing '%0' for '#pragma rs %1'"))
|
|
<< RSExportReduce::KeyAccumulator << getName();
|
|
return;
|
|
}
|
|
|
|
// Make sure the reduction kernel name is unique. (If we were
|
|
// worried there might be a VERY large number of pragmas, then we
|
|
// could do something more efficient than walking a list to search
|
|
// for duplicates.)
|
|
for (auto I = mContext->export_reduce_begin(),
|
|
E = mContext->export_reduce_end();
|
|
I != E; ++I) {
|
|
if ((*I)->getNameReduce() == KeywordValueMap[RSExportReduce::KeyReduce]) {
|
|
PP.Diag(PragmaLocation, PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"reduction kernel '%0' declared multiple "
|
|
"times (first one is at %1)"))
|
|
<< KeywordValueMap[RSExportReduce::KeyReduce]
|
|
<< (*I)->getLocation().printToString(PP.getSourceManager());
|
|
return;
|
|
}
|
|
}
|
|
|
|
// Check API version.
|
|
if (mContext->getTargetAPI() < SLANG_FEATURE_GENERAL_REDUCTION_API) {
|
|
PP.Diag(PragmaLocation,
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"reduction kernels are not supported in SDK levels %0-%1"))
|
|
<< SLANG_MINIMUM_TARGET_API
|
|
<< (SLANG_FEATURE_GENERAL_REDUCTION_API - 1);
|
|
return;
|
|
}
|
|
|
|
// Handle backward reference from pragma (see Backend::HandleTopLevelDecl for forward reference).
|
|
MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyInitializer]);
|
|
MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyAccumulator]);
|
|
MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyCombiner]);
|
|
MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyOutConverter]);
|
|
MarkUsed(PP, KeywordValueMap[RSExportReduce::KeyHalter]);
|
|
|
|
mContext->addExportReduce(RSExportReduce::Create(mContext, PragmaLocation,
|
|
KeywordValueMap[RSExportReduce::KeyReduce],
|
|
KeywordValueMap[RSExportReduce::KeyInitializer],
|
|
KeywordValueMap[RSExportReduce::KeyAccumulator],
|
|
KeywordValueMap[RSExportReduce::KeyCombiner],
|
|
KeywordValueMap[RSExportReduce::KeyOutConverter],
|
|
KeywordValueMap[RSExportReduce::KeyHalter]));
|
|
}
|
|
|
|
private:
|
|
typedef std::map<std::string, std::string> KeywordValueMapType;
|
|
|
|
void MarkUsed(clang::Preprocessor &PP, const std::string &FunctionName) {
|
|
if (FunctionName.empty())
|
|
return;
|
|
|
|
clang::ASTContext &ASTC = mContext->getASTContext();
|
|
clang::TranslationUnitDecl *TUDecl = ASTC.getTranslationUnitDecl();
|
|
slangAssert(TUDecl);
|
|
if (const clang::IdentifierInfo *II = PP.getIdentifierInfo(FunctionName)) {
|
|
for (auto Decl : TUDecl->lookup(II)) {
|
|
clang::FunctionDecl *FDecl = Decl->getAsFunction();
|
|
if (!FDecl || !FDecl->isThisDeclarationADefinition())
|
|
continue;
|
|
// Handle backward reference from pragma (see
|
|
// Backend::HandleTopLevelDecl for forward reference).
|
|
mContext->markUsedByReducePragma(FDecl, RSContext::CheckNameNo);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Return comma-separated list of all keys in the map
|
|
static std::string ListKeywords(const KeywordValueMapType &KeywordValueMap) {
|
|
std::string Ret;
|
|
bool First = true;
|
|
for (auto const &entry : KeywordValueMap) {
|
|
if (First)
|
|
First = false;
|
|
else
|
|
Ret += ", ";
|
|
Ret += "'";
|
|
Ret += entry.first;
|
|
Ret += "'";
|
|
}
|
|
return Ret;
|
|
}
|
|
|
|
// Parse "keyword(value)" and set KeywordValueMap[keyword] = value. (Both
|
|
// "keyword" and "value" are identifiers.)
|
|
// Does both syntactic validation and the following semantic validation:
|
|
// - The keyword must be present in the map.
|
|
// - The map entry for the keyword must not contain a value.
|
|
bool ProcessKeywordAndValue(clang::Preprocessor &PP,
|
|
clang::Token &PragmaToken,
|
|
KeywordValueMapType &KeywordValueMap) {
|
|
// The current token must be an identifier in KeywordValueMap
|
|
KeywordValueMapType::iterator Entry;
|
|
if (PragmaToken.isNot(clang::tok::identifier) ||
|
|
((Entry = KeywordValueMap.find(
|
|
PragmaToken.getIdentifierInfo()->getName())) ==
|
|
KeywordValueMap.end())) {
|
|
// Note that we should never get here for the "reduce" token
|
|
// itself, which should already have been recognized.
|
|
PP.Diag(PragmaToken.getLocation(),
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"did not recognize '%0' for '#pragma %1'; expected one of "
|
|
"the following keywords: %2"))
|
|
<< PragmaToken.getIdentifierInfo()->getName() << getName()
|
|
<< ListKeywords(KeywordValueMap);
|
|
return false;
|
|
}
|
|
// ... and there must be no value for this keyword yet
|
|
if (!Entry->second.empty()) {
|
|
PP.Diag(PragmaToken.getLocation(),
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"more than one '%0' for '#pragma rs %1'"))
|
|
<< Entry->first << getName();
|
|
return false;
|
|
}
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// The current token must be clang::tok::l_paren
|
|
if (PragmaToken.isNot(clang::tok::l_paren)) {
|
|
PP.Diag(PragmaToken.getLocation(),
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"missing '(' after '%0' for '#pragma rs %1'"))
|
|
<< Entry->first << getName();
|
|
return false;
|
|
}
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// The current token must be an identifier (a name)
|
|
if (PragmaToken.isNot(clang::tok::identifier)) {
|
|
PP.Diag(PragmaToken.getLocation(),
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"missing name after '%0(' for '#pragma rs %1'"))
|
|
<< Entry->first << getName();
|
|
return false;
|
|
}
|
|
const std::string Name = PragmaToken.getIdentifierInfo()->getName();
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// The current token must be clang::tok::r_paren
|
|
if (PragmaToken.isNot(clang::tok::r_paren)) {
|
|
PP.Diag(PragmaToken.getLocation(),
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"missing ')' after '%0(%1' for '#pragma rs %2'"))
|
|
<< Entry->first << Name << getName();
|
|
return false;
|
|
}
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// Success
|
|
Entry->second = Name;
|
|
return true;
|
|
}
|
|
};
|
|
|
|
class RSReflectLicensePragmaHandler : public RSPragmaHandler {
|
|
private:
|
|
void handleItem(const std::string &Item) {
|
|
mContext->addPragma(this->getName(), Item);
|
|
mContext->setLicenseNote(Item);
|
|
}
|
|
|
|
public:
|
|
RSReflectLicensePragmaHandler(llvm::StringRef Name, RSContext *Context)
|
|
: RSPragmaHandler(Name, Context) { }
|
|
|
|
void HandlePragma(clang::Preprocessor &PP,
|
|
clang::PragmaIntroducerKind Introducer,
|
|
clang::Token &FirstToken) {
|
|
this->handleOptionalStringLiteralParamPragma(PP, FirstToken);
|
|
}
|
|
};
|
|
|
|
class RSVersionPragmaHandler : public RSPragmaHandler {
|
|
private:
|
|
void handleInt(clang::Preprocessor &PP,
|
|
clang::Token &Tok,
|
|
const int v) {
|
|
if (v != 1) {
|
|
PP.Diag(Tok,
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"pragma for version in source file must be set to 1"));
|
|
mContext->setVersion(1);
|
|
return;
|
|
}
|
|
std::stringstream ss;
|
|
ss << v;
|
|
mContext->addPragma(this->getName(), ss.str());
|
|
mContext->setVersion(v);
|
|
}
|
|
|
|
public:
|
|
RSVersionPragmaHandler(llvm::StringRef Name, RSContext *Context)
|
|
: RSPragmaHandler(Name, Context) { }
|
|
|
|
void HandlePragma(clang::Preprocessor &PP,
|
|
clang::PragmaIntroducerKind Introducer,
|
|
clang::Token &FirstToken) {
|
|
this->handleIntegerParamPragma(PP, FirstToken);
|
|
}
|
|
};
|
|
|
|
// Handles the pragmas rs_fp_full, rs_fp_relaxed, and rs_fp_imprecise.
|
|
// There's one instance of this handler for each of the above values.
|
|
// Only getName() differs between the instances.
|
|
class RSPrecisionPragmaHandler : public RSPragmaHandler {
|
|
public:
|
|
RSPrecisionPragmaHandler(llvm::StringRef Name, RSContext *Context)
|
|
: RSPragmaHandler(Name, Context) {}
|
|
|
|
void HandlePragma(clang::Preprocessor &PP,
|
|
clang::PragmaIntroducerKind Introducer,
|
|
clang::Token &Token) {
|
|
std::string Precision = getName();
|
|
// We are deprecating rs_fp_imprecise.
|
|
if (Precision == "rs_fp_imprecise") {
|
|
PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Warning,
|
|
"rs_fp_imprecise is deprecated. Assuming "
|
|
"rs_fp_relaxed instead."));
|
|
Precision = "rs_fp_relaxed";
|
|
}
|
|
// Check if we have already encountered a precision pragma already.
|
|
std::string PreviousPrecision = mContext->getPrecision();
|
|
if (!PreviousPrecision.empty()) {
|
|
// If the previous specified a different value, it's an error.
|
|
if (PreviousPrecision != Precision) {
|
|
PP.Diag(Token, PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"Multiple float precisions specified. Encountered "
|
|
"%0 previously."))
|
|
<< PreviousPrecision;
|
|
}
|
|
// Otherwise we ignore redundant entries.
|
|
return;
|
|
}
|
|
|
|
mContext->addPragma(Precision, "");
|
|
mContext->setPrecision(Precision);
|
|
}
|
|
};
|
|
|
|
} // namespace
|
|
|
|
void RSPragmaHandler::handleItemListPragma(clang::Preprocessor &PP,
|
|
clang::Token &FirstToken) {
|
|
clang::Token &PragmaToken = FirstToken;
|
|
|
|
// Skip first token, like "export_var"
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// Now, the current token must be clang::tok::lpara
|
|
if (PragmaToken.isNot(clang::tok::l_paren))
|
|
return;
|
|
|
|
while (PragmaToken.isNot(clang::tok::eod)) {
|
|
// Lex variable name
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
if (PragmaToken.is(clang::tok::identifier))
|
|
this->handleItem(PP.getSpelling(PragmaToken));
|
|
else
|
|
break;
|
|
|
|
slangAssert(PragmaToken.isNot(clang::tok::eod));
|
|
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
if (PragmaToken.isNot(clang::tok::comma))
|
|
break;
|
|
}
|
|
}
|
|
|
|
void RSPragmaHandler::handleNonParamPragma(clang::Preprocessor &PP,
|
|
clang::Token &FirstToken) {
|
|
clang::Token &PragmaToken = FirstToken;
|
|
|
|
// Skip first token, like "export_var_all"
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// Should be end immediately
|
|
if (PragmaToken.isNot(clang::tok::eod))
|
|
if (PragmaToken.isNot(clang::tok::r_paren)) {
|
|
PP.Diag(PragmaToken,
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"expected a ')'"));
|
|
return;
|
|
}
|
|
}
|
|
|
|
void RSPragmaHandler::handleOptionalStringLiteralParamPragma(
|
|
clang::Preprocessor &PP, clang::Token &FirstToken) {
|
|
clang::Token &PragmaToken = FirstToken;
|
|
|
|
// Skip first token, like "set_reflect_license"
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// Now, the current token must be clang::tok::lpara
|
|
if (PragmaToken.isNot(clang::tok::l_paren))
|
|
return;
|
|
|
|
// If not ')', eat the following string literal as the license
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
if (PragmaToken.isNot(clang::tok::r_paren)) {
|
|
// Eat the whole string literal
|
|
clang::StringLiteralParser StringLiteral(PragmaToken, PP);
|
|
if (StringLiteral.hadError) {
|
|
// Diagnostics will be generated automatically
|
|
return;
|
|
} else {
|
|
this->handleItem(std::string(StringLiteral.GetString()));
|
|
}
|
|
|
|
// The current token should be clang::tok::r_para
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
if (PragmaToken.isNot(clang::tok::r_paren)) {
|
|
PP.Diag(PragmaToken,
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"expected a ')'"));
|
|
return;
|
|
}
|
|
} else {
|
|
// If no argument, remove the license
|
|
this->handleItem("");
|
|
}
|
|
}
|
|
|
|
void RSPragmaHandler::handleIntegerParamPragma(
|
|
clang::Preprocessor &PP, clang::Token &FirstToken) {
|
|
clang::Token &PragmaToken = FirstToken;
|
|
|
|
// Skip first token, like "version"
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
// Now, the current token must be clang::tok::lpara
|
|
if (PragmaToken.isNot(clang::tok::l_paren)) {
|
|
// If no argument, set the version to 0
|
|
this->handleInt(PP, PragmaToken, 0);
|
|
return;
|
|
}
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
|
|
if (PragmaToken.is(clang::tok::numeric_constant)) {
|
|
llvm::SmallString<128> SpellingBuffer;
|
|
SpellingBuffer.resize(PragmaToken.getLength() + 1);
|
|
llvm::StringRef TokSpelling = PP.getSpelling(PragmaToken, SpellingBuffer);
|
|
clang::NumericLiteralParser NumericLiteral(TokSpelling,
|
|
PragmaToken.getLocation(), PP);
|
|
if (NumericLiteral.hadError) {
|
|
// Diagnostics will be generated automatically
|
|
return;
|
|
} else {
|
|
llvm::APInt Val(32, 0);
|
|
NumericLiteral.GetIntegerValue(Val);
|
|
this->handleInt(PP, PragmaToken, static_cast<int>(Val.getSExtValue()));
|
|
}
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
} else {
|
|
// If no argument, set the version to 0
|
|
this->handleInt(PP, PragmaToken, 0);
|
|
}
|
|
|
|
if (PragmaToken.isNot(clang::tok::r_paren)) {
|
|
PP.Diag(PragmaToken,
|
|
PP.getDiagnostics().getCustomDiagID(
|
|
clang::DiagnosticsEngine::Error,
|
|
"expected a ')'"));
|
|
return;
|
|
}
|
|
|
|
do {
|
|
PP.LexUnexpandedToken(PragmaToken);
|
|
} while (PragmaToken.isNot(clang::tok::eod));
|
|
}
|
|
|
|
void AddPragmaHandlers(clang::Preprocessor &PP, RSContext *RsContext) {
|
|
// For #pragma rs export_type
|
|
PP.AddPragmaHandler("rs",
|
|
new RSExportTypePragmaHandler("export_type", RsContext));
|
|
|
|
// For #pragma rs java_package_name
|
|
PP.AddPragmaHandler(
|
|
"rs", new RSJavaPackageNamePragmaHandler("java_package_name", RsContext));
|
|
|
|
// For #pragma rs reduce
|
|
PP.AddPragmaHandler(
|
|
"rs", new RSReducePragmaHandler(RSExportReduce::KeyReduce, RsContext));
|
|
|
|
// For #pragma rs set_reflect_license
|
|
PP.AddPragmaHandler(
|
|
"rs", new RSReflectLicensePragmaHandler("set_reflect_license", RsContext));
|
|
|
|
// For #pragma version
|
|
PP.AddPragmaHandler(new RSVersionPragmaHandler("version", RsContext));
|
|
|
|
// For #pragma rs_fp*
|
|
PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_full", RsContext));
|
|
PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_relaxed", RsContext));
|
|
PP.AddPragmaHandler(new RSPrecisionPragmaHandler("rs_fp_imprecise", RsContext));
|
|
}
|
|
|
|
|
|
} // namespace slang
|