};
Trivial ret_trivial() { return {}; }
void pass_trivial(Trivial e) {}
-// CHECK-INTEL: [[DEFINE:define( dso_local)?]] i32 @{{.*}}ret_trivial
-// CHECK-AARCH: [[DEFINE:define( dso_local)?]] i32 @{{.*}}ret_trivial
-// CHECK-INTEL: [[DEFINE]] void @{{.*}}pass_trivial{{.*}}(i32 %
-// CHECK-AARCH: [[DEFINE]] void @{{.*}}pass_trivial{{.*}}(i64 %
+// CHECK-INTEL: [[DEF:define( dso_local)?]] i32 @{{.*}}ret_trivial
+// CHECK-AARCH: [[DEF:define( dso_local)?]] i32 @{{.*}}ret_trivial
+// CHECK-INTEL: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i32 %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i64 %
struct NoCopy {
int a;
};
NoCopy ret_nocopy() { return {}; }
void pass_nocopy(NoCopy e) {}
-// CHECK: [[DEFINE]] void @{{.*}}ret_nocopy{{.*}}(%"struct.check_structs::NoCopy"* noalias sret({{[^)]+}}) align 4 %
-// CHECK: [[DEFINE]] void @{{.*}}pass_nocopy{{.*}}(%"struct.check_structs::NoCopy"* noundef %
+// CHECK: [[DEF]] void @{{.*}}ret_nocopy{{.*}}(%"struct.check_structs::NoCopy"* noalias sret({{[^)]+}}) align 4 %
+// CHECK: [[DEF]] void @{{.*}}pass_nocopy{{.*}}(%"struct.check_structs::NoCopy"* noundef %
struct Huge {
int a[1024];
};
Huge ret_huge() { return {}; }
void pass_huge(Huge h) {}
-// CHECK: [[DEFINE]] void @{{.*}}ret_huge{{.*}}(%"struct.check_structs::Huge"* noalias sret({{[^)]+}}) align 4 %
-// CHECK: [[DEFINE]] void @{{.*}}pass_huge{{.*}}(%"struct.check_structs::Huge"* noundef
+// CHECK: [[DEF]] void @{{.*}}ret_huge{{.*}}(%"struct.check_structs::Huge"* noalias sret({{[^)]+}}) align 4 %
+// CHECK: [[DEF]] void @{{.*}}pass_huge{{.*}}(%"struct.check_structs::Huge"* noundef
} // namespace check_structs
//************ Passing unions by value
};
Trivial ret_trivial() { return {}; }
void pass_trivial(Trivial e) {}
-// CHECK-INTEL: [[DEFINE]] i32 @{{.*}}ret_trivial
-// CHECK-AARCH: [[DEFINE]] i32 @{{.*}}ret_trivial
-// CHECK-INTEL: [[DEFINE]] void @{{.*}}pass_trivial{{.*}}(i32 %
-// CHECK-AARCH: [[DEFINE]] void @{{.*}}pass_trivial{{.*}}(i64 %
+// CHECK-INTEL: [[DEF]] i32 @{{.*}}ret_trivial
+// CHECK-AARCH: [[DEF]] i32 @{{.*}}ret_trivial
+// CHECK-INTEL: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i32 %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_trivial{{.*}}(i64 %
union NoCopy {
int a;
};
NoCopy ret_nocopy() { return {}; }
void pass_nocopy(NoCopy e) {}
-// CHECK: [[DEFINE]] void @{{.*}}ret_nocopy{{.*}}(%"union.check_unions::NoCopy"* noalias sret({{[^)]+}}) align 4 %
-// CHECK: [[DEFINE]] void @{{.*}}pass_nocopy{{.*}}(%"union.check_unions::NoCopy"* noundef %
+// CHECK: [[DEF]] void @{{.*}}ret_nocopy{{.*}}(%"union.check_unions::NoCopy"* noalias sret({{[^)]+}}) align 4 %
+// CHECK: [[DEF]] void @{{.*}}pass_nocopy{{.*}}(%"union.check_unions::NoCopy"* noundef %
} // namespace check_unions
//************ Passing `this` pointers
void pass_vec(i32x3 v) {
}
-// CHECK: [[DEFINE]] noundef <3 x i32> @{{.*}}ret_vec{{.*}}()
-// CHECK-INTEL: [[DEFINE]] void @{{.*}}pass_vec{{.*}}(<3 x i32> noundef %
-// CHECK-AARCH: [[DEFINE]] void @{{.*}}pass_vec{{.*}}(<4 x i32> %
+// CHECK: [[DEF]] noundef <3 x i32> @{{.*}}ret_vec{{.*}}()
+// CHECK-INTEL: [[DEF]] void @{{.*}}pass_vec{{.*}}(<3 x i32> noundef %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_vec{{.*}}(<4 x i32> %
} // namespace check_vecs
//************ Passing exotic types
}
// Pointers to arrays/functions are always noundef
-// CHECK: [[DEFINE]] noundef [32 x i32]* @{{.*}}ret_arrptr{{.*}}()
-// CHECK: [[DEFINE]] noundef i32 (i32)* @{{.*}}ret_fnptr{{.*}}()
+// CHECK: [[DEF]] noundef [32 x i32]* @{{.*}}ret_arrptr{{.*}}()
+// CHECK: [[DEF]] noundef i32 (i32)* @{{.*}}ret_fnptr{{.*}}()
// Pointers to members are never noundef
-// CHECK: [[DEFINE]] i64 @{{.*}}ret_mdptr{{.*}}()
-// CHECK-INTEL: [[DEFINE]] { i64, i64 } @{{.*}}ret_mfptr{{.*}}()
-// CHECK-AARCH: [[DEFINE]] [2 x i64] @{{.*}}ret_mfptr{{.*}}()
+// CHECK: [[DEF]] i64 @{{.*}}ret_mdptr{{.*}}()
+// CHECK-INTEL: [[DEF]] { i64, i64 } @{{.*}}ret_mfptr{{.*}}()
+// CHECK-AARCH: [[DEF]] [2 x i64] @{{.*}}ret_mfptr{{.*}}()
// nullptr_t is never noundef
-// CHECK: [[DEFINE]] i8* @{{.*}}ret_npt{{.*}}()
-// CHECK: [[DEFINE]] void @{{.*}}pass_npt{{.*}}(i8* %
+// CHECK: [[DEF]] i8* @{{.*}}ret_npt{{.*}}()
+// CHECK: [[DEF]] void @{{.*}}pass_npt{{.*}}(i8* %
// TODO: for now, ExtInt is only noundef if it is sign/zero-extended
-// CHECK-INTEL: [[DEFINE]] noundef signext i3 @{{.*}}ret_BitInt{{.*}}()
-// CHECK-AARCH: [[DEFINE]] i3 @{{.*}}ret_BitInt{{.*}}()
-// CHECK-INTEL: [[DEFINE]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef signext %
-// CHECK-AARCH: [[DEFINE]] void @{{.*}}pass_BitInt{{.*}}(i3 %
-// CHECK-INTEL: [[DEFINE]] void @{{.*}}pass_large_BitInt{{.*}}(i64 %{{.*}}, i64 %
-// CHECK-AARCH: [[DEFINE]] void @{{.*}}pass_large_BitInt{{.*}}(i127 %
+// CHECK-INTEL: [[DEF]] noundef signext i3 @{{.*}}ret_BitInt{{.*}}()
+// CHECK-AARCH: [[DEF]] i3 @{{.*}}ret_BitInt{{.*}}()
+// CHECK-INTEL: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 noundef signext %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_BitInt{{.*}}(i3 %
+// CHECK-INTEL: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i64 %{{.*}}, i64 %
+// CHECK-AARCH: [[DEF]] void @{{.*}}pass_large_BitInt{{.*}}(i127 %
} // namespace check_exotic
// CHECK: @indirect_callee_union_ptr = [[GLOBAL]] i32 (i32)*
union u1 (*indirect_callee_union_ptr)(union u1);
-// CHECK: [[DEFINE:define( dso_local)?]] noundef i32 @{{.*}}indirect_callee_int{{.*}}(i32 noundef %
+// CHECK: [[DEF:define( dso_local)?]] noundef i32 @{{.*}}indirect_callee_int{{.*}}(i32 noundef %
int indirect_callee_int(int a) { return a; }
-// CHECK: [[DEFINE]] i32 @{{.*}}indirect_callee_union{{.*}}(i32 %
+// CHECK: [[DEF]] i32 @{{.*}}indirect_callee_union{{.*}}(i32 %
union u1 indirect_callee_union(union u1 a) {
return a;
}
// SPARC64-OBSD:#define __UINTMAX_C_SUFFIX__ ULL
// SPARC64-OBSD:#define __UINTMAX_TYPE__ long long unsigned int
//
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64-pc-kfreebsd-gnu < /dev/null | FileCheck -match-full-lines -check-prefix KFREEBSD-DEFINE %s
-// KFREEBSD-DEFINE:#define __FreeBSD_kernel__ 1
-// KFREEBSD-DEFINE:#define __GLIBC__ 1
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=x86_64-pc-kfreebsd-gnu < /dev/null | FileCheck -match-full-lines -check-prefix KFREEBSD-DEF %s
+// KFREEBSD-DEF:#define __FreeBSD_kernel__ 1
+// KFREEBSD-DEF:#define __GLIBC__ 1
//
-// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i686-pc-kfreebsd-gnu < /dev/null | FileCheck -match-full-lines -check-prefix KFREEBSDI686-DEFINE %s
-// KFREEBSDI686-DEFINE:#define __FreeBSD_kernel__ 1
-// KFREEBSDI686-DEFINE:#define __GLIBC__ 1
+// RUN: %clang_cc1 -E -dM -ffreestanding -triple=i686-pc-kfreebsd-gnu < /dev/null | FileCheck -match-full-lines -check-prefix KFREEBSDI686-DEF %s
+// KFREEBSDI686-DEF:#define __FreeBSD_kernel__ 1
+// KFREEBSDI686-DEF:#define __GLIBC__ 1
//
// RUN: %clang_cc1 -x c++ -triple i686-pc-linux-gnu -fobjc-runtime=gcc -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSOURCE %s
// RUN: %clang_cc1 -x c++ -triple sparc-rtems-elf -E -dM < /dev/null | FileCheck -match-full-lines -check-prefix GNUSOURCE %s
further substitution patterns can be defined by each test module. See the
modules :ref:`local-configuration-files`.
-By default, substitutions are expanded exactly once, so that if e.g. a
-substitution ``%build`` is defined in top of another substitution ``%cxx``,
-``%build`` will expand to ``%cxx`` textually, not to what ``%cxx`` expands to.
-However, if the ``recursiveExpansionLimit`` property of the ``TestingConfig``
-is set to a non-negative integer, substitutions will be expanded recursively
-until that limit is reached. It is an error if the limit is reached and
-expanding substitutions again would yield a different result.
-
More detailed information on substitutions can be found in the
:doc:`../TestingGuide`.
``%else %{<else branch>%}`` is optional and treated like ``%else %{%}``
if not present.
+``%(line)``, ``%(line+<number>)``, ``%(line-<number>)``
+
+ The number of the line where this substitution is used, with an
+ optional integer offset. These expand only if they appear
+ immediately in ``RUN:``, ``DEFINE:``, and ``REDEFINE:`` directives.
+ Occurrences in substitutions defined elsewhere are never expanded.
+ For example, this can be used in tests with multiple RUN lines,
+ which reference the test file's line numbers.
+
**LLVM-specific substitutions:**
``%shlibext``
Example: ``.exe`` (Windows), empty on Linux.
-``%(line)``, ``%(line+<number>)``, ``%(line-<number>)``
- The number of the line where this substitution is used, with an optional
- integer offset. This can be used in tests with multiple RUN lines, which
- reference test file's line numbers.
-
-
**Clang-specific substitutions:**
``%clang``
output affects test results. It's usually easy to tell: just look for
redirection or piping of the ``FileCheck`` call's stdout or stderr.
-To add more substitutions, look at ``test/lit.cfg`` or ``lit.local.cfg``.
+.. _Test-specific substitutions:
+
+**Test-specific substitutions:**
+
+Additional substitutions can be defined as follows:
+
+- Lit configuration files (e.g., ``lit.cfg`` or ``lit.local.cfg``) can define
+ substitutions for all tests in a test directory. They do so by extending the
+ substitution list, ``config.substitutions``. Each item in the list is a tuple
+ consisting of a pattern and its replacement, which lit applies using python's
+ ``re.sub`` function.
+- To define substitutions within a single test file, lit supports the
+ ``DEFINE:`` and ``REDEFINE:`` directives, described in detail below. So that
+ they have no effect on other test files, these directives modify a copy of the
+ substitution list that is produced by lit configuration files.
+
+For example, the following directives can be inserted into a test file to define
+``%{cflags}`` and ``%{fcflags}`` substitutions with empty initial values, which
+serve as the parameters of another newly defined ``%{check}`` substitution:
+
+.. code-block:: llvm
+
+ ; DEFINE: %{cflags} =
+ ; DEFINE: %{fcflags} =
+
+ ; DEFINE: %{check} = \
+ ; DEFINE: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %{cflags} \
+ ; DEFINE: -emit-llvm -o - %s | \
+ ; DEFINE: FileCheck %{fcflags} %s
+
+Alternatively, the above substitutions can be defined in a lit configuration
+file to be shared with other test files. Either way, the test file can then
+specify directives like the following to redefine the parameter substitutions as
+desired before each use of ``%{check}`` in a ``RUN:`` line:
+
+.. code-block:: llvm
+
+ ; REDEFINE: %{cflags} = -triple x86_64-apple-darwin10.6.0 -fopenmp-simd
+ ; REDEFINE: %{fcflags} = -check-prefix=SIMD
+ ; RUN: %{check}
+
+ ; REDEFINE: %{cflags} = -triple x86_64-unknown-linux-gnu -fopenmp-simd
+ ; REDEFINE: %{fcflags} = -check-prefix=SIMD
+ ; RUN: %{check}
+
+ ; REDEFINE: %{cflags} = -triple x86_64-apple-darwin10.6.0
+ ; REDEFINE: %{fcflags} = -check-prefix=NO-SIMD
+ ; RUN: %{check}
+
+ ; REDEFINE: %{cflags} = -triple x86_64-unknown-linux-gnu
+ ; REDEFINE: %{fcflags} = -check-prefix=NO-SIMD
+ ; RUN: %{check}
+
+Besides providing initial values, the initial ``DEFINE:`` directives for the
+parameter substitutions in the above example serve a second purpose: they
+establish the substitution order so that both ``%{check}`` and its parameters
+expand as desired. There's a simple way to remember the required definition
+order in a test file: define a substitution before any substitution that might
+refer to it.
+
+In general, substitution expansion behaves as follows:
+
+- Upon arriving at each ``RUN:`` line, lit expands all substitutions in that
+ ``RUN:`` line using their current values from the substitution list. No
+ substitution expansion is performed immediately at ``DEFINE:`` and
+ ``REDEFINE:`` directives except ``%(line)``, ``%(line+<number>)``, and
+ ``%(line-<number>)``.
+- When expanding substitutions in a ``RUN:`` line, lit makes only one pass
+ through the substitution list by default. In this case, a substitution must
+ have been inserted earlier in the substitution list than any substitution
+ appearing in its value in order for the latter to expand. (For greater
+ flexibility, you can enable multiple passes through the substitution list by
+ setting `recursiveExpansionLimit`_ in a lit configuration file.)
+- While lit configuration files can insert anywhere in the substitution list,
+ the insertion behavior of the ``DEFINE:`` and ``REDEFINE:`` directives is
+ specified below and is designed specifically for the use case presented in the
+ example above.
+- Defining a substitution in terms of itself, whether directly or via other
+ substitutions, should be avoided. It usually produces an infinitely recursive
+ definition that cannot be fully expanded. It does *not* define the
+ substitution in terms of its previous value, even when using ``REDEFINE:``.
+
+The relationship between the ``DEFINE:`` and ``REDEFINE:`` directive is
+analogous to the relationship between a variable declaration and variable
+assignment in many programming languages:
+
+- ``DEFINE: %{name} = value``
+
+ This directive assigns the specified value to a new substitution whose
+ pattern is ``%{name}``, or it reports an error if there is already a
+ substitution whose pattern contains ``%{name}`` because that could produce
+ confusing expansions (e.g., a lit configuration file might define a
+ substitution with the pattern ``%{name}\[0\]``). The new substitution is
+ inserted at the start of the substitution list so that it will expand first.
+ Thus, its value can contain any substitution previously defined, whether in
+ the same test file or in a lit configuration file, and both will expand.
+
+- ``REDEFINE: %{name} = value``
+
+ This directive assigns the specified value to an existing substitution whose
+ pattern is ``%{name}``, or it reports an error if there are no substitutions
+ with that pattern or if there are multiple substitutions whose patterns
+ contain ``%{name}``. The substitution's current position in the substitution
+ list does not change so that expansion order relative to other existing
+ substitutions is preserved.
+
+The following properties apply to both the ``DEFINE:`` and ``REDEFINE:``
+directives:
+
+- **Substitution name**: In the directive, whitespace immediately before or
+ after ``%{name}`` is optional and discarded. ``%{name}`` must start with
+ ``%{``, it must end with ``}``, and the rest must start with a letter or
+ underscore and contain only alphanumeric characters, hyphens, underscores, and
+ colons. This syntax has a few advantages:
+
+ - It is impossible for ``%{name}`` to contain sequences that are special in
+ python's ``re.sub`` patterns. Otherwise, attempting to specify
+ ``%{name}`` as a substitution pattern in a lit configuration file could
+ produce confusing expansions.
+ - The braces help avoid the possibility that another substitution's pattern
+ will match part of ``%{name}`` or vice-versa, producing confusing
+ expansions. However, the patterns of substitutions defined by lit
+ configuration files and by lit itself are not restricted to this form, so
+ overlaps are still theoretically possible.
+
+- **Substitution value**: The value includes all text from the first
+ non-whitespace character after ``=`` to the last non-whitespace character. If
+ there is no non-whitespace character after ``=``, the value is the empty
+ string. Escape sequences that can appear in python ``re.sub`` replacement
+ strings are treated as plain text in the value.
+- **Line continuations**: If the last non-whitespace character on the line after
+ ``:`` is ``\``, then the next directive must use the same directive keyword
+ (e.g., ``DEFINE:``) , and it is an error if there is no additional directive.
+ That directive serves as a continuation. That is, before following the rules
+ above to parse the text after ``:`` in either directive, lit joins that text
+ together to form a single directive, replaces the ``\`` with a single space,
+ and removes any other whitespace that is now adjacent to that space. A
+ continuation can be continued in the same manner. A continuation containing
+ only whitespace after its ``:`` is an error.
+
+.. _recursiveExpansionLimit:
+
+**recursiveExpansionLimit:**
+
+As described in the previous section, when expanding substitutions in a ``RUN:``
+line, lit makes only one pass through the substitution list by default. Thus,
+if substitutions are not defined in the proper order, some will remain in the
+``RUN:`` line unexpanded. For example, the following directives refer to
+``%{inner}`` within ``%{outer}`` but do not define ``%{inner}`` until after
+``%{outer}``:
+
+.. code-block:: llvm
+
+ ; By default, this definition order does not enable full expansion.
+
+ ; DEFINE: %{outer} = %{inner}
+ ; DEFINE: %{inner} = expanded
+
+ ; RUN: echo '%{outer}'
+
+``DEFINE:`` inserts substitutions at the start of the substitution list, so
+``%{inner}`` expands first but has no effect because the original ``RUN:`` line
+does not contain ``%{inner}``. Next, ``%{outer}`` expands, and the output of
+the ``echo`` command becomes:
+
+.. code-block:: shell
+
+ %{inner}
+
+Of course, one way to fix this simple case is to reverse the definitions of
+``%{outer}`` and ``%{inner}``. However, if a test has a complex set of
+substitutions that can all reference each other, there might not exist a
+sufficient substitution order.
+
+To address such use cases, lit configuration files support
+``config.recursiveExpansionLimit``, which can be set to a non-negative integer
+to specify the maximum number of passes through the substitution list. Thus, in
+the above example, setting the limit to 2 would cause lit to make a second pass
+that expands ``%{inner}`` in the ``RUN:`` line, and the output from the ``echo``
+command when then be:
+
+.. code-block:: shell
+
+ expanded
+
+To improve performance, lit will stop making passes when it notices the ``RUN:``
+line has stopped changing. In the above example, setting the limit higher than
+2 is thus harmless.
+To facilitate debugging, after reaching the limit, lit will make one extra pass
+and report an error if the ``RUN:`` line changes again. In the above example,
+setting the limit to 1 will thus cause lit to report an error instead of
+producing incorrect output.
Options
-------
; HELP_TEST: OVERVIEW: Resource Converter
; HELP_TEST-DAG: USAGE: llvm-cvtres [options] file...
; HELP_TEST-DAG: OPTIONS:
-; HELP_TEST-NEXT: /DEFINE:symbol Not implemented
+; HELP_TEST-NEXT: /{{DEFINE}}:symbol Not implemented
; HELP_TEST-NEXT: /FOLDDUPS: Not implemented
; HELP_TEST-NEXT: /HELP Display available options
; HELP_TEST-NEXT: /MACHINE:{ARM|ARM64|EBC|IA64|X64|X86}
## Check we can redefine fields of the first SHT_NULL section.
# RUN: yaml2obj --docnum=3 %s -o %t3
-# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=REDEFINE
+# RUN: llvm-readelf --sections %t3 | FileCheck %s --check-prefix=REDEF
-# REDEFINE: Section Headers:
-# REDEFINE-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
-# REDEFINE-NEXT: [ 0] .foo NULL 0000000000000006 000000 000002 03 A 4 5 1
+# REDEF: Section Headers:
+# REDEF-NEXT: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
+# REDEF-NEXT: [ 0] .foo NULL 0000000000000006 000000 000002 03 A 4 5 1
--- !ELF
FileHeader:
def _caching_re_compile(r):
return re.compile(r)
+class ExpandableScriptDirective(object):
+ """
+ Common interface for lit directives for which any lit substitutions must be
+ expanded to produce the shell script. It includes directives (e.g., 'RUN:')
+ specifying shell commands that might have lit substitutions to be expanded.
+ It also includes lit directives (e.g., 'DEFINE:') that adjust substitutions.
+
+ start_line_number: The directive's starting line number.
+ end_line_number: The directive's ending line number, which is
+ start_line_number if the directive has no line continuations.
+ keyword: The keyword that specifies the directive. For example, 'RUN:'.
+ """
+
+ def __init__(self, start_line_number, end_line_number, keyword):
+ # Input line number where the directive starts.
+ self.start_line_number = start_line_number
+ # Input line number where the directive ends.
+ self.end_line_number = end_line_number
+ # The keyword used to indicate the directive.
+ self.keyword = keyword
+
+ def add_continuation(self, line_number, keyword, line):
+ """
+ Add a continuation line to this directive and return True, or do nothing
+ and return False if the specified line is not a continuation for this
+ directive (e.g., previous line does not end in '\', or keywords do not
+ match).
+
+ line_number: The line number for the continuation line.
+ keyword: The keyword that specifies the continuation line. For example,
+ 'RUN:'.
+ line: The content of the continuation line after the keyword.
+ """
+ assert False, "expected method to be called on derived class"
+
+ def needs_continuation(self):
+ """
+ Does this directive require a continuation line?
+
+ '\' is documented as indicating a line continuation even if whitespace
+ separates it from the newline. It looks like a line continuation, and
+ it would be confusing if it didn't behave as one.
+ """
+ assert False, "expected method to be called on derived class"
+
+ def get_location(self):
+ """
+ Get a phrase describing the line or range of lines so far included by
+ this directive and any line continuations.
+ """
+ if self.start_line_number == self.end_line_number:
+ return f'at line {self.start_line_number}'
+ return f'from line {self.start_line_number} to {self.end_line_number}'
+
+class CommandDirective(ExpandableScriptDirective):
+ """
+ A lit directive taking a shell command line. For example,
+ 'RUN: echo hello world'.
+
+ command: The content accumulated so far from the directive and its
+ continuation lines.
+ """
+
+ def __init__(self, start_line_number, end_line_number, keyword, line):
+ super().__init__(start_line_number, end_line_number, keyword)
+ self.command = line.rstrip()
+
+ def add_continuation(self, line_number, keyword, line):
+ if keyword != self.keyword or not self.needs_continuation():
+ return False
+ self.command = self.command[:-1] + line.rstrip()
+ self.end_line_number = line_number
+ return True
+
+ def needs_continuation(self):
+ # Trailing whitespace is stripped immediately when each line is added,
+ # so '\' is never hidden here.
+ return self.command[-1] == '\\'
+
+class SubstDirective(ExpandableScriptDirective):
+ """
+ A lit directive taking a substitution definition or redefinition. For
+ example, 'DEFINE: %{name} = value'.
+
+ new_subst: True if this directive defines a new substitution. False if it
+ redefines an existing substitution.
+ body: The unparsed content accumulated so far from the directive and its
+ continuation lines.
+ name: The substitution's name, or None if more continuation lines are still
+ required.
+ value: The substitution's value, or None if more continuation lines are
+ still required.
+ """
+
+ def __init__(self, start_line_number, end_line_number, keyword, new_subst,
+ line):
+ super().__init__(start_line_number, end_line_number, keyword)
+ self.new_subst = new_subst
+ self.body = line
+ self.name = None
+ self.value = None
+ self._parse_body()
+
+ def add_continuation(self, line_number, keyword, line):
+ if keyword != self.keyword or not self.needs_continuation():
+ return False
+ if not line.strip():
+ raise ValueError("Substitution's continuation is empty")
+ # Append line. Replace the '\' and any adjacent whitespace with a
+ # single space.
+ self.body = self.body.rstrip()[:-1].rstrip() + ' ' + line.lstrip()
+ self.end_line_number = line_number
+ self._parse_body()
+ return True
+
+ def needs_continuation(self):
+ return self.body.rstrip()[-1:] == '\\'
+
+ def _parse_body(self):
+ """
+ If no more line continuations are required, parse all the directive's
+ accumulated lines in order to identify the substitution's name and full
+ value, and raise an exception if invalid.
+ """
+ if self.needs_continuation():
+ return
+
+ # Extract the left-hand side and value, and discard any whitespace
+ # enclosing each.
+ parts = self.body.split('=', 1)
+ if len(parts) == 1:
+ raise ValueError("Substitution's definition does not contain '='")
+ self.name = parts[0].strip()
+ self.value = parts[1].strip()
+
+ # Check the substitution's name.
+ #
+ # Do not extend this to permit '.' or any sequence that's special in a
+ # python pattern. We could escape that automatically for
+ # DEFINE/REDEFINE directives in test files. However, lit configuration
+ # file authors would still have to remember to escape them manually in
+ # substitution names but not in values. Moreover, the manually chosen
+ # and automatically chosen escape sequences would have to be consistent
+ # (e.g., '\.' vs. '[.]') in order for REDEFINE to successfully redefine
+ # a substitution previously defined by a lit configuration file. All
+ # this seems too error prone and confusing to be worthwhile. If you
+ # want your name to express structure, use ':' instead of '.'.
+ #
+ # Actually, '{' and '}' are special if they contain only digits possibly
+ # separated by a comma. Requiring a leading letter avoids that.
+ if not re.fullmatch(r'%{[_a-zA-Z][-_:0-9a-zA-Z]*}', self.name):
+ raise ValueError(
+ f"Substitution name '{self.name}' is malformed as it must "
+ f"start with '%{{', it must end with '}}', and the rest must "
+ f"start with a letter or underscore and contain only "
+ f"alphanumeric characters, hyphens, underscores, and colons")
+
+ def adjust_substitutions(self, substitutions):
+ """
+ Modify the specified substitution list as specified by this directive.
+ """
+ assert not self.needs_continuation(), \
+ "expected directive continuations to be parsed before applying"
+ value_repl = self.value.replace('\\', '\\\\')
+ existing = [i for i, subst in enumerate(substitutions)
+ if self.name in subst[0]]
+ existing_res = ''.join("\nExisting pattern: " + substitutions[i][0]
+ for i in existing)
+ if self.new_subst:
+ if existing:
+ raise ValueError(
+ f"Substitution whose pattern contains '{self.name}' is "
+ f"already defined before '{self.keyword}' directive "
+ f"{self.get_location()}"
+ f"{existing_res}")
+ substitutions.insert(0, (self.name, value_repl))
+ return
+ if len(existing) > 1:
+ raise ValueError(
+ f"Multiple substitutions whose patterns contain '{self.name}' "
+ f"are defined before '{self.keyword}' directive "
+ f"{self.get_location()}"
+ f"{existing_res}")
+ if not existing:
+ raise ValueError(
+ f"No substitution for '{self.name}' is defined before "
+ f"'{self.keyword}' directive {self.get_location()}")
+ if substitutions[existing[0]][0] != self.name:
+ raise ValueError(
+ f"Existing substitution whose pattern contains '{self.name}' "
+ f"does not have the pattern specified by '{self.keyword}' "
+ f"directive {self.get_location()}\n"
+ f"Expected pattern: {self.name}"
+ f"{existing_res}")
+ substitutions[existing[0]] = (self.name, value_repl)
+
+
def applySubstitutions(script, substitutions, conditions={},
recursion_limit=None):
"""
return processed
process = processLine if recursion_limit is None else processLineToFixedPoint
-
- return [unescapePercents(process(ln)) for ln in script]
+ output = []
+ for directive in script:
+ if isinstance(directive, SubstDirective):
+ directive.adjust_substitutions(substitutions)
+ else:
+ if isinstance(directive, CommandDirective):
+ line = directive.command
+ else:
+ # Can come from preamble_commands.
+ assert isinstance(directive, str)
+ line = directive
+ output.append(unescapePercents(process(line)))
+
+ return output
class ParserKind(object):
boolean expressions. Ex 'XFAIL:'
INTEGER: A keyword taking a single integer. Ex 'ALLOW_RETRIES:'
CUSTOM: A keyword with custom parsing semantics.
+ DEFINE: A keyword taking a new lit substitution definition. Ex
+ 'DEFINE: %{name}=value'
+ REDEFINE: A keyword taking a lit substitution redefinition. Ex
+ 'REDEFINE: %{name}=value'
"""
TAG = 0
COMMAND = 1
BOOLEAN_EXPR = 3
INTEGER = 4
CUSTOM = 5
+ DEFINE = 6
+ REDEFINE = 7
@staticmethod
def allowedKeywordSuffixes(value):
ParserKind.LIST: [':'],
ParserKind.BOOLEAN_EXPR: [':'],
ParserKind.INTEGER: [':'],
- ParserKind.CUSTOM: [':', '.']
+ ParserKind.CUSTOM: [':', '.'],
+ ParserKind.DEFINE: [':'],
+ ParserKind.REDEFINE: [':']
} [value]
@staticmethod
ParserKind.LIST: 'LIST',
ParserKind.BOOLEAN_EXPR: 'BOOLEAN_EXPR',
ParserKind.INTEGER: 'INTEGER',
- ParserKind.CUSTOM: 'CUSTOM'
+ ParserKind.CUSTOM: 'CUSTOM',
+ ParserKind.DEFINE: 'DEFINE',
+ ParserKind.REDEFINE: 'REDEFINE'
} [value]
if parser is None:
raise ValueError("ParserKind.CUSTOM requires a custom parser")
self.parser = parser
+ elif kind == ParserKind.DEFINE:
+ self.parser = lambda line_number, line, output: \
+ self._handleSubst(line_number, line, output,
+ self.keyword, new_subst=True)
+ elif kind == ParserKind.REDEFINE:
+ self.parser = lambda line_number, line, output: \
+ self._handleSubst(line_number, line, output,
+ self.keyword,
+ new_subst=False)
else:
raise ValueError("Unknown kind '%s'" % kind)
return (not line.strip() or output)
@staticmethod
- def _handleCommand(line_number, line, output, keyword):
- """A helper for parsing COMMAND type keywords"""
- # Trim trailing whitespace.
- line = line.rstrip()
- # Substitute line number expressions
+ def _substituteLineNumbers(line_number, line):
line = re.sub(r'%\(line\)', str(line_number), line)
-
def replace_line_number(match):
if match.group(1) == '+':
return str(line_number + int(match.group(2)))
if match.group(1) == '-':
return str(line_number - int(match.group(2)))
- line = re.sub(r'%\(line *([\+-]) *(\d+)\)', replace_line_number, line)
- # Collapse lines with trailing '\\'.
- if output and output[-1][-1] == '\\':
- output[-1] = output[-1][:-1] + line
- else:
+ return re.sub(r'%\(line *([\+-]) *(\d+)\)', replace_line_number, line)
+
+ @classmethod
+ def _handleCommand(cls, line_number, line, output, keyword):
+ """A helper for parsing COMMAND type keywords"""
+ # Substitute line number expressions.
+ line = cls._substituteLineNumbers(line_number, line)
+
+ # Collapse lines with trailing '\\', or add line with line number to
+ # start a new pipeline.
+ if not output or not output[-1].add_continuation(line_number, keyword,
+ line):
if output is None:
output = []
pdbg = "%dbg({keyword} at line {line_number})".format(
line = "{pdbg} {real_command}".format(
pdbg=pdbg,
real_command=line)
- output.append(line)
+ output.append(CommandDirective(line_number, line_number, keyword,
+ line))
return output
@staticmethod
BooleanExpression.evaluate(s, [])
return output
+ @classmethod
+ def _handleSubst(cls, line_number, line, output, keyword, new_subst):
+ """A parser for DEFINE and REDEFINE type keywords"""
+ line = cls._substituteLineNumbers(line_number, line)
+ if output and output[-1].add_continuation(line_number, keyword, line):
+ return output
+ if output is None:
+ output = []
+ output.append(SubstDirective(line_number, line_number, keyword,
+ new_subst, line))
+ return output
+
def _parseKeywords(sourcepath, additional_parsers=[],
require_script=True):
Scan an LLVM/Clang style integrated test script and extract all the lines
pertaining to a special parser. This includes 'RUN', 'XFAIL', 'REQUIRES',
- 'UNSUPPORTED' and 'ALLOW_RETRIES', as well as other specified custom
- parsers.
+ 'UNSUPPORTED', 'ALLOW_RETRIES', 'END', 'DEFINE', 'REDEFINE', as well as
+ other specified custom parsers.
Returns a dictionary mapping each custom parser to its value after
parsing the test.
IntegratedTestKeywordParser('REQUIRES:', ParserKind.BOOLEAN_EXPR),
IntegratedTestKeywordParser('UNSUPPORTED:', ParserKind.BOOLEAN_EXPR),
IntegratedTestKeywordParser('ALLOW_RETRIES:', ParserKind.INTEGER),
- IntegratedTestKeywordParser('END.', ParserKind.TAG)
+ IntegratedTestKeywordParser('END.', ParserKind.TAG),
+ IntegratedTestKeywordParser('DEFINE:', ParserKind.DEFINE,
+ initial_value=script),
+ IntegratedTestKeywordParser('REDEFINE:', ParserKind.REDEFINE,
+ initial_value=script)
]
keyword_parsers = {p.keyword: p for p in builtin_parsers}
break
# Verify the script contains a run line.
- if require_script and not script:
+ if require_script and not any(isinstance(directive, CommandDirective)
+ for directive in script):
raise ValueError("Test has no 'RUN:' line")
- # Check for unterminated run lines.
- if script and script[-1][-1] == '\\':
- raise ValueError("Test has unterminated 'RUN:' lines (with '\\')")
+ # Check for unterminated run or subst lines.
+ #
+ # If, after a line continuation for one kind of directive (e.g., 'RUN:',
+ # 'DEFINE:', 'REDEFINE:') in script, the next directive in script is a
+ # different kind, then the '\\' remains on the former, and we report it
+ # here.
+ for directive in script:
+ if directive.needs_continuation():
+ raise ValueError(f"Test has unterminated '{directive.keyword}' "
+ f"directive (with '\\') "
+ f"{directive.get_location()}")
# Check boolean expressions for unterminated lines.
for key in keyword_parsers:
except ValueError as e:
return lit.Test.Result(Test.UNRESOLVED, str(e))
script = parsed['RUN:'] or []
+ assert parsed['DEFINE:'] == script
+ assert parsed['REDEFINE:'] == script
test.xfails += parsed['XFAIL:'] or []
test.requires += parsed['REQUIRES:'] or []
test.unsupported += parsed['UNSUPPORTED:'] or []
--- /dev/null
+# DEFINE: foo %{name}=value
+# RUN: echo %{name}
+
+# CHECK: Substitution name 'foo %{name}' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# ':' is treated like part of the name, so the name is bad.
+
+# DEFINE: %{name}:=value
+# RUN: echo %{name}
+
+# CHECK: Substitution name '%{name}:' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{} = value
+# RUN: echo %{}
+
+# CHECK: Substitution name '%{}' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# In python's re.sub patterns, '.' means any character. If we permitted that
+# in a substitution name (and escaped it before recording it as a substitution),
+# it would be confusing if someone tried to use the same name in a lit
+# configuration file, where the pattern isn't escaped automatically.
+
+# DEFINE: %{foo.bar} = value
+# RUN: echo %{foo.bar}
+
+# CHECK: Substitution name '%{foo.bar}' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# The first equals counts as the equals.
+
+# DEFINE: %{foo=bar} = value
+# RUN: echo %{foo=bar}
+
+# CHECK: Substitution name '%{foo' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE:%{foo\
+# DEFINE:bar} = value
+# RUN: echo %{foo bar}
+
+# CHECK: Substitution name '%{foo bar}' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# In python's re.sub patterns, '%{3}' means three '%%%'. If we permitted that
+# as a substitution name (and escaped it before recording it as a
+# substitution), it would be confusing if someone tried to use the same name in
+# a lit configuration file, where the pattern isn't escaped automatically.
+
+# DEFINE: %{3} = value
+# RUN: echo %{3}
+
+# CHECK: Substitution name '%{3}' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{foo bar} = value
+# RUN: echo %{foo bar}
+
+# CHECK: Substitution name '%{foo bar}' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE:
+# RUN: echo Hello World
+
+# CHECK: Substitution's definition does not contain '='
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{name}: value
+# RUN: echo %{name}
+
+# CHECK: Substitution's definition does not contain '='
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE:=value
+# RUN: echo Hello World
+
+# CHECK: Substitution name '' is malformed {{.*}}
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# v~ whitespace intentional
+# DEFINE:
+# RUN: echo Hello World
+
+# CHECK: Substitution's definition does not contain '='
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# Surely an empty substitution continuation is an accident, so it's an error.
+
+# DEFINE: %{foo} = foo \
+# DEFINE:
+# RUN: echo '%{foo}'
+
+# CHECK: Substitution's continuation is empty
+# CHECK-NEXT: in DEFINE: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# This seems like a way to end a value with a backslash, but it requires an
+# empty substitution continuation, which isn't permitted.
+
+# DEFINE: %{foo} = \\
+# DEFINE:
+# RUN: echo '%{foo}'
+
+# CHECK: Substitution's continuation is empty
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a DEFINE with a REDEFINE. In this case, the REDEFINE
+# is wrong on its own because it's written as a continuation, so the bad
+# REDEFINE is reported.
+
+# DEFINE: %{foo}=echo \
+# REDEFINE: Hello World
+# DEFINE: too late to continue
+# RUN: %{foo}
+
+# CHECK: Substitution's definition does not contain '='
+# CHECK-NEXT: in {{REDEFINE}}: directive on test line [[#@LINE-5]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# Check a define's continuation line that is unterminated.
+
+# RUN: echo "Don't complain about no RUN lines."
+# DEFINE: %{foo} = foo \
+# DEFINE: bar \
+
+# CHECK: Test has unterminated '{{DEFINE}}:' directive (with '\') from line [[#@LINE-3]] to [[#@LINE-2]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a DEFINE with a REDEFINE. In this case, the REDEFINE
+# looks fine on its own, so the unterminated DEFINE is reported.
+
+# DEFINE: %{name}=x
+# DEFINE: %{value}=3
+# DEFINE: %{deceptive-continue}=echo \
+# REDEFINE: %{name}=%{value}
+# DEFINE: %{too-late-to-continue}=
+# RUN: %{deceptive-continue}
+
+# CHECK: Test has unterminated '{{DEFINE}}:' directive (with '\') at line [[#@LINE-5]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a DEFINE with a RUN.
+
+# DEFINE: %{foo}=echo \
+# RUN: %{foo}
+# DEFINE: %{too-late-to-continue}=
+
+# CHECK: Test has unterminated '{{DEFINE}}:' directive (with '\') at line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# Simple case of unterminated define as last directive in the script.
+
+# RUN: echo "Don't complain about no RUN lines."
+# DEFINE: %{foo}=foo\
+
+# CHECK: Test has unterminated '{{DEFINE}}:' directive (with '\') at line [[#@LINE-2]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a REDEFINE with a DEFINE. In this case, the DEFINE is
+# wrong on its own because it's written as a continuation, so the bad DEFINE is
+# reported.
+
+# REDEFINE: %{global:what}=echo \
+# DEFINE: Hello World
+# REDEFINE: too late to continue
+# RUN: %{foo}
+
+# CHECK: Substitution's definition does not contain '='
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-5]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# Check a redefine's continuation line that is unterminated.
+
+# RUN: echo "Don't complain about no RUN lines."
+# REDEFINE: %{global:what} = foo \
+# REDEFINE: bar \
+
+# CHECK: Test has unterminated '{{REDEFINE}}:' directive (with '\') from line [[#@LINE-3]] to [[#@LINE-2]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a REDEFINE with a DEFINE. In this case, the DEFINE
+# looks fine on its own, so the unterminated REDEFINE is reported.
+
+# DEFINE: %{name}=x
+# DEFINE: %{value}=3
+# REDEFINE: %{global:what}=echo \
+# DEFINE: %{name}=%{value}
+# REDEFINE: %{too-late-to-continue}=
+# RUN: %{deceptive-continue}
+
+# CHECK: Test has unterminated '{{REDEFINE}}:' directive (with '\') at line [[#@LINE-5]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a REDEFINE with a RUN.
+
+# REDEFINE: %{global:what}=echo \
+# RUN: %{global:what}
+# REDEFINE: %{too-late-to-continue}=
+
+# CHECK: Test has unterminated '{{REDEFINE}}:' directive (with '\') at line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# Simple case of unterminated redefine as last directive in the script.
+
+# RUN: echo "Don't complain about no RUN lines."
+# REDEFINE: %{global:what}=foo\
+
+# CHECK: Test has unterminated '{{REDEFINE}}:' directive (with '\') at line [[#@LINE-2]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a RUN with a DEFINE.
+
+# RUN: echo \
+# DEFINE: %{foo}=bar
+# RUN: too late to continue
+
+# CHECK: Test has unterminated '{{RUN}}:' directive (with '\') at line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# You cannot continue a RUN with a REDEFINE.
+
+# RUN: echo Hello \
+# REDEFINE: %{global:what}=bar
+# RUN: too late to continue
+
+# CHECK: Test has unterminated '{{RUN}}:' directive (with '\') at line [[#@LINE-4]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# Surely an empty substitution continuation is an accident, so it's an error.
+
+# DEFINE: %{foo} = foo \
+# DEFINE:
+# ^~ whitespace intentional
+# RUN: echo '%{foo}'
+
+# CHECK: Substitution's continuation is empty
+# CHECK-NEXT: in {{DEFINE}}: directive on test line [[#@LINE-5]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{global:greeting}=Hello
+# RUN: %{global:echo}
+
+# CHECK: ValueError: Substitution whose pattern contains '%{global:greeting}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: %{global:greeting}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{foo}=bar
+# RUN: echo %{foo}
+# DEFINE: %{foo}=bar
+# RUN: echo %{foo}
+
+# CHECK: ValueError: Substitution whose pattern contains '%{foo}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: %{foo}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{global:inside} = @
+# RUN: echo '<%{global:inside}>'
+
+# CHECK: ValueError: Substitution whose pattern contains '%{global:inside}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: <%{global:inside}>
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{global:multiple-exact} = @
+# RUN: echo '%{global:multiple-exact}'
+
+# CHECK: ValueError: Substitution whose pattern contains '%{global:multiple-exact}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: %{global:multiple-exact}
+# CHECK-NEXT: Existing pattern: %{global:multiple-exact}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{global:multiple-once-exact} = @
+# RUN: echo '%{global:multiple-once-exact}'
+
+# CHECK: ValueError: Substitution whose pattern contains '%{global:multiple-once-exact}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: <%{global:multiple-once-exact}>
+# CHECK-NEXT: Existing pattern: %{global:multiple-once-exact}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{global:prefix} = @
+# RUN: echo '%{global:prefix}(foo)'
+
+# CHECK: ValueError: Substitution whose pattern contains '%{global:prefix}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: %{global:prefix}\((.*)\)
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{global:suffix} = @
+# RUN: echo '@%{global:suffix}'
+
+# CHECK: ValueError: Substitution whose pattern contains '%{global:suffix}' is already defined before '{{DEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: @%{global:suffix}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# REDEFINE: %{global:inside} = @
+# RUN: echo '<%{global:inside}>'
+
+# CHECK: ValueError: Existing substitution whose pattern contains '%{global:inside}' does not have the pattern specified by '{{REDEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Expected pattern: %{global:inside}
+# CHECK-NEXT: Existing pattern: <%{global:inside}>
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# It's impossible to multiply define a local substitution, but a lit config file
+# substitution can be multiply defined. The trouble is we then don't know which
+# definition to redefine locally.
+
+# REDEFINE: %{global:multiple-exact}=foo
+# RUN: echo %{global:multiple-exact}
+
+# CHECK: ValueError: Multiple substitutions whose patterns contain '%{global:multiple-exact}' are defined before '{{REDEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: %{global:multiple-exact}
+# CHECK-NEXT: Existing pattern: %{global:multiple-exact}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# There's only one substitution whose pattern matches exactly, but there's
+# another partial match, and that can lead to confusing expansions.
+
+# REDEFINE: %{global:multiple-once-exact}=foo
+# RUN: echo %{global:multiple-once-exact}
+
+# CHECK: ValueError: Multiple substitutions whose patterns contain '%{global:multiple-once-exact}' are defined before '{{REDEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Existing pattern: <%{global:multiple-once-exact}>
+# CHECK-NEXT: Existing pattern: %{global:multiple-once-exact}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# REDEFINE: %{local}=foo
+# RUN: echo %{local}
+
+# CHECK: ValueError: No substitution for '%{local}' is defined before '{{REDEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# REDEFINE: %{global:prefix} = @
+# RUN: echo '%{global:prefix}(foo)'
+
+# CHECK: ValueError: Existing substitution whose pattern contains '%{global:prefix}' does not have the pattern specified by '{{REDEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Expected pattern: %{global:prefix}
+# CHECK-NEXT: Existing pattern: %{global:prefix}\((.*)\)
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# REDEFINE: %{global:suffix} = @
+# RUN: echo '@%{global:suffix}'
+
+# CHECK: ValueError: Existing substitution whose pattern contains '%{global:suffix}' does not have the pattern specified by '{{REDEFINE}}:' directive at line [[#@LINE-3]]
+# CHECK-NEXT: Expected pattern: %{global:suffix}
+# CHECK-NEXT: Existing pattern: @%{global:suffix}
+# CHECK-NOT: Existing pattern:
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE: %{foo}=Hello World
+# DEFINE: %{foo}=Hello \
+# DEFINE: World
+# RUN: echo '%{foo}'
+
+# CHECK: ValueError: Substitution whose pattern contains '%{foo}' is already defined before '{{DEFINE}}:' directive from line [[#@LINE-4]] to [[#@LINE-3]]
+
+# CHECK: Unresolved: 1
--- /dev/null
+# DEFINE and REDEFINE are not sufficient. There must be a RUN.
+
+# DEFINE: %{local:echo}=foo
+# REDEFINE: %{global:echo}=bar
+
+# CHECK: Test has no '{{RUN}}:' line
+
+# CHECK: Unresolved: 1
--- /dev/null
+; This example originally appeared in TestingGuide.rst except here we've added
+; echo to the clang/FileCheck command line to be executed.
+
+; DEFINE: %{cflags} =
+; DEFINE: %{fcflags} =
+
+; DEFINE: %{check} = \
+; DEFINE: echo ' \
+; DEFINE: %clang_cc1 -verify -fopenmp -fopenmp-version=51 %{cflags} \
+; DEFINE: -emit-llvm -o - %s | \
+; DEFINE: FileCheck %{fcflags} %s \
+; DEFINE: '
+
+; REDEFINE: %{cflags} = -triple x86_64-apple-darwin10.6.0 -fopenmp-simd
+; REDEFINE: %{fcflags} = -check-prefix=SIMD
+; RUN: %{check}
+; CHECK: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -triple x86_64-apple-darwin10.6.0 -fopenmp-simd -emit-llvm -o - {{.*}} | FileCheck -check-prefix=SIMD {{.*}}
+
+; REDEFINE: %{cflags} = -triple x86_64-unknown-linux-gnu -fopenmp-simd
+; REDEFINE: %{fcflags} = -check-prefix=SIMD
+; RUN: %{check}
+; CHECK: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -triple x86_64-unknown-linux-gnu -fopenmp-simd -emit-llvm -o - {{.*}} | FileCheck -check-prefix=SIMD {{.*}}
+
+; REDEFINE: %{cflags} = -triple x86_64-apple-darwin10.6.0
+; REDEFINE: %{fcflags} = -check-prefix=NO-SIMD
+; RUN: %{check}
+; CHECK: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -triple x86_64-apple-darwin10.6.0 -emit-llvm -o - {{.*}} | FileCheck -check-prefix=NO-SIMD {{.*}}
+
+; REDEFINE: %{cflags} = -triple x86_64-unknown-linux-gnu
+; REDEFINE: %{fcflags} = -check-prefix=NO-SIMD
+; RUN: %{check}
+; CHECK: %clang_cc1 -verify -fopenmp -fopenmp-version=51 -triple x86_64-unknown-linux-gnu -emit-llvm -o - {{.*}} | FileCheck -check-prefix=NO-SIMD {{.*}}
+
+; CHECK: Passed: 1
--- /dev/null
+# Redefine the %{global:greeting} parameter of %{global:echo} before using it.
+# The necessary expansion order was established in the test suite config
+# (%{global:echo} before %{global:greeting}), and redefining the parameter
+# doesn't change that expansion order. That order would be reversed if
+# %{global:greeting} were handled as a new substitution, preventing full
+# expansion.
+#
+# REDEFINE: %{global:greeting}=Hello
+# RUN: %{global:echo}
+# CHECK: GLOBAL: Hello World
+
+# We can redefine the test suite config's substitutions multiple times. Again,
+# the expansion order remains the same (%{global:echo} before %{global:greeting}
+# before %{global:what}) but would be reversed if these were handled as new
+# substitutions, preventing full expansion.
+#
+# REDEFINE: %{global:greeting}=Goodbye %{global:what}
+# REDEFINE: %{global:what}=Sleep
+# RUN: %{global:echo}
+# CHECK: GLOBAL: Goodbye Sleep Sleep
+
+# A new local substitution is prepended to the substitution list so that it can
+# depend on all substitutions that were defined previously, including those from
+# the test suite config.
+#
+# DEFINE: %{local:greeting}=Hey %{global:what}
+# DEFINE: %{local:echo}=echo "LOCAL: %{local:greeting} %{global:what}"
+# RUN: %{local:echo}
+# CHECK: LOCAL: Hey Sleep Sleep
+
+# As for substitutions from the test suite config, redefining local
+# substitutions should not change the expansion order. Again, the expansion
+# order would be reversed if these were instead handled as new substitutions,
+# preventing full expansion.
+#
+# REDEFINE: %{local:greeting}=So Long %{global:what}
+# REDEFINE: %{global:what}=World
+# RUN: %{local:echo}
+# CHECK: LOCAL: So Long World World
+
+# CHECK: Passed: 1
--- /dev/null
+# Does it work as expected directly in RUN lines?
+# RUN: echo %(line), %(line-1), %(line+2)
+# CHECK: [[#@LINE-1]], [[#@LINE-2]], [[#@LINE+1]]
+
+# %(line) substitutions refer to the original DEFINE/REDEFINE line not the RUN
+# line they eventually appear within.
+#
+# DEFINE: %{lines} = %(line)
+# RUN: echo '%{lines}'
+# CHECK: [[#@LINE-2]]
+#
+# REDEFINE: %{lines} = %(line), \
+# REDEFINE: %(line), \
+# REDEFINE: %(line)
+# RUN: echo '%{lines}'
+# CHECK: [[#@LINE-4]], [[#@LINE-3]], [[#@LINE-2]]
+
+# %(line+N) and %{line-N) should work too.
+#
+# DEFINE: %{lines-rel} = %(line+1), \
+# DEFINE: %(line), \
+# DEFINE: %(line-1)
+# RUN: echo '%{lines-rel}'
+# CHECK: [[#@LINE-3]], [[#@LINE-3]], [[#@LINE-3]]
+#
+# REDEFINE: %{lines-rel} = %(line+5), \
+# REDEFINE: %(line+0), \
+# REDEFINE: %(line-10)
+# RUN: echo '%{lines-rel}'
+# CHECK: [[#@LINE+1]], [[#@LINE-3]], [[#@LINE-12]]
+
+# CHECK: Passed: 1
--- /dev/null
+import lit.formats
+config.name = 'shtest-define'
+config.suffixes = ['.txt']
+config.test_format = lit.formats.ShTest()
+config.test_source_root = None
+config.test_exec_root = None
+
+# When config.recursiveExpansionLimit is not specified, it's important to
+# prepend substitutions before substitutions they might now or later (upon a
+# redefinition) depend upon. For example, %{global:greeting} and %{global:what}
+# act as parameters for %{global:echo}, so we make sure the latter expands
+# before the former. Moreover, some tests redefine %{global:greeting} in terms
+# of %{global:what}, so we make sure the former expands before the latter.
+# If we always insert at the beginning of the substitution list (as DEFINE
+# does), then the rule is simple: define a substitution before you refer to it.
+config.substitutions.insert(0, ('%{global:what}', 'World'))
+config.substitutions.insert(0, ('%{global:greeting}', ''))
+config.substitutions.insert(0,
+ ('%{global:echo}', "echo GLOBAL: %{global:greeting} %{global:what}"))
+
+# The following substitution definitions are confusing and should be avoided.
+# We define them here so we can test that 'DEFINE:' and 'REDEFINE:' directives
+# guard against the confusion they cause.
+
+# Even though each of '%{global:inside}', '%{global:prefix}', and
+# '%{global:suffix}' is not already the exact pattern of a substitution,
+# 'DEFINE:' and 'REDEFINE:' will refuse to (re)define a substitution with that
+# pattern because it is a substring of one of the following substitution's
+# patterns.
+config.substitutions.insert(0, ('<%{global:inside}>', '<@>'))
+config.substitutions.insert(0, (r'%{global:prefix}\((.*)\)', r'@(\g<1>)'))
+config.substitutions.insert(0, ('@%{global:suffix}', '@@'))
+
+# These cannot be redefined by 'REDEFINE:', which doesn't know which one to
+# redefine.
+config.substitutions.insert(0, ('%{global:multiple-exact}', 'first'))
+config.substitutions.insert(0, ('%{global:multiple-exact}', 'second'))
+
+# Even though '%{global:multiple-once-exact}' is the exact pattern of only one
+# existing substitution, 'REDEFINE:' will refuse to redefine that substitution
+# because that string is a substring of another substitution's pattern.
+config.substitutions.insert(0, ('%{global:multiple-once-exact}', '@'))
+config.substitutions.insert(0, ('<%{global:multiple-once-exact}>', '<@>'))
+
+recur = lit_config.params.get('recur', None)
+if recur:
+ config.recursiveExpansionLimit = int(recur)
--- /dev/null
+# DEFINE: %{abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789} = ok
+# RUN: echo '%{abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789}'
+# CHECK: ok
+
+# DEFINE: %{FooBar} = ok at %(line)
+# RUN: echo '%{FooBar}'
+# CHECK: ok at [[#@LINE - 2]]
+
+# DEFINE: %{fooBar} = ok at %(line)
+# RUN: echo '%{fooBar}'
+# CHECK: ok at [[#@LINE - 2]]
+
+# DEFINE: %{foo-bar-} = ok at %(line)
+# RUN: echo '%{foo-bar-}'
+# CHECK: ok at [[#@LINE - 2]]
+
+# DEFINE: %{foo:bar:} = ok at %(line)
+# RUN: echo '%{foo:bar:}'
+# CHECK: ok at [[#@LINE - 2]]
+
+# DEFINE: %{_foo_bar_} = ok at %(line)
+# RUN: echo '%{_foo_bar_}'
+# CHECK: ok at [[#@LINE - 2]]
+
+# CHECK: Passed: 1
--- /dev/null
+# These are defined in the wrong order for non-recursive expansion: %{inner} is
+# defined after it's referenced.
+
+# DEFINE: %{outer}=%{inner}
+# DEFINE: %{inner}=expanded
+
+# RUN: echo '%{outer}'
+
+# CHECK-NON-RECUR:%{inner}
+# CHECK-RECUR:expanded
+
+# CHECK: Passed: 1
--- /dev/null
+# RUN: echo shared-substs-0.txt
+
+# Make sure we don't see modifications that other shared-substs-*.txt have made
+# to the test suite config's substitutions.
+#
+# RUN: %{global:echo}
+
+# Next, modify substs that would affect the above. Verify they are set locally.
+#
+# REDEFINE: %{global:what}=LOCAL0:World
+# REDEFINE: %{global:greeting}=LOCAL0:Hello
+# REDEFINE: %{global:echo}=echo LOCAL0: %{global:greeting} %{global:what}
+# RUN: %{global:echo}
+
+# Finally, set a local that other shared-substs-*.txt also set to be sure
+# there's no redefinition complaint because they left it behind. Verify it is
+# set locally.
+#
+# DEFINE: %{local:echo}=echo LOCAL0: subst
+# RUN: %{local:echo}
+
+# CHECK: Passed: 1
--- /dev/null
+# RUN: echo shared-substs-1.txt
+
+# Make sure we don't see modifications that other shared-substs-*.txt have made
+# to the test suite config's substitutions.
+#
+# RUN: %{global:echo}
+
+# Next, modify substs that would affect the above. Verify they are set locally.
+#
+# REDEFINE: %{global:what}=LOCAL1:World
+# REDEFINE: %{global:greeting}=LOCAL1:Hello
+# REDEFINE: %{global:echo}=echo LOCAL1: %{global:greeting} %{global:what}
+# RUN: %{global:echo}
+
+# Finally, set a local that other shared-substs-*.txt also set to be sure
+# there's no redefinition complaint because they left it behind. Verify it is
+# set locally.
+#
+# DEFINE: %{local:echo}=echo LOCAL1: subst
+# RUN: %{local:echo}
+
+# CHECK: Passed: 1
--- /dev/null
+# After the initial '=', the value can contain '=' with no special meaning.
+
+# DEFINE: %{equals} = FileCheck -check-prefixes=FOO,BAR
+# RUN: echo '%{equals}'
+# CHECK: FileCheck -check-prefixes=FOO,BAR
+#
+# REDEFINE: %{equals} == == =
+# RUN: echo '%{equals}'
+# CHECK: = == =
+
+# DEFINE: %{continue-equals} = FileCheck -strict-whitespace -match-full-lines \
+# DEFINE: -check-prefixes=FOO,BAR
+# RUN: echo '%{continue-equals}'
+# CHECK: FileCheck -strict-whitespace -match-full-lines -check-prefixes=FOO,BAR
+#
+# REDEFINE: %{continue-equals} = FileCheck -input-file=test.txt \
+# REDEFINE: -implicit-check-not=foobar \
+# REDEFINE: -check-prefixes=FOO,BAR
+# RUN: echo '%{continue-equals}'
+# CHECK: FileCheck -input-file=test.txt -implicit-check-not=foobar -check-prefixes=FOO,BAR
+
+# CHECK: Passed: 1
--- /dev/null
+# Escape sequences that can appear in python re.sub replacement strings have no
+# special meaning in the value.
+
+# DEFINE: %{escape} = \g<0>\n
+# RUN: echo '%{escape}'
+# CHECK: \g<0>\n
+
+# REDEFINE: %{escape} = \n \
+# REDEFINE: \g<param>
+# RUN: echo '%{escape}'
+# CHECK: \n \g<param>
+
+# CHECK: Passed: 1
--- /dev/null
+# Empty values are permitted and reasonable, especially when just establishing
+# expansion order.
+#
+# DEFINE: %{empty}=
+# RUN: echo "'%{empty}'"
+# CHECK:''
+#
+# REDEFINE: %{empty}=
+# RUN: echo "'%{empty}'"
+# CHECK:''
+
+# A value consisting only of whitespace is trimmed to the empty string.
+#
+# v~~ intentional whitespace
+# DEFINE: %{ws}=
+# RUN: echo "'%{ws}'"
+# CHECK:''
+#
+# v intentional whitespace
+# REDEFINE: %{ws}=
+# RUN: echo "'%{ws}'"
+# CHECK:''
+
+# Whitespace is not required around the name or value.
+#
+# DEFINE:%{no-whitespace}=abc
+# RUN: echo "'%{no-whitespace}'"
+# CHECK:'abc'
+#
+# REDEFINE:%{no-whitespace}=HelloWorld
+# RUN: echo "'%{no-whitespace}'"
+# CHECK:'HelloWorld'
+
+# Whitespace is not required between substitutions in a value.
+#
+# DEFINE: %{adjacent0} = foo
+# DEFINE: %{adjacent1} = bar
+# DEFINE: %{has-adjacent-substs} = %{adjacent0}%{adjacent1}
+# RUN: echo "'%{has-adjacent-substs}'"
+# CHECK:'foobar'
+#
+# REDEFINE: %{has-adjacent-substs} = %{adjacent0}%{adjacent1}%{adjacent0}
+# RUN: echo "'%{has-adjacent-substs}'"
+# CHECK:'foobarfoo'
+
+# Exact whitespace is preserved within the value, but whitespace enclosing the
+# name or value is discarded. ('%{' and '}' are part of the name, and
+# whitespace in between isn't permitted.)
+#
+# v~~ intentional whitespace
+# DEFINE: %{whitespace} = abc def
+# RUN: echo "'%{whitespace}'"
+# CHECK:'abc def'
+# v intentional whitespace
+# REDEFINE: %{whitespace} = Hello World
+# RUN: echo "'%{whitespace}'"
+# CHECK:'Hello World'
+
+# Line continuations in the value are permitted and collapse whitespace.
+#
+# DEFINE: %{continue} = abc\
+# DEFINE:def \
+# DEFINE:ghi\
+# DEFINE: jkl \
+# DEFINE: mno \
+# DEFINE: pqr
+# ^ intentional whitespace
+# RUN: echo "'%{continue}'"
+# CHECK:'abc def ghi jkl mno pqr'
+#
+# REDEFINE: %{continue} = abc \
+# REDEFINE: def
+# RUN: echo "'%{continue}'"
+# CHECK:'abc def'
+
+# Whitespace at the end of the line after a '\' is ignored, and it's treated as
+# a line continuation. Otherwise, the behavior would be hard to understand
+# because it looks like a line continuation.
+#
+# v~~~~~~~~~~~ intentional whitespace
+# DEFINE: %{ws-after-continue}=foo \
+# DEFINE: bar \
+# ^ intentional whitespace
+# DEFINE: baz
+# RUN: echo "'%{ws-after-continue}'"
+# CHECK:'foo bar baz'
+#
+# v intentional whitespace
+# REDEFINE: %{ws-after-continue}=foo \
+# REDEFINE: bar \
+# ^~~~~~~~~~~~ intentional whitespace
+# REDEFINE: baz
+# RUN: echo "'%{ws-after-continue}'"
+# CHECK:'foo bar baz'
+
+# A line continuation is recognized anywhere. It should be used only where
+# whitespace is permitted because it reduces to a single space.
+#
+# Directives with at least one non-whitespace character (could be '\') are
+# permitted even if they contribute nothing to the value. There might be no
+# practical use, but check that it behaves as expected.
+#
+# DEFINE:\
+# DEFINE:%{blank-lines}\
+# DEFINE:\
+# DEFINE:=\
+# DEFINE:\
+# DEFINE:a
+# RUN: echo "'%{blank-lines}'"
+# CHECK:'a'
+#
+# REDEFINE: \
+# REDEFINE: %{blank-lines} \
+# REDEFINE: \
+# REDEFINE: = \
+# REDEFINE: \
+# REDEFINE: a \
+# REDEFINE: \
+# REDEFINE: b \
+# REDEFINE: \
+# REDEFINE: c
+# RUN: echo "'%{blank-lines}'"
+# CHECK:'a b c'
+
+# The fourth DEFINE line is deceptive because it looks like a new substitution,
+# but it's actually a continuation of the previous value.
+#
+# DEFINE: %{name}=x
+# DEFINE: %{value}=3
+# DEFINE: %{deceptive-continue}=echo \
+# DEFINE: %{name}=%{value}
+# RUN: %{deceptive-continue}
+# CHECK:x=3
+
+# CHECK:{{ *}}Passed: 1
--- /dev/null
+RUN: echo 'foo' \
+RUN: 'bar' >> %t.out
+CHECK: foo bar
+
+RUN: echo 'foo' \
+RUN: 'bar' \
+RUN: 'baz' >> %t.out
+CHECK: foo bar baz
+
+# v~~ intentional whitespace
+RUN: echo 'foo' \
+RUN: 'bar' \
+# ^ intentional whitespace
+RUN: 'baz' >> %t.out
+CHECK: foo bar baz
+
+RUN: FileCheck -match-full-lines -input-file=%t.out %s
//
// MY_BOOL_UNTERMINATED: a \
//
+// MY_DEFINE: %{name} = value one
+//
+// MY_REDEFINE: %{name} = value \
+// MY_REDEFINE: two
+//
// END.
// MY_LIST: five
--- /dev/null
+# We're using DEFINE/REDEFINE to help us write tests for DEFINE/REDEFINE.
+
+# RUN: echo '-- Available Tests --' > %t.tests.actual.txt
+
+# DEFINE: %{my-inputs} = %{inputs}/shtest-define
+
+# DEFINE: %{test} =
+# DEFINE: %{lit-pre} =
+# DEFINE: %{lit-args} =
+# DEFINE: %{fc-args} =
+# DEFINE: %{run-test} = \
+# DEFINE: %{lit-pre} %{lit} -va %{lit-args} %{my-inputs}/%{test} 2>&1 | \
+# DEFINE: FileCheck -match-full-lines %{fc-args} %{my-inputs}/%{test}
+# DEFINE: %{record-test} = \
+# DEFINE: echo ' shtest-define :: %{test}' >> %t.tests.actual.txt
+# DEFINE: %{run-and-record-test} = %{run-test} && %{record-test}
+
+# REDEFINE: %{lit-pre} = not
+#
+# REDEFINE: %{test} = errors/assignment/before-name.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/between-name-equals.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/braces-empty.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/braces-with-dot.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/braces-with-equals.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/braces-with-newline.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/braces-with-number.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/braces-with-ws.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/empty.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/no-equals.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/no-name.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/assignment/ws-only.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/empty.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/end-in-double-backslash.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-define-bad-redefine.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-define-continuation.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-define-redefine.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-define-run.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-define.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-redefine-bad-define.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-redefine-continuation.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-redefine-define.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-redefine-run.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-redefine.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-run-define.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/unterminated-run-redefine.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/continuation/ws-only.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-already-by-config.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-already-by-test.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-inside-pattern.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-multiple-exact.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-multiple-once-exact.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-prefixes-pattern.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/define-suffixes-pattern.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/redefine-inside-pattern.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/redefine-multiple-exact.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/redefine-multiple-once-exact.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/redefine-none.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/redefine-prefixes-pattern.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/defined-check/redefine-suffixes-pattern.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/location-range.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{test} = errors/no-run.txt
+# RUN: %{run-and-record-test}
+#
+# REDEFINE: %{lit-pre} =
+
+# REDEFINE: %{test} = examples/param-subst.txt
+# RUN: %{run-and-record-test}
+
+# REDEFINE: %{test} = expansion-order.txt
+# RUN: %{run-and-record-test}
+
+# REDEFINE: %{test} = line-number-substitutions.txt
+# RUN: %{run-and-record-test}
+
+# REDEFINE: %{test} = name-chars.txt
+# RUN: %{run-and-record-test}
+
+# REDEFINE: %{test} = recursiveExpansionLimit.txt
+#
+# REDEFINE: %{fc-args} = -check-prefix=CHECK-NON-RECUR
+# RUN: %{run-test}
+#
+# REDEFINE: %{lit-args} = -Drecur=2
+# REDEFINE: %{fc-args} = -check-prefix=CHECK-RECUR
+# RUN: %{run-test}
+#
+# RUN: %{record-test}
+# REDEFINE: %{lit-args} =
+# REDEFINE: %{fc-args} =
+
+# Check that per-test changes to substitutions don't affect other tests in the
+# same LIT invocation.
+#
+# RUN: %{lit} -va %{my-inputs}/shared-substs-*.txt 2>&1 | \
+# RUN: FileCheck -check-prefix=SHARED-SUBSTS -match-full-lines %s
+#
+# SHARED-SUBSTS: shared-substs-0.txt
+# SHARED-SUBSTS: GLOBAL: World
+# SHARED-SUBSTS: LOCAL0: LOCAL0:Hello LOCAL0:World
+# SHARED-SUBSTS: LOCAL0: subst
+#
+# SHARED-SUBSTS: shared-substs-1.txt
+# SHARED-SUBSTS: GLOBAL: World
+# SHARED-SUBSTS: LOCAL1: LOCAL1:Hello LOCAL1:World
+# SHARED-SUBSTS: LOCAL1: subst
+#
+# REDEFINE: %{test} = shared-substs-0.txt
+# RUN: %{record-test}
+# REDEFINE: %{test} = shared-substs-1.txt
+# RUN: %{record-test}
+
+# REDEFINE: %{test} = value-equals.txt
+# RUN: %{run-and-record-test}
+
+# REDEFINE: %{test} = value-escaped.txt
+# RUN: %{run-and-record-test}
+
+# REDEFINE: %{fc-args} = -strict-whitespace
+# REDEFINE: %{test} = ws-and-continuations.txt
+# RUN: %{run-and-record-test}
+# REDEFINE: %{fc-args} =
+
+# Make sure we didn't forget to run something.
+#
+# RUN: %{lit} --show-tests %{my-inputs} > %t.tests.expected.txt
+# RUN: diff -u %t.tests.expected.txt %t.tests.actual.txt
# CHECK: {{^}}Test has more than one ALLOW_RETRIES lines{{$}}
# CHECK-LABEL: UNRESOLVED: shtest-keyword-parse-errors :: unterminated-run.txt
-# CHECK: {{^}}Test has unterminated 'RUN:' lines (with '\'){{$}}
+# CHECK: {{^}}Test has unterminated 'RUN:' directive (with '\') at line 1{{$}}
# CHECK: error: command failed with exit status: 127
# CHECK: ***
+# CHECK: PASS: shtest-shell :: continuations.txt
+
# CHECK: PASS: shtest-shell :: dev-null.txt
# CHECK: FAIL: shtest-shell :: diff-b.txt
IntegratedTestKeywordParser("MY_RUN:", ParserKind.COMMAND),
IntegratedTestKeywordParser("MY_CUSTOM:", ParserKind.CUSTOM,
custom_parse),
-
+ IntegratedTestKeywordParser("MY_DEFINE:", ParserKind.DEFINE),
+ IntegratedTestKeywordParser("MY_REDEFINE:", ParserKind.REDEFINE),
]
@staticmethod
cmd_parser = self.get_parser(parsers, 'MY_RUN:')
value = cmd_parser.getValue()
self.assertEqual(len(value), 2) # there are only two run lines
- self.assertEqual(value[0].strip(), "%dbg(MY_RUN: at line 4) baz")
- self.assertEqual(value[1].strip(), "%dbg(MY_RUN: at line 7) foo bar")
+ self.assertEqual(value[0].command.strip(),
+ "%dbg(MY_RUN: at line 4) baz")
+ self.assertEqual(value[1].command.strip(),
+ "%dbg(MY_RUN: at line 7) foo bar")
def test_boolean(self):
parsers = self.make_parsers()
value = custom_parser.getValue()
self.assertEqual(value, ['a', 'b', 'c'])
+ def test_defines(self):
+ parsers = self.make_parsers()
+ self.parse_test(parsers)
+ cmd_parser = self.get_parser(parsers, 'MY_DEFINE:')
+ value = cmd_parser.getValue()
+ self.assertEqual(len(value), 1) # there's only one MY_DEFINE directive
+ self.assertEqual(value[0].new_subst, True)
+ self.assertEqual(value[0].name, '%{name}')
+ self.assertEqual(value[0].value, 'value one')
+
+ def test_redefines(self):
+ parsers = self.make_parsers()
+ self.parse_test(parsers)
+ cmd_parser = self.get_parser(parsers, 'MY_REDEFINE:')
+ value = cmd_parser.getValue()
+ self.assertEqual(len(value), 1) # there's only one MY_REDEFINE directive
+ self.assertEqual(value[0].new_subst, False)
+ self.assertEqual(value[0].name, '%{name}')
+ self.assertEqual(value[0].value, 'value two')
+
def test_bad_keywords(self):
def custom_parse(line_number, line, output):
return output