aboutsummaryrefslogtreecommitdiff
path: root/include/llvm/Support/FileCheck.h
blob: 1ebeaee33b2c4f11b0b7ec11d18d03bfcedd5a56 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
//==-- llvm/Support/FileCheck.h ---------------------------*- C++ -*-==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file This file has some utilities to use FileCheck as an API
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_SUPPORT_FILECHECK_H
#define LLVM_SUPPORT_FILECHECK_H

#include "llvm/ADT/StringMap.h"
#include "llvm/Support/MemoryBuffer.h"
#include "llvm/Support/Regex.h"
#include "llvm/Support/SourceMgr.h"
#include <vector>
#include <map>

namespace llvm {

/// Contains info about various FileCheck options.
struct FileCheckRequest {
  std::vector<std::string> CheckPrefixes;
  bool NoCanonicalizeWhiteSpace = false;
  std::vector<std::string> ImplicitCheckNot;
  std::vector<std::string> GlobalDefines;
  bool AllowEmptyInput = false;
  bool MatchFullLines = false;
  bool EnableVarScope = false;
  bool AllowDeprecatedDagOverlap = false;
  bool Verbose = false;
  bool VerboseVerbose = false;
};

//===----------------------------------------------------------------------===//
// Numeric expression handling Code.
//===----------------------------------------------------------------------===//

struct FileCheckNumExprFmtType;

/// Bitfield representing the format a numeric expression value should be
/// printed into for matching.  Used to represent both explicit format
/// specifiers as well as implicit format from using numeric variables.
struct FileCheckNumExprFmtType {
  /// Value is signed.
  unsigned Signed : 1;
  /// Value should be print as hex number.
  unsigned Hex : 1;
  /// Capital case, only used for hex numbers.
  unsigned Cap : 1;

  /// When 0, absence of format, eg. for literals in an expression.
  unsigned Set : 1;

  /// Several conflicting implicit formats in an expression.
  unsigned Conflict : 1;

  /// Define format equality: formats are equal if all bits are identical.
  bool operator==(const struct FileCheckNumExprFmtType &other);
  bool operator!=(const struct FileCheckNumExprFmtType &other) {
    return !(*this == other);
  }
};

/// Initializer for numeric expression without format.
const struct FileCheckNumExprFmtType FmtNone = {0, 0, 0, 0, 0};
/// Initializer for numeric expression matched as unsigned value.
const struct FileCheckNumExprFmtType FmtUnsigned = {0, 0, 0, 1, 0};
/// Initializer for numeric expression matched as signed value.
const struct FileCheckNumExprFmtType FmtSigned = {1, 0, 0, 1, 0};
/// Initializer for numeric expression matched as lower case hex value.
const struct FileCheckNumExprFmtType FmtLowHex = {0, 1, 0, 1, 0};
/// Initializer for numeric expression matched as capital case hex value.
const struct FileCheckNumExprFmtType FmtCapHex = {0, 1, 1, 1, 0};

namespace Check {
/// Phases of FileCheck.  Used to determine at what phase is a numeric
/// expression (and thus value of any potential variable defined by it)
/// available.
enum FileCheckPhase {
  /// Parsing the CHECK pattern.
  ParsePhase = 0,
  /// Pattern substitution and actual regex matching
  MatchPhase,
  /// Constraint check done for numeric expression just after match phase.
  CheckPhase
};
} // namespace Check

/// Class representing a numeric expression's value.  Used to be able to store
/// and return both signed and unsigned value.
class FileCheckNumExprVal {
private:
  /// Signed value.
  int64_t SVal;

  /// Unsigned value.
  uint64_t UVal;

  /// Whether value is signed (and thus is stored in SVal) or not (in which
  /// case it is stored in UVal).
  bool Signed;

  /// Whether this holds an actual value.  Examples of where this would be
  /// false include:
  /// - underflow or overflow of one of the binary operation in the expression
  /// - value of undefined variable
  bool Valid;

  /// Whether this is a tentative value.  True if any of the operand involved
  /// in its computation had a tentative value.
  bool Tentative;

public:
  /// Constructor for an invalid value.
  FileCheckNumExprVal() : Valid(false) {}

