4 import crossplatform_ir_generation
6 Symbol = collections.namedtuple(
15 class Environment(object):
16 def __init__(self, parent):
20 def __getitem__(self, symbol):
21 if symbol in self.symbols:
22 return self.symbols[symbol]
24 if self.parent is None:
25 raise Exception('Symbol "{}" not found'.format(symbol))
27 return self.parent[symbol]
29 def __setitem__(self, symbol, value):
30 self.symbols[symbol] = value
32 def builtin_print(*outputs):
33 outputs = list(outputs)
35 for i in range(len(outputs)):
38 if isinstance(output, bool):
39 outputs[i] = str(output).lower()
41 print(*outputs, end='')
43 BUILTIN_ENVIRONMENT = Environment(None)
44 BUILTIN_ENVIRONMENT.symbols = {
46 'pow': lambda base, exponent: pow(base, exponent),
47 'print': builtin_print,
51 def interpret(program):
52 environment = Environment(BUILTIN_ENVIRONMENT)
56 for i in range(len(program.entry_list)):
57 if isinstance(program.entry_list[i], crossplatform_ir_generation.CIRLabel):
58 if program.entry_list[i].label in label_indices:
59 raise Exception('Label already in labels')
61 label_indices[program.entry_list[i].label] = i
63 program_counter = label_indices['__main__'] + 1
67 while isinstance(program.entry_list[program_counter], crossplatform_ir_generation.CIRLabel):
70 instruction = program.entry_list[program_counter].instruction
71 argument = program.entry_list[program_counter].argument
73 if instruction in ('add', 'idiv', 'mod', 'mul', 'sub'):
77 assert isinstance(left, int)
78 assert isinstance(right, int)
80 if instruction == 'add':
82 elif instruction == 'idiv':
83 result = left // right
84 elif instruction == 'mod':
86 elif instruction == 'mul':
88 elif instruction == 'sub':
93 elif instruction in ('gt', 'gte', 'lt', 'lte'):
97 assert isinstance(left, int)
98 assert isinstance(right, int)
100 if instruction == 'gt':
101 result = left > right
102 elif instruction == 'gte':
103 result = left >= right
104 elif instruction == 'lt':
105 result = left < right
106 elif instruction == 'lte':
107 result = left <= right
111 elif instruction in ('eq', 'neq'):
116 if instruction == 'eq':
117 result = left == right
118 elif instruction == 'neq':
119 result = left != right
123 elif instruction == 'call':
124 assert isinstance(argument, int)
129 for i in range(argument):
130 args.append(stack.pop())
132 args = list(reversed(args))
134 stack.append(f(*args))
136 elif instruction == 'concat':
140 assert isinstance(left, str)
141 assert isinstance(right, str)
143 stack.append(left + right)
145 elif instruction == 'drop':
146 assert argument is None
149 elif instruction == 'end':
150 assert argument is None
153 elif instruction == 'field':
155 structure = stack.pop()
157 result = getattr(structure, key.name, sentinel)
159 assert result is not sentinel
163 elif instruction == 'get':
165 assert isinstance(argument, int)
167 assert isinstance(xs, list)
168 stack.append(xs[index])
170 elif instruction == 'jump_if_false':
171 program_counter = label_indices[argument]
173 elif instruction == 'list':
174 assert isinstance(argument, int)
178 for i in range(argument):
179 result.append(stack.pop())
181 stack.append(list(reversed(result)))
183 elif instruction == 'neg':
184 stack.append(-stack.pop())
186 elif instruction == 'pop':
187 assert argument.startswith('sym(')
188 assert argument.endswith(')')
189 environment[argument[4:-1]] = stack.pop()
191 elif instruction == 'push':
192 assert argument.startswith('sym(')
193 assert argument.endswith(')')
194 stack.append(environment[argument[4:-1]])
196 elif instruction == 'push_integer':
197 assert isinstance(argument, int)
198 stack.append(argument)
200 elif instruction == 'push_string':
201 assert argument.startswith('"')
202 assert argument.endswith('"')
203 stack.append(argument[1:-1].encode('utf-8').decode('unicode_escape'))
205 elif instruction == 'push_symbol':
206 assert argument.startswith('sym(')
207 assert argument.endswith(')')
209 result = SYMBOL_TABLE.get(argument)
211 result = Symbol(name=argument[4:-1])
212 SYMBOL_TABLE[argument] = result
216 elif instruction == 'structure':
219 for i in range(argument):
222 kvps.append((key.name, value))
224 keys = tuple(reversed(list(k for k,v in kvps)))
225 result = collections.namedtuple('Structure', keys)(**dict(kvps))
230 raise Exception('Instruction "{}" not supported (argument {}).'.format(