Dernière activité 2 days ago

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

Révision 699614edabf590fd926878006dd43f462189e064

search.nv Brut Playground
1+
2 `Push a bunch of facts.`
3 0 b
4 1 a 1 b 1 c
5 1 d 1 e 1 f
6 1 e 1 d 1 c
7 1 a
8.
9
10`Did we find what we're looking for?`
11? 0 $a 1 $a
12 - 0
13 + 2 $a
14.
15
16`Put unrelated items to the side.`
17? 0 $a 1 $b
18 - 1
19 + 3 $b
20.
21
22`We couldn't find what we were looking for.`
23? 0 $a
24 - 0
25 + 4 $a
26.
simplest-nova.py Brut 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:
34 if self.code[self.cursor] == '`' and instruction != '`':
35 self.cursor += 1
36 self.seek('`')
37 self.cursor += 1
38 elif self.code[self.cursor] == instruction:
39 break
40 else:
41 self.cursor += 1
42 def branch(self):
43 self.clear()
44 self.seek('.')
45 def transition(new):
46 def instruction(self):
47 self.state = new
48 self.substate = State.FETCH
49 self.cursor += 1
50 return self.cursor >= self.length
51 return instruction
52 def variable(self):
53 if self.substate is State.LITERAL:
54 self.substate = State.VARIABLE
55 self.cursor += 1
56 return self.cursor >= self.length
57 def clear(self):
58 self.variables.clear()
59 for stack in range(0x10):
60 self.offsets[stack] = 0
61 def reset(self):
62 self.clear()
63 self.cursor = 0
64 self.state = State.INSERT
65 self.substate = State.FETCH
66 self.seek('?')
67 for hook in self.hooks:
68 hook(self)
69 def number(self, instruction):
70 try:
71 return int(instruction, 16)
72 except:
73 return None
74 def insert(self, instruction):
75 if self.substate is State.LITERAL:
76 self.stacks[self.stack].append(instruction)
77 else:
78 if instruction in self.variables:
79 self.stacks[self.stack].append(self.variables[instruction])
80 else:
81 self.stacks[self.stack].append(0)
82 self.substate = State.FETCH
83 self.cursor += 1
84 return self.cursor >= self.length
85 def match(self, instruction):
86 depth = len(self.stacks[self.stack])
87 offset = self.offsets[self.stack]
88 if depth == 0 or offset >= depth:
89 self.branch()
90 else:
91 if self.substate is State.LITERAL:
92 if self.stacks[stack][-1 - offset] != instruction:
93 self.branch()
94 elif self.substate is State.VARIABLE:
95 if instruction in self.variables:
96 if self.variables[instruction] != self.stacks[self.stack][-1 - offset]:
97 self.branch()
98 else:
99 self.variables[instruction] = self.stacks[self.stack][-1 - offset]
100 self.substate = State.FETCH
101 self.cursor += 1
102 return self.cursor >= self.length
103 def literal(self, instruction):
104 if self.substate is State.FETCH:
105 if self.state is State.REMOVE:
106 self.stacks[instruction].pop()
107 else:
108 self.stack = instruction
109 self.substate = State.LITERAL
110 self.cursor += 1
111 return self.cursor >= self.length
112 if self.state is State.INSERT:
113 return self.insert(instruction)
114 return self.match(instruction)
115 def comment(self):
116 self.cursor += 1
117 self.seek('`')
118 self.cursor += 1
119 return self.cursor >= self.length
120 def step(self):
121 instructions = {
122 '+': Machine.transition(State.INSERT),
123 '?': Machine.transition(State.MATCH),
124 '-': Machine.transition(State.REMOVE),
125 '$': Machine.variable,
126 '.': Machine.reset,
127 '`': Machine.comment
128 }
129 if self.cursor >= self.length:
130 return True
131 instruction = self.code[self.cursor]
132 if instruction in instructions:
133 return instructions[instruction](self)
134 elif instruction in self.literals:
135 return self.literal(self.number(instruction))
136 self.cursor += 1
137 return False
138 def run(self):
139 halt = False
140 while not halt:
141 halt = self.step()
142 return self
143 def print(self):
144 for index, stack in enumerate(self.stacks):
145 if len(stack) != 0:
146 print(str(index) + ':', " ".join([str(element) for element in stack]))
147
148def main(name, arguments):
149 code = ""
150 if len(arguments) == 0:
151 print("usage:", name, "<files...>")
152 return
153 for argument in arguments:
154 if argument == '-':
155 code += input()
156 continue
157 with open(argument) as file:
158 code += file.read()
159 Machine(code).run().print()
160
161if __name__ == "__main__":
162 main(sys.argv[0], sys.argv[1:])