  /// Constructor for a signed value.
  FileCheckNumExprVal(int64_t Val)
      : SVal(Val), Signed(true), Valid(true), Tentative(false) {}

  /// Constructor for an unsigned value.
  FileCheckNumExprVal(uint64_t Val)
      : UVal(Val), Signed(false), Valid(true), Tentative(false) {}

  /// Define how to compare value.  Used to decide whether a matched numeric
  /// value satisfies its corresponding numeric expression.
  bool operator==(const FileCheckNumExprVal &other);
  bool operator!=(const FileCheckNumExprVal &other) {
    return !(*this == other);
  }

  /// Whether value is signed.
  bool IsSigned() const { return Signed; }

  /// Whether value is valid.
  bool IsValid() const { return Valid; }

  /// Whether value is tentative.
  bool IsTentative() const { return Tentative; }

  /// Return the signed value.  Must only be called if value is signed in the
  /// first place.
  int64_t GetSignedValue() const { return SVal; }

  /// Return the unsigned value.  Must only be called if value is unsigned in
  /// the first place.
  uint64_t GetUnsignedValue() const { return UVal; }

  /// Mark value as tentative.
  bool ToggleTentative() { return Tentative = !Tentative; }

  /// Convert value to a signed value, or mark value invalid if not possible
  /// (original value was not within range for a signed integer).
  void ConvertSigned();

  /// Convert value to an unsigned value, or mark value invalid if not possible
  /// (original value was not within range for an unsigned integer).
  void ConvertUnsigned();

  /// Store in \p StringRepr a string representation of this value given the
  /// matching format \p Fmt.  Return whether value had no such a string
  /// representation (true if value is invalid).
  bool GetStringRepr(struct FileCheckNumExprFmtType Fmt,
                     std::string &StringRepr) const;

  /// Perform an addition operation.  Return an invalid value in case of
  /// underflow or overflow.
  static FileCheckNumExprVal Add(const FileCheckNumExprVal &Op1,
                                 const FileCheckNumExprVal &Op2);

  /// Perform a substraction operation.  Return an invalid value in case of
  /// underflow or overflow.
  static FileCheckNumExprVal Sub(const FileCheckNumExprVal &Op1,
                                 const FileCheckNumExprVal &Op2);
};

/// Base class representing the AST of a given numeric expression.  Only used
/// for AST node of unknown type.  All actual nodes are of another type.
class FileCheckNumExprAST {
public:
  virtual ~FileCheckNumExprAST() = default;

  /// Evaluate the value of the expression represented by this AST.  Return in
  /// \p Fmt the implicit conversion that applies from any variable used or
  /// null if no variable is used by the expression.  This method must be
  /// overrided in all subclasses.
  virtual FileCheckNumExprVal Eval(struct FileCheckNumExprFmtType &Fmt) = 0;

  /// Append names of undefined variables used in the expression represented by
  /// this AST.  Must be overrided in any subclass representing an expression
  /// that can contain a variable.
  virtual void GetUndefVarNames(std::vector<StringRef> &UndefVarNames) const {}
};

/// Class representing a litteral, either in the AST of a numeric expression or
/// in the result of the evaluation of such an expression.
class FileCheckNumExprLiteral : public FileCheckNumExprAST {
private:
  /// Actual value of the literal.
  FileCheckNumExprVal Value;

public:
  /// Constructor for a signed literal.
  FileCheckNumExprLiteral(int64_t Val) : Value(Val) {}

  /// Constructor for an unsigned literal.
  FileCheckNumExprLiteral(uint64_t Val) : Value(Val) {}

  /// Evaluate the value of this literal.  Therefore returns this node itself
  /// and set \p Fmt to null since literals do not carry any implicit
  /// conversion.
  FileCheckNumExprVal Eval(struct FileCheckNumExprFmtType &Fmt);
};

/// Class representing a numeric expression and its matching format.
class FileCheckNumExpr {
private:
  /// Pointer to AST of the numeric expression.
  std::shared_ptr<FileCheckNumExprAST> AST;

