Begin adding some C code
[fur] / crossplatform_ir_generation.py
1 import collections
2
3 import conversion
4
5 def flatten(xses):
6     return tuple(x for xs in xses for x in xs)
7
8 CIRProgram = collections.namedtuple(
9     'CIRProgram',
10     (
11         'entry_list',
12     ),
13 )
14
15 CIRLabel = collections.namedtuple(
16     'CIRLabel',
17     (
18         'label',
19     ),
20 )
21
22 CIRInstruction = collections.namedtuple(
23     'CIRInstruction',
24     (
25         'instruction',
26         'argument',
27     ),
28 )
29
30 def generate_integer_literal(integer):
31     return integer
32
33 def generate_string_literal(string):
34     return '"{}"'.format(string)
35
36 def generate_symbol_literal(symbol):
37     return 'sym({})'.format(symbol)
38
39 def generate_function_call_expression(counters, expression):
40     referenced_entry_list, instruction_list = generate_expression(
41         counters,
42         expression.function_expression,
43     )
44
45     instruction_list += (
46         CIRInstruction(
47             instruction='call',
48             argument=expression.argument_count,
49         ),
50     )
51
52     return referenced_entry_list, instruction_list
53
54 def generate_integer_literal_expression(counters, expression):
55     referenced_entry_list = ()
56     instruction_list = (CIRInstruction(
57         instruction='push_value',
58         argument=generate_integer_literal(expression.integer),
59     ),)
60
61     return referenced_entry_list, instruction_list
62
63 def generate_lambda_expression(counters, expression):
64     if expression.name is None or 'lambda' in expression.name.lower():
65         import ipdb; ipdb.set_trace()
66
67     name_counter = counters.get(expression.name, 0)
68     counters[expression.name] = name_counter + 1
69     label = '{}${}'.format(expression.name, name_counter)
70
71     for argument_name in expression.argument_name_list:
72         import ipdb; ipdb.set_trace()
73
74     referenced_entry_list_list = []
75     instruction_list_list = []
76
77     for statement in expression.statement_list:
78         referenced_entry_list, instruction_list = generate_statement(counters, statement)
79         referenced_entry_list_list.append(referenced_entry_list)
80         instruction_list_list.append(instruction_list)
81
82     referenced_entry_list_list.append(
83         (CIRLabel(label=label),) + flatten(instruction_list_list),
84     )
85
86     instruction_list = (
87         CIRInstruction(instruction='close', argument=label),
88     )
89
90     return flatten(referenced_entry_list_list), instruction_list
91
92 def generate_string_literal_expression(counters, expression):
93     referenced_entry_list = ()
94     instruction_list = (CIRInstruction(
95         instruction='push_value',
96         argument=generate_string_literal(expression.string),
97     ),)
98
99     return referenced_entry_list, instruction_list
100
101 def generate_symbol_expression(counters, expression):
102     referenced_entry_list = ()
103     instruction_list = (CIRInstruction(
104         instruction='push',
105         argument=generate_symbol_literal(expression.symbol),
106     ),)
107
108     return referenced_entry_list, instruction_list
109
110 def generate_variable_expression(counters, expression):
111     referenced_entry_list = ()
112     instruction_list = (CIRInstruction(
113         instruction='push',
114         argument=generate_symbol_literal(expression.variable),
115     ),)
116
117     return referenced_entry_list, instruction_list
118
119 def generate_expression(counters, expression):
120     return {
121         conversion.CPSFunctionCallExpression: generate_function_call_expression,
122         conversion.CPSIntegerLiteralExpression: generate_integer_literal_expression,
123         conversion.CPSLambdaExpression: generate_lambda_expression,
124         conversion.CPSStringLiteralExpression: generate_string_literal_expression,
125         conversion.CPSSymbolExpression: generate_symbol_expression,
126         conversion.CPSVariableExpression: generate_variable_expression,
127     }[type(expression)](counters, expression)
128
129 def generate_expression_statement(counters, statement):
130     referenced_entry_list, instruction_list = generate_expression(
131         counters,
132         statement.expression,
133     )
134
135     instruction_list += (
136         CIRInstruction(
137             instruction='drop',
138             argument=None,
139         ),
140     )
141
142     return referenced_entry_list, instruction_list
143
144 def generate_if_else_statement(counters, statement):
145     if_counter = counters['if']
146     counters['if'] += 1
147
148     referenced_entry_list_list = []
149
150     if_instruction_list_list = []
151     for if_statement in statement.if_statement_list:
152         referenced_entry_list, instruction_list = generate_statement(counters, if_statement)
153         referenced_entry_list_list.append(referenced_entry_list)
154         if_instruction_list_list.append(instruction_list)
155
156     else_instruction_list_list = []
157
158     for else_statement in statement.else_statement_list:
159         referenced_entry_list, instruction_list = generate_statement(counters, else_statement)
160         referenced_entry_list_list.append(referenced_entry_list)
161         else_instruction_list_list.append(instruction_list)
162
163     if_label = '__if${}__'.format(if_counter)
164     else_label = '__else${}__'.format(if_counter)
165     endif_label = '__endif${}__'.format(if_counter)
166
167     instruction_list = (
168         referenced_entry_list_list,
169         generate_expression(counters, statement.condition_expression) + (
170             CIRInstruction(
171                 instruction='jump_if_false',
172                 argument=else_label,
173             ),
174             CIRLabel(label=if_label),
175         ) + flatten(if_instruction_list_list) + (
176             CIRInstruction(
177                 instruction='jump',
178                 argument=endif_label,
179             ),
180             CIRLabel(label=else_label),
181         ) + flatten(else_instruction_list_list) + (
182             CIRLabel(label=endif_label),
183         ),
184     )
185
186     return flatten(referenced_entry_list_list), instruction_list
187
188 def generate_assignment_statement(counters, statement):
189     referenced_entry_list, instruction_list = generate_expression(
190         counters,
191         statement.expression,
192     )
193
194     instruction_list += (
195         CIRInstruction(
196             instruction='pop',
197             argument=generate_symbol_literal(statement.target),
198         ),
199     )
200
201     return referenced_entry_list, instruction_list
202
203 def generate_push_statement(counters, statement):
204     return generate_expression(counters, statement.expression)
205
206 def generate_variable_initialization_statement(counters, statement):
207     referenced_entry_list, instruction_list = generate_expression(
208         counters,
209         statement.expression,
210     )
211
212     instruction_list += (
213         CIRInstruction(
214             instruction='pop',
215             argument=generate_symbol_literal(statement.variable),
216         ),
217     )
218
219     return referenced_entry_list, instruction_list
220
221 def generate_variable_reassignment_statement(counters, statement):
222     referenced_entry_list, instruction_list = generate_expression(
223         counters,
224         statement.expression,
225     )
226
227     instruction_list += (
228         CIRInstruction(
229             instruction='pop',
230             argument=generate_symbol_literal(statement.variable),
231         ),
232     )
233
234     return referenced_entry_list, instruction_list
235
236 def generate_statement(counters, statement):
237     return {
238         conversion.CPSAssignmentStatement: generate_assignment_statement,
239         conversion.CPSExpressionStatement: generate_expression_statement,
240         conversion.CPSIfElseStatement: generate_if_else_statement,
241         conversion.CPSPushStatement: generate_push_statement,
242         conversion.CPSVariableInitializationStatement: generate_variable_initialization_statement,
243         conversion.CPSVariableReassignmentStatement: generate_variable_reassignment_statement,
244     }[type(statement)](counters, statement)
245
246 def generate(converted):
247     referenced_entry_list_list = []
248     instruction_list_list = []
249     counters = {
250         'if': 0,
251     }
252
253     for statement in converted.statement_list:
254         referenced_entry_list, instruction_list = generate_statement(counters, statement)
255         referenced_entry_list_list.append(referenced_entry_list)
256         instruction_list_list.append(instruction_list)
257
258     return CIRProgram(
259         entry_list=(
260             CIRLabel(label='__main__'),
261         ) + flatten(referenced_entry_list_list) + flatten(instruction_list_list),
262     )
263
264 def output(program):
265     lines = []
266
267     for entry in program.entry_list:
268         if isinstance(entry, CIRInstruction):
269             lines.append('    {} {}'.format(entry.instruction, entry.argument))
270
271         if isinstance(entry, CIRLabel):
272             lines.append('\n{}:'.format(entry.label))
273
274     return '\n'.join(lines).lstrip()