Última atividade 2 days ago

The simplest Nova implementation I've got (so far).

Revisão 8a2230ae966adc9b149f028bbc937393c8413e75

simplest-nova.py Bruto Playground
1#!/usr/bin/env python3
2
3import sys
4from enum import Enum
5
6class State(Enum):
7 # States
8 INSERT = 0
9 MATCH = 1
10 REMOVE = 2
11
12 # Substates
13 FETCH = 3
14 LITERAL = 4
15 VARIABLE = 5
16
17class Machine:
18 def __init__(self, code, hooks=[]):
19 self.code = code
20 self.literals = "0123456789abcdefABCDEF"
21 self.length = len(code)
22 self.cursor = 0
23 self.stack = 0
24 self.state = State.INSERT
25 self.substate = State.FETCH
26 self.stacks = [[] for _ in range(0x10)]
27 self.offsets = [0] * 0x10
28 self.variables = {}
29 self.hooks = hooks
30 for hook in hooks:
31 hook(self)
32 def seek(self, instruction):
33 while self.cursor < self.length and self.code[self.cursor] != instruction:
34 self.cursor += 1
35 def branch(self):
36 self.clear()
37 self.seek('.')
38 def transition(new):
39 def instruction(self):
40 self.state = new
41 self.substate = State.FETCH
42 self.cursor += 1
43 return self.cursor >= self.length
44 return instruction
45 def variable(self):
46 if self.substate is State.LITERAL:
47 self.substate = State.VARIABLE
48 self.cursor += 1
49 return self.cursor >= self.length
50 def clear(self):
51 self.variables.clear()
52 for stack in range(0x10):
53 self.offsets[stack] = 0
54 def reset(self):
55 self.clear()
56 self.cursor = 0
57 self.state = State.INSERT
58 self.substate = State.FETCH
59 self.seek('?')
60 for hook in self.hooks:
61 hook(self)
62 def number(self, instruction):
63 try:
64 return int(instruction, 16)
65 except:
66 return None
67 def insert(self, instruction):
68 if self.substate is State.LITERAL:
69 self.stacks[self.stack].append(instruction)
70 else:
71 if instruction in self.variables:
72 self.stacks[self.stack].append(self.variables[instruction])
73 else:
74 self.stacks[self.stack].append(0)
75 self.substate = State.FETCH
76 self.cursor += 1
77 return self.cursor >= self.length
78 def match(self, instruction):
79 depth = len(self.stacks[self.stack])
80 offset = self.offsets[self.stack]
81 if depth == 0 or offset >= depth:
82 self.branch()
83 else:
84 if self.substate is State.LITERAL:
85 if self.stacks[stack][-1 - offset] != instruction:
86 self.branch()
87 elif self.substate is State.VARIABLE:
88 if instruction in self.variables:
89 if self.variables[instruction] != self.stacks[self.stack][-1 - offset]:
90 self.branch()
91 else:
92 self.variables[instruction] = self.stacks[self.stack][-1 - offset]
93 self.substate = State.FETCH
94 self.cursor += 1
95 return self.cursor >= self.length
96 def literal(self, instruction):
97 if self.substate is State.FETCH:
98 if self.state is State.REMOVE:
99 self.stacks[instruction].pop()
100 else:
101 self.stack = instruction
102 self.substate = State.LITERAL
103 self.cursor += 1
104 return self.cursor >= self.length
105 if self.state is State.INSERT:
106 return self.insert(instruction)
107 return self.match(instruction)
108 def step(self):
109 instructions = {
110 '+': Machine.transition(State.INSERT),
111 '?': Machine.transition(State.MATCH),
112 '-': Machine.transition(State.REMOVE),
113 '$': Machine.variable,
114 '.': Machine.reset
115 }
116 if self.cursor >= self.length:
117 return True
118 instruction = self.code[self.cursor]
119 if instruction in instructions:
120 return instructions[instruction](self)
121 elif instruction in self.literals:
122 return self.literal(self.number(instruction))
123 self.cursor += 1
124 return False
125 def run(self):
126 halt = False
127 while not halt:
128 halt = self.step()
129 return self
130 def print(self):
131 for index, stack in enumerate(self.stacks):
132 if len(stack) != 0:
133 print(str(index) + ':', " ".join([str(element) for element in stack]))
134
135def main(name, arguments):
136 code = ""
137 if len(arguments) == 0:
138 print("usage:", name, "<files...>")
139 return
140 for argument in arguments:
141 if argument == '-':
142 code += input()
143 continue
144 with open(argument) as file:
145 code += file.read()
146 Machine(code).run().print()
147
148if __name__ == "__main__":
149 main(sys.argv[0], sys.argv[1:])