  /// Value of the numeric expression.  Set either from evaluating the AST if
  /// any and using only variable defined on previous CHECK line, or from the
  /// matched value if constraint is satisfied.
  FileCheckNumExprVal Value;

  /// Matching format.
  struct FileCheckNumExprFmtType Fmt;

  /// FileCheck phase when this numeric expression can be evaluated.
  enum Check::FileCheckPhase KnownPhase;

public:
  /// Generic constructor for a numeric expression whose equality constraint is
  /// represented by \p AST, matching format is \p Fmt and whose AST can be
  /// evaluated in phase \p KnownPhase.
  FileCheckNumExpr(std::shared_ptr<FileCheckNumExprAST> AST,
                   struct FileCheckNumExprFmtType Fmt,
                   enum Check::FileCheckPhase KnownPhase);

  /// Constructor for numeric expression with a known value in parse phase,
  /// eg. the numeric expression defining the @LINE numeric variable (and
  /// currently only used for that).
  FileCheckNumExpr(FileCheckNumExprVal Value,
                   struct FileCheckNumExprFmtType Fmt);

  /// Return pointer to AST of the numeric expression.  Pointed-to AST is
  /// managed by a shared_ptr and is guaranteed live as long as this object is.
  FileCheckNumExprAST *GetAST() const { return AST.get(); }

  /// Return the matched value for the expression.
  FileCheckNumExprVal GetValue() const { return Value; }

  /// Set Value to \p Val if currently invalid or tentative.  Return whether
  /// Value failed to be set (Value was already valid and final).
  bool SetTentativeValue(FileCheckNumExprVal Val);

  /// Return matching format of the expression.
  struct FileCheckNumExprFmtType GetFormat() const {
    return Fmt;
  }

  /// Return at what FileCheck phase can this expression can be evaluated.
  enum Check::FileCheckPhase GetKnownPhase() { return KnownPhase; }

  /// Store in \p Val the value corresponding to string representation
  /// \p StrVal according to matching format of this numeric expression.
  /// Return whether \p StrVal correspond to a valid and representable value.
  bool ValueFromStringRepr(StringRef StrVal, FileCheckNumExprVal &Val) const;

  /// Store in \p ValueStringRepr the string representation of Value given the
  /// matching format of this numeric expression.  Return whether Value does
  /// not have a string representation (Value is invalid).
  bool GetValueStringRepr(std::string &ValueStringRepr) const {
    return Value.GetStringRepr(Fmt, ValueStringRepr);
  }

  /// Store in \p MatchString the regexp pattern to use to match this
  /// numeric expression given its matching format.  Return whether the
  /// function was unable to determine the regexp pattern.
  bool GetMatchString(enum Check::FileCheckPhase Phase,
                      std::string &MatchString);

  /// Verify that the matched value in \p MatchedValue satisfies the constraint
  /// expressed by this expression.  Return true if constraint is not
  /// satisfied.
  bool VerifyConstraint(FileCheckNumExprVal MatchedValue) const;

  /// Store in \p EvaluatedValue the value evaluated from the constraint of
  /// this numeric expression.  Return whether evaluation failed.
  bool Eval(FileCheckNumExprVal &EvaluatedValue) const;

  /// Set Value from the result of calling Eval().  Return whether it failed.
  bool SetValueFromEval();

  /// Mark value as final.  Return whether value was already final.
  bool CommitValue();
};

/// Class representing a numeric variable with a given value in the AST of a
/// numeric expression.  Each definition of a variable gets its own instance
/// of this class, uses share the same instance as the respective definition.
class FileCheckNumExprVar : public FileCheckNumExprAST {
private:
  /// Name of the numeric variable.
  StringRef Name;

  /// Pointer to numeric expression defining this numeric variable.  Only null
  /// if variable used but not defined.  If numeric expression is empty NumExpr
  /// points to a FileCheckNumExpr with a null AST.
  std::shared_ptr<FileCheckNumExpr> NumExpr;

