Files
Plasma/main.py

112 lines
3.0 KiB
Python
Raw Permalink Normal View History

2025-10-13 06:55:35 +11:00
from lexer import Lexer
2025-10-13 17:41:07 +11:00
from plasma_parser import Parser
2025-10-13 21:05:03 +11:00
from compiler import Compiler
2025-10-13 17:41:07 +11:00
from AST import Program
import json
import time
import sys
from argparse import ArgumentParser, Namespace
2025-10-13 06:55:35 +11:00
2025-10-13 21:05:03 +11:00
from llvmlite import ir
import llvmlite.binding as llvm
2025-10-13 21:05:03 +11:00
from ctypes import CFUNCTYPE, c_int, c_float
def parse_arguments() -> Namespace:
arg_parser: ArgumentParser = ArgumentParser(
"Plasma",
description="The compiler for the Plasma programming language."
)
arg_parser.add_argument("file_path", type=str, help="path to the entry point of your plasma program (ex. \"main.pla\")")
arg_parser.add_argument("--tokens", action="store_true", help="display the tokenized code")
arg_parser.add_argument("--ast", default=None, help="export the generated AST to a JSON file")
arg_parser.add_argument("--llvm", default=None, help="export the generated LLVM IR to a file")
arg_parser.add_argument("--silent", action="store_true", help="don't print anything!!!!")
2025-10-19 19:01:14 +11:00
arg_parser.add_argument("--output", type=str, help="path to where the outputed executable will be. if not provided, the program will be JIT compiled", default=None)
return arg_parser.parse_args()
2025-10-13 06:55:35 +11:00
if __name__ == "__main__":
args = parse_arguments()
if args.silent:
sys.stdout = None
with open(args.file_path) as f:
2025-10-13 06:55:35 +11:00
code: str = f.read()
if args.tokens:
2025-10-13 06:55:35 +11:00
debug_lex: Lexer = Lexer(source=code)
while debug_lex.current_char is not None:
2025-10-13 17:41:07 +11:00
print(debug_lex.next_token())
l: Lexer = Lexer(source=code)
p: Parser = Parser(lexer=l)
parse_st: float = time.time()
2025-10-13 21:05:03 +11:00
program: Program = p.parse_program()
parse_et: float = time.time()
2025-10-18 19:28:54 +11:00
#print(f"Parsed in {round((parse_et - parse_st) * 1000, 6)} ms.")
2025-10-13 21:05:03 +11:00
if len(p.errors) > 0:
for err in p.errors:
print(err)
exit(1)
if args.ast:
2025-10-13 17:41:07 +11:00
print("===== PARSER DEBUG =====")
2025-10-13 21:05:03 +11:00
#program: Program = p.parse_program()
2025-10-13 17:41:07 +11:00
with open(args.ast, "w") as f:
2025-10-13 17:41:07 +11:00
json.dump(program.json(), f, indent=4)
print(f"Wrote AST to \"{args.ast}\" successfully.")
2025-10-13 21:05:03 +11:00
c: Compiler = Compiler()
compiler_st: float = time.time()
2025-10-13 21:05:03 +11:00
c.compile(program)
compiler_et: float = time.time()
2025-10-18 19:28:54 +11:00
#print(f"Compiled in {round((compiler_et - compiler_st) * 1000, 6)} ms.")
2025-10-13 21:05:03 +11:00
module: ir.Module = c.module
module.triple = llvm.get_default_triple()
2025-10-13 21:05:03 +11:00
if args.llvm:
with open(args.llvm, "w") as f:
f.write(str(module))
llvm.initialize_native_target()
llvm.initialize_native_asmparser()
llvm.initialize_native_asmprinter()
try:
llvm_ir_parsed = llvm.parse_assembly(str(module))
llvm_ir_parsed.verify()
except Exception as e:
print(e)
raise
target_machine = llvm.Target.from_default_triple().create_target_machine()
2025-10-19 19:01:14 +11:00
if args.output != None:
obj_data = target_machine.emit_object(llvm_ir_parsed)
with open(args.output, "wb") as f:
f.write(obj_data)
else:
engine = llvm.create_mcjit_compiler(llvm_ir_parsed, target_machine)
engine.finalize_object()
2025-10-19 19:01:14 +11:00
entry = engine.get_function_address("main")
cfunc = CFUNCTYPE(c_int)(entry)
2025-10-19 19:01:14 +11:00
st = time.time()
2025-10-19 19:01:14 +11:00
result = cfunc()
2025-10-19 19:01:14 +11:00
et = time.time()
2025-10-19 19:01:14 +11:00
print(f"\n\nProgram returned: {result}\n=== Executed in {round((et - st) * 1000, 6)} ms. ===")
exit(result)