llvm.org GIT mirror llvm / fd7e210
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 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@366001 91177308-0d34-0410-b5e6-96231b3b80d8 Thomas Preud'homme a month ago
7 changed file(s) with 458 addition(s) and 306 deletion(s). Raw diff Collapse all Expand all
106106 Sets a filecheck pattern variable ``VAR`` with value ``VALUE`` that can be
107107 used in ``CHECK:`` lines.
108108
109 .. option:: -D#=
110
111 Sets a filecheck numeric variable ``NUMVAR`` to ```` that can be used
112 in ``CHECK:`` lines.
109 .. option:: -D#=
110
111 Sets a filecheck numeric variable ``NUMVAR`` to the result of evaluating
112 ```` that can be used in ``CHECK:`` lines. See section
113 ``FileCheck Numeric Variables and Expressions`` for details on the format
114 and meaning of ````.
113115
114116 .. option:: -version
115117
589591
590592 would match ``mov r5, 42`` and set ``REG`` to the value ``5``.
591593
592 The syntax of a numeric substitution is ``[[#]]`` where:
593
594 * ```` is the name of a defined numeric variable.
595
596 * ```` is an optional operation to perform on the value of ````.
597 Currently supported operations are ``+`` and ``-``.
598
599 * ```` is the immediate value that constitutes the second operand of
600 the operation ````. It must be present if ```` is present, absent
601 otherwise.
602
603 Spaces are accepted before, after and between any of these elements.
594 The syntax of a numeric substitution is ``[[#]]`` where ```` is an
595 expression. An expression is recursively defined as:
596
597 * a numeric operand, or
598 * an expression followed by an operator and a numeric operand.
599
600 A numeric operand is a previously defined numeric variable, or an integer
601 literal. The supported operators are ``+`` and ``-``. Spaces are accepted
602 before, after and between any of these elements.
604603
605604 For example:
606605
3939 // Numeric substitution handling code.
4040 //===----------------------------------------------------------------------===//
4141
42 /// Base class representing the AST of a given expression.
43 class FileCheckExpressionAST {
44 public:
45 virtual ~FileCheckExpressionAST() = default;
46
47 /// Evaluates and \returns the value of the expression represented by this
48 /// AST or an error if evaluation fails.
49 virtual Expected eval() const = 0;
50 };
51
52 /// Class representing an unsigned literal in the AST of an expression.
53 class FileCheckExpressionLiteral : public FileCheckExpressionAST {
54 private:
55 /// Actual value of the literal.
56 uint64_t Value;
57
58 public:
59 /// Constructs a literal with the specified value.
60 FileCheckExpressionLiteral(uint64_t Val) : Value(Val) {}
61
62 /// \returns the literal's value.
63 Expected eval() const { return Value; }
64 };
65
66 /// Class to represent an undefined variable error, which quotes that
67 /// variable's name when printed.
68 class FileCheckUndefVarError : public ErrorInfo {
69 private:
70 StringRef VarName;
71
72 public:
73 static char ID;
74
75 FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
76
77 StringRef getVarName() const { return VarName; }
78
79 std::error_code convertToErrorCode() const override {
80 return inconvertibleErrorCode();
81 }
82
83 /// Print name of variable associated with this error.
84 void log(raw_ostream &OS) const override {
85 OS << "\"";
86 OS.write_escaped(VarName) << "\"";
87 }
88 };
89
4290 /// Class representing a numeric variable and its associated current value.
4391 class FileCheckNumericVariable {
4492 private:
80128 size_t getDefLineNumber() { return DefLineNumber; }
81129 };
82130
131 /// Class representing the use of a numeric variable in the AST of an
132 /// expression.
133 class FileCheckNumericVariableUse : public FileCheckExpressionAST {
134 private:
135 /// Name of the numeric variable.
136 StringRef Name;
137
138 /// Pointer to the class instance for the variable this use is about.
139 FileCheckNumericVariable *NumericVariable;
140
141 public:
142 FileCheckNumericVariableUse(StringRef Name,
143 FileCheckNumericVariable *NumericVariable)
144 : Name(Name), NumericVariable(NumericVariable) {}
145
146 /// \returns the value of the variable referenced by this instance.
147 Expected eval() const;
148 };
149
83150 /// Type of functions evaluating a given binary operation.
84151 using binop_eval_t = uint64_t (*)(uint64_t, uint64_t);
85152
86 /// Class to represent an undefined variable error which prints that variable's
87 /// name between quotes when printed.
88 class FileCheckUndefVarError : public ErrorInfo {
89 private:
90 StringRef VarName;
91
92 public:
93 static char ID;
94
95 FileCheckUndefVarError(StringRef VarName) : VarName(VarName) {}
96
97 StringRef getVarName() const { return VarName; }
98
99 std::error_code convertToErrorCode() const override {
100 return inconvertibleErrorCode();
101 }
102
103 /// Print name of variable associated with this error.
104 void log(raw_ostream &OS) const override {
105 OS << "\"";
106 OS.write_escaped(VarName) << "\"";
107 }
108 };
109
110 /// Class representing an expression consisting of either a single numeric
111 /// variable or a binary operation between a numeric variable and an
112 /// immediate.
113 class FileCheckExpression {
153 /// Class representing a single binary operation in the AST of an expression.
154 class FileCheckASTBinop : public FileCheckExpressionAST {
114155 private:
115156 /// Left operand.
116 FileCheckNumericVariable *LeftOp;
157 std::unique_ptr LeftOperand;
117158
118159 /// Right operand.
119 uint64_t RightOp;
160 std::unique_ptr RightOperand;
120161
121162 /// Pointer to function that can evaluate this binary operation.
122163 binop_eval_t EvalBinop;
123164
124165 public:
125 FileCheckExpression(binop_eval_t EvalBinop,
126 FileCheckNumericVariable *OperandLeft,
127 uint64_t OperandRight)
128 : LeftOp(OperandLeft), RightOp(OperandRight), EvalBinop(EvalBinop) {}
129
130 /// Evaluates the value of this expression, using EvalBinop to perform the
131 /// binary operation it consists of. \returns an error if the numeric
132 /// variable used is undefined, or the expression value otherwise.
166 FileCheckASTBinop(binop_eval_t EvalBinop,
167 std::unique_ptr LeftOp,
168 std::unique_ptr RightOp)
169 : EvalBinop(EvalBinop) {
170 LeftOperand = std::move(LeftOp);
171 RightOperand = std::move(RightOp);
172 }
173
174 /// Evaluates the value of the binary operation represented by this AST,
175 /// using EvalBinop on the result of recursively evaluating the operands.
176 /// \returns the expression value or an error if an undefined numeric
177 /// variable is used in one of the operands.
133178 Expected eval() const;
134179 };
135180
186231 private:
187232 /// Pointer to the class representing the expression whose value is to be
188233 /// substituted.
189 FileCheckExpression *Expression;
190
191 public:
192 FileCheckNumericSubstitution(FileCheckPatternContext *Context,
193 StringRef ExpressionStr,
194 FileCheckExpression *Expression,
234 std::unique_ptr ExpressionAST;
235
236 public:
237 FileCheckNumericSubstitution(FileCheckPatternContext *Context, StringRef Expr,
238 std::unique_ptr ExprAST,
195239 size_t InsertIdx)
196 : FileCheckSubstitution(Context, ExpressionStr, InsertIdx),
197 Expression(Expression) {}
240 : FileCheckSubstitution(Context, Expr, InsertIdx) {
241 ExpressionAST = std::move(ExprAST);
242 }
198243
199244 /// \returns a string containing the result of evaluating the expression in
200245 /// this substitution, or an error if evaluation failed.
277322 /// easily updating its value.
278323 FileCheckNumericVariable *LineVariable = nullptr;
279324
280 /// Vector holding pointers to all parsed expressions. Used to automatically
281 /// free the expressions once they are guaranteed to no longer be used.
282 std::vector> Expressions;
283
284325 /// Vector holding pointers to all parsed numeric variables. Used to
285326 /// automatically free them once they are guaranteed to no longer be used.
286327 std::vector> NumericVariables;
312353 void clearLocalVars();
313354
314355 private:
315 /// Makes a new expression instance and registers it for destruction when
316 /// the context is destroyed.
317 FileCheckExpression *makeExpression(binop_eval_t EvalBinop,
318 FileCheckNumericVariable *OperandLeft,
319 uint64_t OperandRight);
320
321356 /// Makes a new numeric variable and registers it for destruction when the
322357 /// context is destroyed.
323358 template
332367 /// the context is destroyed.
333368 FileCheckSubstitution *
334369 makeNumericSubstitution(StringRef ExpressionStr,
335 FileCheckExpression *Expression, size_t InsertIdx);
370 std::unique_ptr ExpressionAST,
371 size_t InsertIdx);
336372 };
337373
338374 /// Class to represent an error holding a diagnostic with location information
457493
458494 /// \returns whether \p C is a valid first character for a variable name.
459495 static bool isValidVarNameStart(char C);
496
497 /// Parsing information about a variable.
498 struct VariableProperties {
499 StringRef Name;
500 bool IsPseudo;
501 };
502
460503 /// Parses the string at the start of \p Str for a variable name. \returns
461 /// an error holding a diagnostic against \p SM if parsing fail, or the
462 /// name of the variable otherwise. In the latter case, sets \p IsPseudo to
463 /// indicate if it is a pseudo variable and strips \p Str from the variable
464 /// name.
465 static Expected parseVariable(StringRef &Str, bool &IsPseudo,
466 const SourceMgr &SM);
504 /// a VariableProperties structure holding the variable name and whether it
505 /// is the name of a pseudo variable, or an error holding a diagnostic
506 /// against \p SM if parsing fail. If parsing was successful, also strips
507 /// \p Str from the variable name.
508 static Expected parseVariable(StringRef &Str,
509 const SourceMgr &SM);
467510 /// Parses \p Expr for the name of a numeric variable to be defined at line
468511 /// \p LineNumber. \returns a pointer to the class instance representing that
469512 /// variable, creating it if needed, or an error holding a diagnostic against
472515 parseNumericVariableDefinition(StringRef &Expr,
473516 FileCheckPatternContext *Context,
474517 size_t LineNumber, const SourceMgr &SM);
475 /// Parses \p Expr for a numeric substitution block. \returns the class
476 /// representing the AST of the expression whose value must be substituted,
477 /// or an error holding a diagnostic against \p SM if parsing fails. If
478 /// substitution was successful, sets \p DefinedNumericVariable to point to
479 /// the class representing the numeric variable defined in this numeric
518 /// Parses \p Expr for a numeric substitution block. Parameter
519 /// \p IsLegacyLineExpr indicates whether \p Expr should be a legacy @LINE
520 /// expression. \returns a pointer to the class instance representing the AST
521 /// of the expression whose value must be substituted, or an error holding a
522 /// diagnostic against \p SM if parsing fails. If substitution was
523 /// successful, sets \p DefinedNumericVariable to point to the class
524 /// representing the numeric variable being defined in this numeric
480525 /// substitution block, or None if this block does not define any variable.
481 Expected<FileCheckExpression *> parseNumericSubstitutionBlock(
526 Expected<std::unique_ptr>
527 parseNumericSubstitutionBlock(
482528 StringRef Expr,
483529 Optional &DefinedNumericVariable,
484 const SourceMgr &SM) const;
530 bool IsLegacyLineExpr, const SourceMgr &SM) const;
485531 /// Parses the pattern in \p PatternStr and initializes this FileCheckPattern
486532 /// instance accordingly.
487533 ///
506552 Expected match(StringRef Buffer, size_t &MatchLen,
507553 const SourceMgr &SM) const;
508554 /// Prints the value of successful substitutions or the name of the undefined
509 /// string or numeric variable preventing a successful substitution.
555 /// string or numeric variables preventing a successful substitution.
510556 void printSubstitutions(const SourceMgr &SM, StringRef Buffer,
511557 SMRange MatchRange = None) const;
512558 void printFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
535581 /// was not found.
536582 size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);
537583
538 /// Parses \p Expr for the use of a numeric variable. \returns the pointer to
539 /// the class instance representing that variable if successful, or an error
584 /// Parses \p Name as a (pseudo if \p IsPseudo is true) numeric variable use.
585 /// \returns the pointer to the class instance representing that variable if
586 /// successful, or an error holding a diagnostic against \p SM otherwise.
587 Expected>
588 parseNumericVariableUse(StringRef Name, bool IsPseudo,
589 const SourceMgr &SM) const;
590 enum class AllowedOperand { LineVar, Literal, Any };
591 /// Parses \p Expr for use of a numeric operand. Accepts both literal values
592 /// and numeric variables, depending on the value of \p AO. \returns the
593 /// class representing that operand in the AST of the expression or an error
540594 /// holding a diagnostic against \p SM otherwise.
541 Expected
542 parseNumericVariableUse(StringRef &Expr, const SourceMgr &SM) const;
543 /// Parses \p Expr for a binary operation.
544 /// \returns the class representing the binary operation of the expression,
545 /// or an error holding a diagnostic against \p SM otherwise.
546 Expected parseBinop(StringRef &Expr,
547 const SourceMgr &SM) const;
595 Expected>
596 parseNumericOperand(StringRef &Expr, AllowedOperand AO,
597 const SourceMgr &SM) const;
598 /// Parses \p Expr for a binary operation. The left operand of this binary
599 /// operation is given in \p LeftOp and \p IsLegacyLineExpr indicates whether
600 /// we are parsing a legacy @LINE expression. \returns the class representing
601 /// the binary operation in the AST of the expression, or an error holding a
602 /// diagnostic against \p SM otherwise.
603 Expected>
604 parseBinop(StringRef &Expr, std::unique_ptr LeftOp,
605 bool IsLegacyLineExpr, const SourceMgr &SM) const;
548606 };
549607
550608 //===----------------------------------------------------------------------===//
3434 Value = None;
3535 }
3636
37 Expected FileCheckExpression::eval() const {
38 assert(LeftOp && "Evaluating an empty expression");
39 Optional LeftOpValue = LeftOp->getValue();
40 // Variable is undefined.
41 if (!LeftOpValue)
42 return make_error(LeftOp->getName());
43 return EvalBinop(*LeftOpValue, RightOp);
37 Expected FileCheckNumericVariableUse::eval() const {
38 Optional Value = NumericVariable->getValue();
39 if (Value)
40 return *Value;
41 return make_error(Name);
42 }
43
44 Expected FileCheckASTBinop::eval() const {
45 Expected LeftOp = LeftOperand->eval();
46 Expected RightOp = RightOperand->eval();
47
48 // Bubble up any error (e.g. undefined variables) in the recursive
49 // evaluation.
50 if (!LeftOp || !RightOp) {
51 Error Err = Error::success();
52 if (!LeftOp)
53 Err = joinErrors(std::move(Err), LeftOp.takeError());
54 if (!RightOp)
55 Err = joinErrors(std::move(Err), RightOp.takeError());
56 return std::move(Err);
57 }
58
59 return EvalBinop(*LeftOp, *RightOp);
4460 }
4561
4662 Expected FileCheckNumericSubstitution::getResult() const {
47 Expected EvaluatedValue = Expression->eval();
63 Expected EvaluatedValue = ExpressionAST->eval();
4864 if (!EvaluatedValue)
4965 return EvaluatedValue.takeError();
5066 return utostr(*EvaluatedValue);
6278 return C == '_' || isalpha(C);
6379 }
6480
65 Expected FileCheckPattern::parseVariable(StringRef &Str,
66 bool &IsPseudo,
67 const SourceMgr &SM) {
81 Expected
82 FileCheckPattern::parseVariable(StringRef &Str, const SourceMgr &SM) {
6883 if (Str.empty())
6984 return FileCheckErrorDiagnostic::get(SM, Str, "empty variable name");
7085
7186 bool ParsedOneChar = false;
7287 unsigned I = 0;
73 IsPseudo = Str[0] == '@';
88 bool IsPseudo = Str[0] == '@';
7489
7590 // Global vars start with '$'.
7691 if (Str[0] == '$' || IsPseudo)
88103
89104 StringRef Name = Str.take_front(I);
90105 Str = Str.substr(I);
91 return Name;
106 return VariableProperties {Name, IsPseudo};
92107 }
93108
94109 // StringRef holding all characters considered as horizontal whitespaces by
110125 FileCheckPattern::parseNumericVariableDefinition(
111126 StringRef &Expr, FileCheckPatternContext *Context, size_t LineNumber,
112127 const SourceMgr &SM) {
113 bool IsPseudo;
114 Expected<StringRef> ParseVarResult = parseVariable(Expr, IsPseudo, SM);
128 Expected<VariableProperties> ParseVarResult = parseVariable(Expr, SM);
115129 if (!ParseVarResult)
116130 return ParseVarResult.takeError();
117 StringRef Name = *ParseVarResult;
118
119 if (IsPseudo)
131 StringRef Name = ParseVarResult->Name;
132
133 if (ParseVarResult->IsPseudo)
120134 return FileCheckErrorDiagnostic::get(
121135 SM, Name, "definition of pseudo numeric variable unsupported");
122136
142156 return DefinedNumericVariable;
143157 }
144158
145 Expected
146 FileCheckPattern::parseNumericVariableUse(StringRef &Expr,
159 Expected>
160 FileCheckPattern::parseNumericVariableUse(StringRef Name, bool IsPseudo,
147161 const SourceMgr &SM) const {
148 bool IsPseudo;
149 Expected ParseVarResult = parseVariable(Expr, IsPseudo, SM);
150 if (!ParseVarResult)
151 return ParseVarResult.takeError();
152 StringRef Name = *ParseVarResult;
153
154162 if (IsPseudo && !Name.equals("@LINE"))
155163 return FileCheckErrorDiagnostic::get(
156164 SM, Name, "invalid pseudo numeric variable '" + Name + "'");
177185 SM, Name,
178186 "numeric variable '" + Name + "' defined on the same line as used");
179187
180 return NumericVariable;
188 return llvm::make_unique(Name, NumericVariable);
189 }
190
191 Expected>
192 FileCheckPattern::parseNumericOperand(StringRef &Expr, AllowedOperand AO,
193 const SourceMgr &SM) const {
194 if (AO == AllowedOperand::LineVar || AO == AllowedOperand::Any) {
195 // Try to parse as a numeric variable use.
196 Expected ParseVarResult =
197 parseVariable(Expr, SM);
198 if (ParseVarResult)
199 return parseNumericVariableUse(ParseVarResult->Name,
200 ParseVarResult->IsPseudo, SM);
201 if (AO == AllowedOperand::LineVar)
202 return ParseVarResult.takeError();
203 // Ignore the error and retry parsing as a literal.
204 consumeError(ParseVarResult.takeError());
205 }
206
207 // Otherwise, parse it as a literal.
208 uint64_t LiteralValue;
209 if (!Expr.consumeInteger(/*Radix=*/10, LiteralValue))
210 return llvm::make_unique(LiteralValue);
211
212 return FileCheckErrorDiagnostic::get(SM, Expr,
213 "invalid operand format '" + Expr + "'");
181214 }
182215
183216 static uint64_t add(uint64_t LeftOp, uint64_t RightOp) {
188221 return LeftOp - RightOp;
189222 }
190223
191 Expected
192 FileCheckPattern::parseBinop(StringRef &Expr, const SourceMgr &SM) const {
193 Expected LeftParseResult =
194 parseNumericVariableUse(Expr, SM);
195 if (!LeftParseResult) {
196 return LeftParseResult.takeError();
197 }
198 FileCheckNumericVariable *LeftOp = *LeftParseResult;
224 Expected>
225 FileCheckPattern::parseBinop(StringRef &Expr,
226 std::unique_ptr LeftOp,
227 bool IsLegacyLineExpr, const SourceMgr &SM) const {
228 Expr = Expr.ltrim(SpaceChars);
229 if (Expr.empty())
230 return std::move(LeftOp);
199231
200232 // Check if this is a supported operation and select a function to perform
201233 // it.
202 Expr = Expr.ltrim(SpaceChars);
203 if (Expr.empty())
204 return Context->makeExpression(add, LeftOp, 0);
205234 SMLoc OpLoc = SMLoc::getFromPointer(Expr.data());
206235 char Operator = popFront(Expr);
207236 binop_eval_t EvalBinop;
222251 if (Expr.empty())
223252 return FileCheckErrorDiagnostic::get(SM, Expr,
224253 "missing operand in expression");
225 uint64_t RightOp;
226 if (Expr.consumeInteger(10, RightOp))
227 return FileCheckErrorDiagnostic::get(
228 SM, Expr, "invalid offset in expression '" + Expr + "'");
254 // The second operand in a legacy @LINE expression is always a literal.
255 AllowedOperand AO =
256 IsLegacyLineExpr ? AllowedOperand::Literal : AllowedOperand::Any;
257 Expected> RightOpResult =
258 parseNumericOperand(Expr, AO, SM);
259 if (!RightOpResult)
260 return RightOpResult;
261
229262 Expr = Expr.ltrim(SpaceChars);
230 if (!Expr.empty())
231 return FileCheckErrorDiagnostic::get(
232 SM, Expr, "unexpected characters at end of expression '" + Expr + "'");
233
234 return Context->makeExpression(EvalBinop, LeftOp, RightOp);
235 }
236
237 Expected FileCheckPattern::parseNumericSubstitutionBlock(
263 return llvm::make_unique(EvalBinop, std::move(LeftOp),
264 std::move(*RightOpResult));
265 }
266
267 Expected>
268 FileCheckPattern::parseNumericSubstitutionBlock(
238269 StringRef Expr,
239270 Optional &DefinedNumericVariable,
240 const SourceMgr &SM) const {
271 bool IsLegacyLineExpr, const SourceMgr &SM) const {
241272 // Parse the numeric variable definition.
242273 DefinedNumericVariable = None;
243274 size_t DefEnd = Expr.find(':');
258289 return ParseResult.takeError();
259290 DefinedNumericVariable = *ParseResult;
260291
261 return Context->makeExpression(add, nullptr, 0);
292 return nullptr;
262293 }
263294
264295 // Parse the expression itself.
265296 Expr = Expr.ltrim(SpaceChars);
266 return parseBinop(Expr, SM);
297 // The first operand in a legacy @LINE expression is always the @LINE pseudo
298 // variable.
299 AllowedOperand AO =
300 IsLegacyLineExpr ? AllowedOperand::LineVar : AllowedOperand::Any;
301 Expected> ParseResult =
302 parseNumericOperand(Expr, AO, SM);
303 while (ParseResult && !Expr.empty()) {
304 ParseResult =
305 parseBinop(Expr, std::move(*ParseResult), IsLegacyLineExpr, SM);
306 // Legacy @LINE expressions only allow 2 operands.
307 if (ParseResult && IsLegacyLineExpr && !Expr.empty())
308 return FileCheckErrorDiagnostic::get(
309 SM, Expr,
310 "unexpected characters at end of expression '" + Expr + "'");
311 }
312 if (!ParseResult)
313 return ParseResult;
314 return std::move(*ParseResult);
267315 }
268316
269317 bool FileCheckPattern::parsePattern(StringRef PatternStr, StringRef Prefix,
374422 PatternStr = UnparsedPatternStr.substr(End + 2);
375423
376424 bool IsDefinition = false;
425 // Whether the substitution block is a legacy use of @LINE with string
426 // substitution block syntax.
427 bool IsLegacyLineExpr = false;
377428 StringRef DefName;
378429 StringRef SubstStr;
379430 StringRef MatchRegexp;
380431 size_t SubstInsertIdx = RegExStr.size();
381432
382 // Parse string variable or legacy expression.
433 // Parse string variable or legacy @LINE expression.
383434 if (!IsNumBlock) {
384435 size_t VarEndIdx = MatchStr.find(":");
385436 size_t SpacePos = MatchStr.substr(0, VarEndIdx).find_first_of(" \t");
390441 }
391442
392443 // Get the name (e.g. "foo") and verify it is well formed.
393 bool IsPseudo;
394444 StringRef OrigMatchStr = MatchStr;
395 Expected ParseVarResult =
396 parseVariable(MatchStr, IsPseudo, SM);
445 Expected ParseVarResult =
446 parseVariable(MatchStr, SM);
397447 if (!ParseVarResult) {
398448 logAllUnhandledErrors(ParseVarResult.takeError(), errs());
399449 return true;
400450 }
401 StringRef Name = *ParseVarResult;
451 StringRef Name = ParseVarResult->Name;
452 bool IsPseudo = ParseVarResult->IsPseudo;
402453
403454 IsDefinition = (VarEndIdx != StringRef::npos);
404455 if (IsDefinition) {
423474 } else {
424475 if (IsPseudo) {
425476 MatchStr = OrigMatchStr;
426 IsNumBlock = true;
477 IsLegacyLineExpr = IsNumBlock = true;
427478 } else
428479 SubstStr = Name;
429480 }
430481 }
431482
432483 // Parse numeric substitution block.
433 FileCheckExpression *Expression;
484 std::unique_ptr ExpressionAST;
434485 Optional DefinedNumericVariable;
435486 if (IsNumBlock) {
436 Expected ParseResult =
437 parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable, SM);
487 Expected> ParseResult =
488 parseNumericSubstitutionBlock(MatchStr, DefinedNumericVariable,
489 IsLegacyLineExpr, SM);
438490 if (!ParseResult) {
439491 logAllUnhandledErrors(ParseResult.takeError(), errs());
440492 return true;
441493 }
442 Expression = *ParseResult;
494 ExpressionAST = std::move(*ParseResult);
443495 if (DefinedNumericVariable) {
444496 IsDefinition = true;
445497 DefName = (*DefinedNumericVariable)->getName();
467519 // previous CHECK patterns, and substitution of expressions.
468520 FileCheckSubstitution *Substitution =
469521 IsNumBlock
470 ? Context->makeNumericSubstitution(SubstStr, Expression,
471 SubstInsertIdx)
522 ? Context->makeNumericSubstitution(
523 SubstStr, std::move(ExpressionAST), SubstInsertIdx)
472524 : Context->makeStringSubstitution(SubstStr, SubstInsertIdx);
473525 Substitutions.push_back(Substitution);
474526 }
659711 Expected MatchedValue = Substitution->getResult();
660712
661713 // Substitution failed or is not known at match time, print the undefined
662 // variable it uses.
714 // variables it uses.
663715 if (!MatchedValue) {
664716 bool UndefSeen = false;
665717 handleAllErrors(MatchedValue.takeError(),
668720 [](const FileCheckErrorDiagnostic &E) {},
669721 [&](const FileCheckUndefVarError &E) {
670722 if (!UndefSeen) {
671 OS << "uses undefined variable ";
723 OS << "uses undefined variable(s):";
672724 UndefSeen = true;
673725 }
726 OS << " ";
674727 E.log(OS);
675 },
676 [](const ErrorInfoBase &E) {
677 llvm_unreachable("Unexpected error");
678728 });
679729 } else {
680730 // Substitution succeeded. Print substituted value.
767817 return VarIter->second;
768818 }
769819
770 FileCheckExpression *
771 FileCheckPatternContext::makeExpression(binop_eval_t EvalBinop,
772 FileCheckNumericVariable *OperandLeft,
773 uint64_t OperandRight) {
774 Expressions.push_back(llvm::make_unique(
775 EvalBinop, OperandLeft, OperandRight));
776 return Expressions.back().get();
777 }
778
779820 template
780821 FileCheckNumericVariable *
781822 FileCheckPatternContext::makeNumericVariable(Types... args) {
793834 }
794835
795836 FileCheckSubstitution *FileCheckPatternContext::makeNumericSubstitution(
796 StringRef ExpressionStr, FileCheckExpression *Expression,
797 size_t InsertIdx) {
837 StringRef ExpressionStr,
838 std::unique_ptr ExpressionAST, size_t InsertIdx) {
798839 Substitutions.push_back(llvm::make_unique(
799 this, ExpressionStr, Expression, InsertIdx));
840 this, ExpressionStr, std::move(ExpressionAST), InsertIdx));
800841 return Substitutions.back().get();
801842 }
802843
17761817 std::pair CmdlineNameVal = CmdlineDef.split('=');
17771818 StringRef CmdlineName = CmdlineNameVal.first;
17781819 StringRef OrigCmdlineName = CmdlineName;
1779 bool IsPseudo;
1780 Expected ParseVarResult =
1781 FileCheckPattern::parseVariable(CmdlineName, IsPseudo, SM);
1820 Expected ParseVarResult =
1821 FileCheckPattern::parseVariable(CmdlineName, SM);
17821822 if (!ParseVarResult) {
17831823 Errs = joinErrors(std::move(Errs), ParseVarResult.takeError());
17841824 continue;
17861826 // Check that CmdlineName does not denote a pseudo variable is only
17871827 // composed of the parsed numeric variable. This catches cases like
17881828 // "FOO+2" in a "FOO+2=10" definition.
1789 if (IsPseudo || !CmdlineName.empty()) {
1829 if (ParseVarResult->IsPseudo || !CmdlineName.empty()) {
17901830 Errs = joinErrors(std::move(Errs),
17911831 FileCheckErrorDiagnostic::get(
17921832 SM, OrigCmdlineName,
17941834 OrigCmdlineName + "'"));
17951835 continue;
17961836 }
1797 StringRef Name = *ParseVarResult;
1837 StringRef Name = ParseVarResult->Name;
17981838
17991839 // Detect collisions between string and numeric variables when the former
18001840 // is created later than the latter.
4949 50 ERR9: line-count.txt:[[#@LINE-1]]:17: error: unsupported operation '*'
5050 51
5151 52 BAD10: [[@LINE-x]]
52 53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid offset in expression 'x'
52 53 ERR10: line-count.txt:[[#@LINE-1]]:19: error: invalid operand format 'x'
5353 54
5454 55 BAD11: [[@LINE-1x]]
5555 56 ERR11: line-count.txt:[[#@LINE-1]]:20: error: unexpected characters at end of expression 'x'
5858 CHECK-NEXT: [[# VAR1 - 1]]
5959 CHECK-NEXT: [[# VAR1 - 1 ]]
6060
61 ; Numeric expressions using variables defined on the command-line and an
62 ; immediate interpreted as an unsigned value.
61 ; Numeric expressions using variables defined on other lines and an immediate
62 ; interpreted as an unsigned value.
6363 ; Note: 9223372036854775819 = 0x8000000000000000 + 11
6464 ; 9223372036854775808 = 0x8000000000000000
6565 USE UNSIGNED IMM
6767 CHECK-LABEL: USE UNSIGNED IMM
6868 CHECK-NEXT: [[#VAR1+9223372036854775808]]
6969
70 ; Numeric expression using undefined variable.
70 ; Numeric expressions using more than one variable defined on other lines.
71 USE MULTI VAR
72 31
73 42
74 CHECK-LABEL: USE MULTI VAR
75 CHECK-NEXT: [[#VAR2:]]
76 CHECK-NEXT: [[#VAR1+VAR2]]
77
78 ; Numeric expression using undefined variables.
7179 RUN: not FileCheck --check-prefix UNDEF-USE --input-file %s %s 2>&1 \
7280 RUN: | FileCheck --strict-whitespace --check-prefix UNDEF-USE-MSG %s
7381
7482 UNDEF VAR USE
7583 UNDEFVAR: 11
7684 UNDEF-USE-LABEL: UNDEF VAR USE
77 UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR]]
85 UNDEF-USE-NEXT: UNDEFVAR: [[#UNDEFVAR1+UNDEFVAR2]]
7886 UNDEF-USE-MSG: numeric-expression.txt:[[#@LINE-1]]:17: error: {{U}}NDEF-USE-NEXT: expected string not found in input
79 UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR\]\]}}
87 UNDEF-USE-MSG-NEXT: {{U}}NDEF-USE-NEXT: UNDEFVAR: {{\[\[#UNDEFVAR1\+UNDEFVAR2\]\]}}
8088 UNDEF-USE-MSG-NEXT: {{^ \^$}}
8189 UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-6]]:1: note: scanning from here
8290 UNDEF-USE-MSG-NEXT: UNDEFVAR: 11
8391 UNDEF-USE-MSG-NEXT: {{^\^$}}
84 UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-9]]:1: note: uses undefined variable "UNDEFVAR"
92 UNDEF-USE-MSG-NEXT: numeric-expression.txt:[[#@LINE-9]]:1: note: uses undefined variable(s): "UNDEFVAR1" "UNDEFVAR2"
8593 UNDEF-USE-MSG-NEXT: UNDEFVAR: 11
8694 UNDEF-USE-MSG-NEXT: {{^\^$}}
8795
3333 GLOBAL: [[$GLOBAL]][[#$GLOBNUM+2]]
3434
3535 ERRUNDEF: expected string not found in input
36 ERRUNDEFLOCAL: uses undefined variable "LOCAL"
37 ERRUNDEFLOCNUM: uses undefined variable "LOCNUM"
36 ERRUNDEFLOCAL: uses undefined variable(s): "LOCAL"
37 ERRUNDEFLOCNUM: uses undefined variable(s): "LOCNUM"
77
88 #include "llvm/Support/FileCheck.h"
99 #include "gtest/gtest.h"
10 #include
1011
1112 using namespace llvm;
1213 namespace {
1314
1415 class FileCheckTest : public ::testing::Test {};
1516
17 TEST_F(FileCheckTest, Literal) {
18 // Eval returns the literal's value.
19 FileCheckExpressionLiteral Ten(10);
20 Expected Value = Ten.eval();
21 EXPECT_TRUE(bool(Value));
22 EXPECT_EQ(10U, *Value);
23
24 // Max value can be correctly represented.
25 FileCheckExpressionLiteral Max(std::numeric_limits::max());
26 Value = Max.eval();
27 EXPECT_TRUE(bool(Value));
28 EXPECT_EQ(std::numeric_limits::max(), *Value);
29 }
30
31 static std::string toString(const std::unordered_set &Set) {
32 bool First = true;
33 std::string Str;
34 for (StringRef S : Set) {
35 Str += Twine(First ? "{" + S : ", " + S).str();
36 First = false;
37 }
38 Str += '}';
39 return Str;
40 }
41
42 static void
43 expectUndefErrors(std::unordered_set ExpectedUndefVarNames,
44 Error Err) {
45 handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
46 ExpectedUndefVarNames.erase(E.getVarName());
47 });
48 EXPECT_TRUE(ExpectedUndefVarNames.empty()) << toString(ExpectedUndefVarNames);
49 }
50
51 static void expectUndefError(const Twine &ExpectedUndefVarName, Error Err) {
52 expectUndefErrors({ExpectedUndefVarName.str()}, std::move(Err));
53 }
54
1655 TEST_F(FileCheckTest, NumericVariable) {
17 // Undefined variable: getValue fails, setValue does not trigger assert.
56 // Undefined variable: getValue and eval fail, error returned by eval holds
57 // the name of the undefined variable and setValue does not trigger assert.
1858 FileCheckNumericVariable FooVar = FileCheckNumericVariable(1, "FOO");
1959 EXPECT_EQ("FOO", FooVar.getName());
20 llvm::Optional Value = FooVar.getValue();
21 EXPECT_FALSE(Value);
22 FooVar.clearValue();
60 FileCheckNumericVariableUse FooVarUse =
61 FileCheckNumericVariableUse("FOO", &FooVar);
62 EXPECT_FALSE(FooVar.getValue());
63 Expected EvalResult = FooVarUse.eval();
64 EXPECT_FALSE(EvalResult);
65 expectUndefError("FOO", EvalResult.takeError());
2366 FooVar.setValue(42);
2467
25 // Defined variable: getValue returns value set.
26 Value = FooVar.getValue();
27 EXPECT_TRUE(Value);
68 // Defined variable: getValue and eval return value set.
69 Optional Value = FooVar.getValue();
70 EXPECT_TRUE(bool(Value));
2871 EXPECT_EQ(42U, *Value);
29
30 // Clearing variable: getValue fails.
72 EvalResult = FooVarUse.eval();
73 EXPECT_TRUE(bool(EvalResult));
74 EXPECT_EQ(42U, *EvalResult);
75
76 // Clearing variable: getValue and eval fail. Error returned by eval holds
77 // the name of the cleared variable.
3178 FooVar.clearValue();
3279 Value = FooVar.getValue();
3380 EXPECT_FALSE(Value);
81 EvalResult = FooVarUse.eval();
82 EXPECT_FALSE(EvalResult);
83 expectUndefError("FOO", EvalResult.takeError());
3484 }
3585
3686 uint64_t doAdd(uint64_t OpL, uint64_t OpR) { return OpL + OpR; }
3787
38 static void expectUndefError(const Twine &ExpectedStr, Error Err) {
39 handleAllErrors(std::move(Err), [&](const FileCheckUndefVarError &E) {
40 EXPECT_EQ(ExpectedStr.str(), E.getVarName());
41 });
42 }
43
44 TEST_F(FileCheckTest, Expression) {
88 TEST_F(FileCheckTest, Binop) {
4589 FileCheckNumericVariable FooVar = FileCheckNumericVariable("FOO", 42);
46 FileCheckExpression Expression = FileCheckExpression(doAdd, &FooVar, 18);
90 std::unique_ptr FooVarUse =
91 llvm::make_unique("FOO", &FooVar);
92 FileCheckNumericVariable BarVar = FileCheckNumericVariable("BAR", 18);
93 std::unique_ptr BarVarUse =
94 llvm::make_unique("BAR", &BarVar);
95 FileCheckASTBinop Binop =
96 FileCheckASTBinop(doAdd, std::move(FooVarUse), std::move(BarVarUse));
4797
4898 // Defined variable: eval returns right value.
49 Expected Value = Expression.eval();
99 Expected Value = Binop.eval();
50100 EXPECT_TRUE(bool(Value));
51101 EXPECT_EQ(60U, *Value);
52102
53 // Undefined variable: eval fails, undefined variable returned. We call
54 // getUndefVarName first to check that it can be called without calling
55 // eval() first.
103 // 1 undefined variable: eval fails, error contains name of undefined
104 // variable.
56105 FooVar.clearValue();
57 Error EvalError = Expression.eval().takeError();
58 EXPECT_TRUE(errorToBool(std::move(EvalError)));
59 expectUndefError("FOO", std::move(EvalError));
106 Value = Binop.eval();
107 EXPECT_FALSE(Value);
108 expectUndefError("FOO", Value.takeError());
109
110 // 2 undefined variables: eval fails, error contains names of all undefined
111 // variables.
112 BarVar.clearValue();
113 Value = Binop.eval();
114 EXPECT_FALSE(Value);
115 expectUndefErrors({"FOO", "BAR"}, Value.takeError());
60116 }
61117
62118 TEST_F(FileCheckTest, ValidVarNameStart) {
83139 SourceMgr SM;
84140 StringRef OrigVarName = bufferize(SM, "GoodVar42");
85141 StringRef VarName = OrigVarName;
86 bool IsPseudo = true;
87 Expected ParsedName =
88 FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
89 EXPECT_TRUE(bool(ParsedName));
90 EXPECT_EQ(*ParsedName, OrigVarName);
142 Expected ParsedVarResult =
143 FileCheckPattern::parseVariable(VarName, SM);
144 EXPECT_TRUE(bool(ParsedVarResult));
145 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
91146 EXPECT_TRUE(VarName.empty());
92 EXPECT_FALSE(IsPseudo);
147 EXPECT_FALSE(ParsedVarResult->IsPseudo);
93148
94149 VarName = OrigVarName = bufferize(SM, "$GoodGlobalVar");
95 IsPseudo = true;
96 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
97 EXPECT_TRUE(bool(ParsedName));
98 EXPECT_EQ(*ParsedName, OrigVarName);
150 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
151 EXPECT_TRUE(bool(ParsedVarResult));
152 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
99153 EXPECT_TRUE(VarName.empty());
100 EXPECT_FALSE(IsPseudo);
154 EXPECT_FALSE(ParsedVarResult->IsPseudo);
101155
102156 VarName = OrigVarName = bufferize(SM, "@GoodPseudoVar");
103 IsPseudo = true;
104 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
105 EXPECT_TRUE(bool(ParsedName));
106 EXPECT_EQ(*ParsedName, OrigVarName);
157 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
158 EXPECT_TRUE(bool(ParsedVarResult));
159 EXPECT_EQ(ParsedVarResult->Name, OrigVarName);
107160 EXPECT_TRUE(VarName.empty());
108 EXPECT_TRUE(IsPseudo);
161 EXPECT_TRUE(ParsedVarResult->IsPseudo);
109162
110163 VarName = bufferize(SM, "42BadVar");
111 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
112 EXPECT_TRUE(errorToBool(ParsedName.takeError()));
164 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
165 EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
113166
114167 VarName = bufferize(SM, "$@");
115 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
116 EXPECT_TRUE(errorToBool(ParsedName.takeError()));
168 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
169 EXPECT_TRUE(errorToBool(ParsedVarResult.takeError()));
117170
118171 VarName = OrigVarName = bufferize(SM, "B@dVar");
119 IsPseudo = true;
120 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
121 EXPECT_TRUE(bool(ParsedName));
172 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
173 EXPECT_TRUE(bool(ParsedVarResult));
122174 EXPECT_EQ(VarName, OrigVarName.substr(1));
123 EXPECT_EQ(*ParsedName, "B");
124 EXPECT_FALSE(IsPseudo);
175 EXPECT_EQ(ParsedVarResult->Name, "B");
176 EXPECT_FALSE(ParsedVarResult->IsPseudo);
125177
126178 VarName = OrigVarName = bufferize(SM, "B$dVar");
127 IsPseudo = true;
128 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
129 EXPECT_TRUE(bool(ParsedName));
179 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
180 EXPECT_TRUE(bool(ParsedVarResult));
130181 EXPECT_EQ(VarName, OrigVarName.substr(1));
131 EXPECT_EQ(*ParsedName, "B");
132 EXPECT_FALSE(IsPseudo);
182 EXPECT_EQ(ParsedVarResult->Name, "B");
183 EXPECT_FALSE(ParsedVarResult->IsPseudo);
133184
134185 VarName = bufferize(SM, "BadVar+");
135 IsPseudo = true;
136 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
137 EXPECT_TRUE(bool(ParsedName));
186 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
187 EXPECT_TRUE(bool(ParsedVarResult));
138188 EXPECT_EQ(VarName, "+");
139 EXPECT_EQ(*ParsedName, "BadVar");
140 EXPECT_FALSE(IsPseudo);
189 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
190 EXPECT_FALSE(ParsedVarResult->IsPseudo);
141191
142192 VarName = bufferize(SM, "BadVar-");
143 IsPseudo = true;
144 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
145 EXPECT_TRUE(bool(ParsedName));
193 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
194 EXPECT_TRUE(bool(ParsedVarResult));
146195 EXPECT_EQ(VarName, "-");
147 EXPECT_EQ(*ParsedName, "BadVar");
148 EXPECT_FALSE(IsPseudo);
196 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
197 EXPECT_FALSE(ParsedVarResult->IsPseudo);
149198
150199 VarName = bufferize(SM, "BadVar:");
151 IsPseudo = true;
152 ParsedName = FileCheckPattern::parseVariable(VarName, IsPseudo, SM);
153 EXPECT_TRUE(bool(ParsedName));
200 ParsedVarResult = FileCheckPattern::parseVariable(VarName, SM);
201 EXPECT_TRUE(bool(ParsedVarResult));
154202 EXPECT_EQ(VarName, ":");
155 EXPECT_EQ(*ParsedName, "BadVar");
156 EXPECT_FALSE(IsPseudo);
203 EXPECT_EQ(ParsedVarResult->Name, "BadVar");
204 EXPECT_FALSE(ParsedVarResult->IsPseudo);
157205 }
158206
159207 class PatternTester {
196244 StringRef ExprBufferRef = bufferize(SM, Expr);
197245 Optional DefinedNumericVariable;
198246 return errorToBool(P.parseNumericSubstitutionBlock(
199 ExprBufferRef, DefinedNumericVariable, SM)
247 ExprBufferRef, DefinedNumericVariable, false, SM)
200248 .takeError());
201249 }
202250
268316 // Missing offset operand.
269317 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+"));
270318
271 // Cannot parse offset operand.
272 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+x"));
273
274 // Unexpected string at end of numeric expression.
275 EXPECT_TRUE(Tester.parseSubstExpect("@LINE+5x"));
276
277319 // Valid expression.
278320 EXPECT_FALSE(Tester.parseSubstExpect("@LINE+5"));
279321 EXPECT_FALSE(Tester.parseSubstExpect("FOO+4"));
322 Tester.initNextPattern();
323 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+FOO]]"));
324 EXPECT_FALSE(Tester.parsePatternExpect("[[#FOO+3-FOO]]"));
280325 }
281326
282327 TEST_F(FileCheckTest, ParsePattern) {
305350 EXPECT_TRUE(Tester.parsePatternExpect("[[#42INVALID]]"));
306351 EXPECT_TRUE(Tester.parsePatternExpect("[[#@FOO]]"));
307352 EXPECT_TRUE(Tester.parsePatternExpect("[[#@LINE/2]]"));
308 EXPECT_TRUE(Tester.parsePatternExpect("[[#2+@LINE]]"));
309353 EXPECT_TRUE(Tester.parsePatternExpect("[[#YUP:@LINE]]"));
310354
311355 // Valid numeric expressions and numeric variable definition.
364408 // the right value.
365409 FileCheckNumericVariable LineVar = FileCheckNumericVariable("@LINE", 42);
366410 FileCheckNumericVariable NVar = FileCheckNumericVariable("N", 10);
367 FileCheckExpression LineExpression = FileCheckExpression(doAdd, &LineVar, 0);
368 FileCheckExpression NExpression = FileCheckExpression(doAdd, &NVar, 3);
369 FileCheckNumericSubstitution SubstitutionLine =
370 FileCheckNumericSubstitution(&Context, "@LINE", &LineExpression, 12);
411 auto LineVarUse =
412 llvm::make_unique("@LINE", &LineVar);
413 auto NVarUse = llvm::make_unique("N", &NVar);
414 FileCheckNumericSubstitution SubstitutionLine = FileCheckNumericSubstitution(
415 &Context, "@LINE", std::move(LineVarUse), 12);
371416 FileCheckNumericSubstitution SubstitutionN =
372 FileCheckNumericSubstitution(&Context, "N", &NExpression, 30);
373 Expected Value = SubstitutionLine.getResult();
374 EXPECT_TRUE(bool(Value));
375 EXPECT_EQ("42", *Value);
376 Value = SubstitutionN.getResult();
377 EXPECT_TRUE(bool(Value));
378 EXPECT_EQ("13", *Value);
379
380 // Substitution of an undefined numeric variable fails.
417 FileCheckNumericSubstitution(&Context, "N", std::move(NVarUse), 30);
418 SubstValue = SubstitutionLine.getResult();
419 EXPECT_TRUE(bool(SubstValue));
420 EXPECT_EQ("42", *SubstValue);
421 SubstValue = SubstitutionN.getResult();
422 EXPECT_TRUE(bool(SubstValue));
423 EXPECT_EQ("10", *SubstValue);
424
425 // Substitution of an undefined numeric variable fails, error holds name of
426 // undefined variable.
381427 LineVar.clearValue();
382 SubstValue = SubstitutionLine.getResult().takeError();
428 SubstValue = SubstitutionLine.getResult();
383429 EXPECT_FALSE(bool(SubstValue));
384430 expectUndefError("@LINE", SubstValue.takeError());
385431 NVar.clearValue();
386 SubstValue = SubstitutionN.getResult().takeError();
432 SubstValue = SubstitutionN.getResult();
387433 EXPECT_FALSE(bool(SubstValue));
388434 expectUndefError("N", SubstValue.takeError());
389435
390436 // Substitution of a defined string variable returns the right value.
391437 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Context, 1);
392438 StringSubstitution = FileCheckStringSubstitution(&Context, "FOO", 42);
393 Value = StringSubstitution.getResult();
394 EXPECT_TRUE(bool(Value));
395 EXPECT_EQ("BAR", *Value);
439 SubstValue = StringSubstitution.getResult();
440 EXPECT_TRUE(bool(SubstValue));
441 EXPECT_EQ("BAR", *SubstValue);
396442 }
397443
398444 TEST_F(FileCheckTest, FileCheckContext) {
455501 Expected LocalVar = Cxt.getPatternVarValue(LocalVarStr);
456502 FileCheckPattern P = FileCheckPattern(Check::CheckPlain, &Cxt, 1);
457503 Optional DefinedNumericVariable;
458 Expected Expression = P.parseNumericSubstitutionBlock(
459 LocalNumVarRef, DefinedNumericVariable, SM);
504 Expected> ExpressionAST =
505 P.parseNumericSubstitutionBlock(LocalNumVarRef, DefinedNumericVariable,
506 /*IsLegacyLineExpr=*/false, SM);
507 EXPECT_TRUE(bool(LocalVar));
508 EXPECT_EQ(*LocalVar, "FOO");
460509 Expected EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
461510 Expected UnknownVar = Cxt.getPatternVarValue(UnknownVarStr);
462 EXPECT_TRUE(bool(LocalVar));
463 EXPECT_EQ(*LocalVar, "FOO");
464 EXPECT_TRUE(bool(Expression));
465 Expected ExpressionVal = (*Expression)->eval();
511 EXPECT_TRUE(bool(ExpressionAST));
512 Expected ExpressionVal = (*ExpressionAST)->eval();
466513 EXPECT_TRUE(bool(ExpressionVal));
467514 EXPECT_EQ(*ExpressionVal, 18U);
468515 EXPECT_TRUE(bool(EmptyVar));
477524 // local variables, if it was created before. This is important because local
478525 // variable clearing due to --enable-var-scope happens after numeric
479526 // expressions are linked to the numeric variables they use.
480 EXPECT_TRUE(errorToBool((*Expression)->eval().takeError()));
527 EXPECT_TRUE(errorToBool((*ExpressionAST)->eval().takeError()));
481528 P = FileCheckPattern(Check::CheckPlain, &Cxt, 2);
482 Expression = P.parseNumericSubstitutionBlock(LocalNumVarRef,
483 DefinedNumericVariable, SM);
484 EXPECT_TRUE(bool(Expression));
485 ExpressionVal = (*Expression)->eval();
529 ExpressionAST = P.parseNumericSubstitutionBlock(
530 LocalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
531 EXPECT_TRUE(bool(ExpressionAST));
532 ExpressionVal = (*ExpressionAST)->eval();
486533 EXPECT_TRUE(errorToBool(ExpressionVal.takeError()));
487534 EmptyVar = Cxt.getPatternVarValue(EmptyVarStr);
488535 EXPECT_TRUE(errorToBool(EmptyVar.takeError()));
500547 EXPECT_TRUE(bool(GlobalVar));
501548 EXPECT_EQ(*GlobalVar, "BAR");
502549 P = FileCheckPattern(Check::CheckPlain, &Cxt, 3);
503 Expression = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
504 DefinedNumericVariable, SM);
505 EXPECT_TRUE(bool(Expression));
506 ExpressionVal = (*Expression)->eval();
550 ExpressionAST = P.parseNumericSubstitutionBlock(
551 GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
552 EXPECT_TRUE(bool(ExpressionAST));
553 ExpressionVal = (*ExpressionAST)->eval();
507554 EXPECT_TRUE(bool(ExpressionVal));
508555 EXPECT_EQ(*ExpressionVal, 36U);
509556
511558 Cxt.clearLocalVars();
512559 EXPECT_FALSE(errorToBool(Cxt.getPatternVarValue(GlobalVarStr).takeError()));
513560 P = FileCheckPattern(Check::CheckPlain, &Cxt, 4);
514 Expression = P.parseNumericSubstitutionBlock(GlobalNumVarRef,
515 DefinedNumericVariable, SM);
516 EXPECT_TRUE(bool(Expression));
517 ExpressionVal = (*Expression)->eval();
561 ExpressionAST = P.parseNumericSubstitutionBlock(
562 GlobalNumVarRef, DefinedNumericVariable, /*IsLegacyLineExpr=*/false, SM);
563 EXPECT_TRUE(bool(ExpressionAST));
564 ExpressionVal = (*ExpressionAST)->eval();
518565 EXPECT_TRUE(bool(ExpressionVal));
519566 EXPECT_EQ(*ExpressionVal, 36U);
520567 }