  /// Line number where this variable is defined.  Used to determine whether a
  /// variable is defined on the same line as a given use.
  unsigned DefLineNumber;

public:
  /// Constructor for an undefined variable \p Name.
  FileCheckNumExprVar(StringRef Name)
      : Name(Name), NumExpr(nullptr), DefLineNumber(0) {}

  /// Constructor for a variable \p Name defined at line \p DefLineNumber.
  FileCheckNumExprVar(StringRef Name, unsigned DefLineNumber)
      : Name(Name), NumExpr(nullptr), DefLineNumber(DefLineNumber) {}

  /// Constructor for numeric variable \p Name with a known \p Value at parse
  /// time (eg. the @LINE numeric variable).  Matching format of the variable
  /// is given in \p Fmt and \p DefLineNumber indicates when does this variable
  /// starts to be defined.
  FileCheckNumExprVar(StringRef Name, FileCheckNumExprVal Value,
                      struct FileCheckNumExprFmtType Fmt,
                      unsigned DefLineNumber);

  /// Return name of that numeric variable.
  StringRef GetName() const { return Name; }

  /// Return pointer to the numeric expression defining this numeric variable.
  FileCheckNumExpr *GetNumExpr() const { return NumExpr.get(); }

  /// Return line number where this variable is defined.
  unsigned GetDefLineNumber() { return DefLineNumber; }

  /// Set pointer to numeric expression defining this numeric variable.
  void SetNumExpr(std::shared_ptr<FileCheckNumExpr> NumExpr) {
    this->NumExpr = NumExpr;
  }

  /// Evaluate the value of this numeric variable.  Therefore returns the value
  /// and implicit conversion of this numeric variable stored in its
  /// corresponding numeric expression class.
  FileCheckNumExprVal Eval(struct FileCheckNumExprFmtType &Fmt);

  /// Append numeric variable's name to UndefVarNames if undefined.
  void GetUndefVarNames(std::vector<StringRef> &UndefVarNames) const;
};

/// Type of functions evaluating a given binary operation.
using binop_eval_t = FileCheckNumExprVal (*)(const FileCheckNumExprVal &,
                                             const FileCheckNumExprVal &);

/// Class representing a single binary operation in the AST of a numeric
/// expression.
class FileCheckASTBinop : public FileCheckNumExprAST {
private:
  /// Left operand.
  std::shared_ptr<FileCheckNumExprAST> Opl;

  /// Right operand.
  std::shared_ptr<FileCheckNumExprAST> Opr;

  /// Pointer to function that can evaluate this binary operation.
  binop_eval_t EvalBinop;

public:
  FileCheckASTBinop(binop_eval_t EvalBinop,
                    std::shared_ptr<FileCheckNumExprAST> OperandLeft,
                    std::shared_ptr<FileCheckNumExprAST> OperandRight)
      : Opl(OperandLeft), Opr(OperandRight), EvalBinop(EvalBinop) {}

  /// Evaluate the value of the binary operation represented by this AST.  Uses
  /// EvalBinop to perform the binary operation on the values of recursively
  /// evaluating the left and right operands.
  FileCheckNumExprVal Eval(struct FileCheckNumExprFmtType &Fmt);

  /// Append to UnderVarNames the names of undefined numeric variables used in
  /// any of the operands.
  void GetUndefVarNames(std::vector<StringRef> &UndefVarNames) const;
};

class FileCheckPatternContext;

/// Class representing a substitution to perform in the string to match, either
/// a pattern variable to replace by its value or a numeric expression to
/// replace by an appropriate wildcard pattern.
class FileCheckPatternSubst {
private:
  /// Pointer to a class instance holding among other thing the table with the
  /// values of live pattern variables at the start of any given CHECK line.
  /// Used for substituting pattern variables (numeric variables have their
  /// value in the FileCheckNumExpr class instance pointed to by NumExpr).
  FileCheckPatternContext *Context;

  /// Whether this represents a numeric expression substitution.
  bool isNumExpr;

  /// The string that needs to be substituted for something else.  For a
  /// pattern variable this is its name, otherwise this is the whole numeric
  /// expression.
  StringRef SubstStr;

