// Numeric substitution handling code.
//===----------------------------------------------------------------------===//
-/// Class representing a numeric variable with a given value in a numeric
-/// expression. Each definition of a variable gets its own instance of this
-/// class. Variable uses share the same instance as their respective
-/// definition.
+/// Class representing a numeric variable and its associated current value.
class FileCheckNumericVariable {
private:
/// Name of the numeric variable.
StringMap<bool> DefinedVariableTable;
/// When matching a given pattern, this holds the pointers to the classes
- /// representing the last definitions of numeric variables defined in
- /// previous patterns. Earlier definitions of the variables, if any, have
- /// their own class instance not referenced by this table. When matching a
- /// pattern all definitions for that pattern are recorded in the
+ /// representing the numeric variables defined in previous patterns. When
+ /// matching a pattern all definitions for that pattern are recorded in the
/// NumericVariableDefs table in the FileCheckPattern instance of that
/// pattern.
StringMap<FileCheckNumericVariable *> GlobalNumericVariableTable;
+ /// Pointer to the class instance representing the @LINE pseudo variable for
+ /// easily updating its value.
+ FileCheckNumericVariable *LineVariable = nullptr;
+
/// Vector holding pointers to all parsed expressions. Used to automatically
/// free the expressions once they are guaranteed to no longer be used.
std::vector<std::unique_ptr<FileCheckExpression>> Expressions;
Error defineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
SourceMgr &SM);
+ /// Create @LINE pseudo variable. Value is set when pattern are being
+ /// matched.
+ void createLineVariable();
+
/// Undefines local variables (variables whose name does not start with a '$'
/// sign), i.e. removes them from GlobalVariableTable and from
/// GlobalNumericVariableTable and also clears the value of numeric
/// name.
static Expected<StringRef> parseVariable(StringRef &Str, bool &IsPseudo,
const SourceMgr &SM);
- /// Parses \p Expr for the name of a numeric variable to be defined. \returns
- /// an error holding a diagnostic against \p SM should defining such a
- /// variable be invalid, or Success otherwise. In the latter case, sets
- /// \p Name to the name of the parsed numeric variable name.
- static Error parseNumericVariableDefinition(StringRef &Expr, StringRef &Name,
- FileCheckPatternContext *Context,
- const SourceMgr &SM);
+ /// Parses \p Expr for the name of a numeric variable to be defined at line
+ /// \p LineNumber. \returns a pointer to the class instance representing that
+ /// variable, creating it if needed, or an error holding a diagnostic against
+ /// \p SM should defining such a variable be invalid.
+ static Expected<FileCheckNumericVariable *>
+ parseNumericVariableDefinition(StringRef &Expr,
+ FileCheckPatternContext *Context,
+ size_t LineNumber, const SourceMgr &SM);
/// Parses \p Expr for a numeric substitution block. \returns the class
/// representing the AST of the expression whose value must be substituted,
/// or an error holding a diagnostic against \p SM if parsing fails. If
char FileCheckErrorDiagnostic::ID = 0;
char FileCheckNotFoundError::ID = 0;
-Error FileCheckPattern::parseNumericVariableDefinition(
- StringRef &Expr, StringRef &Name, FileCheckPatternContext *Context,
+Expected<FileCheckNumericVariable *>
+FileCheckPattern::parseNumericVariableDefinition(
+ StringRef &Expr, FileCheckPatternContext *Context, size_t LineNumber,
const SourceMgr &SM) {
bool IsPseudo;
Expected<StringRef> ParseVarResult = parseVariable(Expr, IsPseudo, SM);
if (!ParseVarResult)
return ParseVarResult.takeError();
- Name = *ParseVarResult;
+ StringRef Name = *ParseVarResult;
if (IsPseudo)
return FileCheckErrorDiagnostic::get(
return FileCheckErrorDiagnostic::get(
SM, Expr, "unexpected characters after numeric variable name");
- return Error::success();
+ FileCheckNumericVariable *DefinedNumericVariable;
+ auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
+ if (VarTableIter != Context->GlobalNumericVariableTable.end())
+ DefinedNumericVariable = VarTableIter->second;
+ else
+ DefinedNumericVariable = Context->makeNumericVariable(LineNumber, Name);
+
+ return DefinedNumericVariable;
}
Expected<FileCheckNumericVariable *>
// Numeric variable definitions and uses are parsed in the order in which
// they appear in the CHECK patterns. For each definition, the pointer to the
// class instance of the corresponding numeric variable definition is stored
- // in GlobalNumericVariableTable in parsePattern. Therefore, the pointer we
- // get below is for the class instance corresponding to the last definition
- // of this variable use. If we don't find a variable definition we create a
- // dummy one so that parsing can continue. All uses of undefined variables,
- // whether string or numeric, are then diagnosed in printSubstitutions()
- // after failing to match.
+ // in GlobalNumericVariableTable in parsePattern. Therefore, if the pointer
+ // we get below is null, it means no such variable was defined before. When
+ // that happens, we create a dummy variable so that parsing can continue. All
+ // uses of undefined variables, whether string or numeric, are then diagnosed
+ // in printSubstitutions() after failing to match.
auto VarTableIter = Context->GlobalNumericVariableTable.find(Name);
FileCheckNumericVariable *NumericVariable;
if (VarTableIter != Context->GlobalNumericVariableTable.end())
"unexpected string after variable definition: '" + UseExpr + "'");
DefExpr = DefExpr.ltrim(SpaceChars);
- StringRef Name;
- Error Err = parseNumericVariableDefinition(DefExpr, Name, Context, SM);
- if (Err)
- return std::move(Err);
- DefinedNumericVariable = Context->makeNumericVariable(LineNumber, Name);
+ Expected<FileCheckNumericVariable *> ParseResult =
+ parseNumericVariableDefinition(DefExpr, Context, LineNumber, SM);
+ if (!ParseResult)
+ return ParseResult.takeError();
+ DefinedNumericVariable = *ParseResult;
return Context->makeExpression(add, nullptr, 0);
}
PatternLoc = SMLoc::getFromPointer(PatternStr.data());
- // Create fake @LINE pseudo variable definition.
- StringRef LinePseudo = "@LINE";
- uint64_t LineNumber64 = LineNumber;
- FileCheckNumericVariable *LinePseudoVar =
- Context->makeNumericVariable(LinePseudo, LineNumber64);
- Context->GlobalNumericVariableTable[LinePseudo] = LinePseudoVar;
-
if (!(Req.NoCanonicalizeWhiteSpace && Req.MatchFullLines))
// Ignore trailing whitespace.
while (!PatternStr.empty() &&
std::string TmpStr;
if (!Substitutions.empty()) {
TmpStr = RegExStr;
+ Context->LineVariable->setValue(LineNumber);
size_t InsertOffset = 0;
// Substitute all string variables and expressions whose values are only
// Match the newly constructed regex.
RegExToMatch = TmpStr;
+ Context->LineVariable->clearValue();
}
SmallVector<StringRef, 4> MatchInfo;
return {StringRef(), StringRef()};
}
+void FileCheckPatternContext::createLineVariable() {
+ assert(!LineVariable && "@LINE pseudo numeric variable already created");
+ StringRef LineName = "@LINE";
+ LineVariable = makeNumericVariable(0, LineName);
+ GlobalNumericVariableTable[LineName] = LineVariable;
+}
+
bool FileCheck::ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
std::vector<FileCheckString> &CheckStrings) {
Error DefineError =
return true;
}
+ PatternContext.createLineVariable();
+
std::vector<FileCheckPattern> ImplicitNegativeChecks;
for (const auto &PatternString : Req.ImplicitCheckNot) {
// Create a buffer with fake command line content in order to display the
// Numeric variable definition.
if (CmdlineDef[0] == '#') {
StringRef CmdlineName = CmdlineDef.substr(1, EqIdx - 1);
- StringRef VarName;
- Error ErrorDiagnostic = FileCheckPattern::parseNumericVariableDefinition(
- CmdlineName, VarName, this, SM);
- if (ErrorDiagnostic) {
- Errs = joinErrors(std::move(Errs), std::move(ErrorDiagnostic));
+ Expected<FileCheckNumericVariable *> ParseResult =
+ FileCheckPattern::parseNumericVariableDefinition(CmdlineName, this, 0,
+ SM);
+ if (!ParseResult) {
+ Errs = joinErrors(std::move(Errs), ParseResult.takeError());
continue;
}
CmdlineVal + "'"));
continue;
}
- auto DefinedNumericVariable = makeNumericVariable(0, VarName);
+ FileCheckNumericVariable *DefinedNumericVariable = *ParseResult;
DefinedNumericVariable->setValue(Val);
// Record this variable definition.