2023-09-25 16:15:02 +02:00
|
|
|
#!/bin/python3
|
|
|
|
import argparse
|
2024-10-02 15:59:24 +02:00
|
|
|
import os
|
2023-09-25 16:15:02 +02:00
|
|
|
from glob import glob
|
2024-10-02 16:18:42 +02:00
|
|
|
import subprocess
|
2024-11-17 18:03:40 +01:00
|
|
|
from colorama import Fore, Style
|
|
|
|
|
|
|
|
|
|
|
|
def check_dependencies() -> None:
|
|
|
|
# Necessary commands list
|
|
|
|
commands = ["astyle", "gcc", "ghc", "java", "javac", "mvn", "python3"]
|
|
|
|
|
|
|
|
for command in commands:
|
|
|
|
if os.system(f"which {command} > /dev/null") != 0:
|
|
|
|
print(f"{Fore.RED}Error: {command} not found{Style.RESET_ALL}")
|
|
|
|
return
|
2023-09-25 16:15:02 +02:00
|
|
|
|
2024-10-02 15:59:24 +02:00
|
|
|
def run_input_cases(program, verbose, output=False, tests_dir="."):
|
|
|
|
input_files = glob(os.path.join(tests_dir, "*.in"))
|
2024-10-02 16:18:42 +02:00
|
|
|
|
2023-09-25 16:15:02 +02:00
|
|
|
if len(input_files) < 1:
|
2024-10-02 15:59:24 +02:00
|
|
|
return os.system(program)
|
2024-10-02 16:18:42 +02:00
|
|
|
|
2023-09-25 16:15:02 +02:00
|
|
|
for input_file in input_files:
|
|
|
|
print(f"Running {input_file}")
|
2023-09-28 22:14:28 +02:00
|
|
|
end_command = f"{program} < {input_file}"
|
2024-10-02 16:18:42 +02:00
|
|
|
|
|
|
|
with open(input_file, 'r') as f:
|
|
|
|
input_data = f.read()
|
|
|
|
|
|
|
|
out_file = input_file.replace(".in", ".out")
|
|
|
|
expected_output = None
|
|
|
|
if os.path.exists(out_file):
|
|
|
|
with open(out_file, 'r') as f:
|
|
|
|
expected_output = f.read()
|
|
|
|
|
|
|
|
result = subprocess.run(end_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
|
|
|
program_output = result.stdout
|
|
|
|
|
2023-09-25 16:15:02 +02:00
|
|
|
if verbose:
|
|
|
|
print("Input:")
|
2024-10-02 16:18:42 +02:00
|
|
|
print(input_data)
|
2023-09-28 22:14:28 +02:00
|
|
|
print("")
|
2024-10-02 16:18:42 +02:00
|
|
|
if expected_output is not None:
|
2024-10-02 15:59:24 +02:00
|
|
|
print("Expected output:")
|
2024-10-02 16:18:42 +02:00
|
|
|
print(expected_output)
|
2024-10-02 15:59:24 +02:00
|
|
|
print("")
|
2024-10-02 16:18:42 +02:00
|
|
|
print("Program output:")
|
|
|
|
print(program_output.strip())
|
|
|
|
print("")
|
|
|
|
|
|
|
|
|
|
|
|
if output:
|
|
|
|
if expected_output is not None:
|
|
|
|
# Compare the outputs
|
|
|
|
if program_output == expected_output:
|
|
|
|
print("✅")
|
|
|
|
else:
|
|
|
|
print("❌")
|
2024-11-17 18:03:40 +01:00
|
|
|
# green expected output and red program output
|
|
|
|
print(f"{Fore.GREEN}Expected output:{Style.RESET_ALL}")
|
|
|
|
print(expected_output)
|
|
|
|
print(f"{Fore.RED}Program output:{Style.RESET_ALL}")
|
2024-10-02 16:18:42 +02:00
|
|
|
print(program_output.strip())
|
|
|
|
else:
|
2024-11-17 18:03:40 +01:00
|
|
|
print(f"{Fore.YELLOW}Expected output file not found; cannot compare outputs.{Style.RESET_ALL}")
|
2024-10-02 16:18:42 +02:00
|
|
|
if not verbose:
|
|
|
|
print("Program output:")
|
|
|
|
print(program_output.strip())
|
|
|
|
else:
|
|
|
|
if not verbose:
|
|
|
|
print(program_output.strip())
|
|
|
|
|
2023-09-28 22:14:28 +02:00
|
|
|
print("-----------")
|
2023-09-25 16:15:02 +02:00
|
|
|
return
|
|
|
|
|
2024-10-02 15:59:24 +02:00
|
|
|
def python_compile(file_name, verbose=False, tests_dir="."):
|
|
|
|
run_input_cases("python3 " + file_name, verbose, tests_dir=tests_dir)
|
2023-09-25 16:15:02 +02:00
|
|
|
return
|
|
|
|
|
2024-10-02 15:59:24 +02:00
|
|
|
def java_compile(file_name, maven=False, verbose=False, tests_dir="."):
|
2023-09-25 16:15:02 +02:00
|
|
|
if maven:
|
2024-10-02 15:59:24 +02:00
|
|
|
os.system("mvn clean verify")
|
|
|
|
os.system("java -jar target/*.jar")
|
2023-09-25 16:15:02 +02:00
|
|
|
return
|
2024-10-02 15:59:24 +02:00
|
|
|
os.system("javac " + file_name)
|
|
|
|
run_input_cases("java " + file_name[:file_name.rfind(".")], verbose, tests_dir=tests_dir)
|
2023-09-25 16:15:02 +02:00
|
|
|
return
|
|
|
|
|
2024-11-17 18:03:40 +01:00
|
|
|
def haskell_compile(file_name, verbose=False, tests_dir="."):
|
|
|
|
os.system("ghc -O2 " + file_name + " -o program")
|
|
|
|
run_input_cases("./program", verbose, tests_dir=tests_dir)
|
|
|
|
return
|
|
|
|
|
2024-10-02 15:59:24 +02:00
|
|
|
def c_compile(file_name, verbose=False, output=False, tests_dir="."):
|
2023-10-05 11:06:11 +02:00
|
|
|
# Style the code in Meijster's way
|
2024-10-02 15:59:24 +02:00
|
|
|
os.system("astyle -A2s2cxgk3W3xbj " + file_name)
|
|
|
|
os.system("gcc -Wall -pedantic --std=c99 -g -o program -lm -Wno-unused-result " + file_name)
|
|
|
|
run_input_cases("./program", verbose, output, tests_dir=tests_dir)
|
2023-09-25 16:15:02 +02:00
|
|
|
return
|
|
|
|
|
|
|
|
def main():
|
2024-11-17 18:03:40 +01:00
|
|
|
SUPPORTED_LANGS = [".c", ".py", ".java", ".hs"]
|
2023-09-25 16:15:02 +02:00
|
|
|
parser = argparse.ArgumentParser(
|
2024-10-02 15:59:24 +02:00
|
|
|
prog='UCompiler',
|
|
|
|
description='Compiles based on language',
|
|
|
|
epilog='LOL')
|
|
|
|
parser.add_argument("filename", metavar="<file>", type=str, help="File to compile")
|
|
|
|
parser.add_argument("-v", "--verbose", action="store_true", default=False, help="Prints input and output")
|
|
|
|
parser.add_argument("-a", "--alternative", action="store_true", default=False, help="Uses alternative compiler to compile")
|
|
|
|
parser.add_argument("-o", "--output", action="store_true", default=False, help="Checks diff for each .in file with .out file")
|
|
|
|
parser.add_argument("-t", "--tests", metavar="<path>", type=str, help="Directory to run tests")
|
2023-09-28 22:14:28 +02:00
|
|
|
|
2023-09-25 16:15:02 +02:00
|
|
|
args = parser.parse_args()
|
|
|
|
file_name = args.filename
|
|
|
|
file_ext = file_name[file_name.rfind("."):]
|
|
|
|
if file_ext not in SUPPORTED_LANGS:
|
|
|
|
print("Unsupported language")
|
|
|
|
return
|
|
|
|
|
2024-10-02 16:18:42 +02:00
|
|
|
# Use the specified tests directory or default to current directory
|
2024-10-02 15:59:24 +02:00
|
|
|
tests_dir = args.tests if args.tests else "."
|
|
|
|
|
2023-09-25 16:15:02 +02:00
|
|
|
if file_ext == ".c":
|
2024-10-02 15:59:24 +02:00
|
|
|
c_compile(file_name, args.verbose, args.output, tests_dir=tests_dir)
|
2023-09-25 16:15:02 +02:00
|
|
|
elif file_ext == ".py":
|
2024-10-02 15:59:24 +02:00
|
|
|
python_compile(file_name, args.verbose, tests_dir=tests_dir)
|
2023-09-25 16:15:02 +02:00
|
|
|
elif file_ext == ".java":
|
2024-10-02 15:59:24 +02:00
|
|
|
java_compile(file_name, args.alternative, args.verbose, tests_dir=tests_dir)
|
2024-11-17 18:03:40 +01:00
|
|
|
elif file_ext == ".hs":
|
|
|
|
haskell_compile(file_name, args.verbose, tests_dir=tests_dir)
|
2024-10-02 15:59:24 +02:00
|
|
|
return
|
2023-09-25 16:15:02 +02:00
|
|
|
|
|
|
|
if __name__ == "__main__":
|
2024-11-17 18:03:40 +01:00
|
|
|
check_dependencies()
|
2023-09-25 16:15:02 +02:00
|
|
|
main()
|