Add symbol and structure support
[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             'field': generate_null_argument_from(2),
61             'get': generate_null_argument_from(2),
62             'gt': generate_null_argument_from(2),
63             'gte': generate_null_argument_from(2),
64             'idiv': generate_null_argument_from(2),
65             'jump': generate_label_argument,
66             'jump_if_false': generate_label_argument,
67             'list': generate_integer_argument,
68             'lt': generate_null_argument_from(2),
69             'lte': generate_null_argument_from(2),
70             'mod': generate_null_argument_from(2),
71             'mul': generate_null_argument_from(2),
72             'neg': generate_null_argument_from(1),
73             'neq': generate_null_argument_from(2),
74             'pop': generate_symbol_argument,
75             'push': generate_symbol_argument,
76             'push_integer': generate_integer_argument,
77             'push_string': generate_string_argument,
78             'push_symbol': generate_symbol_argument,
79             'return': generate_null_argument,
80             'structure': generate_integer_argument,
81             'sub': generate_null_argument_from(2),
82         }[instruction.instruction](instruction.argument)
83
84     except KeyError:
85         import ipdb; ipdb.set_trace()
86
87 def generate(ir):
88     environment = jinja2.Environment(loader=jinja2.FileSystemLoader(TEMPLATE_PATH))
89     template = environment.get_template('program2.c')
90
91     labels_to_instruction_indices, instruction_list = separate_labels_and_instructions(
92         ir.entry_list,
93     )
94
95     return template.render(
96         labels_to_instruction_indices=labels_to_instruction_indices,
97         instruction_list=instruction_list,
98         generate_argument=generate_argument,
99     )