0e66abb82d8883fe1b52c167e339bd9b2b99e2a9
[fur] / c_generation.py
1 import os
2
3 import jinja2
4
5 import crossplatform_ir_generation
6
7 TEMPLATE_PATH = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'templates')
8
9 def separate_labels_and_instructions(entry_list):
10     labels_to_instruction_indices = {}
11     instruction_list = []
12
13     for entry in entry_list:
14         if isinstance(entry, crossplatform_ir_generation.CIRInstruction):
15             instruction_list.append(entry)
16         elif isinstance(entry, crossplatform_ir_generation.CIRLabel):
17             labels_to_instruction_indices[entry.label] = len(instruction_list)
18
19     return labels_to_instruction_indices, tuple(instruction_list)
20
21 def generate_integer_argument(argument):
22     assert isinstance(argument, int)
23     return '(int32_t){}'.format(argument)
24
25 def generate_label_argument(argument):
26     return 'LABEL_{}'.format(argument)
27
28 def generate_null_argument(argument):
29     assert argument is None
30     return 'NULL'
31
32 def generate_null_argument_from(argument_count):
33     def generator(argument):
34         assert isinstance(argument, int)
35         assert argument == argument_count
36         return 'NULL'
37     return generator
38
39 def generate_size_t_argument(argument):
40     assert isinstance(argument, int)
41     return '(size_t){}'.format(argument)
42
43 def generate_string_argument(argument):
44     return argument[0] + ''.join('\\"' if ch == '"' else ch for ch in argument[1:-1]) + argument[-1]
45
46 def generate_symbol_argument(argument):
47     assert argument.startswith('sym(') and argument.endswith(')')
48     return '"{}"'.format(argument[4:-1])
49
50 def generate_argument(instruction):
51     try:
52         return {
53             'add': generate_null_argument_from(2),
54             'call': generate_size_t_argument,
55             'close': generate_label_argument,
56             'concat': generate_integer_argument,
57             'drop': generate_null_argument,
58             'end': generate_null_argument,
59             'eq': generate_null_argument_from(2),
60             'get': generate_null_argument_from(2),
61             'gt': generate_null_argument_from(2),
62             'gte': generate_null_argument_from(2),
63             'idiv': generate_null_argument_from(2),
64             'jump': generate_label_argument,
65             'jump_if_false': generate_label_argument,
66             'list': generate_integer_argument,
67             'lt': generate_null_argument_from(2),
68             'lte': generate_null_argument_from(2),
69             'mod': generate_null_argument_from(2),
70             'mul': generate_null_argument_from(2),
71             'neg': generate_null_argument_from(1),
72             'neq': generate_null_argument_from(2),
73             'pop': generate_symbol_argument,
74             'push': generate_symbol_argument,
75             'push_integer': generate_integer_argument,
76             'push_string': generate_string_argument,
77             'push_symbol': generate_symbol_argument,
78             'return': generate_null_argument,
79             'structure': generate_integer_argument,
80             'sub': generate_null_argument_from(2),
81         }[instruction.instruction](instruction.argument)
82
83     except KeyError:
84         import ipdb; ipdb.set_trace()
85
86 def generate(ir):
87     environment = jinja2.Environment(loader=jinja2.FileSystemLoader(TEMPLATE_PATH))
88     template = environment.get_template('program2.c')
89
90     labels_to_instruction_indices, instruction_list = separate_labels_and_instructions(
91         ir.entry_list,
92     )
93
94     return template.render(
95         labels_to_instruction_indices=labels_to_instruction_indices,
96         instruction_list=instruction_list,
97         generate_argument=generate_argument,
98     )