[llvm] r366001 - FileCheck [7/12]: Arbitrary long numeric expressions
Thomas Preud'homme via llvm-commits
llvm-commits at lists.llvm.org
Sat Jul 13 06:24:31 PDT 2019
Author: thopre
Date: Sat Jul 13 06:24:30 2019
New Revision: 366001
URL: http://llvm.org/viewvc/llvm-project?rev=366001&view=rev
Log:
FileCheck [7/12]: Arbitrary long numeric expressions
Summary:
This patch is part of a patch series to add support for FileCheck
numeric expressions. This specific patch extend numeric expression to
support an arbitrary number of operands, either variable or literals.
Copyright:
- Linaro (changes up to diff 183612 of revision D55940)
- GraphCore (changes in later versions of revision D55940 and
in new revision created off D55940)
Reviewers: jhenderson, chandlerc, jdenny, probinson, grimar, arichardson, rnk
Subscribers: hiraditya, llvm-commits, probinson, dblaikie, grimar, arichardson, tra, rnk, kristina, hfinkel, rogfer01, JonChesterfield
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D60387
Modified:
llvm/trunk/docs/CommandGuide/FileCheck.rst
llvm/trunk/include/llvm/Support/FileCheck.h
llvm/trunk/lib/Support/FileCheck.cpp
llvm/trunk/test/FileCheck/line-count.txt
llvm/trunk/test/FileCheck/numeric-expression.txt
llvm/trunk/test/FileCheck/var-scope.txt
llvm/trunk/unittests/Support/FileCheckTest.cpp
Modified: llvm/trunk/docs/CommandGuide/FileCheck.rst
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/docs/CommandGuide/FileCheck.rst?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/docs/CommandGuide/FileCheck.rst (original)
+++ llvm/trunk/docs/CommandGuide/FileCheck.rst Sat Jul 13 06:24:30 2019
@@ -107,10 +107,12 @@ and from the command line.
Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be
used in ``CHECK:`` lines.
-.. option:: -D#<NUMVAR>=<VALUE>
+.. option:: -D#<NUMVAR>=<VALUE EXPRESSION>
- Sets a filecheck numeric variable ``NUMVAR`` to ``<VALUE>`` that can be used
- in ``CHECK:`` lines.
+ Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating
+ ``<VALUE EXPRESSION>`` that can be used in ``CHECK:`` lines. See section
+ ``FileCheck Numeric Variables and Expressions`` for details on the format
+ and meaning of ``<VALUE EXPRESSION>``.
.. option:: -version
@@ -590,18 +592,15 @@ For example:
would match ``mov r5, 42`` and set ``REG`` to the value ``5``.
-The syntax of a numeric substitution is ``[[#<NUMVAR><op><offset>]]`` where:
+The syntax of a numeric substitution is ``[[#<expr>]]`` where ``<expr>`` is an
+expression. An expression is recursively defined as:
-* ``<NUMVAR>`` is the name of a defined numeric variable.
+* a numeric operand, or
+* an expression followed by an operator and a numeric operand.
-* ``<op>`` is an optional operation to perform on the value of ``<NUMVAR>``.
- Currently supported operations are ``+`` and ``-``.
-
-* ``<offset>`` is the immediate value that constitutes the second operand of
- the operation ``<op>``. It must be present if ``<op>`` is present, absent
- otherwise.
-
-Spaces are accepted before, after and between any of these elements.
+A numeric operand is a previously defined numeric variable, or an integer
+literal. The supported operators are ``+`` and ``-``. Spaces are accepted
+before, after and between any of these elements.
For example:
Modified: llvm/trunk/include/llvm/Support/FileCheck.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/FileCheck.h?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/FileCheck.h (original)
+++ llvm/trunk/include/llvm/Support/FileCheck.h Sat Jul 13 06:24:30 2019
@@ -40,6 +40,54 @@ struct FileCheckRequest {
// Numeric substitution handling code.
//===----------------------------------------------------------------------===//
+/// Base class representing the AST of a given expression.
+class FileCheckExpressionAST {
+public:
+ virtual ~FileCheckExpressionAST() = default;
+
+ /// Evaluates and \returns the value of the expression represented by this
+ /// AST or an error if evaluation fails.
+ virtual Expected<uint64_t> eval() const = 0;
+};
+
+/// Class representing an unsigned literal in the AST of an expression.
+class FileCheckExpressionLiteral : public FileCheckExpressionAST {
+private:
+ /// Actual value of the literal.
+ uint64_t Value;
+
+public:
+ /// Constructs a literal with the specified value.
+ FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {}
+
+ /// \returns the literal's value.
+ Expected<uint64_t> eval() const { return Value; }
+};
+
+/// Class to represent an undefined variable error, which quotes that
+/// variable's name when printed.
+class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> {
+private:
+ StringRef VarName;
+
+public:
+ static char ID;
+
+ FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
+
+ StringRef getVarName() const { return VarName; }
+
+ std::error_code convertToErrorCode() const override {
+ return inconvertibleErrorCode();
+ }
+
+ /// Print name of variable associated with this error.
+ void log(raw_ostream &OS) const override {
+ OS << "\"";
+ OS.write_escaped(VarName) << "\"";
+ }
+};
+
/// Class representing a numeric variable and its associated current value.
class FileCheckNumericVariable {
private:
@@ -81,56 +129,53 @@ public:
size_t getDefLineNumber() { return DefLineNumber; }
};
-/// Type of functions evaluating a given binary operation.
-using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
-
-/// Class to represent an undefined variable error which prints that variable's
-/// name between quotes when printed.
-class FileCheckUndefVarError : public ErrorInfo<FileCheckUndefVarError> {
+/// Class representing the use of a numeric variable in the AST of an
+/// expression.
+class FileCheckNumericVariableUse : public FileCheckExpressionAST {
private:
- StringRef VarName;
-
-public:
- static char ID;
-
- FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
+ /// Name of the numeric variable.
+ StringRef Name;
- StringRef getVarName() const { return VarName; }
+ /// Pointer to the class instance for the variable this use is about.
+ FileCheckNumericVariable *NumericVariable;
- std::error_code convertToErrorCode() const override {
- return inconvertibleErrorCode();
- }
+public:
+ FileCheckNumericVariableUse(StringRef Name,
+ FileCheckNumericVariable *NumericVariable)
+ : Name(Name), NumericVariable(NumericVariable) {}
- /// Print name of variable associated with this error.
- void log(raw_ostream &OS) const override {
- OS << "\"";
- OS.write_escaped(VarName) << "\"";
- }
+ /// \returns the value of the variable referenced by this instance.
+ Expected<uint64_t> eval() const;
};
-/// Class representing an expression consisting of either a single numeric
-/// variable or a binary operation between a numeric variable and an
-/// immediate.
-class FileCheckExpression {
+/// Type of functions evaluating a given binary operation.
+using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
+
+/// Class representing a single binary operation in the AST of an expression.
+class FileCheckASTBinop : public FileCheckExpressionAST {
private:
/// Left operand.
- FileCheckNumericVariable *LeftOp;
+ std::unique_ptr<FileCheckExpressionAST> LeftOperand;
/// Right operand.
- uint64_t RightOp;
+ std::unique_ptr<FileCheckExpressionAST> RightOperand;
/// Pointer to function that can evaluate this binary operation.
binop_eval_t EvalBinop;
public:
- FileCheckExpression(binop_eval_t EvalBinop,
- FileCheckNumericVariable *OperandLeft,
- uint64_t OperandRight)
- : LeftOp(OperandLeft), RightOp(OperandRight), EvalBinop(EvalBinop) {}
-
- /// Evaluates the value of this expression, using EvalBinop to perform the
- /// binary operation it consists of. \returns an error if the numeric
- /// variable used is undefined, or the expression value otherwise.
+ FileCheckASTBinop(binop_eval_t EvalBinop,
+ std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ std::unique_ptr<FileCheckExpressionAST> RightOp)
+ : EvalBinop(EvalBinop) {
+ LeftOperand = std::move(LeftOp);
+ RightOperand = std::move(RightOp);
+ }
+
+ /// Evaluates the value of the binary operation represented by this AST,
+ /// using EvalBinop on the result of recursively evaluating the operands.
+ /// \returns the expression value or an error if an undefined numeric
+ /// variable is used in one of the operands.
Expected<uint64_t> eval() const;
};
@@ -187,15 +232,15 @@ class FileCheckNumericSubstitution : pub
private:
/// Pointer to the class representing the expression whose value is to be
/// substituted.
- FileCheckExpression *Expression;
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
public:
- FileCheckNumericSubstitution(FileCheckPatternContext *Context,
- StringRef ExpressionStr,
- FileCheckExpression *Expression,
+ FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,
+ std::unique_ptr<FileCheckExpressionAST> ExprAST,
size_t InsertIdx)
- : FileCheckSubstitution(Context, ExpressionStr, InsertIdx),
- Expression(Expression) {}
+ : FileCheckSubstitution(Context, Expr, InsertIdx) {
+ ExpressionAST = std::move(ExprAST);
+ }
/// \returns a string containing the result of evaluating the expression in
/// this substitution, or an error if evaluation failed.
@@ -278,10 +323,6 @@ private:
/// 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;
-
/// Vector holding pointers to all parsed numeric variables. Used to
/// automatically free them once they are guaranteed to no longer be used.
std::vector<std::unique_ptr<FileCheckNumericVariable>> NumericVariables;
@@ -313,12 +354,6 @@ public:
void clearLocalVars();
private:
- /// Makes a new expression instance and registers it for destruction when
- /// the context is destroyed.
- FileCheckExpression *makeExpression(binop_eval_t EvalBinop,
- FileCheckNumericVariable *OperandLeft,
- uint64_t OperandRight);
-
/// Makes a new numeric variable and registers it for destruction when the
/// context is destroyed.
template <class... Types>
@@ -333,7 +368,8 @@ private:
/// the context is destroyed.
FileCheckSubstitution *
makeNumericSubstitution(StringRef ExpressionStr,
- FileCheckExpression *Expression, size_t InsertIdx);
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST,
+ size_t InsertIdx);
};
/// Class to represent an error holding a diagnostic with location information
@@ -458,13 +494,20 @@ public:
/// \returns whether \p C is a valid first character for a variable name.
static bool isValidVarNameStart(char C);
+
+ /// Parsing information about a variable.
+ struct VariableProperties {
+ StringRef Name;
+ bool IsPseudo;
+ };
+
/// Parses the string at the start of \p Str for a variable name. \returns
- /// an error holding a diagnostic against \p SM if parsing fail, or the
- /// name of the variable otherwise. In the latter case, sets \p IsPseudo to
- /// indicate if it is a pseudo variable and strips \p Str from the variable
- /// name.
- static Expected<StringRef> parseVariable(StringRef &Str, bool &IsPseudo,
- const SourceMgr &SM);
+ /// a VariableProperties structure holding the variable name and whether it
+ /// is the name of a pseudo variable, or an error holding a diagnostic
+ /// against \p SM if parsing fail. If parsing was successful, also strips
+ /// \p Str from the variable name.
+ static Expected<VariableProperties> parseVariable(StringRef &Str,
+ 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
@@ -473,16 +516,19 @@ public:
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
- /// substitution was successful, sets \p DefinedNumericVariable to point to
- /// the class representing the numeric variable defined in this numeric
+ /// Parses \p Expr for a numeric substitution block. Parameter
+ /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE
+ /// expression. \returns a pointer to the class instance representing the AST
+ /// of the expression whose value must be substituted, or an error holding a
+ /// diagnostic against \p SM if parsing fails. If substitution was
+ /// successful, sets \p DefinedNumericVariable to point to the class
+ /// representing the numeric variable being defined in this numeric
/// substitution block, or None if this block does not define any variable.
- Expected<FileCheckExpression *> parseNumericSubstitutionBlock(
+ Expected<std::unique_ptr<FileCheckExpressionAST>>
+ parseNumericSubstitutionBlock(
StringRef Expr,
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
- const SourceMgr &SM) const;
+ bool IsLegacyLineExpr, const SourceMgr &SM) const;
/// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
/// instance accordingly.
///
@@ -507,7 +553,7 @@ public:
Expected<size_t> match(StringRef Buffer, size_t &MatchLen,
const SourceMgr &SM) const;
/// Prints the value of successful substitutions or the name of the undefined
- /// string or numeric variable preventing a successful substitution.
+ /// string or numeric variables preventing a successful substitution.
void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
SMRange MatchRange = None) const;
void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
@@ -536,16 +582,28 @@ private:
/// was not found.
size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
- /// Parses \p Expr for the use of a numeric variable. \returns the pointer to
- /// the class instance representing that variable if successful, or an error
+ /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use.
+ /// \returns the pointer to the class instance representing that variable if
+ /// successful, or an error holding a diagnostic against \p SM otherwise.
+ Expected<std::unique_ptr<FileCheckNumericVariableUse>>
+ parseNumericVariableUse(StringRef Name, bool IsPseudo,
+ const SourceMgr &SM) const;
+ enum class AllowedOperand { LineVar, Literal, Any };
+ /// Parses \p Expr for use of a numeric operand. Accepts both literal values
+ /// and numeric variables, depending on the value of \p AO. \returns the
+ /// class representing that operand in the AST of the expression or an error
/// holding a diagnostic against \p SM otherwise.
- Expected<FileCheckNumericVariable *>
- parseNumericVariableUse(StringRef &Expr, const SourceMgr &SM) const;
- /// Parses \p Expr for a binary operation.
- /// \returns the class representing the binary operation of the expression,
- /// or an error holding a diagnostic against \p SM otherwise.
- Expected<FileCheckExpression *> parseBinop(StringRef &Expr,
- const SourceMgr &SM) const;
+ Expected<std::unique_ptr<FileCheckExpressionAST>>
+ parseNumericOperand(StringRef &Expr, AllowedOperand AO,
+ const SourceMgr &SM) const;
+ /// Parses \p Expr for a binary operation. The left operand of this binary
+ /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether
+ /// we are parsing a legacy @LINE expression. \returns the class representing
+ /// the binary operation in the AST of the expression, or an error holding a
+ /// diagnostic against \p SM otherwise.
+ Expected<std::unique_ptr<FileCheckExpressionAST>>
+ parseBinop(StringRef &Expr, std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ bool IsLegacyLineExpr, const SourceMgr &SM) const;
};
//===----------------------------------------------------------------------===//
Modified: llvm/trunk/lib/Support/FileCheck.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Support/FileCheck.cpp?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/lib/Support/FileCheck.cpp (original)
+++ llvm/trunk/lib/Support/FileCheck.cpp Sat Jul 13 06:24:30 2019
@@ -35,17 +35,33 @@ void FileCheckNumericVariable::clearValu
Value = None;
}
-Expected<uint64_t> FileCheckExpression::eval() const {
- assert(LeftOp && "Evaluating an empty expression");
- Optional<uint64_t> LeftOpValue = LeftOp->getValue();
- // Variable is undefined.
- if (!LeftOpValue)
- return make_error<FileCheckUndefVarError>(LeftOp->getName());
- return EvalBinop(*LeftOpValue, RightOp);
+Expected<uint64_t> FileCheckNumericVariableUse::eval() const {
+ Optional<uint64_t> Value = NumericVariable->getValue();
+ if (Value)
+ return *Value;
+ return make_error<FileCheckUndefVarError>(Name);
+}
+
+Expected<uint64_t> FileCheckASTBinop::eval() const {
+ Expected<uint64_t> LeftOp = LeftOperand->eval();
+ Expected<uint64_t> RightOp = RightOperand->eval();
+
+ // Bubble up any error (e.g. undefined variables) in the recursive
+ // evaluation.
+ if (!LeftOp || !RightOp) {
+ Error Err = Error::success();
+ if (!LeftOp)
+ Err = joinErrors(std::move(Err), LeftOp.takeError());
+ if (!RightOp)
+ Err = joinErrors(std::move(Err), RightOp.takeError());
+ return std::move(Err);
+ }
+
+ return EvalBinop(*LeftOp, *RightOp);
}
Expected<std::string> FileCheckNumericSubstitution::getResult() const {
- Expected<uint64_t> EvaluatedValue = Expression->eval();
+ Expected<uint64_t> EvaluatedValue = ExpressionAST->eval();
if (!EvaluatedValue)
return EvaluatedValue.takeError();
return utostr(*EvaluatedValue);
@@ -63,15 +79,14 @@ bool FileCheckPattern::isValidVarNameSta
return C == '_' || isalpha(C);
}
-Expected<StringRef> FileCheckPattern::parseVariable(StringRef &Str,
- bool &IsPseudo,
- const SourceMgr &SM) {
+Expected<FileCheckPattern::VariableProperties>
+FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
if (Str.empty())
return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");
bool ParsedOneChar = false;
unsigned I = 0;
- IsPseudo = Str[0] == '@';
+ bool IsPseudo = Str[0] == '@';
// Global vars start with '$'.
if (Str[0] == '$' || IsPseudo)
@@ -89,7 +104,7 @@ Expected<StringRef> FileCheckPattern::pa
StringRef Name = Str.take_front(I);
Str = Str.substr(I);
- return Name;
+ return VariableProperties {Name, IsPseudo};
}
// StringRef holding all characters considered as horizontal whitespaces by
@@ -111,13 +126,12 @@ Expected<FileCheckNumericVariable *>
FileCheckPattern::parseNumericVariableDefinition(
StringRef &Expr, FileCheckPatternContext *Context, size_t LineNumber,
const SourceMgr &SM) {
- bool IsPseudo;
- Expected<StringRef> ParseVarResult = parseVariable(Expr, IsPseudo, SM);
+ Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
if (!ParseVarResult)
return ParseVarResult.takeError();
- StringRef Name = *ParseVarResult;
+ StringRef Name = ParseVarResult->Name;
- if (IsPseudo)
+ if (ParseVarResult->IsPseudo)
return FileCheckErrorDiagnostic::get(
SM, Name, "definition of pseudo numeric variable unsupported");
@@ -143,15 +157,9 @@ FileCheckPattern::parseNumericVariableDe
return DefinedNumericVariable;
}
-Expected<FileCheckNumericVariable *>
-FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
+Expected<std::unique_ptr<FileCheckNumericVariableUse>>
+FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
const SourceMgr &SM) const {
- bool IsPseudo;
- Expected<StringRef> ParseVarResult = parseVariable(Expr, IsPseudo, SM);
- if (!ParseVarResult)
- return ParseVarResult.takeError();
- StringRef Name = *ParseVarResult;
-
if (IsPseudo && !Name.equals("@LINE"))
return FileCheckErrorDiagnostic::get(
SM, Name, "invalid pseudo numeric variable '" + Name + "'");
@@ -178,7 +186,32 @@ FileCheckPattern::parseNumericVariableUs
SM, Name,
"numeric variable '" + Name + "' defined on the same line as used");
- return NumericVariable;
+ return llvm::make_unique<FileCheckNumericVariableUse>(Name, NumericVariable);
+}
+
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
+ const SourceMgr &SM) const {
+ if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
+ // Try to parse as a numeric variable use.
+ Expected<FileCheckPattern::VariableProperties> ParseVarResult =
+ parseVariable(Expr, SM);
+ if (ParseVarResult)
+ return parseNumericVariableUse(ParseVarResult->Name,
+ ParseVarResult->IsPseudo, SM);
+ if (AO == AllowedOperand::LineVar)
+ return ParseVarResult.takeError();
+ // Ignore the error and retry parsing as a literal.
+ consumeError(ParseVarResult.takeError());
+ }
+
+ // Otherwise, parse it as a literal.
+ uint64_t LiteralValue;
+ if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
+ return llvm::make_unique<FileCheckExpressionLiteral>(LiteralValue);
+
+ return FileCheckErrorDiagnostic::get(SM, Expr,
+ "invalid operand format '" + Expr + "'");
}
static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
@@ -189,20 +222,16 @@ static uint64_t sub(uint64_t LeftOp, uin
return LeftOp - RightOp;
}
-Expected<FileCheckExpression *>
-FileCheckPattern::parseBinop(StringRef &Expr, const SourceMgr &SM) const {
- Expected<FileCheckNumericVariable *> LeftParseResult =
- parseNumericVariableUse(Expr, SM);
- if (!LeftParseResult) {
- return LeftParseResult.takeError();
- }
- FileCheckNumericVariable *LeftOp = *LeftParseResult;
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseBinop(StringRef &Expr,
+ std::unique_ptr<FileCheckExpressionAST> LeftOp,
+ bool IsLegacyLineExpr, const SourceMgr &SM) const {
+ Expr = Expr.ltrim(SpaceChars);
+ if (Expr.empty())
+ return std::move(LeftOp);
// Check if this is a supported operation and select a function to perform
// it.
- Expr = Expr.ltrim(SpaceChars);
- if (Expr.empty())
- return Context->makeExpression(add, LeftOp, 0);
SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
char Operator = popFront(Expr);
binop_eval_t EvalBinop;
@@ -223,22 +252,24 @@ FileCheckPattern::parseBinop(StringRef &
if (Expr.empty())
return FileCheckErrorDiagnostic::get(SM, Expr,
"missing operand in expression");
- uint64_t RightOp;
- if (Expr.consumeInteger(10, RightOp))
- return FileCheckErrorDiagnostic::get(
- SM, Expr, "invalid offset in expression '" + Expr + "'");
- Expr = Expr.ltrim(SpaceChars);
- if (!Expr.empty())
- return FileCheckErrorDiagnostic::get(
- SM, Expr, "unexpected characters at end of expression '" + Expr + "'");
+ // The second operand in a legacy @LINE expression is always a literal.
+ AllowedOperand AO =
+ IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> RightOpResult =
+ parseNumericOperand(Expr, AO, SM);
+ if (!RightOpResult)
+ return RightOpResult;
- return Context->makeExpression(EvalBinop, LeftOp, RightOp);
+ Expr = Expr.ltrim(SpaceChars);
+ return llvm::make_unique<FileCheckASTBinop>(EvalBinop, std::move(LeftOp),
+ std::move(*RightOpResult));
}
-Expected<FileCheckExpression *> FileCheckPattern::parseNumericSubstitutionBlock(
+Expected<std::unique_ptr<FileCheckExpressionAST>>
+FileCheckPattern::parseNumericSubstitutionBlock(
StringRef Expr,
Optional<FileCheckNumericVariable *> &DefinedNumericVariable,
- const SourceMgr &SM) const {
+ bool IsLegacyLineExpr, const SourceMgr &SM) const {
// Parse the numeric variable definition.
DefinedNumericVariable = None;
size_t DefEnd = Expr.find(':');
@@ -259,12 +290,29 @@ Expected<FileCheckExpression *> FileChec
return ParseResult.takeError();
DefinedNumericVariable = *ParseResult;
- return Context->makeExpression(add, nullptr, 0);
+ return nullptr;
}
// Parse the expression itself.
Expr = Expr.ltrim(SpaceChars);
- return parseBinop(Expr, SM);
+ // The first operand in a legacy @LINE expression is always the @LINE pseudo
+ // variable.
+ AllowedOperand AO =
+ IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
+ parseNumericOperand(Expr, AO, SM);
+ while (ParseResult && !Expr.empty()) {
+ ParseResult =
+ parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM);
+ // Legacy @LINE expressions only allow 2 operands.
+ if (ParseResult && IsLegacyLineExpr && !Expr.empty())
+ return FileCheckErrorDiagnostic::get(
+ SM, Expr,
+ "unexpected characters at end of expression '" + Expr + "'");
+ }
+ if (!ParseResult)
+ return ParseResult;
+ return std::move(*ParseResult);
}
bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
@@ -375,12 +423,15 @@ bool FileCheckPattern::parsePattern(Stri
PatternStr = UnparsedPatternStr.substr(End + 2);
bool IsDefinition = false;
+ // Whether the substitution block is a legacy use of @LINE with string
+ // substitution block syntax.
+ bool IsLegacyLineExpr = false;
StringRef DefName;
StringRef SubstStr;
StringRef MatchRegexp;
size_t SubstInsertIdx = RegExStr.size();
- // Parse string variable or legacy expression.
+ // Parse string variable or legacy @LINE expression.
if (!IsNumBlock) {
size_t VarEndIdx = MatchStr.find(":");
size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
@@ -391,15 +442,15 @@ bool FileCheckPattern::parsePattern(Stri
}
// Get the name (e.g. "foo") and verify it is well formed.
- bool IsPseudo;
StringRef OrigMatchStr = MatchStr;
- Expected<StringRef> ParseVarResult =
- parseVariable(MatchStr, IsPseudo, SM);
+ Expected<FileCheckPattern::VariableProperties> ParseVarResult =
+ parseVariable(MatchStr, SM);
if (!ParseVarResult) {
logAllUnhandledErrors(ParseVarResult.takeError(), errs());
return true;
}
- StringRef Name = *ParseVarResult;
+ StringRef Name = ParseVarResult->Name;
+ bool IsPseudo = ParseVarResult->IsPseudo;
IsDefinition = (VarEndIdx != StringRef::npos);
if (IsDefinition) {
@@ -424,23 +475,24 @@ bool FileCheckPattern::parsePattern(Stri
} else {
if (IsPseudo) {
MatchStr = OrigMatchStr;
- IsNumBlock = true;
+ IsLegacyLineExpr = IsNumBlock = true;
} else
SubstStr = Name;
}
}
// Parse numeric substitution block.
- FileCheckExpression *Expression;
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST;
Optional<FileCheckNumericVariable *> DefinedNumericVariable;
if (IsNumBlock) {
- Expected<FileCheckExpression *> ParseResult =
- parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, SM);
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ParseResult =
+ parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
+ IsLegacyLineExpr, SM);
if (!ParseResult) {
logAllUnhandledErrors(ParseResult.takeError(), errs());
return true;
}
- Expression = *ParseResult;
+ ExpressionAST = std::move(*ParseResult);
if (DefinedNumericVariable) {
IsDefinition = true;
DefName = (*DefinedNumericVariable)->getName();
@@ -468,8 +520,8 @@ bool FileCheckPattern::parsePattern(Stri
// previous CHECK patterns, and substitution of expressions.
FileCheckSubstitution *Substitution =
IsNumBlock
- ? Context->makeNumericSubstitution(SubstStr, Expression,
- SubstInsertIdx)
+ ? Context->makeNumericSubstitution(
+ SubstStr, std::move(ExpressionAST), SubstInsertIdx)
: Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
Substitutions.push_back(Substitution);
}
@@ -660,7 +712,7 @@ void FileCheckPattern::printSubstitution
Expected<std::string> MatchedValue = Substitution->getResult();
// Substitution failed or is not known at match time, print the undefined
- // variable it uses.
+ // variables it uses.
if (!MatchedValue) {
bool UndefSeen = false;
handleAllErrors(MatchedValue.takeError(),
@@ -669,13 +721,11 @@ void FileCheckPattern::printSubstitution
[](const FileCheckErrorDiagnostic &E) {},
[&](const FileCheckUndefVarError &E) {
if (!UndefSeen) {
- OS << "uses undefined variable ";
+ OS << "uses undefined variable(s):";
UndefSeen = true;
}
+ OS << " ";
E.log(OS);
- },
- [](const ErrorInfoBase &E) {
- llvm_unreachable("Unexpected error");
});
} else {
// Substitution succeeded. Print substituted value.
@@ -768,15 +818,6 @@ FileCheckPatternContext::getPatternVarVa
return VarIter->second;
}
-FileCheckExpression *
-FileCheckPatternContext::makeExpression(binop_eval_t EvalBinop,
- FileCheckNumericVariable *OperandLeft,
- uint64_t OperandRight) {
- Expressions.push_back(llvm::make_unique<FileCheckExpression>(
- EvalBinop, OperandLeft, OperandRight));
- return Expressions.back().get();
-}
-
template <class... Types>
FileCheckNumericVariable *
FileCheckPatternContext::makeNumericVariable(Types... args) {
@@ -794,10 +835,10 @@ FileCheckPatternContext::makeStringSubst
}
FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
- StringRef ExpressionStr, FileCheckExpression *Expression,
- size_t InsertIdx) {
+ StringRef ExpressionStr,
+ std::unique_ptr<FileCheckExpressionAST> ExpressionAST, size_t InsertIdx) {
Substitutions.push_back(llvm::make_unique<FileCheckNumericSubstitution>(
- this, ExpressionStr, Expression, InsertIdx));
+ this, ExpressionStr, std::move(ExpressionAST), InsertIdx));
return Substitutions.back().get();
}
@@ -1777,9 +1818,8 @@ Error FileCheckPatternContext::defineCmd
std::pair<StringRef, StringRef> CmdlineNameVal = CmdlineDef.split('=');
StringRef CmdlineName = CmdlineNameVal.first;
StringRef OrigCmdlineName = CmdlineName;
- bool IsPseudo;
- Expected<StringRef> ParseVarResult =
- FileCheckPattern::parseVariable(CmdlineName, IsPseudo, SM);
+ Expected<FileCheckPattern::VariableProperties> ParseVarResult =
+ FileCheckPattern::parseVariable(CmdlineName, SM);
if (!ParseVarResult) {
Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
continue;
@@ -1787,7 +1827,7 @@ Error FileCheckPatternContext::defineCmd
// Check that CmdlineName does not denote a pseudo variable is only
// composed of the parsed numeric variable. This catches cases like
// "FOO+2" in a "FOO+2=10" definition.
- if (IsPseudo || !CmdlineName.empty()) {
+ if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
Errs = joinErrors(std::move(Errs),
FileCheckErrorDiagnostic::get(
SM, OrigCmdlineName,
@@ -1795,7 +1835,7 @@ Error FileCheckPatternContext::defineCmd
OrigCmdlineName + "'"));
continue;
}
- StringRef Name = *ParseVarResult;
+ StringRef Name = ParseVarResult->Name;
// Detect collisions between string and numeric variables when the former
// is created later than the latter.
Modified: llvm/trunk/test/FileCheck/line-count.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/line-count.txt?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/test/FileCheck/line-count.txt (original)
+++ llvm/trunk/test/FileCheck/line-count.txt Sat Jul 13 06:24:30 2019
@@ -50,7 +50,7 @@
50 ERR9: line-count.txt:[[#@LINE-1]]:17: error: unsupported operation '*'
51
52 BAD10: [[@LINE-x]]
-53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid offset in expression 'x'
+53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid operand format 'x'
54
55 BAD11: [[@LINE-1x]]
56 ERR11: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of expression 'x'
Modified: llvm/trunk/test/FileCheck/numeric-expression.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/numeric-expression.txt?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/test/FileCheck/numeric-expression.txt (original)
+++ llvm/trunk/test/FileCheck/numeric-expression.txt Sat Jul 13 06:24:30 2019
@@ -59,8 +59,8 @@ CHECK-NEXT: [[# VAR1 -1]]
CHECK-NEXT: [[# VAR1 - 1]]
CHECK-NEXT: [[# VAR1 - 1 ]]
-; Numeric expressions using variables defined on the command-line and an
-; immediate interpreted as an unsigned value.
+; Numeric expressions using variables defined on other lines and an immediate
+; interpreted as an unsigned value.
; Note: 9223372036854775819 = 0x8000000000000000 + 11
; 9223372036854775808 = 0x8000000000000000
USE UNSIGNED IMM
@@ -68,21 +68,29 @@ USE UNSIGNED IMM
CHECK-LABEL: USE UNSIGNED IMM
CHECK-NEXT: [[#VAR1+9223372036854775808]]
-; Numeric expression using undefined variable.
+; Numeric expressions using more than one variable defined on other lines.
+USE MULTI VAR
+31
+42
+CHECK-LABEL: USE MULTI VAR
+CHECK-NEXT: [[#VAR2:]]
+CHECK-NEXT: [[#VAR1+VAR2]]
+
+; Numeric expression using undefined variables.
RUN: not FileCheck --check-prefix UNDEF-USE --input-file %s %s 2>&1 \
RUN: | FileCheck --strict-whitespace --check-prefix UNDEF-USE-MSG %s
UNDEF VAR USE
UNDEFVAR: 11
UNDEF-USE-LABEL: UNDEF VAR USE
-UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR]]
+UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR1+UNDEFVAR2]]
UNDEF-USE-MSG: numeric-expression.txt:[[#@LINE-1]]:17: error: {{U}}NDEF-USE-NEXT: expected string not found in input
-UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR\]\]}}
+UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR1\+UNDEFVAR2\]\]}}
UNDEF-USE-MSG-NEXT: {{^ \^$}}
UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-6]]:1: note: scanning from here
UNDEF-USE-MSG-NEXT: UNDEFVAR: 11
UNDEF-USE-MSG-NEXT: {{^\^$}}
-UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-9]]:1: note: uses undefined variable "UNDEFVAR"
+UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-9]]:1: note: uses undefined variable(s): "UNDEFVAR1" "UNDEFVAR2"
UNDEF-USE-MSG-NEXT: UNDEFVAR: 11
UNDEF-USE-MSG-NEXT: {{^\^$}}
Modified: llvm/trunk/test/FileCheck/var-scope.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/FileCheck/var-scope.txt?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/test/FileCheck/var-scope.txt (original)
+++ llvm/trunk/test/FileCheck/var-scope.txt Sat Jul 13 06:24:30 2019
@@ -34,5 +34,5 @@ LOCAL3: [[LOCAL]][[#LOCNUM+2]]
GLOBAL: [[$GLOBAL]][[#$GLOBNUM+2]]
ERRUNDEF: expected string not found in input
-ERRUNDEFLOCAL: uses undefined variable "LOCAL"
-ERRUNDEFLOCNUM: uses undefined variable "LOCNUM"
+ERRUNDEFLOCAL: uses undefined variable(s): "LOCAL"
+ERRUNDEFLOCNUM: uses undefined variable(s): "LOCNUM"
Modified: llvm/trunk/unittests/Support/FileCheckTest.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/unittests/Support/FileCheckTest.cpp?rev=366001&r1=366000&r2=366001&view=diff
==============================================================================
--- llvm/trunk/unittests/Support/FileCheckTest.cpp (original)
+++ llvm/trunk/unittests/Support/FileCheckTest.cpp Sat Jul 13 06:24:30 2019
@@ -8,56 +8,112 @@
#include "llvm/Support/FileCheck.h"
#include "gtest/gtest.h"
+#include <unordered_set>
using namespace llvm;
namespace {
class FileCheckTest : public ::testing::Test {};
+TEST_F(FileCheckTest, Literal) {
+ // Eval returns the literal's value.
+ FileCheckExpressionLiteral Ten(10);
+ Expected<uint64_t> Value = Ten.eval();
+ EXPECT_TRUE(bool(Value));
+ EXPECT_EQ(10U, *Value);
+
+ // Max value can be correctly represented.
+ FileCheckExpressionLiteral Max(std::numeric_limits<uint64_t>::max());
+ Value = Max.eval();
+ EXPECT_TRUE(bool(Value));
+ EXPECT_EQ(std::numeric_limits<uint64_t>::max(), *Value);
+}
+
+static std::string toString(const std::unordered_set<std::string> &Set) {
+ bool First = true;
+ std::string Str;
+ for (StringRef S : Set) {
+ Str += Twine(First ? "{" + S : ", " + S).str();
+ First = false;
+ }
+ Str += '}';
+ return Str;
+}
+
+static void
+expectUndefErrors(std::unordered_set<std::string> ExpectedUndefVarNames,
+ Error Err) {
+ handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
+ ExpectedUndefVarNames.erase(E.getVarName());
+ });
+ EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
+}
+
+static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) {
+ expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err));
+}
+
TEST_F(FileCheckTest, NumericVariable) {
- // Undefined variable: getValue fails, setValue does not trigger assert.
+ // Undefined variable: getValue and eval fail, error returned by eval holds
+ // the name of the undefined variable and setValue does not trigger assert.
FileCheckNumericVariable FooVar = FileCheckNumericVariable(1, "FOO");
EXPECT_EQ("FOO", FooVar.getName());
- llvm::Optional<uint64_t> Value = FooVar.getValue();
- EXPECT_FALSE(Value);
- FooVar.clearValue();
+ FileCheckNumericVariableUse FooVarUse =
+ FileCheckNumericVariableUse("FOO", &FooVar);
+ EXPECT_FALSE(FooVar.getValue());
+ Expected<uint64_t> EvalResult = FooVarUse.eval();
+ EXPECT_FALSE(EvalResult);
+ expectUndefError("FOO", EvalResult.takeError());
FooVar.setValue(42);
- // Defined variable: getValue returns value set.
- Value = FooVar.getValue();
- EXPECT_TRUE(Value);
+ // Defined variable: getValue and eval return value set.
+ Optional<uint64_t> Value = FooVar.getValue();
+ EXPECT_TRUE(bool(Value));
EXPECT_EQ(42U, *Value);
+ EvalResult = FooVarUse.eval();
+ EXPECT_TRUE(bool(EvalResult));
+ EXPECT_EQ(42U, *EvalResult);
- // Clearing variable: getValue fails.
+ // Clearing variable: getValue and eval fail. Error returned by eval holds
+ // the name of the cleared variable.
FooVar.clearValue();
Value = FooVar.getValue();
EXPECT_FALSE(Value);
+ EvalResult = FooVarUse.eval();
+ EXPECT_FALSE(EvalResult);
+ expectUndefError("FOO", EvalResult.takeError());
}
uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
-static void expectUndefError(const Twine &ExpectedStr, Error Err) {
- handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
- EXPECT_EQ(ExpectedStr.str(), E.getVarName());
- });
-}
-
-TEST_F(FileCheckTest, Expression) {
+TEST_F(FileCheckTest, Binop) {
FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
- FileCheckExpression Expression = FileCheckExpression(doAdd, &FooVar, 18);
+ std::unique_ptr<FileCheckNumericVariableUse> FooVarUse =
+ llvm::make_unique<FileCheckNumericVariableUse>("FOO", &FooVar);
+ FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 18);
+ std::unique_ptr<FileCheckNumericVariableUse> BarVarUse =
+ llvm::make_unique<FileCheckNumericVariableUse>("BAR", &BarVar);
+ FileCheckASTBinop Binop =
+ FileCheckASTBinop(doAdd, std::move(FooVarUse), std::move(BarVarUse));
// Defined variable: eval returns right value.
- Expected<uint64_t> Value = Expression.eval();
+ Expected<uint64_t> Value = Binop.eval();
EXPECT_TRUE(bool(Value));
EXPECT_EQ(60U, *Value);
- // Undefined variable: eval fails, undefined variable returned. We call
- // getUndefVarName first to check that it can be called without calling
- // eval() first.
+ // 1 undefined variable: eval fails, error contains name of undefined
+ // variable.
FooVar.clearValue();
- Error EvalError = Expression.eval().takeError();
- EXPECT_TRUE(errorToBool(std::move(EvalError)));
- expectUndefError("FOO", std::move(EvalError));
+ Value = Binop.eval();
+ EXPECT_FALSE(Value);
+ expectUndefError("FOO", Value.takeError());
+
+ // 2 undefined variables: eval fails, error contains names of all undefined
+ // variables.
+ BarVar.clearValue();
+ Value = Binop.eval();
+ EXPECT_FALSE(Value);
+ expectUndefErrors({"FOO", "BAR"}, Value.takeError());
}
TEST_F(FileCheckTest, ValidVarNameStart) {
@@ -84,77 +140,69 @@ TEST_F(FileCheckTest, ParseVar) {
SourceMgr SM;
StringRef OrigVarName = bufferize(SM, "GoodVar42");
StringRef VarName = OrigVarName;
- bool IsPseudo = true;
- Expected<StringRef> ParsedName =
- FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
- EXPECT_EQ(*ParsedName, OrigVarName);
+ Expected<FileCheckPattern::VariableProperties> ParsedVarResult =
+ FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
+ EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
EXPECT_TRUE(VarName.empty());
- EXPECT_FALSE(IsPseudo);
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
- EXPECT_EQ(*ParsedName, OrigVarName);
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
+ EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
EXPECT_TRUE(VarName.empty());
- EXPECT_FALSE(IsPseudo);
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
- EXPECT_EQ(*ParsedName, OrigVarName);
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
+ EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
EXPECT_TRUE(VarName.empty());
- EXPECT_TRUE(IsPseudo);
+ EXPECT_TRUE(ParsedVarResult->IsPseudo);
VarName = bufferize(SM, "42BadVar");
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(errorToBool(ParsedName.takeError()));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
VarName = bufferize(SM, "$@");
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(errorToBool(ParsedName.takeError()));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
VarName = OrigVarName = bufferize(SM, "B at dVar");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
EXPECT_EQ(VarName, OrigVarName.substr(1));
- EXPECT_EQ(*ParsedName, "B");
- EXPECT_FALSE(IsPseudo);
+ EXPECT_EQ(ParsedVarResult->Name, "B");
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
VarName = OrigVarName = bufferize(SM, "B$dVar");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
EXPECT_EQ(VarName, OrigVarName.substr(1));
- EXPECT_EQ(*ParsedName, "B");
- EXPECT_FALSE(IsPseudo);
+ EXPECT_EQ(ParsedVarResult->Name, "B");
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
VarName = bufferize(SM, "BadVar+");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
EXPECT_EQ(VarName, "+");
- EXPECT_EQ(*ParsedName, "BadVar");
- EXPECT_FALSE(IsPseudo);
+ EXPECT_EQ(ParsedVarResult->Name, "BadVar");
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
VarName = bufferize(SM, "BadVar-");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
EXPECT_EQ(VarName, "-");
- EXPECT_EQ(*ParsedName, "BadVar");
- EXPECT_FALSE(IsPseudo);
+ EXPECT_EQ(ParsedVarResult->Name, "BadVar");
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
VarName = bufferize(SM, "BadVar:");
- IsPseudo = true;
- ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
- EXPECT_TRUE(bool(ParsedName));
+ ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
+ EXPECT_TRUE(bool(ParsedVarResult));
EXPECT_EQ(VarName, ":");
- EXPECT_EQ(*ParsedName, "BadVar");
- EXPECT_FALSE(IsPseudo);
+ EXPECT_EQ(ParsedVarResult->Name, "BadVar");
+ EXPECT_FALSE(ParsedVarResult->IsPseudo);
}
class PatternTester {
@@ -197,7 +245,7 @@ public:
StringRef ExprBufferRef = bufferize(SM, Expr);
Optional<FileCheckNumericVariable *> DefinedNumericVariable;
return errorToBool(P.parseNumericSubstitutionBlock(
- ExprBufferRef, DefinedNumericVariable, SM)
+ ExprBufferRef, DefinedNumericVariable, false, SM)
.takeError());
}
@@ -269,15 +317,12 @@ TEST_F(FileCheckTest, ParseExpr) {
// Missing offset operand.
EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
- // Cannot parse offset operand.
- EXPECT_TRUE(Tester.parseSubstExpect("@LINE+x"));
-
- // Unexpected string at end of numeric expression.
- EXPECT_TRUE(Tester.parseSubstExpect("@LINE+5x"));
-
// Valid expression.
EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
+ Tester.initNextPattern();
+ EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]"));
+ EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]"));
}
TEST_F(FileCheckTest, ParsePattern) {
@@ -306,7 +351,6 @@ TEST_F(FileCheckTest, ParsePattern) {
EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
- EXPECT_TRUE(Tester.parsePatternExpect("[[#2+ at LINE]]"));
EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));
// Valid numeric expressions and numeric variable definition.
@@ -365,35 +409,37 @@ TEST_F(FileCheckTest, Substitution) {
// the right value.
FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 10);
- FileCheckExpression LineExpression = FileCheckExpression(doAdd, &LineVar, 0);
- FileCheckExpression NExpression = FileCheckExpression(doAdd, &NVar, 3);
- FileCheckNumericSubstitution SubstitutionLine =
- FileCheckNumericSubstitution(&Context, "@LINE", &LineExpression, 12);
+ auto LineVarUse =
+ llvm::make_unique<FileCheckNumericVariableUse>("@LINE", &LineVar);
+ auto NVarUse = llvm::make_unique<FileCheckNumericVariableUse>("N", &NVar);
+ FileCheckNumericSubstitution SubstitutionLine = FileCheckNumericSubstitution(
+ &Context, "@LINE", std::move(LineVarUse), 12);
FileCheckNumericSubstitution SubstitutionN =
- FileCheckNumericSubstitution(&Context, "N", &NExpression, 30);
- Expected<std::string> Value = SubstitutionLine.getResult();
- EXPECT_TRUE(bool(Value));
- EXPECT_EQ("42", *Value);
- Value = SubstitutionN.getResult();
- EXPECT_TRUE(bool(Value));
- EXPECT_EQ("13", *Value);
+ FileCheckNumericSubstitution(&Context, "N", std::move(NVarUse), 30);
+ SubstValue = SubstitutionLine.getResult();
+ EXPECT_TRUE(bool(SubstValue));
+ EXPECT_EQ("42", *SubstValue);
+ SubstValue = SubstitutionN.getResult();
+ EXPECT_TRUE(bool(SubstValue));
+ EXPECT_EQ("10", *SubstValue);
- // Substitution of an undefined numeric variable fails.
+ // Substitution of an undefined numeric variable fails, error holds name of
+ // undefined variable.
LineVar.clearValue();
- SubstValue = SubstitutionLine.getResult().takeError();
+ SubstValue = SubstitutionLine.getResult();
EXPECT_FALSE(bool(SubstValue));
expectUndefError("@LINE", SubstValue.takeError());
NVar.clearValue();
- SubstValue = SubstitutionN.getResult().takeError();
+ SubstValue = SubstitutionN.getResult();
EXPECT_FALSE(bool(SubstValue));
expectUndefError("N", SubstValue.takeError());
// Substitution of a defined string variable returns the right value.
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
- Value = StringSubstitution.getResult();
- EXPECT_TRUE(bool(Value));
- EXPECT_EQ("BAR", *Value);
+ SubstValue = StringSubstitution.getResult();
+ EXPECT_TRUE(bool(SubstValue));
+ EXPECT_EQ("BAR", *SubstValue);
}
TEST_F(FileCheckTest, FileCheckContext) {
@@ -456,14 +502,15 @@ TEST_F(FileCheckTest, FileCheckContext)
Expected<StringRef> LocalVar = Cxt.getPatternVarValue(LocalVarStr);
FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
Optional<FileCheckNumericVariable *> DefinedNumericVariable;
- Expected<FileCheckExpression *> Expression = P.parseNumericSubstitutionBlock(
- LocalNumVarRef, DefinedNumericVariable, SM);
- Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
- Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
+ Expected<std::unique_ptr<FileCheckExpressionAST>> ExpressionAST =
+ P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable,
+ /*IsLegacyLineExpr=*/false, SM);
EXPECT_TRUE(bool(LocalVar));
EXPECT_EQ(*LocalVar, "FOO");
- EXPECT_TRUE(bool(Expression));
- Expected<uint64_t> ExpressionVal = (*Expression)->eval();
+ Expected<StringRef> EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
+ Expected<StringRef> UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
+ EXPECT_TRUE(bool(ExpressionAST));
+ Expected<uint64_t> ExpressionVal = (*ExpressionAST)->eval();
EXPECT_TRUE(bool(ExpressionVal));
EXPECT_EQ(*ExpressionVal, 18U);
EXPECT_TRUE(bool(EmptyVar));
@@ -478,12 +525,12 @@ TEST_F(FileCheckTest, FileCheckContext)
// local variables, if it was created before. This is important because local
// variable clearing due to --enable-var-scope happens after numeric
// expressions are linked to the numeric variables they use.
- EXPECT_TRUE(errorToBool((*Expression)->eval().takeError()));
+ EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));
P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
- Expression = P.parseNumericSubstitutionBlock(LocalNumVarRef,
- DefinedNumericVariable, SM);
- EXPECT_TRUE(bool(Expression));
- ExpressionVal = (*Expression)->eval();
+ ExpressionAST = P.parseNumericSubstitutionBlock(
+ LocalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
+ EXPECT_TRUE(bool(ExpressionAST));
+ ExpressionVal = (*ExpressionAST)->eval();
EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
@@ -501,10 +548,10 @@ TEST_F(FileCheckTest, FileCheckContext)
EXPECT_TRUE(bool(GlobalVar));
EXPECT_EQ(*GlobalVar, "BAR");
P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
- Expression = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
- DefinedNumericVariable, SM);
- EXPECT_TRUE(bool(Expression));
- ExpressionVal = (*Expression)->eval();
+ ExpressionAST = P.parseNumericSubstitutionBlock(
+ GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
+ EXPECT_TRUE(bool(ExpressionAST));
+ ExpressionVal = (*ExpressionAST)->eval();
EXPECT_TRUE(bool(ExpressionVal));
EXPECT_EQ(*ExpressionVal, 36U);
@@ -512,10 +559,10 @@ TEST_F(FileCheckTest, FileCheckContext)
Cxt.clearLocalVars();
EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
- Expression = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
- DefinedNumericVariable, SM);
- EXPECT_TRUE(bool(Expression));
- ExpressionVal = (*Expression)->eval();
+ ExpressionAST = P.parseNumericSubstitutionBlock(
+ GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
+ EXPECT_TRUE(bool(ExpressionAST));
+ ExpressionVal = (*ExpressionAST)->eval();
EXPECT_TRUE(bool(ExpressionVal));
EXPECT_EQ(*ExpressionVal, 36U);
}
More information about the llvm-commits
mailing list