blob: 1a5bbf0ed3e1c7d82ea53c74010cd8b87e34e098 [file] [log] [blame]
"""Parser for .test files"""
from lit.TestRunner import (
parseIntegratedTestScriptCommands,
getDefaultSubstitutions,
applySubstitutions,
)
from litsupport import shellcommand
import logging
import os
import shlex
def _parseShellCommand(script, ln):
# Trim trailing whitespace.
ln = ln.rstrip()
# Collapse lines with trailing '\\'.
if script and script[-1][-1] == "\\":
script[-1] = script[-1][:-1] + ln
else:
script.append(ln)
def clean_verify_command_for_windows(command_str):
"""Prepares a command string for execution in Windows command line by
formatting paths and arguments."""
# Replace backslashes with forward slashes and split into tokens
tokens = shlex.split(command_str.replace("\\", "/"))
# Enclose each token in double quotes and convert slashes back
tokens_quoted = ['"{}"'.format(token.replace('/', '\\')) for token in tokens]
# Join the tokens into a single command string and return
return ' '.join(tokens_quoted)
def parse(context, filename):
"""Parse a .test file as used in the llvm test-suite.
The file comporises of a number of lines starting with RUN: and VERIFY:
specifying shell commands to run the benchmark and verifying the result.
Returns a tuple with two arrays for the run and verify commands."""
# Collect the test lines from the script.
preparescript = []
runscript = []
verifyscript = []
metricscripts = {}
# Note that we keep both "RUN" and "RUN:" in the list to stay compatible
# with older lit versions.
keywords = [
"PREPARE:",
"PREPARE",
"RUN:",
"RUN",
"VERIFY:",
"VERIFY",
"METRIC:",
"METRIC",
]
for line_number, command_type, ln in parseIntegratedTestScriptCommands(
filename, keywords
):
if command_type.startswith("PREPARE"):
_parseShellCommand(preparescript, ln)
elif command_type.startswith("RUN"):
_parseShellCommand(runscript, ln)
elif command_type.startswith("VERIFY"):
_parseShellCommand(verifyscript, ln)
elif command_type.startswith("METRIC"):
metric, ln = ln.split(":", 1)
metricscript = metricscripts.setdefault(metric.strip(), list())
_parseShellCommand(metricscript, ln)
else:
raise ValueError("unknown script command type: %r" % (command_type,))
# Verify the script contains a run line.
if runscript == []:
raise ValueError("Test has no RUN: line!")
# Check for unterminated run lines.
for script in preparescript, runscript, verifyscript:
if script and script[-1][-1] == "\\":
raise ValueError(
"Test has unterminated RUN/VERIFY lines " + "(ending with '\\')"
)
# Apply the usual lit substitutions (%s, %S, %p, %T, ...)
outfile = context.tmpBase + ".out"
substitutions = getDefaultSubstitutions(
context.test, context.tmpDir, context.tmpBase
)
substitutions += [("%o", outfile)]
preparescript = applySubstitutions(preparescript, substitutions)
runscript = applySubstitutions(runscript, substitutions)
verifyscript = applySubstitutions(verifyscript, substitutions)
if os.name == 'nt':
verifyscript = [clean_verify_command_for_windows(cmd) for cmd in verifyscript]
metricscripts = {
k: applySubstitutions(v, substitutions) for k, v in metricscripts.items()
}
# Put things into the context
context.parsed_preparescript = preparescript
context.parsed_runscript = runscript
context.parsed_verifyscript = verifyscript
context.parsed_metricscripts = metricscripts
context.executable = shellcommand.getMainExecutable(context)
if not context.executable:
logging.error("Could not determine executable name in %s" % filename)