  /// If this is a numeric expression substitution, this is the pointer to the
  /// class representing that numeric expression.
  std::shared_ptr<FileCheckNumExpr> NumExpr;

  // Index in RegExStr of where to do the substitution.
  unsigned InsertIdx;

public:
  /// Constructor for a pattern variable substitution.
  FileCheckPatternSubst(FileCheckPatternContext *Context, StringRef VarName,
                        unsigned InsertIdx)
      : Context(Context), isNumExpr(false), SubstStr(VarName),
        InsertIdx(InsertIdx) {}

  /// Constructor for a numeric expression substitution.
  FileCheckPatternSubst(FileCheckPatternContext *Context, StringRef Expr,
                        std::shared_ptr<FileCheckNumExpr> NumExpr,
                        unsigned InsertIdx)
      : Context(Context), isNumExpr(true), SubstStr(Expr), NumExpr(NumExpr),
        InsertIdx(InsertIdx) {}

  /// Return whether this is a numeric expression substitution.
  bool IsNumExpr() const { return isNumExpr; }

  /// Return the string to be substituted.
  StringRef GetSubstString() const { return SubstStr; }

  /// Return the index where the substitution is to be performed.
  unsigned GetIndex() const { return InsertIdx; }

  /// Perform in \p SubstValue the substitution represented by this class
  /// instance.  For a numeric variable we replace it by its value if known at
  /// match time or a suitable wildcard pattern otherwise.  For a pattern
  /// variable we simply replace it by the text its definition matched.
  /// Return whether substitution failed.
  bool Substitute(std::string &SubstValue) const;

  /// Write in \p MatchedValue the value successfully matched (ie. constraint
  /// is verified for a numeric expression) by the substitution.  Return
  /// whether match failed for that substitution.
  bool MatchedValue(std::string &MatchedValue) const;

  /// Append to UnderVarNames the names of undefined pattern or numeric
  /// variables used in this substitution.
  void GetUndefVarNames(std::vector<StringRef> &UndefVarNames) const;
};

//===----------------------------------------------------------------------===//
// Pattern Handling Code.
//===----------------------------------------------------------------------===//

namespace Check {

enum FileCheckKind {
  CheckNone = 0,
  CheckPlain,
  CheckNext,
  CheckSame,
  CheckNot,
  CheckDAG,
  CheckLabel,
  CheckEmpty,

  /// Indicates the pattern only matches the end of file. This is used for
  /// trailing CHECK-NOTs.
  CheckEOF,

  /// Marks when parsing found a -NOT check combined with another CHECK suffix.
  CheckBadNot,

  /// Marks when parsing found a -COUNT directive with invalid count value.
  CheckBadCount
};

class FileCheckType {
  FileCheckKind Kind;
  int Count; ///< optional Count for some checks

public:
  FileCheckType(FileCheckKind Kind = CheckNone) : Kind(Kind), Count(1) {}
  FileCheckType(const FileCheckType &) = default;

  operator FileCheckKind() const { return Kind; }

  int getCount() const { return Count; }
  FileCheckType &setCount(int C);

  std::string getDescription(StringRef Prefix) const;
};
} // namespace Check

/// Structure representing the definition of a numeric variable in a pattern.
/// It holds the parenthesized capture number and the pointer to the class
/// representing the numeric expression and its matching format.
struct FileCheckNumExprMatch {
  /// Pointer to class representing the numeric expression and its matching
  /// format.
  std::shared_ptr<FileCheckNumExpr> NumExpr;

  /// Parenthesized capture number for this numeric expression
  unsigned CaptureParen;
};

/// Class holding the FileCheckPattern global state, shared by all patterns:
/// tables holding values of variables and whether they are defined or not at
/// any given time in the matching process.
class FileCheckPatternContext {
  friend class FileCheckPattern;

private:
  /// When matching a given pattern, this holds the value of all the FileCheck
  /// pattern variables defined in previous patterns.  In a pattern only the
  /// last definition for a given variable is recorded in this table,
  /// back-references are used for uses after any the other definition.
  StringMap<StringRef> GlobalVariableTable;

