Ostatnio aktywny 1748061902

capitalex's Avatar capitalex zrewidował ten Gist 1748061902. Przejdź do rewizji

2 files changed, 1238 insertions

novaweb-compiler.nv(stworzono plik)

@@ -0,0 +1,134 @@
1 + || :: load entry point into source
2 + :: process novaweb
3 +
4 + |:: load entry point into source? :entry point: $char|
5 + :processed: $char
6 + |:: load entry point into source? :processed: $char|
7 + :source: $char
8 + |:: load entry point into source|
9 +
10 + |:: process novaweb? :second pass needed:? :processed: $char|
11 + :source: $char
12 + |:: process novaweb? :second pass needed:|
13 + |:: process novaweb? :source: "@@@"|
14 + :: signal a second pass is needed
15 + :: load link :strip left: :strip right:
16 + :: search dictionary
17 + |:: process novaweb? :source: $char|
18 + :processed: $char
19 + |::process novaweb|
20 + :: finished compiling
21 +
22 +
23 + |:: signal a second pass is needed :second pass needed:?|
24 + |:: signal a second pass is needed|
25 + :second pass needed:
26 +
27 +
28 + |:: load link? :source: "@@@"? :incoming link: 9 :strip right:?|
29 + |:: load link? :source: "@@@"? :incoming link: 10 :strip right:?|
30 + |:: load link? :source: "@@@"? :incoming link: 13 :strip right:?|
31 + |:: load link? :source: "@@@"? :incoming link: 32 :strip right:?|
32 + |:: load link? :source: "@@@"? :strip right:|
33 + |:: load link? :source: "@@@"? :incoming link: $char|
34 + :link: $char
35 + |:: load link :source: "@@@"|
36 +
37 + |:: load link? :source: 9 :strip left:?|
38 + |:: load link? :source: 10 :strip left:?|
39 + |:: load link? :source: 13 :strip left:?|
40 + |:: load link? :source: 32 :strip left:?|
41 + |:: load link? :strip left:|
42 + |:: load link? :source: $char|
43 + :incoming link: $char
44 +
45 +
46 + |:: search dictionary? :link: $char? :name: $char?|
47 + :: match made
48 + |:: search dictionary? :link: $char? :name:?|
49 + :: search failed
50 + |:: search dictionary? :link: $char? :name: $other-char?|
51 + :: search failed
52 + |:: search dictionary :name:?|
53 + :: search succeeded
54 + |:: search dictionary? :link: $char?|
55 + :: search exhausted
56 +
57 + |:: search succeeded|
58 + :: restore name dictionary
59 + :: flush link
60 + :: push code to processed
61 + :: restore code
62 +
63 + |:: restore name dictionary? :consumed name:|
64 + :name:
65 + |:: restore name dictionary? :consumed name: $char|
66 + :name: $char
67 + |:: restore name dictionary|
68 +
69 +
70 + |:: restore code? :consumed code:|
71 + :code:
72 + |:: restore code? :consumed code: $char|
73 + :code: $char
74 + |:: restore code|
75 +
76 +
77 + |:: flush link? :consumed link: $char|
78 + |:: flush link|
79 +
80 +
81 + |:: push code to processed? :code: $char|
82 + :processed: $char :consumed code: $char
83 + |:: push code to processed :code:|
84 + :consumed code:
85 +
86 +
87 + |:: search failed|
88 + :: next name in dictionary
89 + :: next page of code
90 + :: reset link
91 +
92 + |:: next name in dictionary :name:|
93 + :consumed name:
94 + |:: next name in dictionary? :name: $char|
95 + :consumed name: $char
96 +
97 + |:: next page of code :code:|
98 + :consumed code:
99 + |:: next page of code? :code: $char|
100 + :consumed code: $char
101 +
102 + |:: reset link? :consumed link: $char|
103 + :link: $char
104 + |:: reset link|
105 +
106 + |:: search exhausted|
107 + :: show error :error message: "No reference found for"
108 + :error message: (58 32)
109 + :: exit
110 +
111 + |:: show error? :error message: $char|
112 + :@stdio: write $char
113 + |:: show error? :link: $char|
114 + :@stdio: write $char
115 + |:: show error|
116 + :@stdio: write 10
117 +
118 + |:: match made|
119 + :: advance link
120 + :: advance name dictionary
121 +
122 + |:: advance link :link: $char|
123 + :consumed link: $char
124 + |:: advance name dictionary :name: $char|
125 + :consumed name: $char
126 +
127 + |:: finished compiling? :processed: $char|
128 + :source: $char
129 + |:: finished compiling|
130 + :: print source
131 +
132 + |:: print source? :source: $char|
133 + :@stdio: write $char
134 + |:: print source|

novaweb-nova.nv(stworzono plik)

