Implement and/or, introducing jumps and labels
[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
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             'drop': generate_null_argument,
56             'end': generate_null_argument,
57             'eq': generate_null_argument_from(2),
58             'gt': generate_null_argument_from(2),
59             'gte': generate_null_argument_from(2),
60             'idiv': generate_null_argument_from(2),
61             'jump': generate_label_argument,
62             'jump_if_false': generate_label_argument,
63             'lt': generate_null_argument_from(2),
64             'lte': generate_null_argument_from(2),
65             'mod': generate_null_argument_from(2),
66             'mul': generate_null_argument_from(2),
67             'neg': generate_null_argument_from(1),
68             'neq': generate_null_argument_from(2),
69             'pop': generate_symbol_argument,
70             'push': generate_symbol_argument,
71             'push_integer': generate_integer_argument,
72             'push_string': generate_string_argument,
73             'sub': generate_null_argument_from(2),
74         }[instruction.instruction](instruction.argument)
75
76     except KeyError:
77         import ipdb; ipdb.set_trace()
78
79 def generate(ir):
80     environment = jinja2.Environment(loader=jinja2.FileSystemLoader(TEMPLATE_PATH))
81     template = environment.get_template('program2.c')
82
83     labels_to_instruction_indices, instruction_list = separate_labels_and_instructions(
84         ir.entry_list,
85     )
86
87     return template.render(
88         labels_to_instruction_indices=labels_to_instruction_indices,
89         instruction_list=instruction_list,
90         generate_argument=generate_argument,
91     )