  /// Map of all pattern variables defined so far.  Used at parse time to
  /// detect a name conflict between a numeric variable and a pattern variable
  /// when the former is defined on a later line than the latter.
  StringMap<bool> DefinedVariableTable;

  /// When matching a given pattern, this holds the pointers to the classes
  /// representing the AST of all numeric variables defined in previous
  /// patterns along with their values.  In a pattern only the last definition
  /// for a given variable is recorded in this table.  When matching a pattern
  /// all definitions for that pattern are recorded in NumericVariableDefs
  /// table.
  StringMap<std::shared_ptr<FileCheckNumExprVar>> GlobalNumericVariableTable;

public:
  /// Store in \p VarValue the value of pattern variable \p VarName.
  bool GetPatternVarValue(StringRef VarName, StringRef &VarValue);

  /// Define pattern and numeric variables from definitions given on the
  /// command line passed as a vector of VAR=VAL strings in \p CmdlineDefines.
  /// Report any error to \p SM.
  bool DefineCmdlineVariables(std::vector<std::string> &CmdlineDefines,
                              SourceMgr &SM);

  /// Undefine local variables (variables whose name does not start with a '$'
  /// sign), ie remove them from GlobalVariableTable.
  void ClearLocalVars(void);
};

struct FileCheckDiag;

class FileCheckPattern {
  SMLoc PatternLoc;

  /// A fixed string to match as the pattern or empty if this pattern requires
  /// a regex match.
  StringRef FixedStr;

  /// A regex string to match as the pattern or empty if this pattern requires
  /// a fixed string to match.
  std::string RegExStr;

  /// Entries in this vector represent uses of a pattern variable or a numeric
  /// expression in the pattern that need to be substituted in the regexp
  /// pattern at match time, e.g. "foo[[bar]]baz[[#N+1]]".  In this case, the
  /// RegExStr will contain "foobaz" and we'll get two entries in this vector
  /// that tells us to insert the value of pattern variable "bar" at offset 3
  /// and the value of numeric expression "N+1" at offset 6.  Uses are
  /// represented by a FileCheckPatternSubst class to abstract whether it is a
  /// pattern variable or a numeric expression.
  std::vector<FileCheckPatternSubst> MatchSubsts;

  /// Entries in this vector represent any use of a pattern variable or a
  /// numeric expression in the pattern.  Substitution are represented in the
  /// same way as in MatchSubsts above.
  std::vector<FileCheckPatternSubst> AllSubsts;

  /// Maps names of pattern variables defined in a pattern to the parenthesized
  /// capture numbers of their last definition.
  ///
  /// E.g. for the pattern "foo[[bar:.*]]baz[[bar]]quux[[bar:.*]]",
  /// VariableDefs will map "bar" to 2 corresponding to the second definition
  /// of "bar".
  ///
  /// Note: uses std::map rather than StringMap to be able to get the key when
  /// iterating over values.
  std::map<StringRef, unsigned> VariableDefs;

  /// Holds the capture parentheses number and pointer to corresponding
  /// FileCheckNumExpr class instance of all numeric expressions whose matching
  /// result must be captured, that is numeric expressions with a variable
  /// definition or using numeric variable defined on the same line.  Used to
  /// record the matched value of all those expressions and for those with a
  /// constraint to check that the matched value satisfies it.
  std::vector<FileCheckNumExprMatch> CapturedNumericExpressions;

  /// Pointer to a class instance holding the global state shared by all
  /// patterns:
  /// - tables with the values of live pattern and numeric variables at
  ///   the start of any given CHECK line;
  /// - table holding whether a pattern variable has been defined at any given
  ///   point during the parsing phase.
  FileCheckPatternContext *Context;

  Check::FileCheckType CheckTy;

  /// Line number for this CHECK pattern.  Used to determine whether a variable
  /// definition is made on an earlier line to the one with this CHECK.
  unsigned LineNumber;

public:
  explicit FileCheckPattern(Check::FileCheckType Ty,
                            FileCheckPatternContext *Context)
      : Context(Context), CheckTy(Ty) {}