@@ -0,0 +1,1104 @@
1 + ^^
2 + ~entry point~ "
3 + @@@ Import Python core libraries @@@
4 + @@@ Set up PyGame @@@
5 + @@@ Set up NFC @@@
6 + @@@ The implementation of a Nova parser @@@
7 + @@@ The implementation of a Nova interpreter @@@
8 + @@@ The built-in modules @@@
9 + @@@ Let's include a REPL @@@
10 + @@@ Finally, the main program @@@
11 + "
12 +
13 + ~name~
14 + "The implementation of a Nova parser"
15 + ~name~
16 + ~code~
17 + "
18 + @@@ Parse the container format @@@
19 + @@@ Parse the label format @@@
20 + @@@ Parse the pattern format @@@
21 + @@@ Chain these steps together for the parser @@@
22 + "
23 + ~code~
24 +
25 + ~name~
26 + "The built-in modules"
27 + ~name~
28 + ~code~
29 + "
30 + @@@ The Math Module @@@
31 + @@@ The Arrays Module @@@
32 + @@@ The Graphics Module @@@
33 + @@@ The Midi Module @@@
34 + @@@ The Time Module @@@
35 + @@@ The Stdio Module @@@
36 + @@@ The NFC Module @@@
37 + "
38 + ~code~
39 +
40 + ~name~
41 + "Parse the container format"
42 + ~name~
43 + ~code~
44 + "
45 + def parse_container(string):
46 + left = []
47 + right = []
48 + target = left
49 + characters = (character for character in list(string) + [None])
50 + delimiter = None
51 + for character in characters:
52 + if character in {' ', '\n', '\r', '\t'}:
53 + continue
54 + delimiter = character
55 + break
56 + if delimiter is None:
57 + return None
58 + for character in characters:
59 + if character in {delimiter, None}:
60 + if target is left:
61 + target = right
62 + else:
63 + target = left
64 + yield (left.copy(), right.copy())
65 + left.clear()
66 + right.clear()
67 + else:
68 + target.append(character)
69 + "
70 + ~code~
71 +
72 + ~name~
73 + "Parse the label format"
74 + ~name~
75 + ~code~
76 + "
77 + def parse_labels(rules):
78 + left = []
79 + right = []
80 + pair = ([], [])
81 + target = left
82 + delimiter = None
83 + for condition, result in rules:
84 + for side in (condition, result):
85 + characters = (character for character in side + [None])
86 + state = "find delimiter"
87 + for character in characters:
88 + if character == None:
89 + label = "".join(pair[0]).strip()
90 + pattern = "".join(pair[1]).strip()
91 + if not(len(label) == 0 and len(pattern) == 0):
92 + target.append((label, pattern))
93 + pair[0].clear()
94 + pair[1].clear()
95 + break
96 + elif state == "find delimiter":
97 + if character in {' ', '\n', '\r', '\t'}:
98 + continue
99 + delimiter = character
100 + state = "parse label"
101 + elif state == "parse label":
102 + if character == delimiter:
103 + state = "parse pattern"
104 + continue
105 + pair[0].append(character)
106 + elif state == "parse pattern":
107 + if character in {delimiter, None}:
108 + state = "parse label"
109 + label = "".join(pair[0]).strip()
110 + pattern = "".join(pair[1]).strip()
111 + if not(len(label) == 0 and len(pattern) == 0):
112 + target.append((label, pattern))
113 + pair[0].clear()
114 + pair[1].clear()
115 + continue
116 + pair[1].append(character)
117 + if target is left:
118 + target = right
119 + else:
120 + target = left
121 + yield (left.copy(), right.copy())
122 + left.clear()
123 + right.clear()
124 + "
125 + ~code~
126 +
127 + ~name~
128 + "Parse the pattern format"
129 + ~name~
130 + ~code~
131 + "
132 + def parse_patterns(rules):
133 + for condition, result in rules:
134 + left = []
135 + right = []
136 + preserves = []
137 + for label, pattern in condition:
138 + preserve = False
139 + if pattern.endswith('?'):
140 + pattern = pattern[:-1]
141 + preserve = True
142 + if (pattern.startswith('"') or pattern.startswith("'")) and (pattern.endswith('"') or pattern.endswith("'")):
143 + for character in pattern[1:-1]:
144 + left.append((label, [str(ord(character))]))
145 + if preserve:
146 + right.append((label, [str(ord(character))]))
147 + elif pattern.startswith('(') and pattern.endswith(')'):
148 + for token in pattern[1:-1].split():
149 + left.append((label, [token]))
150 + if preserve:
151 + right.append((label, [token]))
152 + elif pattern.startswith('.'):
153 + for tuple in pattern.split('.'):
154 + tuple = tuple.strip()
155 + if len(tuple) != 0:
156 + left.append((label, tuple.split()))
157 + if preserve:
158 + right.append((label, tuple.split()))
159 + else:
160 + left.append((label, pattern.split()))
161 + if preserve:
162 + preserves.append((label, pattern.split()))
163 + for label, pattern in result:
164 + if (pattern.startswith('"') or pattern.startswith("'")) and (pattern.endswith('"') or pattern.endswith("'")):
165 + for character in pattern[1:-1]:
166 + right.append((label, [str(ord(character))]))
167 + elif pattern.startswith('(') and pattern.endswith(')'):
168 + for token in pattern[1:-1].split():
169 + right.append((label, [token]))
170 + elif pattern.startswith('.'):
171 + for tuple in pattern.split('.'):
172 + tuple = tuple.strip()
173 + if len(tuple) != 0:
174 + right.append((label, tuple.split()))
175 + else:
176 + right.append((label, pattern.split()))
177 + yield (left.copy(), right.copy() + preserves.copy())
178 + left.clear()
179 + right.clear()
180 + preserves.clear()
181 + "
182 + ~code~
183 +
184 + ~name~
185 + "Chain these steps together for the parser"
186 + ~name~
187 + ~code~
188 + "
189 + def parse(string):
190 + return parse_patterns(parse_labels(parse_container(string)))
191 + "
192 + ~code~
193 +
194 + ~name~
195 + "The implementation of a Nova interpreter"
196 + ~name~
197 + ~code~
198 + "
199 + def facts(ruleset):
200 + for left, right in ruleset:
201 + if not left:
202 + for element in right:
203 + yield element
204 +
205 + def rules(ruleset):
206 + for left, right in ruleset:
207 + if left:
208 + yield (left, right)
209 +
210 + def match(pattern, knowledge, variables=None):
211 + if variables is None:
212 + variables = {}
213 + label, elements = pattern
214 + if label not in knowledge or not knowledge[label][0]:
215 + return None
216 + if knowledge[label][1] >= len(knowledge[label][0]):
217 + knowledge[label][1] = 0
218 + return None
219 + top = knowledge[label][0][(-1 - knowledge[label][1])]
220 + len_top = len(top)
221 + if len_top != len(elements):
222 + knowledge[label][1] = 0
223 + return None
224 + for index in range(len_top):
225 + left = elements[index]
226 + right = top[index]
227 + if left[0] == '$':
228 + variable = left[1:]
229 + if variable not in variables:
230 + variables[variable] = right
231 + elif variables[variable] != right:
232 + knowledge[label][1] = 0
233 + return None
234 + elif left != right:
235 + knowledge[label][1] = 0
236 + return None
237 + knowledge[label][1] += 1
238 + return variables
239 +
240 + def consume(pattern, knowledge):
241 + if type(pattern) == str:
242 + knowledge[pattern][0].pop()
243 + knowledge[pattern][1] = 0
244 + else:
245 + label, _ = pattern
246 + knowledge[label][0].pop()
247 + knowledge[label][1] = 0
248 +
249 + def produce(pattern, knowledge, variables=None):
250 + if variables is None:
251 + variables = {}
252 + label, elements = pattern
253 + len_elements = len(elements)
254 + fact = [None] * len_elements
255 + for index in range(len_elements):
256 + element = elements[index]
257 + if element[0] == '$':
258 + variable = element[1:]
259 + if variable in variables:
260 + element = variables[variable]
261 + fact[index] = element
262 + if label not in knowledge:
263 + knowledge[label] = [[], 0]
264 + knowledge[label][0].append(fact)
265 + knowledge[label][1] = 0
266 +
267 + def reset(pattern, knowledge):
268 + label, _ = pattern
269 + if label in knowledge:
270 + knowledge[label][1] = 0
271 +
272 + def prepare(ruleset, knowledge=None):
273 + if knowledge == None:
274 + knowledge = {}
275 + for fact in reversed(list(facts(ruleset))):
276 + label, elements = fact
277 + if label not in knowledge:
278 + knowledge[label] = [[], 0]
279 + knowledge[label][0].append(elements)
280 + return knowledge
281 +
282 + def print_knowledge(knowledge, debug=0, maximum=10):
283 + for label, facts in knowledge.items():
284 + facts = facts[0]
285 + if not facts:
286 + continue
287 + if not label:
288 + label = ":"
289 + print(label + ': ', end="")
290 + if len(facts) >= maximum and debug % 2:
291 + print("...", len(facts), "...")
292 + continue
293 + if facts:
294 + if len(facts[-1]) == 0:
295 + print("<blank>")
296 + else:
297 + print(" ".join(facts[-1]))
298 + for fact in reversed(facts[:-1]):
299 + if len(fact) == 0:
300 + fact = ["<blank>"]
301 + print(' ' * (len(label) + 1), " ".join(fact))
302 +
303 + def step(ruleset, primitives=[], knowledge=None, snapshots=[], debug=0, trace=False):
304 + variables = {}
305 + steps = 0
306 + if debug >= 3:
307 + print_knowledge(knowledge, debug)
308 + print("")
309 + matched = False
310 + for primitive in primitives:
311 + steps += 1
312 + if primitive(ruleset, knowledge, snapshots):
313 + matched = True
314 + break
315 + if matched:
316 + return (True, steps, knowledge)
317 + for left, right in ruleset:
318 + steps += 1
319 + matched = True
320 + variables.clear()
321 + for pattern in left:
322 + if match(pattern, knowledge, variables) is None:
323 + matched = False
324 + for pattern in left:
325 + reset(pattern, knowledge)
326 + break
327 + if matched:
328 + for pattern in left:
329 + consume(pattern, knowledge)
330 + for pattern in reversed(right):
331 + produce(pattern, knowledge, variables)
332 + break
333 + return (matched, steps, knowledge)
334 +
335 + def run(ruleset, primitives=[], knowledge=None, debug=0, trace=False):
336 + knowledge = prepare(ruleset, knowledge)
337 + ruleset = list(rules(ruleset))
338 + matched = True
339 + steps = 0
340 + snapshots = []
341 + while matched:
342 + matched, completed, knowledge = step(ruleset, primitives, knowledge, snapshots, debug, trace)
343 + steps += completed
344 + if trace:
345 + snapshots.append(copy.deepcopy(knowledge))
346 + if debug:
347 + print("Took", steps, "steps.")
348 + return (knowledge, snapshots)
349 +
350 + def usage(name):
351 + print(name, ":: a nova interpreter")
352 + print("usage:")
353 + print('\t' + name, "<file> [-d] [-r]")
354 + "
355 + ~code~
356 +
357 + ~name~
358 + "The Math Module"
359 + ~name~
360 + ~code~
361 + "
362 + def math(ruleset, knowledge, snapshots=[], trace=False):
363 + if (variables := match(("@math", ["$operation", "$x", "$y"]), knowledge)) is not None:
364 + operation = variables["operation"]
365 + x = int(variables["x"])
366 + y = int(variables["y"])
367 + if operation == "add":
368 + variables["z"] = str(x + y)
369 + elif operation == "subtract":
370 + variables["z"] = str(x - y)
371 + elif operation == "multiply":
372 + variables["z"] = str(x * y)
373 + elif operation == "divide":
374 + variables["z"] = str(x // y)
375 + elif operation == "modulo":
376 + variables["z"] = str(x % y)
377 + elif operation == "compare":
378 + if x < y:
379 + variables["z"] = "less"
380 + elif x == y:
381 + variables["z"] = "equal"
382 + else:
383 + variables["z"] = "greater"
384 + elif operation == "random":
385 + if y < x:
386 + x, y = y, x
387 + variables["z"] = str(random.randrange(x, y))
388 + consume("@math", knowledge)
389 + produce(("@math", ["$z"]), knowledge, variables)
390 + return True
391 + return False
392 + "
393 + ~code~
394 +
395 + ~name~
396 + "The Arrays Module"
397 + ~name~
398 + ~code~
399 + "
400 + def arrays():
401 + arrays = {}
402 + def create(ruleset, knowledge, snapshots=[], trace=False):
403 + nonlocal arrays
404 + if (variables := match(("@array", ["create", "$array", "$size"]), knowledge)) is not None:
405 + array = variables["array"]
406 + size = int(variables["size"])
407 + consume("@array", knowledge)
408 + if array in arrays:
409 + produce(("@array", ["$array", "exists"]), knowledge, variables)
410 + else:
411 + arrays[array] = [None] * size
412 + return True
413 + return False
414 + def set(ruleset, knowledge, snapshots=[], trace=False):
415 + nonlocal arrays
416 + if (variables := match(("@array", ["set", "$array", "$index", "$value"]), knowledge)) is not None:
417 + array = variables["array"]
418 + index = int(variables["index"])
419 + value = variables["value"]
420 + consume("@array", knowledge)
421 + if array not in arrays:
422 + produce(("@array", ["$array", "not", "found"]), knowledge, variables)
423 + elif index >= len(arrays[array]):
424 + produce(("@array", ["$index", "out", "of", "bounds", "for", "$array"]), knowledge, variables)
425 + else:
426 + arrays[array][index] = value
427 + return True
428 + return False
429 + def get(ruleset, knowledge, snapshots=[], trace=False):
430 + nonlocal arrays
431 + if (variables := match(("@array", ["get", "$array", "$index"]), knowledge)) is not None:
432 + array = variables["array"]
433 + index = int(variables["index"])
434 + consume("@array", knowledge)
435 + if array not in arrays:
436 + produce(("@array", ["$array", "not", "found"]), knowledge, variables)
437 + elif index >= len(arrays[array]):
438 + produce(("@array", ["$index", "out", "of", "bounds", "for", "$array"]), knowledge, variables)
439 + else:
440 + if arrays[array][index] == None:
441 + produce(("@array", ["$array", "$index"]), knowledge, variables)
442 + else:
443 + variables["value"] = str(arrays[array][index])
444 + produce(("@array", ["$array", "$index", "$value"]), knowledge, variables)
445 + return True
446 + return False
447 + return [
448 + create,
449 + set,
450 + get
451 + ]
452 + "
453 + ~code~
454 +
455 + ~name~
456 + "The Graphics Module"
457 + ~name~
458 + ~code~
459 + "
460 + def graphics():
461 + keys = {}
462 + mouse_buttons = {}
463 + screen = None
464 + pixels = None
465 + clock = None
466 + font = None
467 + resolution = (0, 0)
468 + def poll_input(ruleset, knowledge, snapshots=[]):
469 + nonlocal keys
470 + nonlocal mouse_buttons
471 + if match(("@input", ["poll-input"]), knowledge) is not None:
472 + consume("@input", knowledge)
473 + for event in pygame.event.get():
474 + if event.type == pygame.QUIT:
475 + produce(("@signal", ["quit"]), knowledge)
476 + keys = pygame.key.get_pressed()
477 + mouse_buttons = pygame.mouse.get_pressed()
478 + return True
479 + return False
480 + def check_key(ruleset, knowledge, snapshots=[]):
481 + nonlocal keys
482 + if (variables := match(("@input", ["check-key", "$key"]), knowledge)) is not None:
483 + consume("@input", knowledge)
484 + keycode = pygame.key.key_code(variables["key"])
485 + if keys[keycode]:
486 + produce(("@input", ["key-pressed", "$key"]), knowledge, variables)
487 + else:
488 + produce(("@input", ["key-released", "$key"]), knowledge, variables)
489 + return True
490 + return False
491 + def check_mouse_button(ruleset, knowledge, snapshots=[]):
492 + nonlocal mouse_buttons
493 + if (variables := match(("@input", ["check-mouse-button", "$button"]), knowledge)) is not None:
494 + consume("@input", knowledge)
495 + button = int(variables["button"])
496 + if mouse_buttons[button]:
497 + produce(("@input", ["mouse-button-pressed", "$button"]), knowledge, variables)
498 + else:
499 + produce(("@input", ["mouse-button-released", "$button"]), knowledge, variables)
500 + return True
501 + return False
502 + def get_mouse_position(ruleset, knowledge, snapshots=[]):
503 + if (variables := match(("@input", ["get-mouse-position"]), knowledge)) is not None:
504 + consume("@input", knowledge)
505 + position = pygame.mouse.get_pos()
506 + variables["x"], variables["y"] = (str(position[0]), str(position[1]))
507 + produce(("@input", ["mouse-position", "$x", "$y"]), knowledge, variables)
508 + return True
509 + return False
510 + def set_pixel(ruleset, knowledge, snapshots=[]):
511 + nonlocal pixels
512 + if (variables := match(("@graphics", ["set-pixel", "$x", "$y", "$r", "$g", "$b"]), knowledge)) is not None:
513 + x = int(variables["x"])
514 + y = int(variables["y"])
515 + r = int(variables["r"])
516 + g = int(variables["g"])
517 + b = int(variables["b"])
518 + pixels[x % resolution[0], y % resolution[1]] = (r % 256, g % 256, b % 256)
519 + consume("@graphics", knowledge)
520 + return True
521 + return False
522 + def draw_line(ruleset, knowledge, snapshots=[]):
523 + nonlocal screen
524 + if (variables := match(("@graphics", ["draw-line", "$x1", "$y1", "$x2", "$y2", "$r", "$g", "$b", "$w"]), knowledge)) is not None:
525 + x1 = int(variables["x1"])
526 + y1 = int(variables["y1"])
527 + x2 = int(variables["x2"])
528 + y2 = int(variables["y2"])
529 + r = int(variables["r"])
530 + g = int(variables["g"])
531 + b = int(variables["b"])
532 + w = int(variables["w"])
533 + pygame.draw.line(screen, (r % 256, g % 256, b % 256), (x1, y1), (x2, y2), w)
534 + consume("@graphics", knowledge)
535 + return True
536 + return False
537 + def draw_rect(ruleset, knowledge, snapshots=[]):
538 + nonlocal screen
539 + if (variables := match(("@graphics", ["draw-rect", "$x1", "$y1", "$x2", "$y2", "$r", "$g", "$b", "$w"]), knowledge)) is not None:
540 + x1 = int(variables["x1"])
541 + y1 = int(variables["y1"])
542 + x2 = int(variables["x2"])
543 + y2 = int(variables["y2"])
544 + r = int(variables["r"])
545 + g = int(variables["g"])
546 + b = int(variables["b"])
547 + w = int(variables["w"])
548 + pygame.draw.rect(screen, (r % 256, g % 256, b % 256), (x1, y1, x2, y2), w)
549 + consume("@graphics", knowledge)
550 + return True
551 + return False
552 + def draw_circle(ruleset, knowledge, snapshots=[]):
553 + nonlocal screen
554 + if (variables := match(("@graphics", ["draw-circle", "$x", "$y", "$d", "$r", "$g", "$b", "$w"]), knowledge)) is not None:
555 + x = int(variables["x"])
556 + y = int(variables["y"])
557 + d = int(variables["d"])
558 + r = int(variables["r"])
559 + g = int(variables["g"])
560 + b = int(variables["b"])
561 + w = int(variables["w"])
562 + pygame.draw.circle(screen, (r % 256, g % 256, b % 256), (x, y), d, w)
563 + consume("@graphics", knowledge)
564 + return True
565 + return False
566 + def clear_screen(ruleset, knowledge, snapshots=[]):
567 + nonlocal screen
568 + if (variables := match(("@graphics", ["clear-screen", "$r", "$g", "$b"]), knowledge)) is not None:
569 + r = int(variables["r"])
570 + g = int(variables["g"])
571 + b = int(variables["b"])
572 + screen.fill((r % 256, g % 256, b % 256))
573 + consume("@graphics", knowledge)
574 + return True
575 + return False
576 + def draw_fps(ruleset, knowledge, snapshots=[]):
577 + nonlocal pixels
578 + nonlocal screen
579 + nonlocal clock
580 + nonlocal font
581 + if match(("@graphics", ["draw-fps"]), knowledge) is not None:
582 + if clock is None:
583 + clock = pygame.time.Clock()
584 + clock.tick()
585 + if font is None:
586 + font = pygame.font.SysFont("m3x6", 16)
587 + framerate = clock.get_fps()
588 + if framerate <= 1_000_000:
589 + fps = font.render(str(int(clock.get_fps())) , 1, pygame.Color("RED"))
590 + pixels.close()
591 + screen.blit(fps, (0, 0))
592 + pixels = pygame.PixelArray(screen)
593 + consume("@graphics", knowledge)
594 + return True
595 + return False
596 + def display(ruleset, knowledge, snapshots=[]):
597 + nonlocal pixels
598 + if match(("@graphics", ["display"]), knowledge) is not None:
599 + pixels.close()
600 + pygame.display.flip()
601 + pixels = pygame.PixelArray(screen)
602 + consume("@graphics", knowledge)
603 + return True
604 + return False
605 + def draw_text(ruleset, knowledge, snapshots=[]):
606 + nonlocal font
607 + nonlocal screen
608 + nonlocal pixels
609 + if (variables := match(("@graphics", ["draw-text", "$x", "$y"]), knowledge)) is not None:
610 + x = int(variables["x"])
611 + y = int(variables["y"])
612 + if font is None:
613 + font = pygame.font.SysFont("m3x6", 16)
614 + text = ''.join(chr(int(n[0])) for n in reversed(knowledge["@text to draw"][0]))
615 + knowledge["@text to draw"] = [[], 0]
616 + drawn_text = font.render(text, False, pygame.Color("WHITE"))
617 + pixels.close()
618 + pygame.draw.rect(screen, (0, 0, 0), (0, 48, 64, 64))
619 + screen.blit(drawn_text, (x, y))
620 + pixels = pygame.PixelArray(screen)
621 + consume("@graphics", knowledge)
622 + return True
623 + return False
624 +
625 +
626 + def set_resolution(ruleset, knowledge, snapshots=[]):
627 + nonlocal screen
628 + nonlocal pixels
629 + nonlocal resolution
630 + if (variables := match(("@graphics", ["set-resolution", "$x", "$y"]), knowledge)) is not None:
631 + if screen is None:
632 + pygame.init()
633 + x = int(variables["x"])
634 + y = int(variables["y"])
635 + screen = pygame.display.set_mode((x, y))
636 + pygame.display.set_caption("Nova")
637 + icon = pygame.Surface((32, 32))
638 + icon.fill("black")
639 + icon.set_colorkey((0, 0, 0))
640 + pygame.display.set_icon(icon)
641 + pixels = pygame.PixelArray(screen)
642 + resolution = (x, y)
643 + consume("@graphics", knowledge)
644 + return True
645 + elif (variables := match(("@graphics", ["set-resolution", "fullscreen", "$x", "$y"]), knowledge)) is not None:
646 + if screen is None:
647 + pygame.init()
648 + x = int(variables["x"])
649 + y = int(variables["y"])
650 + screen = pygame.display.set_mode((x, y), flags=pygame.FULLSCREEN | pygame.SCALED)
651 + pygame.display.set_caption("Nova")
652 + icon = pygame.Surface((32, 32))
653 + icon.fill("black")
654 + icon.set_colorkey((0, 0, 0))
655 + pygame.display.set_icon(icon)
656 + pixels = pygame.PixelArray(screen)
657 + resolution = (x, y)
658 + consume("@graphics", knowledge)
659 + return True
660 + elif (variables := match(("@graphics", ["set-resolution", "fullscreen"]), knowledge)) is not None:
661 + if screen is None:
662 + pygame.init()
663 + screen = pygame.display.set_mode((0, 0), flags=pygame.FULLSCREEN)
664 + pygame.display.set_caption("Nova")
665 + icon = pygame.Surface((32, 32))
666 + icon.fill("black")
667 + icon.set_colorkey((0, 0, 0))
668 + pygame.display.set_icon(icon)
669 + pixels = pygame.PixelArray(screen)
670 + resolution = pygame.display.get_surface().get_size()
671 + consume("@graphics", knowledge)
672 + return True
673 + return False
674 + return [
675 + set_pixel,
676 + draw_line,
677 + draw_rect,
678 + draw_circle,
679 + draw_text,
680 + display,
681 + poll_input,
682 + draw_fps,
683 + clear_screen,
684 + check_key,
685 + check_mouse_button,
686 + get_mouse_position,
687 + set_resolution
688 + ]
689 + "
690 + ~code~
691 + ~name~
692 + "The Midi Module"
693 + ~name~
694 + ~code~
695 + "
696 + def midi():
697 + output = None
698 + def set_output(ruleset, knowledge, snapshots=[]):
699 + nonlocal output
700 + if (variables := match(("@midi", ["set-output", "$x"]), knowledge)) is not None:
701 + if output is None:
702 + pygame.midi.init()
703 + else:
704 + del output
705 + output = pygame.midi.Output(int(variables["x"]))
706 + consume("@midi", knowledge)
707 + return True
708 + return False
709 + def abort(ruleset, knowledge, snapshots=[]):
710 + nonlocal output
711 + if (variables := match(("@midi", ["abort"]), knowledge)) is not None:
712 + output.abort()
713 + consume("@midi", knowledge)
714 + return True
715 + return False
716 + def set_instrument(ruleset, knowledge, snapshots=[]):
717 + nonlocal output
718 + if (variables := match(("@midi", ["set-instrument", "$x"]), knowledge)) is not None:
719 + output.set_instrument(int(variables["x"]))
720 + consume("@midi", knowledge)
721 + return True
722 + return False
723 + def note(ruleset, knowledge, snapshots=[]):
724 + nonlocal output
725 + if (variables := match(("@midi", ["note", "$x", "$y", "$z", "$w"]), knowledge)) is not None:
726 + state = variables["x"]
727 + note = int(variables["y"])
728 + velocity = int(variables["z"])
729 + channel = int(variables["w"])
730 + if state == "on":
731 + output.note_on(note, velocity, channel)
732 + elif state == "off":
733 + output.note_off(note, velocity, channel)
734 + else:
735 + return False
736 + consume("@midi", knowledge)
737 + return True
738 + elif (variables := match(("@midi", ["note", "$x", "$y", "$z"]), knowledge)) is not None:
739 + state = variables["x"]
740 + note = int(variables["y"])
741 + velocity = int(variables["z"])
742 + if state == "on":
743 + output.note_on(note, velocity)
744 + elif state == "off":
745 + output.note_off(note, velocity)
746 + else:
747 + return False
748 + consume("@midi", knowledge)
749 + return True
750 + return False
751 + return [
752 + set_output,
753 + abort,
754 + set_instrument,
755 + note
756 + ]
757 + "
758 + ~code~
759 +
760 + ~name~
761 + "The Time Module"
762 + ~name~
763 + ~code~
764 + "
765 + def _time():
766 + def sleep(ruleset, knowledge, snapshots=[]):
767 + if (variables := match(("@time", ["sleep", "$x", "$y"]), knowledge)) is not None:
768 + duration = int(variables["x"])
769 + unit = variables["y"]
770 + if unit == "seconds":
771 + time.sleep(duration)
772 + elif unit == "milliseconds":
773 + time.sleep(0.001 * duration)
774 + else:
775 + return False
776 + consume("@time", knowledge)
777 + return True
778 + return False
779 + return [
780 + sleep
781 + ]
782 + "
783 + ~code~
784 +
785 + ~name~
786 + "The Stdio Module"
787 + ~name~
788 + ~code~
789 + "
790 + def stdio():
791 + def read(ruleset, knowledge, snapshots=[]):
792 + if (variables := match(("@stdio", ["read", "$x"]), knowledge)) is not None:
793 + try:
794 + amount = int(variables["x"])
795 + bytes = sys.stdin.read(amount)
796 + consume("@stdio", knowledge)
797 + for byte in reversed(bytes.encode()):
798 + variables["x"] = str(byte)
799 + produce(("@stdio", ["$x"]), knowledge, variables)
800 + return True
801 + except KeyboardInterrupt:
802 + consume("@stdio", knowledge)
803 + return True
804 + except:
805 + pass
806 + elif (variables := match(("@stdio", ["read"]), knowledge)) is not None:
807 + try:
808 + variables["x"] = str(ord(sys.stdin.read(1)))
809 + consume("@stdio", knowledge)
810 + produce(("@stdio", ["$x"]), knowledge, variables)
811 + return True
812 + except KeyboardInterrupt:
813 + consume("@stdio", knowledge)
814 + return True
815 + except:
816 + pass
817 + return False
818 + def write(ruleset, knowledge, snapshots=[]):
819 + if (variables := match(("@stdio", ["write", "$x", "$y"]), knowledge)) is not None:
820 + try:
821 + byte = int(variables["x"])
822 + length = int(variables["y"])
823 + if byte < 0:
824 + sys.stdout.buffer.write(byte.to_bytes(length, signed=True))
825 + else:
826 + sys.stdout.buffer.write(byte.to_bytes(length))
827 + sys.stdout.buffer.flush()
828 + consume("@stdio", knowledge)
829 + variables["x"] = str(length)
830 + produce(("@stdio", ["wrote", "$x"]), knowledge, variables)
831 + return True
832 + except OverflowError:
833 + length = (byte.bit_length() + 7) // 8
834 + if length == 0:
835 + length = 1
836 + if byte < 0:
837 + sys.stdout.buffer.write(byte.to_bytes(length, signed=True))
838 + else:
839 + sys.stdout.buffer.write(byte.to_bytes(length))
840 + sys.stdout.buffer.flush()
841 + consume("@stdio", knowledge)
842 + variables["x"] = str(length)
843 + produce(("@stdio", ["wrote", "$x"]), knowledge, variables)
844 + return True
845 + except:
846 + pass
847 + elif (variables := match(("@stdio", ["write", "$x"]), knowledge)) is not None:
848 + try:
849 + byte = int(variables["x"])
850 + length = (byte.bit_length() + 7) // 8
851 + if length == 0:
852 + length = 1
853 + if byte < 0:
854 + sys.stdout.buffer.write(byte.to_bytes(length, signed=True))
855 + else:
856 + sys.stdout.buffer.write(byte.to_bytes(length))
857 + sys.stdout.buffer.flush()
858 + consume("@stdio", knowledge)
859 + variables["x"] = str(length)
860 + produce(("@stdio", ["wrote", "$x"]), knowledge, variables)
861 + return True
862 + except:
863 + pass
864 + return False
865 + return [
866 + read, write
867 + ]
868 + "
869 + ~code~
870 +
871 + ~name~
872 + "The NFC Module"
873 + ~name~
874 + ~code~
875 + "
876 + def _nfc():
877 + clf = None
878 + last_card = None
879 + def nfc_read_card():
880 + nonlocal clf
881 + payload = []
882 + identifier = None
883 + card_types = [RemoteTarget('106A'), RemoteTarget('106B'), RemoteTarget('212F')]
884 + target = clf.sense(*card_types)
885 + if target is not None:
886 + tag = nfc.tag.activate(clf, target)
887 + if tag is not None and tag.ndef is not None:
888 + for record in tag.ndef.records:
889 + text = zlib.decompress(base64.b64decode(record.text)).decode()
890 + payload += list(parse(text))
891 + identifier = tag.identifier
892 + return (payload, identifier)
893 + def open(ruleset, knowledge, snapshots=[]):
894 + nonlocal clf
895 + if (variables := match(("@nfc", ["open"]), knowledge)) is not None:
896 + try:
897 + consume("@nfc", knowledge)
898 + clf = nfc.ContactlessFrontend('usb')
899 + return True
900 + except:
901 + produce(("@nfc", ["no-device"]), knowledge)
902 + return True
903 + return False
904 + def close(ruleset, knowledge, snapshots=[]):
905 + nonlocal clf
906 + if (variables := match(("@nfc", ["close"]), knowledge)) is not None:
907 + try:
908 + consume("@nfc", knowledge)
909 + clf.close()
910 + return True
911 + except:
912 + produce(("@nfc", ["no-device"]), knowledge)
913 + return True
914 + return False
915 + def read_card(ruleset, knowledge, snapshots=[]):
916 + nonlocal last_card
917 + if (variables := match(("@nfc", ["read-card"]), knowledge)) is not None:
918 + try:
919 + consume("@nfc", knowledge)
920 + (payload, identifier) = nfc_read_card()
921 + variables["x"] = "".join([hex(byte)[2:] for byte in identifier])
922 + last_card = payload
923 + produce(("@nfc", ["card", "$x"]), knowledge, variables)
924 + return True
925 + except:
926 + produce(("@nfc", ["read-failed"]), knowledge)
927 + return True
928 + return False
929 + def load_card_rules(ruleset, knowledge, snapshots=[]):
930 + nonlocal last_card
931 + if (variables := match(("@nfc", ["load-rules"]), knowledge)) is not None:
932 + try:
933 + for rule in rules(reversed(last_card)):
934 + ruleset.insert(0, rule)
935 + consume("@nfc", knowledge)
936 + return True
937 + except:
938 + pass
939 + return False
940 + def load_card_facts(ruleset, knowledge, snapshots=[]):
941 + if (variables := match(("@nfc", ["load-facts"]), knowledge)) is not None:
942 + try:
943 + prepare(last_card, knowledge)
944 + consume("@nfc", knowledge)
945 + return True
946 + except:
947 + pass
948 + return False
949 + return [
950 + open,
951 + close,
952 + read_card,
953 + load_card_rules,
954 + load_card_facts
955 + ]
956 + "
957 + ~code~
958 +
959 + ~name~
960 + "Let's include a REPL"
961 + ~name~
962 + ~code~
963 + "
964 + def repl(rulesets, primitives, debug):
965 + try:
966 + knowledge, _ = run(rulesets)
967 + print_knowledge(knowledge, debug)
968 + current_stack = ""
969 + command = input("::> ")
970 + while command != "@quit":
971 + if command in {"@run", '!'}:
972 + knowledge, _ = run(rulesets, primitives, knowledge)
973 + if debug:
974 + print_knowledge(knowledge, debug)
975 + if match(("@signal", ["quit"]), knowledge) != None:
976 + break
977 + elif command.startswith('@'):
978 + current_stack = command[1:]
979 + elif command.startswith('.'):
980 + command = command[1:]
981 + knowledge, _ = run(list(parse(command)) + list(rules(rulesets)), primitives, knowledge, debug)
982 + if debug:
983 + print_knowledge(knowledge, debug)
984 + if match(("@signal", ["quit"]), knowledge) != None:
985 + break
986 + elif command.startswith(':'):
987 + command = command[1:]
988 + rulesets = list(parse(command)) + rulesets
989 + knowledge, _ = run(rulesets, primitives, knowledge, debug)
990 + if debug:
991 + print_knowledge(knowledge, debug)
992 + if match(("@signal", ["quit"]), knowledge) != None:
993 + break
994 + elif len(command) != 0:
995 + command = "||:" + current_stack + ':' + command
996 + knowledge, _ = run(list(parse(command)) + list(rules(rulesets)), primitives, knowledge, debug)
997 + if debug:
998 + print_knowledge(knowledge, debug)
999 + if match(("@signal", ["quit"]), knowledge) != None:
1000 + break
1001 + else:
1002 + if debug:
1003 + print_knowledge(knowledge, debug)
1004 + command = input(":" + current_stack + ":> ")
1005 + except EOFError:
1006 + pass
1007 + except KeyboardInterrupt:
1008 + pass
1009 + "
1010 + ~code~
1011 +
1012 + ~name~
1013 + "Import Python core libraries"
1014 + ~name~
1015 + ~code~
1016 + "import sys, time, random, copy"
1017 + ~code~
1018 +
1019 + ~name~
1020 + "Set up PyGame"
1021 + ~name~
1022 + ~code~
1023 + "
1024 + try:
1025 + import warnings
1026 + warnings.filterwarnings("ignore")
1027 + from os import environ
1028 + environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1'
1029 + import pygame
1030 + import pygame.midi
1031 + pygame_supported = True
1032 + except:
1033 + pygame_supported = False
1034 + pass
1035 + "
1036 + ~code~
1037 +
1038 + ~name~
1039 + "Set up NFC"
1040 + ~name~
1041 + ~code~
1042 + "
1043 + try:
1044 + import nfc, ndef, zlib, base64
1045 + from nfc.clf import RemoteTarget
1046 + nfc_supported = True
1047 + except:
1048 + nfc_supported = False
1049 + pass
1050 + "
1051 + ~code~
1052 +
1053 +
1054 + ~name~
1055 + "Finally, the main program"
1056 + ~name~
1057 + ~code~
1058 + "
1059 + def main(name, arguments):
1060 + primitives = _time() + [math] + arrays() + stdio()
1061 + if pygame_supported:
1062 + primitives += graphics() + midi()
1063 + if nfc_supported:
1064 + primitives += _nfc()
1065 + rulesets = []
1066 + debug = 0
1067 + prompt = False
1068 + trace = False
1069 + if not arguments:
1070 + usage(name)
1071 + return
1072 + for argument in arguments:
1073 + if argument == '-d':
1074 + debug += 1
1075 + elif argument == '-r':
1076 + prompt = True
1077 + elif argument == '-t':
1078 + trace = True
1079 + else:
1080 + with open(argument) as file:
1081 + rulesets += list(parse(file.read()))
1082 + if prompt:
1083 + repl(rulesets, primitives, debug)
1084 + else:
1085 + if len(rulesets) == 0:
1086 + usage(name)
1087 + return
1088 + if debug:
1089 + knowledge, snapshots = run(rulesets, primitives, None, debug, trace)
1090 + if trace:
1091 + for index in range(len(snapshots)):
1092 + print("Snapshot", str(index) + ':')
1093 + print("----------------")
1094 + print_knowledge(snapshots[index], debug)
1095 + print("")
1096 + else:
1097 + print_knowledge(knowledge, debug)
1098 + else:
1099 + run(rulesets, primitives, None, debug, trace)
1100 +
1101 + if __name__ == "__main__":
1102 + main(sys.argv[0], sys.argv[1:])
1103 + "
1104 + ~code~
Nowsze Starsze