11import argparse
2- import typing
2+ import pathlib
33import yaml
4- from time import gmtime , strftime
54
6- parser = argparse .ArgumentParser ()
7- parser .add_argument ("input" , type = str , help = "OpCode definition file path" )
8- parser .add_argument ("template" , type = str , help = "Template file path" )
9- parser .add_argument ("output" , type = str , help = "Output file name" )
10-
11- args = parser .parse_args ()
5+ from datetime import datetime
6+ from jinja2 import Environment , FunctionLoader , Template , select_autoescape
127
138
149class Indent :
@@ -25,94 +20,134 @@ def decrease(self):
2520 def reset (self ):
2621 self .value = 0
2722
28- def generate_spaces (self ):
29- return " " * (self .step_size * self .value )
23+ def as_string (self , whitespace = " " ):
24+ return whitespace * (self .step_size * self .value )
3025
3126
32- class OpCodeCppListGenerator :
33- def __init__ (self ):
34- self .prefix = ''
35- self .indent = Indent ()
27+ def load_template_file_contents (id : str ) -> str :
28+ with open (pathlib .Path ("templates" ) / id ) as f :
29+ return f .read ()
30+
31+
32+ if __name__ == "__main__" :
33+ parser = argparse .ArgumentParser ()
34+ parser .add_argument ("input" , type = str , help = "Opcode definition file path" )
35+ parser .add_argument ("template" , type = str , help = "Template name" )
36+ parser .add_argument ("--output" , dest = "output" , type = str , help = "Output file path" )
37+
38+ args = parser .parse_args ()
39+
40+ with open (args .input , 'r' ) as f :
41+ opcode_list = yaml .load (f )
42+ opcode_list = opcode_list ['mnemonics' ]
43+
44+ template_environment_variables = {
45+ "generated_at" : datetime .utcnow ().strftime ("%Y-%m-%d %H:%M:%S" ) + " UTC"
46+ }
47+
3648
37- def format_name (self , name ):
38- return str .upper (name ).replace ('.' , '_' )
49+ def render_c_lines (items , prefix = "" ) -> str :
50+ indent = Indent ()
51+ indent .increase ()
3952
40- def generate_key (self , name ):
41- return self .prefix + name
53+ lines = []
4254
43- def generate_value ( self , code ):
44- return code
55+ def format_name ( name ):
56+ return prefix + str . upper ( name ). replace ( '.' , '_' )
4557
46- def prepare_items ( self , items ):
47- result = []
58+ def render_item ( name , code ):
59+ return indent . as_string () + format_name ( name ) + " = " + code
4860
4961 for i in items :
5062 if type (i ['name' ]) == type (list ()):
5163 primary_name = i ['name' ][0 ]
5264
5365 for n in i ['name' ]:
54- string_to_append = self .indent .generate_spaces () + self .generate_key (self .format_name (n )) \
55- + " = " + self .generate_value (i ['code' ])
66+ string_to_append = render_item (n , i ["code" ])
5667
57- if ( n != primary_name ) :
58- string_to_append += " /* alias for " + self . format_name (primary_name ) + " */"
68+ if n != primary_name :
69+ string_to_append += " // alias for " + format_name (primary_name )
5970
60- result .append (string_to_append )
71+ lines .append (string_to_append )
6172 else :
62- result .append (self . indent . generate_spaces () + self . generate_key ( self . format_name ( i [ ' name' ])) + " = " + self . generate_value ( i [ ' code' ]))
73+ lines .append (render_item ( i [ " name" ], i [ " code" ]))
6374
64- return result
75+ lines = str . join ( ', \n ' , lines )
6576
66- def generate_enumeration_lines (self , items ):
67- lines = self .prepare_items (items )
77+ return lines
6878
69- # Do not use 'os.linesep' on Windows. It generates an extra line break
70- return str .join (',\n ' , lines )
7179
80+ def render_c_template (template : Template ) -> str :
81+ lines = render_c_lines (opcode_list , "OPCODE_" )
7282
73- current_time = strftime ("%Y-%m-%d %H:%M:%S %z" , gmtime ())
83+ template_variables = {
84+ "environment" : template_environment_variables ,
85+ "name" : "_GeneratedOpCodes" ,
86+ "lines" : lines ,
87+ }
7488
75- # Read definition file
76- input_file = open (args .input , 'r' )
77- opcode_list = yaml .load (input_file )
78- opcode_list = opcode_list ['mnemonics' ]
79- input_file .close ()
89+ return template .render (** template_variables )
8090
81- # Read template
82- template_file = open (args .template , mode = 'r' )
83- template_content = template_file .read ()
84- template_file .close ()
8591
86- output_file_name = args .output
92+ def render_cpp_template (template : Template ) -> str :
93+ lines = render_c_lines (opcode_list , "OPCODE_" )
8794
88- if output_file_name is None :
89- output_file_name = '/._opcodes.h'
95+ template_variables = {
96+ "environment" : template_environment_variables ,
97+ "name" : "_GeneratedOpCodes" ,
98+ "lines" : lines ,
99+ }
90100
91- opcodes_file_generator_settings = {
92- "outputFileName" : output_file_name ,
93- "fileTemplate" : template_content ,
94- "name" : "_GeneratedOpCodes" ,
95- "prefix" : "OPCODE_" ,
96- }
101+ return template .render (** template_variables )
97102
98- with open (opcodes_file_generator_settings ["outputFileName" ], 'w' ) as f :
99- cpp_enumeration_generator = OpCodeCppListGenerator ()
100- cpp_enumeration_generator .prefix = opcodes_file_generator_settings ["prefix" ]
101103
102- cpp_enumeration_generator .indent .increase ()
103- renderedItems = cpp_enumeration_generator .generate_enumeration_lines (
104- opcode_list )
105- cpp_enumeration_generator .indent .reset ()
104+ def render_rust_template (template : Template ) -> str :
105+ lines = render_c_lines (opcode_list )
106106
107- result = opcodes_file_generator_settings ["fileTemplate" ]
107+ template_variables = {
108+ "environment" : template_environment_variables ,
109+ "name" : "Opcodes" ,
110+ "lines" : lines ,
111+ }
108112
109- parameters = {
110- "${generated_at}" : current_time ,
111- '${name}' : opcodes_file_generator_settings ["name" ],
112- '${items}' : renderedItems
113+ return template .render (** template_variables )
114+
115+
116+ template_map = {
117+ "c" : {
118+ "template" : "c-header.template" ,
119+ "renderer" : render_c_template ,
120+ },
121+ "cpp" : {
122+ "template" : "cpp-header.template" ,
123+ "renderer" : render_cpp_template ,
124+ },
125+ "rust" : {
126+ "template" : "rust.template" ,
127+ "renderer" : render_rust_template ,
128+ }
113129 }
114130
115- for k , v in parameters .items ():
116- result = result .replace (k , v )
131+ jinja_environment = Environment (
132+ loader = FunctionLoader (load_template_file_contents ),
133+ autoescape = select_autoescape (),
134+ keep_trailing_newline = True
135+ )
136+
137+ requested_template = args .template
138+
139+ template_descriptor = template_map [requested_template ]
140+
141+ jinja_template = jinja_environment .get_template (template_descriptor ["template" ])
142+
143+ result = template_descriptor ["renderer" ](jinja_template )
144+
145+ if args .output :
146+ output_file_path = pathlib .Path (args .output )
147+
148+ with open (output_file_path , 'w+' ) as f :
149+ f .write (result )
150+ else :
151+ print (result )
117152
118- f . write ( result )
153+ exit ( 0 )
0 commit comments