  /// Returns the location in source code.
  SMLoc getLoc() const { return PatternLoc; }

  /// Returns the pointer to the global state for all patterns in this
  /// FileCheck instance.
  FileCheckPatternContext *GetContext() const { return Context; }

  bool ParseVariable(StringRef Str, bool &IsPseudo, unsigned &TrailIdx) const;
  std::shared_ptr<FileCheckNumExpr>
  ParseNumericExpression(StringRef Expr,
                         std::shared_ptr<FileCheckNumExprVar> &NumVarDef,
                         const SourceMgr &SM) const;
  bool ParsePattern(StringRef PatternStr, StringRef Prefix, SourceMgr &SM,
                    unsigned LineNumber, const FileCheckRequest &Req);
  size_t Match(StringRef Buffer, size_t &MatchLen, const SourceMgr &SM) const;
  void PrintSubsts(const SourceMgr &SM, StringRef Buffer,
                   SMRange MatchRange = None) const;
  void PrintFuzzyMatch(const SourceMgr &SM, StringRef Buffer,
                       std::vector<FileCheckDiag> *Diags) const;

  bool hasVariable() const {
    return !(AllSubsts.empty() && VariableDefs.empty());
  }

  Check::FileCheckType getCheckTy() const { return CheckTy; }

  int getCount() const { return CheckTy.getCount(); }

private:
  bool AddRegExToRegEx(StringRef RS, unsigned &CurParen, SourceMgr &SM);
  void AddBackrefToRegEx(unsigned BackrefNum);
  unsigned ComputeMatchDistance(StringRef Buffer) const;
  size_t FindRegexVarEnd(StringRef Str, SourceMgr &SM);

  /// Numeric expression parsing helpers.
  std::shared_ptr<FileCheckNumExprVar>
  ParseNumericVariable(StringRef &Expr, bool IsDefinition,
                       const SourceMgr &SM) const;
  std::shared_ptr<FileCheckNumExprAST>
  ParseNumericOperand(StringRef &Expr, const SourceMgr &SM,
                      struct FileCheckNumExprFmtType &ImplicitFmt,
                      enum Check::FileCheckPhase &KnownPhase) const;
  std::shared_ptr<FileCheckNumExprAST>
  ParseFileCheckBinop(StringRef &Expr, std::shared_ptr<FileCheckNumExprAST> Opl,
                      const SourceMgr &SM,
                      struct FileCheckNumExprFmtType &ImplicitFmt,
                      enum Check::FileCheckPhase &KnownPhase) const;
  std::shared_ptr<FileCheckNumExpr>
  ParseLegacyNumericExpression(StringRef Expr, StringRef Name,
                               StringRef Trailer, const SourceMgr &SM) const;
};

//===----------------------------------------------------------------------===//
/// Summary of a FileCheck diagnostic.
//===----------------------------------------------------------------------===//

struct FileCheckDiag {
  /// What is the FileCheck directive for this diagnostic?
  Check::FileCheckType CheckTy;
  /// Where is the FileCheck directive for this diagnostic?
  unsigned CheckLine, CheckCol;
  /// What type of match result does this diagnostic describe?
  ///
  /// A directive's supplied pattern is said to be either expected or excluded
  /// depending on whether the pattern must have or must not have a match in
  /// order for the directive to succeed.  For example, a CHECK directive's
  /// pattern is expected, and a CHECK-NOT directive's pattern is excluded.
  /// All match result types whose names end with "Excluded" are for excluded
  /// patterns, and all others are for expected patterns.
  ///
  /// There might be more than one match result for a single pattern.  For
  /// example, there might be several discarded matches
  /// (MatchFoundButDiscarded) before either a good match
  /// (MatchFoundAndExpected) or a failure to match (MatchNoneButExpected),
  /// and there might be a fuzzy match (MatchFuzzy) after the latter.
  enum MatchType {
    /// Indicates a good match for an expected pattern.
    MatchFoundAndExpected,
    /// Indicates a match for an excluded pattern.
    MatchFoundButExcluded,
    /// Indicates a match for an expected pattern, but the match is on the
    /// wrong line.
    MatchFoundButWrongLine,
    /// Indicates a discarded match for an expected pattern.
    MatchFoundButDiscarded,
    /// Indicates no match for an excluded pattern.
    MatchNoneAndExcluded,
    /// Indicates no match for an expected pattern, but this might follow good
    /// matches when multiple matches are expected for the pattern, or it might
    /// follow discarded matches for the pattern.
    MatchNoneButExpected,
    /// Indicates a fuzzy match that serves as a suggestion for the next
    /// intended match for an expected pattern with too few or no good matches.
    MatchFuzzy,
  } MatchTy;
  /// The search range if MatchTy is MatchNoneAndExcluded or
  /// MatchNoneButExpected, or the match range otherwise.
  unsigned InputStartLine;
  unsigned InputStartCol;
  unsigned InputEndLine;
  unsigned InputEndCol;
  FileCheckDiag(const SourceMgr &SM, const Check::FileCheckType &CheckTy,
                SMLoc CheckLoc, MatchType MatchTy, SMRange InputRange);
};

//===----------------------------------------------------------------------===//
// Check Strings.
//===----------------------------------------------------------------------===//

/// A check that we found in the input file.
struct FileCheckString {
  /// The pattern to match.
  FileCheckPattern Pat;

