#!/usr/bin/env python3 import sys, time, random, copy try: import warnings warnings.filterwarnings("ignore") from os import environ environ['PYGAME_HIDE_SUPPORT_PROMPT'] = '1' import pygame import pygame.midi pygame_supported = True except: pygame_supported = False pass try: import nfc, ndef, zlib, base64 from nfc.clf import RemoteTarget nfc_supported = True except: nfc_supported = False pass def parse_container(string): left = [] right = [] target = left characters = (character for character in list(string) + [None]) delimiter = None for character in characters: if character in {' ', '\n', '\r', '\t'}: continue delimiter = character break if delimiter is None: return None for character in characters: if character in {delimiter, None}: if target is left: target = right else: target = left yield (left.copy(), right.copy()) left.clear() right.clear() else: target.append(character) def parse_labels(rules): left = [] right = [] pair = ([], []) target = left delimiter = None for condition, result in rules: for side in (condition, result): characters = (character for character in side + [None]) state = "find delimiter" for character in characters: if character == None: label = "".join(pair[0]).strip() pattern = "".join(pair[1]).strip() if not(len(label) == 0 and len(pattern) == 0): target.append((label, pattern)) pair[0].clear() pair[1].clear() break elif state == "find delimiter": if character in {' ', '\n', '\r', '\t'}: continue delimiter = character state = "parse label" elif state == "parse label": if character == delimiter: state = "parse pattern" continue pair[0].append(character) elif state == "parse pattern": if character in {delimiter, None}: state = "parse label" label = "".join(pair[0]).strip() pattern = "".join(pair[1]).strip() if not(len(label) == 0 and len(pattern) == 0): target.append((label, pattern)) pair[0].clear() pair[1].clear() continue pair[1].append(character) if target is left: target = right else: target = left yield (left.copy(), right.copy()) left.clear() right.clear() def parse_patterns(rules): for condition, result in rules: left = [] right = [] preserves = [] for label, pattern in condition: preserve = False if pattern.endswith('?'): pattern = pattern[:-1] preserve = True if (pattern.startswith('"') or pattern.startswith("'")) and (pattern.endswith('"') or pattern.endswith("'")): for character in pattern[1:-1]: left.append((label, [str(ord(character))])) if preserve: right.append((label, [str(ord(character))])) elif pattern.startswith('(') and pattern.endswith(')'): for token in pattern[1:-1].split(): left.append((label, [token])) if preserve: right.append((label, [token])) elif pattern.startswith('.'): for tuple in pattern.split('.'): tuple = tuple.strip() if len(tuple) != 0: left.append((label, tuple.split())) if preserve: right.append((label, tuple.split())) else: left.append((label, pattern.split())) if preserve: preserves.append((label, pattern.split())) for label, pattern in result: if (pattern.startswith('"') or pattern.startswith("'")) and (pattern.endswith('"') or pattern.endswith("'")): for character in pattern[1:-1]: right.append((label, [str(ord(character))])) elif pattern.startswith('(') and pattern.endswith(')'): for token in pattern[1:-1].split(): right.append((label, [token])) elif pattern.startswith('.'): for tuple in pattern.split('.'): tuple = tuple.strip() if len(tuple) != 0: right.append((label, tuple.split())) else: right.append((label, pattern.split())) yield (left.copy(), right.copy() + preserves.copy()) left.clear() right.clear() preserves.clear() def parse(string): return parse_patterns(parse_labels(parse_container(string))) def facts(ruleset): for left, right in ruleset: if not left: for element in right: yield element def rules(ruleset): for left, right in ruleset: if left: yield (left, right) def match(pattern, knowledge, variables=None): if variables is None: variables = {} label, elements = pattern if label not in knowledge or not knowledge[label][0]: return None if knowledge[label][1] >= len(knowledge[label][0]): knowledge[label][1] = 0 return None top = knowledge[label][0][(-1 - knowledge[label][1])] len_top = len(top) if len_top != len(elements): knowledge[label][1] = 0 return None for index in range(len_top): left = elements[index] right = top[index] if left[0] == '$': variable = left[1:] if variable not in variables: variables[variable] = right elif variables[variable] != right: knowledge[label][1] = 0 return None elif left != right: knowledge[label][1] = 0 return None knowledge[label][1] += 1 return variables def consume(pattern, knowledge): if type(pattern) == str: knowledge[pattern][0].pop() knowledge[pattern][1] = 0 else: label, _ = pattern knowledge[label][0].pop() knowledge[label][1] = 0 def produce(pattern, knowledge, variables=None): if variables is None: variables = {} label, elements = pattern len_elements = len(elements) fact = [None] * len_elements for index in range(len_elements): element = elements[index] if element[0] == '$': variable = element[1:] if variable in variables: element = variables[variable] fact[index] = element if label not in knowledge: knowledge[label] = [[], 0] knowledge[label][0].append(fact) knowledge[label][1] = 0 def reset(pattern, knowledge): label, _ = pattern if label in knowledge: knowledge[label][1] = 0 def prepare(ruleset, knowledge=None): if knowledge == None: knowledge = {} for fact in reversed(list(facts(ruleset))): label, elements = fact if label not in knowledge: knowledge[label] = [[], 0] knowledge[label][0].append(elements) return knowledge def print_knowledge(knowledge, debug=0, maximum=10): for label, facts in knowledge.items(): facts = facts[0] if not facts: continue if not label: label = ":" print(label + ': ', end="") if len(facts) >= maximum and debug % 2: print("...", len(facts), "...") continue if facts: if len(facts[-1]) == 0: print("") else: print(" ".join(facts[-1])) for fact in reversed(facts[:-1]): if len(fact) == 0: fact = [""] print(' ' * (len(label) + 1), " ".join(fact)) def step(ruleset, primitives=[], knowledge=None, snapshots=[], debug=0, trace=False): variables = {} steps = 0 if debug >= 3: print_knowledge(knowledge, debug) print("") matched = False for primitive in primitives: steps += 1 if primitive(ruleset, knowledge, snapshots): matched = True break if matched: return (True, steps, knowledge) for left, right in ruleset: steps += 1 matched = True variables.clear() for pattern in left: if match(pattern, knowledge, variables) is None: matched = False for pattern in left: reset(pattern, knowledge) break if matched: for pattern in left: consume(pattern, knowledge) for pattern in reversed(right): produce(pattern, knowledge, variables) break return (matched, steps, knowledge) def run(ruleset, primitives=[], knowledge=None, debug=0, trace=False): knowledge = prepare(ruleset, knowledge) ruleset = list(rules(ruleset)) matched = True steps = 0 snapshots = [] while matched: matched, completed, knowledge = step(ruleset, primitives, knowledge, snapshots, debug, trace) steps += completed if trace: snapshots.append(copy.deepcopy(knowledge)) if debug: print("Took", steps, "steps.") return (knowledge, snapshots) def usage(name): print(name, ":: a nova interpreter") print("usage:") print('\t' + name, " [-d] [-r]") def math(ruleset, knowledge, snapshots=[], trace=False): if (variables := match(("@math", ["$operation", "$x", "$y"]), knowledge)) is not None: try: operation = variables["operation"] x = int(variables["x"]) y = int(variables["y"]) if operation == "add": variables["z"] = str(x + y) elif operation == "subtract": variables["z"] = str(x - y) elif operation == "multiply": variables["z"] = str(x * y) elif operation == "divide": variables["z"] = str(x // y) elif operation == "modulo": variables["z"] = str(x % y) elif operation == "compare": if x < y: variables["z"] = "less" elif x == y: variables["z"] = "equal" else: variables["z"] = "greater" elif operation == "random": if y < x: x, y = y, x variables["z"] = str(random.randrange(x, y)) consume("@math", knowledge) produce(("@math", ["$z"]), knowledge, variables) return True except Exception as e: print(e) pass return False def arrays(): arrays = {} def create(ruleset, knowledge, snapshots=[], trace=False): nonlocal arrays if (variables := match(("@array", ["create", "$array", "$size"]), knowledge)) is not None: try: array = variables["array"] size = int(variables["size"]) consume("@array", knowledge) if array in arrays: produce(("@array", ["$array", "exists"]), knowledge, variables) else: arrays[array] = [None] * size return True except: pass return False def set(ruleset, knowledge, snapshots=[], trace=False): nonlocal arrays if (variables := match(("@array", ["set", "$array", "$index", "$value"]), knowledge)) is not None: try: array = variables["array"] index = int(variables["index"]) value = variables["value"] consume("@array", knowledge) if array not in arrays: produce(("@array", ["$array", "not", "found"]), knowledge, variables) elif index >= len(arrays[array]): produce(("@array", ["$index", "out", "of", "bounds", "for", "$array"]), knowledge, variables) else: arrays[array][index] = value return True except: pass return False def get(ruleset, knowledge, snapshots=[], trace=False): nonlocal arrays if (variables := match(("@array", ["get", "$array", "$index"]), knowledge)) is not None: try: array = variables["array"] index = int(variables["index"]) consume("@array", knowledge) if array not in arrays: produce(("@array", ["$array", "not", "found"]), knowledge, variables) elif index >= len(arrays[array]): produce(("@array", ["$index", "out", "of", "bounds", "for", "$array"]), knowledge, variables) else: if arrays[array][index] == None: produce(("@array", ["$array", "$index"]), knowledge, variables) else: variables["value"] = str(arrays[array][index]) produce(("@array", ["$array", "$index", "$value"]), knowledge, variables) return True except: pass return False return [ create, set, get ] def graphics(): keys = {} mouse_buttons = {} screen = None pixels = None clock = None font = None resolution = (0, 0) def poll_input(ruleset, knowledge, snapshots=[]): nonlocal keys nonlocal mouse_buttons if match(("@input", ["poll-input"]), knowledge) is not None: consume("@input", knowledge) for event in pygame.event.get(): if event.type == pygame.QUIT: produce(("@signal", ["quit"]), knowledge) keys = pygame.key.get_pressed() mouse_buttons = pygame.mouse.get_pressed() return True return False def check_key(ruleset, knowledge, snapshots=[]): nonlocal keys if (variables := match(("@input", ["check-key", "$key"]), knowledge)) is not None: consume("@input", knowledge) keycode = pygame.key.key_code(variables["key"]) if keys[keycode]: produce(("@input", ["key-pressed", "$key"]), knowledge, variables) else: produce(("@input", ["key-released", "$key"]), knowledge, variables) return True return False def check_mouse_button(ruleset, knowledge, snapshots=[]): nonlocal mouse_buttons if (variables := match(("@input", ["check-mouse-button", "$button"]), knowledge)) is not None: consume("@input", knowledge) button = int(variables["button"]) if mouse_buttons[button]: produce(("@input", ["mouse-button-pressed", "$button"]), knowledge, variables) else: produce(("@input", ["mouse-button-released", "$button"]), knowledge, variables) return True return False def get_mouse_position(ruleset, knowledge, snapshots=[]): if (variables := match(("@input", ["get-mouse-position"]), knowledge)) is not None: consume("@input", knowledge) position = pygame.mouse.get_pos() variables["x"], variables["y"] = (str(position[0]), str(position[1])) produce(("@input", ["mouse-position", "$x", "$y"]), knowledge, variables) return True return False def set_pixel(ruleset, knowledge, snapshots=[]): nonlocal pixels if (variables := match(("@graphics", ["set-pixel", "$x", "$y", "$r", "$g", "$b"]), knowledge)) is not None: try: x = int(variables["x"]) y = int(variables["y"]) r = int(variables["r"]) g = int(variables["g"]) b = int(variables["b"]) pixels[x % resolution[0], y % resolution[1]] = (r % 256, g % 256, b % 256) consume("@graphics", knowledge) return True except: pass return False def draw_line(ruleset, knowledge, snapshots=[]): nonlocal screen if (variables := match(("@graphics", ["draw-line", "$x1", "$y1", "$x2", "$y2", "$r", "$g", "$b", "$w"]), knowledge)) is not None: try: x1 = int(variables["x1"]) y1 = int(variables["y1"]) x2 = int(variables["x2"]) y2 = int(variables["y2"]) r = int(variables["r"]) g = int(variables["g"]) b = int(variables["b"]) w = int(variables["w"]) pygame.draw.line(screen, (r % 256, g % 256, b % 256), (x1, y1), (x2, y2), w) consume("@graphics", knowledge) return True except: pass return False def draw_rect(ruleset, knowledge, snapshots=[]): nonlocal screen if (variables := match(("@graphics", ["draw-rect", "$x1", "$y1", "$x2", "$y2", "$r", "$g", "$b", "$w"]), knowledge)) is not None: try: x1 = int(variables["x1"]) y1 = int(variables["y1"]) x2 = int(variables["x2"]) y2 = int(variables["y2"]) r = int(variables["r"]) g = int(variables["g"]) b = int(variables["b"]) w = int(variables["w"]) pygame.draw.rect(screen, (r % 256, g % 256, b % 256), (x1, y1, x2, y2), w) consume("@graphics", knowledge) return True except: pass return False def draw_circle(ruleset, knowledge, snapshots=[]): nonlocal screen if (variables := match(("@graphics", ["draw-circle", "$x", "$y", "$d", "$r", "$g", "$b", "$w"]), knowledge)) is not None: try: x = int(variables["x"]) y = int(variables["y"]) d = int(variables["d"]) r = int(variables["r"]) g = int(variables["g"]) b = int(variables["b"]) w = int(variables["w"]) pygame.draw.circle(screen, (r % 256, g % 256, b % 256), (x, y), d, w) consume("@graphics", knowledge) return True except: pass return False def clear_screen(ruleset, knowledge, snapshots=[]): nonlocal screen if (variables := match(("@graphics", ["clear-screen", "$r", "$g", "$b"]), knowledge)) is not None: try: r = int(variables["r"]) g = int(variables["g"]) b = int(variables["b"]) screen.fill((r % 256, g % 256, b % 256)) consume("@graphics", knowledge) return True except: pass return False def draw_fps(ruleset, knowledge, snapshots=[]): nonlocal pixels nonlocal screen nonlocal clock nonlocal font if match(("@graphics", ["draw-fps"]), knowledge) is not None: if clock is None: clock = pygame.time.Clock() clock.tick() if font is None: font = pygame.font.SysFont("m3x6", 16) framerate = clock.get_fps() if framerate <= 1_000_000: fps = font.render(str(int(clock.get_fps())) , 1, pygame.Color("RED")) pixels.close() screen.blit(fps, (0, 0)) pixels = pygame.PixelArray(screen) consume("@graphics", knowledge) return True return False def display(ruleset, knowledge, snapshots=[]): nonlocal pixels if match(("@graphics", ["display"]), knowledge) is not None: pixels.close() pygame.display.flip() pixels = pygame.PixelArray(screen) consume("@graphics", knowledge) return True return False def draw_text(ruleset, knowledge, snapshots=[]): nonlocal font nonlocal screen nonlocal pixels if (variables := match(("@graphics", ["draw-text", "$x", "$y"]), knowledge)) is not None: x = int(variables["x"]) y = int(variables["y"]) if font is None: font = pygame.font.SysFont("m3x6", 16) text = ''.join(chr(int(n[0])) for n in reversed(knowledge["@text to draw"][0])) knowledge["@text to draw"] = [[], 0] drawn_text = font.render(text, False, pygame.Color("WHITE")) pixels.close() pygame.draw.rect(screen, (0, 0, 0), (0, 48, 64, 64)) screen.blit(drawn_text, (x, y)) pixels = pygame.PixelArray(screen) consume("@graphics", knowledge) return True return False def set_resolution(ruleset, knowledge, snapshots=[]): nonlocal screen nonlocal pixels nonlocal resolution if (variables := match(("@graphics", ["set-resolution", "$x", "$y"]), knowledge)) is not None: try: if screen is None: pygame.init() x = int(variables["x"]) y = int(variables["y"]) screen = pygame.display.set_mode((x, y)) pygame.display.set_caption("Nova") icon = pygame.Surface((32, 32)) icon.fill("black") icon.set_colorkey((0, 0, 0)) pygame.display.set_icon(icon) pixels = pygame.PixelArray(screen) resolution = (x, y) consume("@graphics", knowledge) return True except: pass elif (variables := match(("@graphics", ["set-resolution", "fullscreen", "$x", "$y"]), knowledge)) is not None: try: if screen is None: pygame.init() x = int(variables["x"]) y = int(variables["y"]) screen = pygame.display.set_mode((x, y), flags=pygame.FULLSCREEN | pygame.SCALED) pygame.display.set_caption("Nova") icon = pygame.Surface((32, 32)) icon.fill("black") icon.set_colorkey((0, 0, 0)) pygame.display.set_icon(icon) pixels = pygame.PixelArray(screen) resolution = (x, y) consume("@graphics", knowledge) return True except: pass elif (variables := match(("@graphics", ["set-resolution", "fullscreen"]), knowledge)) is not None: try: if screen is None: pygame.init() screen = pygame.display.set_mode((0, 0), flags=pygame.FULLSCREEN) pygame.display.set_caption("Nova") icon = pygame.Surface((32, 32)) icon.fill("black") icon.set_colorkey((0, 0, 0)) pygame.display.set_icon(icon) pixels = pygame.PixelArray(screen) resolution = pygame.display.get_surface().get_size() consume("@graphics", knowledge) return True except: pass return False return [ set_pixel, draw_line, draw_rect, draw_circle, draw_text, display, poll_input, draw_fps, clear_screen, check_key, check_mouse_button, get_mouse_position, set_resolution ] def midi(): output = None def set_output(ruleset, knowledge, snapshots=[]): nonlocal output if (variables := match(("@midi", ["set-output", "$x"]), knowledge)) is not None: try: if output is None: pygame.midi.init() else: del output output = pygame.midi.Output(int(variables["x"])) consume("@midi", knowledge) return True except: pass return False def abort(ruleset, knowledge, snapshots=[]): nonlocal output if (variables := match(("@midi", ["abort"]), knowledge)) is not None: try: output.abort() consume("@midi", knowledge) return True except: pass return False def set_instrument(ruleset, knowledge, snapshots=[]): nonlocal output if (variables := match(("@midi", ["set-instrument", "$x"]), knowledge)) is not None: try: output.set_instrument(int(variables["x"])) consume("@midi", knowledge) return True except: pass return False def note(ruleset, knowledge, snapshots=[]): nonlocal output if (variables := match(("@midi", ["note", "$x", "$y", "$z", "$w"]), knowledge)) is not None: try: state = variables["x"] note = int(variables["y"]) velocity = int(variables["z"]) channel = int(variables["w"]) if state == "on": output.note_on(note, velocity, channel) elif state == "off": output.note_off(note, velocity, channel) else: return False consume("@midi", knowledge) return True except: pass elif (variables := match(("@midi", ["note", "$x", "$y", "$z"]), knowledge)) is not None: try: state = variables["x"] note = int(variables["y"]) velocity = int(variables["z"]) if state == "on": output.note_on(note, velocity) elif state == "off": output.note_off(note, velocity) else: return False consume("@midi", knowledge) return True except: pass return False return [ set_output, abort, set_instrument, note ] def _time(): def sleep(ruleset, knowledge, snapshots=[]): if (variables := match(("@time", ["sleep", "$x", "$y"]), knowledge)) is not None: try: duration = int(variables["x"]) unit = variables["y"] if unit == "seconds": time.sleep(duration) elif unit == "milliseconds": time.sleep(0.001 * duration) else: return False consume("@time", knowledge) return True except: pass return False return [ sleep ] def stdio(): def read(ruleset, knowledge, snapshots=[]): if (variables := match(("@stdio", ["read", "$x"]), knowledge)) is not None: try: amount = int(variables["x"]) bytes = sys.stdin.read(amount) consume("@stdio", knowledge) for byte in reversed(bytes.encode()): variables["x"] = str(byte) produce(("@stdio", ["$x"]), knowledge, variables) return True except KeyboardInterrupt: consume("@stdio", knowledge) return True except: pass elif (variables := match(("@stdio", ["read"]), knowledge)) is not None: try: variables["x"] = str(ord(sys.stdin.read(1))) consume("@stdio", knowledge) produce(("@stdio", ["$x"]), knowledge, variables) return True except KeyboardInterrupt: consume("@stdio", knowledge) return True except: pass return False def write(ruleset, knowledge, snapshots=[]): if (variables := match(("@stdio", ["write", "$x", "$y"]), knowledge)) is not None: try: byte = int(variables["x"]) length = int(variables["y"]) if byte < 0: sys.stdout.buffer.write(byte.to_bytes(length, signed=True)) else: sys.stdout.buffer.write(byte.to_bytes(length)) sys.stdout.buffer.flush() consume("@stdio", knowledge) variables["x"] = str(length) produce(("@stdio", ["wrote", "$x"]), knowledge, variables) return True except OverflowError: length = (byte.bit_length() + 7) // 8 if length == 0: length = 1 if byte < 0: sys.stdout.buffer.write(byte.to_bytes(length, signed=True)) else: sys.stdout.buffer.write(byte.to_bytes(length)) sys.stdout.buffer.flush() consume("@stdio", knowledge) variables["x"] = str(length) produce(("@stdio", ["wrote", "$x"]), knowledge, variables) return True except: pass elif (variables := match(("@stdio", ["write", "$x"]), knowledge)) is not None: try: byte = int(variables["x"]) length = (byte.bit_length() + 7) // 8 if length == 0: length = 1 if byte < 0: sys.stdout.buffer.write(byte.to_bytes(length, signed=True)) else: sys.stdout.buffer.write(byte.to_bytes(length)) sys.stdout.buffer.flush() consume("@stdio", knowledge) variables["x"] = str(length) produce(("@stdio", ["wrote", "$x"]), knowledge, variables) return True except: pass return False return [ read, write ] def _nfc(): clf = None last_card = None def nfc_read_card(): nonlocal clf payload = [] identifier = None card_types = [RemoteTarget('106A'), RemoteTarget('106B'), RemoteTarget('212F')] target = clf.sense(*card_types) if target is not None: tag = nfc.tag.activate(clf, target) if tag is not None and tag.ndef is not None: for record in tag.ndef.records: text = zlib.decompress(base64.b64decode(record.text)).decode() payload += list(parse(text)) identifier = tag.identifier return (payload, identifier) def open(ruleset, knowledge, snapshots=[]): nonlocal clf if (variables := match(("@nfc", ["open"]), knowledge)) is not None: try: consume("@nfc", knowledge) clf = nfc.ContactlessFrontend('usb') return True except: produce(("@nfc", ["no-device"]), knowledge) return True return False def close(ruleset, knowledge, snapshots=[]): nonlocal clf if (variables := match(("@nfc", ["close"]), knowledge)) is not None: try: consume("@nfc", knowledge) clf.close() return True except: produce(("@nfc", ["no-device"]), knowledge) return True return False def read_card(ruleset, knowledge, snapshots=[]): nonlocal last_card if (variables := match(("@nfc", ["read-card"]), knowledge)) is not None: try: consume("@nfc", knowledge) (payload, identifier) = nfc_read_card() variables["x"] = "".join([hex(byte)[2:] for byte in identifier]) last_card = payload produce(("@nfc", ["card", "$x"]), knowledge, variables) return True except: produce(("@nfc", ["read-failed"]), knowledge) return True return False def load_card_rules(ruleset, knowledge, snapshots=[]): nonlocal last_card if (variables := match(("@nfc", ["load-rules"]), knowledge)) is not None: try: for rule in rules(reversed(last_card)): ruleset.insert(0, rule) consume("@nfc", knowledge) return True except: pass return False def load_card_facts(ruleset, knowledge, snapshots=[]): if (variables := match(("@nfc", ["load-facts"]), knowledge)) is not None: try: prepare(last_card, knowledge) consume("@nfc", knowledge) return True except: pass return False return [ open, close, read_card, load_card_rules, load_card_facts ] def repl(rulesets, primitives, debug): try: knowledge, _ = run(rulesets) print_knowledge(knowledge, debug) current_stack = "" command = input("::> ") while command != "@quit": if command in {"@run", '!'}: knowledge, _ = run(rulesets, primitives, knowledge) if debug: print_knowledge(knowledge, debug) if match(("@signal", ["quit"]), knowledge) != None: break elif command.startswith('@'): current_stack = command[1:] elif command.startswith('.'): command = command[1:] knowledge, _ = run(list(parse(command)) + list(rules(rulesets)), primitives, knowledge, debug) if debug: print_knowledge(knowledge, debug) if match(("@signal", ["quit"]), knowledge) != None: break elif command.startswith(':'): command = command[1:] rulesets = list(parse(command)) + rulesets knowledge, _ = run(rulesets, primitives, knowledge, debug) if debug: print_knowledge(knowledge, debug) if match(("@signal", ["quit"]), knowledge) != None: break elif len(command) != 0: command = "||:" + current_stack + ':' + command knowledge, _ = run(list(parse(command)) + list(rules(rulesets)), primitives, knowledge, debug) if debug: print_knowledge(knowledge, debug) if match(("@signal", ["quit"]), knowledge) != None: break else: if debug: print_knowledge(knowledge, debug) command = input(":" + current_stack + ":> ") except EOFError: pass except KeyboardInterrupt: pass def main(name, arguments): primitives = _time() + [math] + arrays() + stdio() if pygame_supported: primitives += graphics() + midi() if nfc_supported: primitives += _nfc() rulesets = [] debug = 0 prompt = False trace = False if not arguments: usage(name) return for argument in arguments: if argument == '-d': debug += 1 elif argument == '-r': prompt = True elif argument == '-t': trace = True else: with open(argument) as file: rulesets += list(parse(file.read())) if prompt: repl(rulesets, primitives, debug) else: if len(rulesets) == 0: usage(name) return if debug: knowledge, snapshots = run(rulesets, primitives, None, debug, trace) if trace: for index in range(len(snapshots)): print("Snapshot", str(index) + ':') print("----------------") print_knowledge(snapshots[index], debug) print("") else: print_knowledge(knowledge, debug) else: run(rulesets, primitives, None, debug, trace) if __name__ == "__main__": main(sys.argv[0], sys.argv[1:])