mirror of
https://github.com/iritmaximus/compilers.git
synced 2026-10-12 19:13:35 +03:00
129 lines
4.1 KiB
Python
129 lines
4.1 KiB
Python
from base64 import b64encode
|
|
import json
|
|
import re
|
|
import sys
|
|
from socketserver import ForkingTCPServer, StreamRequestHandler
|
|
from traceback import format_exception
|
|
from typing import Any
|
|
import subprocess
|
|
|
|
def call_compiler(source_code: str) -> bytes:
|
|
# *** TODO ***
|
|
# Call your compiler here and return the compiled executable.
|
|
# Raise an exception on compilation error.
|
|
# *** TODO ***
|
|
print("Compiling:", "./compilers_compiler", source_code)
|
|
import uuid
|
|
|
|
# Give the compiler a file to write the result to
|
|
filename = "compile-result-" + str(uuid.uuid4())
|
|
response = subprocess.run(["./compilers_compiler", source_code, filename], check=True, capture_output=True).stdout
|
|
print(response)
|
|
|
|
try:
|
|
# Read the updated file and fetch compiler result
|
|
with open(filename,"rb") as file_content:
|
|
content = file_content.read()
|
|
print(content)
|
|
|
|
except FileNotFoundError as e:
|
|
print("File not found", filename, e)
|
|
content = b""
|
|
|
|
|
|
return content
|
|
|
|
|
|
def main() -> int:
|
|
# === Option parsing ===
|
|
command: str | None = None
|
|
input_file: str | None = None
|
|
output_file: str | None = None
|
|
host = "127.0.0.1"
|
|
port = 3000
|
|
for arg in sys.argv[1:]:
|
|
if (m := re.fullmatch(r'--output=(.+)', arg)) is not None:
|
|
output_file = m[1]
|
|
elif (m := re.fullmatch(r'--host=(.+)', arg)) is not None:
|
|
host = m[1]
|
|
elif (m := re.fullmatch(r'--port=(.+)', arg)) is not None:
|
|
port = int(m[1])
|
|
elif arg.startswith('-'):
|
|
raise Exception(f"Unknown argument: {arg}")
|
|
elif command is None:
|
|
command = arg
|
|
elif input_file is None:
|
|
input_file = arg
|
|
else:
|
|
raise Exception("Multiple input files not supported")
|
|
|
|
valid_commands = ['compile', 'serve']
|
|
if command is None:
|
|
print(f"Error: command argument missing. Valid commands: {', '.join(valid_commands)}", file=sys.stderr)
|
|
return 1
|
|
|
|
if command not in valid_commands:
|
|
print(f"Error: unknown command: {command}", file=sys.stderr)
|
|
return 1
|
|
|
|
def read_source_code() -> str:
|
|
if input_file is not None:
|
|
with open(input_file) as f:
|
|
return f.read()
|
|
else:
|
|
return sys.stdin.read()
|
|
|
|
# === Command implementations ===
|
|
|
|
if command == 'compile':
|
|
source_code = read_source_code()
|
|
if output_file is None:
|
|
raise Exception("Output file flag --output=... required")
|
|
executable = call_compiler(source_code)
|
|
with open(output_file, 'wb') as f:
|
|
f.write(executable)
|
|
elif command == 'serve':
|
|
try:
|
|
run_server(host, port)
|
|
except KeyboardInterrupt:
|
|
pass
|
|
return 0
|
|
|
|
|
|
def run_server(host: str, port: int) -> None:
|
|
class Server(ForkingTCPServer):
|
|
allow_reuse_address = True
|
|
request_queue_size = 32
|
|
|
|
class Handler(StreamRequestHandler):
|
|
def handle(self) -> None:
|
|
print("Got a request?")
|
|
result: dict[str, Any] = {}
|
|
try:
|
|
input_str = self.rfile.read().decode()
|
|
print("INPUTSTR:", input_str)
|
|
input = json.loads(input_str)
|
|
print("JSONINPUT", input)
|
|
if input["command"] == "compile":
|
|
source_code = input["code"]
|
|
executable = call_compiler(source_code)
|
|
result["program"] = b64encode(executable).decode()
|
|
elif input["command"] == "ping":
|
|
pass
|
|
else:
|
|
result["error"] = "Unknown command: " + input['command']
|
|
except Exception as e:
|
|
print("ERROR!!", e)
|
|
result["error"] = "".join(format_exception(e))
|
|
result_str = json.dumps(result)
|
|
print(result_str)
|
|
self.request.sendall(str.encode(result_str))
|
|
|
|
print(f"Starting TCP server at {host}:{port}")
|
|
with Server((host, port), Handler) as server:
|
|
server.serve_forever()
|
|
|
|
|
|
if __name__ == '__main__':
|
|
sys.exit(main())
|