  /// Which prefix name this check matched.
  StringRef Prefix;

  /// The location in the match file that the check string was specified.
  SMLoc Loc;

  /// All of the strings that are disallowed from occurring between this match
  /// string and the previous one (or start of file).
  std::vector<FileCheckPattern> DagNotStrings;

  FileCheckString(const FileCheckPattern &P, StringRef S, SMLoc L)
      : Pat(P), Prefix(S), Loc(L) {}

  size_t Check(const SourceMgr &SM, StringRef Buffer, bool IsLabelScanMode,
               size_t &MatchLen, FileCheckRequest &Req,
               std::vector<FileCheckDiag> *Diags) const;

  bool CheckNext(const SourceMgr &SM, StringRef Buffer) const;
  bool CheckSame(const SourceMgr &SM, StringRef Buffer) const;
  bool CheckNot(const SourceMgr &SM, StringRef Buffer,
                const std::vector<const FileCheckPattern *> &NotStrings,
                const FileCheckRequest &Req,
                std::vector<FileCheckDiag> *Diags) const;
  size_t CheckDag(const SourceMgr &SM, StringRef Buffer,
                  std::vector<const FileCheckPattern *> &NotStrings,
                  const FileCheckRequest &Req,
                  std::vector<FileCheckDiag> *Diags) const;
};

/// FileCheck class takes the request and exposes various methods that
/// use information from the request.
class FileCheck {
  FileCheckRequest Req;

public:
  FileCheck(FileCheckRequest Req) : Req(Req) {}

  // Combines the check prefixes into a single regex so that we can efficiently
  // scan for any of the set.
  //
  // The semantics are that the longest-match wins which matches our regex
  // library.
  Regex buildCheckPrefixRegex();

  /// Read the check file, which specifies the sequence of expected strings.
  ///
  /// The strings are added to the CheckStrings vector. Returns true in case of
  /// an error, false otherwise.
  bool ReadCheckFile(SourceMgr &SM, StringRef Buffer, Regex &PrefixRE,
                     std::vector<FileCheckString> &CheckStrings);

  bool ValidateCheckPrefixes();

  /// Canonicalize whitespaces in the file. Line endings are replaced with
  /// UNIX-style '\n'.
  StringRef CanonicalizeFile(MemoryBuffer &MB,
                             SmallVectorImpl<char> &OutputBuffer);

  /// Check the input to FileCheck provided in the \p Buffer against the \p
  /// CheckStrings read from the check file.
  ///
  /// Returns false if the input fails to satisfy the checks.
  bool CheckInput(SourceMgr &SM, StringRef Buffer,
                  ArrayRef<FileCheckString> CheckStrings,
                  std::vector<FileCheckDiag> *Diags = nullptr);
};
} // namespace llvm
#endif