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
2025-10-14 19:22:59 +11:00
import time
2025-10-18 07:40:47 +11:00
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
2025-10-14 19:22:59 +11:00
import llvmlite . binding as llvm
2025-10-13 21:05:03 +11:00
from ctypes import CFUNCTYPE , c_int , c_float
2025-10-18 07:40:47 +11:00
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 )
2025-10-18 07:40:47 +11:00
return arg_parser . parse_args ( )
2025-10-13 06:55:35 +11:00
if __name__ == " __main__ " :
2025-10-18 07:40:47 +11:00
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 ( )
2025-10-18 07:40:47 +11:00
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 )
2025-10-18 07:40:47 +11:00
parse_st : float = time . time ( )
2025-10-13 21:05:03 +11:00
program : Program = p . parse_program ( )
2025-10-18 07:40:47 +11:00
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-18 07:40:47 +11:00
2025-10-13 21:05:03 +11:00
if len ( p . errors ) > 0 :
for err in p . errors :
print ( err )
exit ( 1 )
2025-10-18 07:40:47 +11:00
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
2025-10-18 07:40:47 +11:00
with open ( args . ast , " w " ) as f :
2025-10-13 17:41:07 +11:00
json . dump ( program . json ( ) , f , indent = 4 )
2025-10-18 07:40:47 +11:00
print ( f " Wrote AST to \" { args . ast } \" successfully. " )
2025-10-13 21:05:03 +11:00
c : Compiler = Compiler ( )
2025-10-18 07:40:47 +11:00
compiler_st : float = time . time ( )
2025-10-13 21:05:03 +11:00
c . compile ( program )
2025-10-18 07:40:47 +11:00
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
2025-10-14 19:22:59 +11:00
module . triple = llvm . get_default_triple ( )
2025-10-13 21:05:03 +11:00
2025-10-18 07:40:47 +11:00
if args . llvm :
with open ( args . llvm , " w " ) as f :
2025-10-14 19:22:59 +11:00
f . write ( str ( module ) )
2025-10-18 07:40:47 +11:00
llvm . initialize_native_target ( )
llvm . initialize_native_asmparser ( )
llvm . initialize_native_asmprinter ( )
2025-10-14 19:22:59 +11:00
2025-10-18 07:40:47 +11:00
try :
llvm_ir_parsed = llvm . parse_assembly ( str ( module ) )
llvm_ir_parsed . verify ( )
except Exception as e :
print ( e )
raise
2025-10-14 19:22:59 +11:00
2025-10-18 07:40:47 +11:00
target_machine = llvm . Target . from_default_triple ( ) . create_target_machine ( )
2025-10-14 19:22:59 +11:00
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-14 19:22:59 +11:00
2025-10-19 19:01:14 +11:00
entry = engine . get_function_address ( " main " )
cfunc = CFUNCTYPE ( c_int ) ( entry )
2025-10-14 19:22:59 +11:00
2025-10-19 19:01:14 +11:00
st = time . time ( )
2025-10-14 19:22:59 +11:00
2025-10-19 19:01:14 +11:00
result = cfunc ( )
2025-10-14 19:22:59 +11:00
2025-10-19 19:01:14 +11:00
et = time . time ( )
2025-10-14 19:22:59 +11:00
2025-10-19 19:01:14 +11:00
print ( f " \n \n Program returned: { result } \n === Executed in { round ( ( et - st ) * 1000 , 6 ) } ms. === " )
exit ( result )