From 5c0b3c39c12185fcf8cc00b74a2b8a9bbb421e55 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Thu, 28 Apr 2022 16:25:27 -0400 Subject: [PATCH 001/121] add quackery state --- quackery.py | 1357 +++++++++++++++++++++++++-------------------------- 1 file changed, 675 insertions(+), 682 deletions(-) diff --git a/quackery.py b/quackery.py index 42678f8..1d1e6ed 100644 --- a/quackery.py +++ b/quackery.py @@ -9,67 +9,81 @@ except: pass +def isNest(item): + return isinstance(item, list) -class QuackeryError(Exception): - pass - - -def quackery(source_string): - - """ Perform a Quackery program. Return the stack as a string. """ - - def failed(message): - traverse(build(""" stacksize pack - decimal unbuild - return$ - nestdepth ]bailby[ """)) - returnstack = string_from_stack() - thestack = string_from_stack() - raise QuackeryError('\n Problem: ' + message + - '\nQuackery Stack: ' + str(thestack)[2:-2] + - '\n Return stack: ' + str(returnstack)) - - def isNest(item): - return isinstance(item, list) - - def isNumber(item): - return isinstance(item, int) - - def isOperator(item): - return isinstance(item, types.FunctionType) - - def expect_something(): - nonlocal qstack - if qstack == []: - failed('Stack unexpectedly empty.') - - def top_of_stack(): - nonlocal qstack - return(qstack[-1]) +def isNumber(item): + return isinstance(item, int) - def expect_nest(): - expect_something() - if not isNest(top_of_stack()): - failed('Expected nest on stack.') +def isOperator(item): + return isinstance(item, types.FunctionType) - def expect_number(): - expect_something() - if not isNumber(top_of_stack()): - failed('Expected number on stack.') +def isinteger(string): + numstr = string + if len(numstr) > 0 and numstr[0] == '-': + numstr = numstr[1:] + return numstr.isdigit() - def to_stack(item): - nonlocal qstack - qstack.append(item) +def ishex(string): + hexstr = string + if len(hexstr) > 1 and hexstr[0] == '-': + hexstr = hexstr[1:] + for char in hexstr: + if char.lower() not in '0123456789abcdef': + return False + return True - def from_stack(): - nonlocal qstack - expect_something() - return qstack.pop() +class QuackeryError(Exception): + pass - def string_from_stack(): - expect_nest() +class QuackeryState: + def __init__(self, qstack = None, operators = None, builders = None): + self.qstack = [] if qstack is None else qstack + self.rstack = [] + self.operators = predefined_operators.copy() if operators is None else operators + self.builders = predefined_builders.copy() if builders is None else builders + self.program_counter = 0 + self.current_nest = [] + self.source = '' + self.current_build = [] + + def copy(self): + new = QuackeryState(self.qstack.copy(), self.operators.copy(), self.builders.copy()) + new.rstack = self.rstack.copy() + new.program_counter = self.program_counter + new.current_nest = self.current_nest.copy() + new.source = self.source + new.current_build = self.current_build.copy() + return new + + def expect_something(self): + if self.qstack == []: + self.failed('Stack unexpectedly empty.') + + def top_of_stack(self): + return self.qstack[-1] + + def expect_nest(self): + self.expect_something() + if not isNest(self.top_of_stack()): + self.failed('Expected nest on stack.') + + def expect_number(self): + self.expect_something() + if not isNumber(self.top_of_stack()): + self.failed('Expected number on stack.') + + def to_stack(self, item): + self.qstack.append(item) + + def from_stack(self): + self.expect_something() + return self.qstack.pop() + + def string_from_stack(self): + self.expect_nest() result = '' - for ch in from_stack(): + for ch in self.from_stack(): if ch == 13: # \r result += '\n' elif 31 < ch < 127: @@ -78,657 +92,114 @@ def string_from_stack(): result += '?' # XXX @dragoncoder047 maybe use \uFFFD on platforms that support unicode? return result - def string_to_stack(str): + def string_to_stack(self, string): result = [] - for ch in str: + for ch in string: if ch == '\n': result.append(13) elif 31 < ord(ch) < 127: result.append(ord(ch)) else: result.append(ord('?')) # XXX @dragoncoder047 maybe \0 or NULL to signify bad char? - to_stack(result) - - def python(): - nonlocal to_stack - nonlocal from_stack - nonlocal string_to_stack - nonlocal string_from_stack - try: - exec(string_from_stack()) - except QuackeryError: - raise - except Exception as diagnostics: - failed('Python reported: "' + str(diagnostics) + '"') - - def qfail(): - message = string_from_stack() - failed(message) - - def stack_size(): - nonlocal qstack - to_stack(len(qstack)) - - def qreturn(): - nonlocal rstack - to_stack(rstack) - - def dup(): - a = from_stack() - to_stack(a) - to_stack(a) - - def drop(): - from_stack() - - def swap(): - a = from_stack() - b = from_stack() - to_stack(a) - to_stack(b) - - def rot(): # XXX @dragoncoder047 maybe simplify to [ dip swap swap ] is rot ? There are no cyclic references that would prevent this - a = from_stack() - swap() - to_stack(a) - swap() - - def over(): # XXX @dragoncoder047 maybe simplify to [ dip dup swap ] is over ? same reason as above - a = from_stack() - dup() - to_stack(a) - swap() - - def nest_depth(): - nonlocal rstack - to_stack(len(rstack) // 2) - - def to_return(item): - nonlocal rstack - rstack.append(item) - - def from_return(): - nonlocal rstack - if rstack == []: - failed('Return stack unexpectedly empty.') - return rstack.pop() - - true = 1 - - false = 0 - - def bool_to_stack(qbool): - to_stack(true if qbool else false) - - def nand(): - expect_number() - a = from_stack() - expect_number() - bool_to_stack(from_stack() == false or a == false) - - def equal(): - expect_something() - a = from_stack() - expect_something() - bool_to_stack(a == from_stack()) - - def greater(): - expect_number() - a = from_stack() - expect_number() - bool_to_stack(from_stack() > a) - - def inc(): - expect_number() - to_stack(1 + from_stack()) - - def plus(): - expect_number() - a = from_stack() - expect_number() - to_stack(a + from_stack()) - - def negate(): - expect_number() - to_stack(-from_stack()) - - def multiply(): - expect_number() - a = from_stack() - expect_number() - to_stack(a * from_stack()) - - def qdivmod(): - expect_number() - a = from_stack() - if a == 0: - failed('Division by zero.') - expect_number() - results = divmod(from_stack(), a) - to_stack(results[0]) - to_stack(results[1]) - - def exponentiate(): - expect_number() - a = from_stack() - if a < 0: - failed('Tried to raise to a negative power: ' + str(a)) - expect_number() - to_stack(from_stack() ** a) - - def shift_left(): - expect_number() - a = from_stack() - if a < 0: - failed('Cannot << by a negative amount: ' + str(a)) - expect_number() - to_stack(from_stack() << a) - - def shift_right(): - expect_number() - a = from_stack() - if a < 0: - failed('Cannot >> by a negative amount: ' + str(a)) - expect_number() - to_stack(from_stack() >> a) - - def bitwise_and(): - expect_number() - a = from_stack() - expect_number() - to_stack(a & from_stack()) - - def bitwise_or(): - expect_number() - a = from_stack() - expect_number() - to_stack(a | from_stack()) - - def bitwise_xor(): - expect_number() - a = from_stack() - expect_number() - to_stack(a ^ from_stack()) - - def bitwise_not(): - expect_number() - to_stack(~from_stack()) - - def qtime(): - to_stack(int(time.time()*1000000)) - - def meta_done(): - from_return() - from_return() - - def meta_again(): - from_return() - to_return(-1) - - def meta_if(): - expect_number() - if from_stack() == 0: - to_return(from_return() + 1) - - def meta_iff(): - expect_number() - if from_stack() == 0: - to_return(from_return() + 2) - - def meta_else(): - to_return(from_return() + 1) - - def meta_literal(): - pc = from_return() + 1 - return_nest = from_return() - if len(return_nest) == pc: - failed('''Found a "'" at the end of a nest.''') - to_stack(return_nest[pc]) - to_return(return_nest) - to_return(pc) - - def meta_this(): - pc = from_return() - return_nest = from_return() - to_stack(return_nest) - to_return(return_nest) - to_return(pc) - - def meta_do(): - expect_something() - the_thing = from_stack() - if not isNest(the_thing): - the_thing = [the_thing] - to_return(the_thing) - to_return(-1) - - def meta_bail_by(): - expect_number() - a = 2*(from_stack()) - if a <= len(rstack): - for _ in range(a): - from_return() - else: - failed('Bailed out of Quackery.') - - def qput(): - expect_nest() - a = from_stack() - expect_something() - b = from_stack() - a.append(b) - - def immovable(): - pass - - def take(): - expect_nest() - a = from_stack() - if len(a) == 0: - failed('Unexpectedly empty nest.') - if len(a) == 1: - if isNest(a[0]) and len(a[0]) > 0 and a[0][0] == immovable: - failed('Cannot remove an immovable item.') - to_stack(a.pop()) - - def create_nest(): - to_stack([]) - - def qsplit(): - expect_number() - a = from_stack() - expect_nest() - b = from_stack() - to_stack(b[:a]) - to_stack(b[a:]) - - def join(): - expect_something() - b = from_stack() - if not isNest(b): - b = [b] - expect_something() - a = from_stack() - if not isNest(a): - a = [a] - to_stack(a + b) - - def qsize(): - expect_nest() - to_stack(len(from_stack())) - - def qfind(): - expect_nest() - nest = from_stack() - expect_something() - a = from_stack() - if a in nest: - to_stack(nest.index(a)) - else: - to_stack(len(nest)) - - def peek(): - expect_number() - index = from_stack() - expect_nest() - nest = from_stack() - if index >= len(nest) or ( - index < 0 and len(nest) < abs(index)): - failed('Cannot peek an item outside a nest.') - else: - to_stack(nest[index]) - - def poke(): - expect_number() - index = from_stack() - expect_nest() - nest = from_stack().copy() - expect_something() - value = from_stack() - if index >= len(nest) or ( - index < 0 and len(nest) < abs(index)): - failed('Cannot poke an item outside a nest.') - else: - nest[index] = value - to_stack(nest) - - def qnest(): - expect_something() - bool_to_stack(isNest(from_stack())) - - def qnumber(): - expect_something() - bool_to_stack(isNumber(from_stack())) - - def qoperator(): - expect_something() - bool_to_stack(isOperator(from_stack())) - - def quid(): - expect_something() - to_stack(id(from_stack())) - - def qemit(): - expect_number() - char = from_stack() - if char == 13: - sys.stdout.write('\n') - elif 31 < char < 127: - sys.stdout.write(chr(char)) - else: - sys.stdout.write('?') # XXX @dragoncoder047 maybe use \uFFFD on platforms that support unicode? - - def ding(): - sys.stdout.write('\a') - - def qinput(): - prompt = string_from_stack() - string_to_stack(input(prompt)) - - filepath = [] - - def putfile(): - nonlocal filepath - filename = string_from_stack() - if len(filepath) > 1: - to_stack(filepath[-1]) - filename = string_from_stack() + filename - filetext = string_from_stack() - try: - with open(filename, 'x'): pass - except FileExistsError: - to_stack(false) - except: - raise - else: - try: - with open(filename, 'w') as f: f.write(filetext) - except: - raise - else: - to_stack(true) - - def releasefile(): - nonlocal filepath - filename = string_from_stack() - if len(filepath) > 1: - to_stack(filepath[-1]) - filename = string_from_stack() + filename - try: - os.remove(filename) - except FileNotFoundError: - to_stack(false) - except: - raise - else: - to_stack(true) - - def sharefile(): - nonlocal filepath - dup() - filename = string_from_stack() - if len(filepath) > 1: - to_stack(filepath[-1]) - filename = string_from_stack() + filename - try: - with open(filename) as f: filetext = f.read() - except FileNotFoundError: - to_stack(false) - except: - raise + self.to_stack(result) + + def bool_to_stack(self, qbool): + self.to_stack(true if qbool else false) + + def to_return(self, item): + self.rstack.append(item) + + def from_return(self.): + if len(self.rstack) == 0: + self.failed('Return stack unexpectedly empty.') + return self.rstack.pop() + + def failed(self, message): + self.traverse(self.build("stacksize pack decimal unbuild return$ nestdepth ]bailby[")) + returnstack = self.string_from_stack() + thestack = self.string_from_stack() + raise QuackeryError('\n Problem: ' + message + + '\nQuackery Stack: ' + str(thestack)[2:-2] + + '\n Return stack: ' + str(returnstack)) + + def tick(self): + if self.program_counter >= len(self.current_nest): + self.program_counter = self.from_return() + self.current_nest = self.from_return() + self.program_counter += 1 + return + current_item = self.current_nest[self.program_counter] + if isNest(current_item): + self.to_return(current_nest) + self.to_return(program_counter) + self.current_nest = current_item + self.program_counter = 0 + elif isOperator(current_item): + current_item(self) + self.program_counter += 1 + elif isNumber(current_item): + self.to_stack(current_item) + self.program_counter += 1 else: - drop() - string_to_stack(filetext) - to_stack(true) - - operators = { - 'python': python, # ( $ --> ) - 'fail': qfail, # ( $ --> ) - 'nand': nand, # ( b b --> b ) - '=': equal, # ( x x --> b ) - '>': greater, # ( n n --> b ) - '1+': inc, # ( n --> n ) - '+': plus, # ( n n --> n ) - 'negate': negate, # ( n --> n ) - '*': multiply, # ( n n --> n ) - '/mod': qdivmod, # ( n n --> n n ) - '**': exponentiate, # ( n n --> n ) - '<<': shift_left, # ( f n --> f ) - '>>': shift_right, # ( f n --> f ) - '&': bitwise_and, # ( f f --> f ) - '|': bitwise_or, # ( f f --> f ) - '^': bitwise_xor, # ( f f --> f ) - '~': bitwise_not, # ( f --> f ) - 'time': qtime, # ( --> n ) - 'stacksize': stack_size, # ( --> n ) - 'nestdepth': nest_depth, # ( --> n ) - 'return': qreturn, # ( --> [ ) - 'dup': dup, # ( x --> x x ) - 'drop': drop, # ( x --> ) - 'swap': swap, # ( x x --> x x ) - 'rot': rot, # ( x x x --> x x x ) - 'over': over, # ( x x --> x x x ) - ']done[': meta_done, # ( --> ) - ']again[': meta_again, # ( --> ) - ']if[': meta_if, # ( b --> ) - ']iff[': meta_iff, # ( b --> ) - ']else[': meta_else, # ( --> ) - "]'[": meta_literal, # ( --> x ) - ']this[': meta_this, # ( --> [ ) - ']do[': meta_do, # ( x --> ) - ']bailby[': meta_bail_by, # ( n --> ) - 'put': qput, # ( x [ --> ) - 'immovable': immovable, # ( --> ) - 'take': take, # ( [ --> x ) - '[]': create_nest, # ( --> n ) - 'split': qsplit, # ( [ n --> [ [ ) - 'join': join, # ( x x --> [ ) - 'find': qfind, # ( x --> b ) - 'peek': peek, # ( [ n --> x ) - 'poke': poke, # ( x [ n --> ) - 'size': qsize, # ( [ --> n ) - 'nest?': qnest, # ( x --> b ) - 'number?': qnumber, # ( x --> b ) - 'operator?': qoperator, # ( x --> b ) - 'quid': quid, # ( x --> n ) - 'emit': qemit, # ( c --> ) - 'ding': ding, # ( --> ) - 'input': qinput, # ( $ --> $ ) - 'filepath': filepath, # ( --> s ) - 'putfile': putfile, # ( $ --> b ) - 'releasefile': releasefile, # ( $ --> b ) - 'sharefile': sharefile} # ( $ --> $ b ) - - qstack = [] - - rstack = [] - - current_nest = [] - - program_counter = 0 - - def traverse(the_nest): - nonlocal current_nest - nonlocal program_counter - nonlocal rstack - current_nest = the_nest - program_counter = 0 - while True: - if program_counter >= len(current_nest): - if len(rstack) == 0: - break - else: - program_counter = from_return() - current_nest = from_return() - program_counter += 1 - continue - current_item = current_nest[program_counter] - if isNest(current_item): - to_return(current_nest) - to_return(program_counter) - current_nest = current_item - program_counter = 0 - elif isOperator(current_item): - current_item() - program_counter += 1 - elif isNumber(current_item): - to_stack(current_item) - program_counter += 1 - else: - failed('Quackery was worried by a python.') - - def isinteger(string): - numstr = string - if len(numstr) > 0 and numstr[0] == '-': - numstr = numstr[1:] - return numstr.isdigit() - - def next_char(): - nonlocal source - if len(source) > 0: - char = source[0] - source = source[1:] + self.failed('Quackery was worried by a python.') + + + def traverse(self, the_nest): + self.current_nest = the_nest + self.program_counter = 0 + orig_depth = len(self.rstack) + while len(self.rstack) > orig_depth: + self.tick() + + def next_char(self): + if len(self.source) > 0: + char = self.source[0] + self.source = self.source[1:] return char else: return '' - def next_word(): + def next_word(self): result = '' while True: - char = next_char() + char = self.next_char() if char == '': - return(result) + return result if ord(char) < 33: if result == '': continue return result result += char - def one_char(): + def one_char(self): while True: - char = next_char() + char = self.next_char() if char == '': return char if ord(char) < 33: continue return char - def get_name(): - name = next_word() + def get_name(self): + name = selfnext_word() if name == '': raise EOFError('Unexpected end of program text.') return name - def check_build(): - nonlocal current_build - if len(current_build) == 0: + def check_build(self): + if len(self.current_build) == 0: raise IndexError('Nothing to name.') - - def qis(): - nonlocal operators - nonlocal current_build - check_build() - name = get_name() - operators[name] = current_build.pop() - - def qcomment(): - word = '' - while word != ')': - word = next_word() - if word == '': - raise EOFError('Unclosed comment.') - - def endcomment(): - raise SyntaxError('Too many end of comments.') - - def unresolved(): - raise TypeError('Unresolved forward reference.') - - def forward(): - nonlocal current_build - current_build.append([unresolved]) - - def resolves(): - nonlocal current_build - name = get_name() - if name in operators: - if operators[name][0] != unresolved: - raise TypeError(name + ' is not a forward reference.') - check_build() - operators[name][0] = current_build.pop() - else: - raise NameError('Unrecognised word: ' + name) - - def char_literal(): - nonlocal current_build - char = one_char() - if char == '': - raise SyntaxError('No character found.') - current_build.append(ord(char)) - - def string_literal(): - nonlocal current_build - delimiter = '' - result = [] - while delimiter == '': - char = next_char() - if char == '': - raise EOFError('No string found.') - if ord(char) > 32: - delimiter = char - char = '' - while char != delimiter: - char = next_char() - if char == '': - raise EOFError('Endless string discovered.') - if char != delimiter: - result.append(ord(char)) - current_build.append([[meta_literal], result]) - - def ishex(string): - hexstr = string - if len(hexstr) > 1 and hexstr[0] == '-': - hexstr = hexstr[1:] - for char in hexstr: - if char.lower() not in '0123456789abcdef': - return False - return True - - def hexnum(): - nonlocal current_build - word = get_name() - if not ishex(word): - raise SyntaxError(word + " is not hexadecimal.") - current_build.append(int(word, 16)) - - builders = {'is': qis, - '(': qcomment, - ')': endcomment, - 'forward': forward, - 'resolves': resolves, - 'char': char_literal, - '$': string_literal, - 'hex': hexnum} - - current_build = [] - - source = '' - - the_nest = [] - - def build(source_string): - nonlocal source - nonlocal the_nest - source = source_string + + def build(self, source_string): + self.source = source_string nesting = 0 def sub_build(): nonlocal nesting - nonlocal current_build the_nest = [] while True: - current_build = the_nest - word = next_word() + self.current_build = the_nest + word = self.next_word() if word == '': return the_nest elif word == '[': @@ -739,10 +210,10 @@ def sub_build(): if nesting < 0: raise SyntaxError('Unexpected end of nest.') return(the_nest) - elif word in builders.keys(): - builders[word]() - elif word in operators.keys(): - the_nest.append(operators[word]) + elif word in self.builders.keys(): + self.builders[word](self) + elif word in self.operators.keys(): + the_nest.append(self.operators[word]) elif isinteger(word): the_nest.append(int(word, 10)) else: @@ -751,9 +222,526 @@ def sub_build(): the_nest = sub_build() if nesting > 0: raise SyntaxError('Unfinished nest.') - return(the_nest) + return the_nest + + def run(self, source_string): + self.traverse(self.build(source_string)) + + def bootstrap(self): + self.run(predefined_qky) + + + +def python(qs): + """For backwards compatibility only""" + scope = { + "to_stack": qs.to_stack, + "from_stack": qs.from_stack, + "string_to_stack": qs.string_to_stack, + "string_from_stack": qs.string_from_stack, + "qs": qs, + } + try: + exec(qs.string_from_stack(), scope, globals()) + except QuackeryError: + raise + except Exception as diagnostics: + qs.failed('Python reported: "' + str(diagnostics) + '"') + +def qfail(qs): + qs.failed(qs.string_from_stack()) + +def stack_size(qs): + qs.to_stack(len(qs.qstack)) + +def qreturn(qs): + qs.to_stack(qs.rstack) + +def dup(qs): + a = qs.from_stack() + qs.to_stack(a) + qs.to_stack(a) + +def drop(qs): + qs.from_stack() + +def swap(qs): + a = qs.from_stack() + b = qs.from_stack() + qs.to_stack(a) + qs.to_stack(b) + +def rot(qs): # XXX @dragoncoder047 maybe simplify to [ dip swap swap ] is rot ? There are no cyclic references that would prevent this + a = qs.from_stack() + swap(qs) + qs.to_stack(a) + swap(qs) + +def over(qs): # XXX @dragoncoder047 maybe simplify to [ dip dup swap ] is over ? same reason as above + a = qs.from_stack() + dup(qs) + qs.to_stack(a) + swap(qs) + +def nest_depth(qs): + qs.to_stack(len(qs.rstack) // 2) + +true = 1 + +false = 0 + +def nand(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.bool_to_stack(qs.from_stack() == false or a == false) + +def equal(qs): + qs.expect_something() + a = qs.from_stack() + qs.expect_something() + qs.bool_to_stack(a == qs.from_stack()) + +def greater(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.bool_to_stack(qs.from_stack() > a) + +def inc(qs): + qs.expect_number() + qs.to_stack(1 + qs.from_stack()) + +def plus(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.to_stack(a + qs.from_stack()) + +def negate(qs): + qs.expect_number() + qs.to_stack(-qs.from_stack()) + +def multiply(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.to_stack(a * qs.from_stack()) + +def qdivmod(qs): + qs.expect_number() + a = qs.from_stack() + if a == 0: + qs.failed('Division by zero.') + qs.expect_number() + results = divmod(qs.from_stack(), a) + qs.to_stack(results[0]) + qs.to_stack(results[1]) + +def exponentiate(qs): + qs.expect_number() + a = qs.from_stack() + if a < 0: + qs.failed('Tried to raise to a negative power: ' + str(a)) + qs.expect_number() + qs.to_stack(qs.from_stack() ** a) + +def shift_left(qs): + qs.expect_number() + a = qs.from_stack() + if a < 0: + qs.failed('Cannot << by a negative amount: ' + str(a)) + qs.expect_number() + qs.to_stack(qs.from_stack() << a) + +def shift_right(qs): + qs.expect_number() + a = qs.from_stack() + if a < 0: + qs.failed('Cannot >> by a negative amount: ' + str(a)) + qs.expect_number() + qs.to_stack(qs.from_stack() >> a) + +def bitwise_and(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.to_stack(a & qs.from_stack()) + +def bitwise_or(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.to_stack(a | qs.from_stack()) + +def bitwise_xor(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_number() + qs.to_stack(a ^ qs.from_stack()) + +def bitwise_not(qs): + qs.expect_number() + qs.to_stack(~qs.from_stack()) + +def qtime(qs): + qs.to_stack(int(time.time()*1000000)) + +def meta_done(qs): + qs.from_return() + qs.from_return() + +def meta_again(qs): + qs.from_return() + qs.to_return(-1) + +def meta_if(qs): + qs.expect_number() + if qs.from_stack() == 0: + qs.to_return(qs.from_return() + 1) + +def meta_iff(qs): + qs.expect_number() + if qs.from_stack() == 0: + qs.to_return(qs.from_return() + 2) + +def meta_else(qs): + qs.to_return(qs.from_return() + 1) + +def meta_literal(qs): + pc = qs.from_return() + 1 + return_nest = qs.from_return() + if len(return_nest) == pc: + qs.failed('Found a "\'" at the end of a nest.') + qs.to_stack(return_nest[pc]) + qs.to_return(return_nest) + qs.to_return(pc) + +def meta_this(qs): + pc = qs.from_return() + return_nest = qs.from_return() + qs.to_stack(return_nest) + qs.to_return(return_nest) + qs.to_return(pc) + +def meta_do(qs): + qs.expect_something() + the_thing = qs.from_stack() + if not isNest(the_thing): + the_thing = [the_thing] + qs.to_return(the_thing) + qs.to_return(-1) + +def meta_bail_by(qs): + qs.expect_number() + a = 2 * qs.from_stack() + if a <= len(qs.rstack): + for _ in range(a): + qs.from_return() + else: + qs.failed('Bailed out of Quackery.') - predefined = r""" +def qput(qs): + qs.expect_nest() + a = qs.from_stack() + qs.expect_something() + b = qs.from_stack() + a.append(b) + +def immovable(qs): + pass + +def take(qs): + qs.expect_nest() + a = qs.from_stack() + if len(a) == 0: + qs.failed('Unexpectedly empty nest.') + if len(a) == 1: + if isNest(a[0]) and len(a[0]) > 0 and a[0][0] == immovable: + qs.failed('Cannot remove an immovable item.') + qs.to_stack(a.pop()) + +def create_nest(qs): + qs.to_stack([]) + +def qsplit(qs): + qs.expect_number() + a = qs.from_stack() + qs.expect_nest() + b = qs.from_stack() + qs.to_stack(b[:a]) + qs.to_stack(b[a:]) + +def join(qs): + qs.expect_something() + b = qs.from_stack() + if not isNest(b): + b = [b] + qs.expect_something() + a = from_stack() + if not isNest(a): + a = [a] + qs.to_stack(a + b) + +def qsize(qs): + qs.expect_nest() + qs.to_stack(len(qs.from_stack())) + +def qfind(qs): + qs.expect_nest() + nest = qs.from_stack() + qs.expect_something() + a = qs.from_stack() + if a in nest: + qs.to_stack(nest.index(a)) + else: + qs.to_stack(len(nest)) + +def peek(qs): + qs.expect_number() + index = qs.from_stack() + qs.expect_nest() + nest = qs.from_stack() + if index >= len(nest) or ( + index < 0 and len(nest) < abs(index)): + failed('Cannot peek an item outside a nest.') + else: + to_stack(nest[index]) + +def poke(qs): + qs.expect_number() + index = qs.from_stack() + qs.expect_nest() + nest = qs.from_stack().copy() + qs.expect_something() + value = qs.from_stack() + if index >= len(nest) or ( + index < 0 and len(nest) < abs(index)): + qs.failed('Cannot poke an item outside a nest.') + else: + nest[index] = value + qs.to_stack(nest) + +def qnest(qs): + qs.expect_something() + qs.bool_to_stack(isNest(qs.from_stack())) + +def qnumber(qs): + qs.expect_something() + qs.bool_to_stack(isNumber(qs.from_stack())) + +def qoperator(qs): + qs.expect_something() + qs.bool_to_stack(isOperator(qs.from_stack())) + +def quid(qs): + qs.expect_something() + qs.to_stack(id(qs.from_stack())) + +def qemit(qs): + qs.expect_number() + char = qs.from_stack() + if char == 13: + sys.stdout.write('\n') + elif 31 < char < 127: + sys.stdout.write(chr(char)) + else: + sys.stdout.write('?') # XXX @dragoncoder047 maybe use \uFFFD on platforms that support unicode? + +def ding(qs): + sys.stdout.write('\a') + +def qinput(qs): + prompt = qs.string_from_stack() + qs.string_to_stack(input(prompt)) + +filepath = [] + +def putfile(qs): + filename = qs.string_from_stack() + if len(filepath) > 1: + qs.to_stack(filepath[-1]) + filename = qs.string_from_stack() + filename + filetext = qs.string_from_stack() + try: + with open(filename, 'x'): pass + except FileExistsError: + qs.to_stack(false) + except: + raise + else: + try: + with open(filename, 'w') as f: f.write(filetext) + except: + raise + else: + qs.to_stack(true) + +def releasefile(qs): + nonlocal filepath + filename = qs.string_from_stack() + if len(filepath) > 1: + qs.to_stack(filepath[-1]) + filename = qs.string_from_stack() + filename + try: + os.remove(filename) + except FileNotFoundError: + qs.to_stack(false) + except: + raise + else: + qs.to_stack(true) + +def sharefile(qs): + dup(qs) + filename = qs.string_from_stack() + if len(filepath) > 1: + qs.to_stack(filepath[-1]) + filename = qs.string_from_stack() + filename + try: + with open(filename) as f: filetext = f.read() + except FileNotFoundError: + qsto_stack(false) + except: + raise + else: + drop(qs) + qs.string_to_stack(filetext) + qs.to_stack(true) + +predefined_operators = { + 'python': python, # ( $ --> ) + 'fail': qfail, # ( $ --> ) + 'nand': nand, # ( b b --> b ) + '=': equal, # ( x x --> b ) + '>': greater, # ( n n --> b ) + '1+': inc, # ( n --> n ) + '+': plus, # ( n n --> n ) + 'negate': negate, # ( n --> n ) + '*': multiply, # ( n n --> n ) + '/mod': qdivmod, # ( n n --> n n ) + '**': exponentiate, # ( n n --> n ) + '<<': shift_left, # ( f n --> f ) + '>>': shift_right, # ( f n --> f ) + '&': bitwise_and, # ( f f --> f ) + '|': bitwise_or, # ( f f --> f ) + '^': bitwise_xor, # ( f f --> f ) + '~': bitwise_not, # ( f --> f ) + 'time': qtime, # ( --> n ) + 'stacksize': stack_size, # ( --> n ) + 'nestdepth': nest_depth, # ( --> n ) + 'return': qreturn, # ( --> [ ) + 'dup': dup, # ( x --> x x ) + 'drop': drop, # ( x --> ) + 'swap': swap, # ( x x --> x x ) + 'rot': rot, # ( x x x --> x x x ) + 'over': over, # ( x x --> x x x ) + ']done[': meta_done, # ( --> ) + ']again[': meta_again, # ( --> ) + ']if[': meta_if, # ( b --> ) + ']iff[': meta_iff, # ( b --> ) + ']else[': meta_else, # ( --> ) + "]'[": meta_literal, # ( --> x ) + ']this[': meta_this, # ( --> [ ) + ']do[': meta_do, # ( x --> ) + ']bailby[': meta_bail_by, # ( n --> ) + 'put': qput, # ( x [ --> ) + 'immovable': immovable, # ( --> ) + 'take': take, # ( [ --> x ) + '[]': create_nest, # ( --> n ) + 'split': qsplit, # ( [ n --> [ [ ) + 'join': join, # ( x x --> [ ) + 'find': qfind, # ( x --> b ) + 'peek': peek, # ( [ n --> x ) + 'poke': poke, # ( x [ n --> ) + 'size': qsize, # ( [ --> n ) + 'nest?': qnest, # ( x --> b ) + 'number?': qnumber, # ( x --> b ) + 'operator?': qoperator, # ( x --> b ) + 'quid': quid, # ( x --> n ) + 'emit': qemit, # ( c --> ) + 'ding': ding, # ( --> ) + 'input': qinput, # ( $ --> $ ) + 'filepath': filepath, # ( --> s ) + 'putfile': putfile, # ( $ --> b ) + 'releasefile': releasefile, # ( $ --> b ) + 'sharefile': sharefile # ( $ --> $ b ) +} + +def qis(qs): + qs.check_build() + name = qs.get_name() + qs.operators[name] = qs.current_build.pop() + +def qcomment(qs): + word = '' + while word != ')': + word = qs.next_word() + if word == '': + raise EOFError('Unclosed comment.') + +def endcomment(qs): + raise SyntaxError('Too many end of comments.') + +def unresolved(qs): + raise TypeError('Unresolved forward reference.') + +def forward(qs): + qs.current_build.append([unresolved]) + +def resolves(qs): + name = qs.get_name() + if name in qs.operators: + if qs.operators[name][0] != unresolved: + raise TypeError(name + ' is not a forward reference.') + qs.check_build() + operators[name][0] = current_build.pop() + else: + raise NameError('Unrecognised word: ' + name) + +def char_literal(qs): + char = qs.one_char() + if char == '': + raise SyntaxError('No character found.') + qs.current_build.append(ord(char)) + +def string_literal(qs): + delimiter = '' + result = [] + while delimiter == '': + char = qs.next_char() + if char == '': + raise EOFError('No string found.') + if ord(char) > 32: + delimiter = char + char = '' + while char != delimiter: + char = qs.next_char() + if char == '': + raise EOFError('Endless string discovered.') + if char != delimiter: + result.append(ord(char)) + qs.current_build.append([[meta_literal], result]) + +def hexnum(qs): + word = qs.get_name() + if not ishex(word): + raise SyntaxError(word + " is not hexadecimal.") + qs.current_build.append(int(word, 16)) + +predefined_builders = { + 'is': qis, + '(': qcomment, + ')': endcomment, + 'forward': forward, + 'resolves': resolves, + 'char': char_literal, + '$': string_literal, + 'hex': hexnum +} + + +predefined_qky = r""" [ 0 ] is false ( --> b ) @@ -1650,11 +1638,18 @@ def sub_build(): """ - traverse(build(predefined)) +def quackery(source_string, qs = None): + + if qs is None: + qs = QuackeryState() + qs.bootstrap() + else: + if 'quackery' not in qs.operators.keys(): + raise NameError('QuackeryState must have word `quackery` defined.') + while True: - to_stack([ord(char) for char in source_string]) - try: - traverse(build('quackery')) + qs.to_stack([ord(char) for char in source_string]) + try: qs.run('quackery') except QuackeryError as diagnostics: if __name__ == '__main__' and len(sys.argv) == 1: print(diagnostics) @@ -1664,13 +1659,11 @@ def sub_build(): except Exception as diagnostics: print('Quackery system damage detected.') print('Python error: ' + str(diagnostics)) - sys.exit(1) + raise else: - traverse(build('stacksize pack decimal unbuild')) - result = '' - for ch in qstack[0][2:-2]: - result += chr(ch) - return result + qs.run('stacksize pack decimal unbuild') + the_stack = qs.from_stack() + return ''.join(map(chr, the_stack[2:-2])) if __name__ == '__main__': if len(sys.argv) > 1: From d9a7d872e0ec2ede183ae1a409cfb96d5494fae7 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Thu, 28 Apr 2022 18:02:44 -0400 Subject: [PATCH 002/121] oops, unicode error --- quackery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quackery.py b/quackery.py index 85d2018..6276fd9 100644 --- a/quackery.py +++ b/quackery.py @@ -1687,8 +1687,8 @@ def quackery(source_string, qs = None): print('Python error: ' + str(diagnostics)) sys.exit(1) else: - print(‘\nWelcome to Quackery.’) - print(‘\nEnter "leave" to leave the shell.') + print('\nWelcome to Quackery.') + print('\nEnter "leave" to leave the shell.') quackscript = r""" $ 'extensions.qky' dup name? not From 38b17b43f51f534178f67d8d9a2c5f2a7e830e1d Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Thu, 28 Apr 2022 18:04:00 -0400 Subject: [PATCH 003/121] bootstrap only once --- quackery.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/quackery.py b/quackery.py index 6276fd9..b1232bb 100644 --- a/quackery.py +++ b/quackery.py @@ -1638,11 +1638,17 @@ def hexnum(qs): """ +# bootstrap only once +_qs = QuackeryState() +_qs.bootstrap() +predefined_operators = _qs.operators +del _qs + + def quackery(source_string, qs = None): if qs is None: qs = QuackeryState() - qs.bootstrap() else: if 'quackery' not in qs.operators.keys(): raise NameError('QuackeryState must have word `quackery` defined.') From f6f61ce0ba12d68b6165e4b0b07fb96d0ad64b38 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Thu, 28 Apr 2022 18:05:26 -0400 Subject: [PATCH 004/121] rename `qs` to `self` as with Python convention --- quackery.py | 602 ++++++++++++++++++++++++++-------------------------- 1 file changed, 301 insertions(+), 301 deletions(-) diff --git a/quackery.py b/quackery.py index b1232bb..5fbee44 100644 --- a/quackery.py +++ b/quackery.py @@ -232,315 +232,315 @@ def bootstrap(self): -def python(qs): +def python(self): """For backwards compatibility only""" scope = { - "to_stack": qs.to_stack, - "from_stack": qs.from_stack, - "string_to_stack": qs.string_to_stack, - "string_from_stack": qs.string_from_stack, - "qs": qs, + "to_stack": self.to_stack, + "from_stack": self.from_stack, + "string_to_stack": self.string_to_stack, + "string_from_stack": self.string_from_stack, + "self": self, } try: - exec(qs.string_from_stack(), scope, globals()) + exec(self.string_from_stack(), scope, globals()) except QuackeryError: raise except Exception as diagnostics: - qs.failed('Python reported: "' + str(diagnostics) + '"') + self.failed('Python reported: "' + str(diagnostics) + '"') -def qfail(qs): - qs.failed(qs.string_from_stack()) +def qfail(self): + self.failed(self.string_from_stack()) -def stack_size(qs): - qs.to_stack(len(qs.qstack)) +def stack_size(self): + self.to_stack(len(self.qstack)) -def qreturn(qs): - qs.to_stack(qs.rstack) +def qreturn(self): + self.to_stack(self.rstack) -def dup(qs): - a = qs.from_stack() - qs.to_stack(a) - qs.to_stack(a) +def dup(self): + a = self.from_stack() + self.to_stack(a) + self.to_stack(a) -def drop(qs): - qs.from_stack() +def drop(self): + self.from_stack() -def swap(qs): - a = qs.from_stack() - b = qs.from_stack() - qs.to_stack(a) - qs.to_stack(b) +def swap(self): + a = self.from_stack() + b = self.from_stack() + self.to_stack(a) + self.to_stack(b) -def rot(qs): # XXX @dragoncoder047 maybe simplify to [ dip swap swap ] is rot ? There are no cyclic references that would prevent this - a = qs.from_stack() - swap(qs) - qs.to_stack(a) - swap(qs) +def rot(self): # XXX @dragoncoder047 maybe simplify to [ dip swap swap ] is rot ? There are no cyclic references that would prevent this + a = self.from_stack() + swap(self) + self.to_stack(a) + swap(self) -def over(qs): # XXX @dragoncoder047 maybe simplify to [ dip dup swap ] is over ? same reason as above - a = qs.from_stack() - dup(qs) - qs.to_stack(a) - swap(qs) +def over(self): # XXX @dragoncoder047 maybe simplify to [ dip dup swap ] is over ? same reason as above + a = self.from_stack() + dup(self) + self.to_stack(a) + swap(self) -def nest_depth(qs): - qs.to_stack(len(qs.rstack) // 2) +def nest_depth(self): + self.to_stack(len(self.rstack) // 2) true = 1 false = 0 -def nand(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.bool_to_stack(qs.from_stack() == false or a == false) - -def equal(qs): - qs.expect_something() - a = qs.from_stack() - qs.expect_something() - qs.bool_to_stack(a == qs.from_stack()) - -def greater(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.bool_to_stack(qs.from_stack() > a) - -def inc(qs): - qs.expect_number() - qs.to_stack(1 + qs.from_stack()) - -def plus(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.to_stack(a + qs.from_stack()) - -def negate(qs): - qs.expect_number() - qs.to_stack(-qs.from_stack()) - -def multiply(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.to_stack(a * qs.from_stack()) - -def qdivmod(qs): - qs.expect_number() - a = qs.from_stack() +def nand(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.bool_to_stack(self.from_stack() == false or a == false) + +def equal(self): + self.expect_something() + a = self.from_stack() + self.expect_something() + self.bool_to_stack(a == self.from_stack()) + +def greater(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.bool_to_stack(self.from_stack() > a) + +def inc(self): + self.expect_number() + self.to_stack(1 + self.from_stack()) + +def plus(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.to_stack(a + self.from_stack()) + +def negate(self): + self.expect_number() + self.to_stack(-self.from_stack()) + +def multiply(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.to_stack(a * self.from_stack()) + +def qdivmod(self): + self.expect_number() + a = self.from_stack() if a == 0: - qs.failed('Division by zero.') - qs.expect_number() - results = divmod(qs.from_stack(), a) - qs.to_stack(results[0]) - qs.to_stack(results[1]) - -def exponentiate(qs): - qs.expect_number() - a = qs.from_stack() + self.failed('Division by zero.') + self.expect_number() + results = divmod(self.from_stack(), a) + self.to_stack(results[0]) + self.to_stack(results[1]) + +def exponentiate(self): + self.expect_number() + a = self.from_stack() if a < 0: - qs.failed('Tried to raise to a negative power: ' + str(a)) - qs.expect_number() - qs.to_stack(qs.from_stack() ** a) + self.failed('Tried to raise to a negative power: ' + str(a)) + self.expect_number() + self.to_stack(self.from_stack() ** a) -def shift_left(qs): - qs.expect_number() - a = qs.from_stack() +def shift_left(self): + self.expect_number() + a = self.from_stack() if a < 0: - qs.failed('Cannot << by a negative amount: ' + str(a)) - qs.expect_number() - qs.to_stack(qs.from_stack() << a) + self.failed('Cannot << by a negative amount: ' + str(a)) + self.expect_number() + self.to_stack(self.from_stack() << a) -def shift_right(qs): - qs.expect_number() - a = qs.from_stack() +def shift_right(self): + self.expect_number() + a = self.from_stack() if a < 0: - qs.failed('Cannot >> by a negative amount: ' + str(a)) - qs.expect_number() - qs.to_stack(qs.from_stack() >> a) - -def bitwise_and(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.to_stack(a & qs.from_stack()) - -def bitwise_or(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.to_stack(a | qs.from_stack()) - -def bitwise_xor(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_number() - qs.to_stack(a ^ qs.from_stack()) - -def bitwise_not(qs): - qs.expect_number() - qs.to_stack(~qs.from_stack()) - -def qtime(qs): - qs.to_stack(int(time.time()*1000000)) - -def meta_done(qs): - qs.from_return() - qs.from_return() - -def meta_again(qs): - qs.from_return() - qs.to_return(-1) - -def meta_if(qs): - qs.expect_number() - if qs.from_stack() == 0: - qs.to_return(qs.from_return() + 1) - -def meta_iff(qs): - qs.expect_number() - if qs.from_stack() == 0: - qs.to_return(qs.from_return() + 2) - -def meta_else(qs): - qs.to_return(qs.from_return() + 1) - -def meta_literal(qs): - pc = qs.from_return() + 1 - return_nest = qs.from_return() + self.failed('Cannot >> by a negative amount: ' + str(a)) + self.expect_number() + self.to_stack(self.from_stack() >> a) + +def bitwise_and(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.to_stack(a & self.from_stack()) + +def bitwise_or(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.to_stack(a | self.from_stack()) + +def bitwise_xor(self): + self.expect_number() + a = self.from_stack() + self.expect_number() + self.to_stack(a ^ self.from_stack()) + +def bitwise_not(self): + self.expect_number() + self.to_stack(~self.from_stack()) + +def qtime(self): + self.to_stack(int(time.time()*1000000)) + +def meta_done(self): + self.from_return() + self.from_return() + +def meta_again(self): + self.from_return() + self.to_return(-1) + +def meta_if(self): + self.expect_number() + if self.from_stack() == 0: + self.to_return(self.from_return() + 1) + +def meta_iff(self): + self.expect_number() + if self.from_stack() == 0: + self.to_return(self.from_return() + 2) + +def meta_else(self): + self.to_return(self.from_return() + 1) + +def meta_literal(self): + pc = self.from_return() + 1 + return_nest = self.from_return() if len(return_nest) == pc: - qs.failed('Found a "\'" at the end of a nest.') - qs.to_stack(return_nest[pc]) - qs.to_return(return_nest) - qs.to_return(pc) - -def meta_this(qs): - pc = qs.from_return() - return_nest = qs.from_return() - qs.to_stack(return_nest) - qs.to_return(return_nest) - qs.to_return(pc) - -def meta_do(qs): - qs.expect_something() - the_thing = qs.from_stack() + self.failed('Found a "\'" at the end of a nest.') + self.to_stack(return_nest[pc]) + self.to_return(return_nest) + self.to_return(pc) + +def meta_this(self): + pc = self.from_return() + return_nest = self.from_return() + self.to_stack(return_nest) + self.to_return(return_nest) + self.to_return(pc) + +def meta_do(self): + self.expect_something() + the_thing = self.from_stack() if not isNest(the_thing): the_thing = [the_thing] - qs.to_return(the_thing) - qs.to_return(-1) + self.to_return(the_thing) + self.to_return(-1) -def meta_bail_by(qs): - qs.expect_number() - a = 2 * qs.from_stack() - if a <= len(qs.rstack): +def meta_bail_by(self): + self.expect_number() + a = 2 * self.from_stack() + if a <= len(self.rstack): for _ in range(a): - qs.from_return() + self.from_return() else: - qs.failed('Bailed out of Quackery.') + self.failed('Bailed out of Quackery.') -def qput(qs): - qs.expect_nest() - a = qs.from_stack() - qs.expect_something() - b = qs.from_stack() +def qput(self): + self.expect_nest() + a = self.from_stack() + self.expect_something() + b = self.from_stack() a.append(b) -def immovable(qs): +def immovable(self): pass -def take(qs): - qs.expect_nest() - a = qs.from_stack() +def take(self): + self.expect_nest() + a = self.from_stack() if len(a) == 0: - qs.failed('Unexpectedly empty nest.') + self.failed('Unexpectedly empty nest.') if len(a) == 1: if isNest(a[0]) and len(a[0]) > 0 and a[0][0] == immovable: - qs.failed('Cannot remove an immovable item.') - qs.to_stack(a.pop()) - -def create_nest(qs): - qs.to_stack([]) - -def qsplit(qs): - qs.expect_number() - a = qs.from_stack() - qs.expect_nest() - b = qs.from_stack() - qs.to_stack(b[:a]) - qs.to_stack(b[a:]) - -def join(qs): - qs.expect_something() - b = qs.from_stack() + self.failed('Cannot remove an immovable item.') + self.to_stack(a.pop()) + +def create_nest(self): + self.to_stack([]) + +def qsplit(self): + self.expect_number() + a = self.from_stack() + self.expect_nest() + b = self.from_stack() + self.to_stack(b[:a]) + self.to_stack(b[a:]) + +def join(self): + self.expect_something() + b = self.from_stack() if not isNest(b): b = [b] - qs.expect_something() + self.expect_something() a = from_stack() if not isNest(a): a = [a] - qs.to_stack(a + b) + self.to_stack(a + b) -def qsize(qs): - qs.expect_nest() - qs.to_stack(len(qs.from_stack())) +def qsize(self): + self.expect_nest() + self.to_stack(len(self.from_stack())) -def qfind(qs): - qs.expect_nest() - nest = qs.from_stack() - qs.expect_something() - a = qs.from_stack() +def qfind(self): + self.expect_nest() + nest = self.from_stack() + self.expect_something() + a = self.from_stack() if a in nest: - qs.to_stack(nest.index(a)) + self.to_stack(nest.index(a)) else: - qs.to_stack(len(nest)) + self.to_stack(len(nest)) -def peek(qs): - qs.expect_number() - index = qs.from_stack() - qs.expect_nest() - nest = qs.from_stack() +def peek(self): + self.expect_number() + index = self.from_stack() + self.expect_nest() + nest = self.from_stack() if index >= len(nest) or ( index < 0 and len(nest) < abs(index)): failed('Cannot peek an item outside a nest.') else: to_stack(nest[index]) -def poke(qs): - qs.expect_number() - index = qs.from_stack() - qs.expect_nest() - nest = qs.from_stack().copy() - qs.expect_something() - value = qs.from_stack() +def poke(self): + self.expect_number() + index = self.from_stack() + self.expect_nest() + nest = self.from_stack().copy() + self.expect_something() + value = self.from_stack() if index >= len(nest) or ( index < 0 and len(nest) < abs(index)): - qs.failed('Cannot poke an item outside a nest.') + self.failed('Cannot poke an item outside a nest.') else: nest[index] = value - qs.to_stack(nest) + self.to_stack(nest) -def qnest(qs): - qs.expect_something() - qs.bool_to_stack(isNest(qs.from_stack())) +def qnest(self): + self.expect_something() + self.bool_to_stack(isNest(self.from_stack())) -def qnumber(qs): - qs.expect_something() - qs.bool_to_stack(isNumber(qs.from_stack())) +def qnumber(self): + self.expect_something() + self.bool_to_stack(isNumber(self.from_stack())) -def qoperator(qs): - qs.expect_something() - qs.bool_to_stack(isOperator(qs.from_stack())) +def qoperator(self): + self.expect_something() + self.bool_to_stack(isOperator(self.from_stack())) -def quid(qs): - qs.expect_something() - qs.to_stack(id(qs.from_stack())) +def quid(self): + self.expect_something() + self.to_stack(id(self.from_stack())) -def qemit(qs): - qs.expect_number() - char = qs.from_stack() +def qemit(self): + self.expect_number() + char = self.from_stack() if char == 13: sys.stdout.write('\n') elif 31 < char < 127: @@ -548,25 +548,25 @@ def qemit(qs): else: sys.stdout.write('?') # XXX @dragoncoder047 maybe use \uFFFD on platforms that support unicode? -def ding(qs): +def ding(self): sys.stdout.write('\a') -def qinput(qs): - prompt = qs.string_from_stack() - qs.string_to_stack(input(prompt)) +def qinput(self): + prompt = self.string_from_stack() + self.string_to_stack(input(prompt)) filepath = [] -def putfile(qs): - filename = qs.string_from_stack() +def putfile(self): + filename = self.string_from_stack() if len(filepath) > 1: - qs.to_stack(filepath[-1]) - filename = qs.string_from_stack() + filename - filetext = qs.string_from_stack() + self.to_stack(filepath[-1]) + filename = self.string_from_stack() + filename + filetext = self.string_from_stack() try: with open(filename, 'x'): pass except FileExistsError: - qs.to_stack(false) + self.to_stack(false) except: raise else: @@ -575,29 +575,29 @@ def putfile(qs): except: raise else: - qs.to_stack(true) + self.to_stack(true) -def releasefile(qs): +def releasefile(self): nonlocal filepath - filename = qs.string_from_stack() + filename = self.string_from_stack() if len(filepath) > 1: - qs.to_stack(filepath[-1]) - filename = qs.string_from_stack() + filename + self.to_stack(filepath[-1]) + filename = self.string_from_stack() + filename try: os.remove(filename) except FileNotFoundError: - qs.to_stack(false) + self.to_stack(false) except: raise else: - qs.to_stack(true) + self.to_stack(true) -def sharefile(qs): - dup(qs) - filename = qs.string_from_stack() +def sharefile(self): + dup(self) + filename = self.string_from_stack() if len(filepath) > 1: - qs.to_stack(filepath[-1]) - filename = qs.string_from_stack() + filename + self.to_stack(filepath[-1]) + filename = self.string_from_stack() + filename try: with open(filename) as f: filetext = f.read() except FileNotFoundError: @@ -605,9 +605,9 @@ def sharefile(qs): except: raise else: - drop(qs) - qs.string_to_stack(filetext) - qs.to_stack(true) + drop(self) + self.string_to_stack(filetext) + self.to_stack(true) predefined_operators = { 'python': python, # ( $ --> ) @@ -668,66 +668,66 @@ def sharefile(qs): 'sharefile': sharefile # ( $ --> $ b ) } -def qis(qs): - qs.check_build() - name = qs.get_name() - qs.operators[name] = qs.current_build.pop() +def qis(self): + self.check_build() + name = self.get_name() + self.operators[name] = self.current_build.pop() -def qcomment(qs): +def qcomment(self): word = '' while word != ')': - word = qs.next_word() + word = self.next_word() if word == '': raise EOFError('Unclosed comment.') -def endcomment(qs): +def endcomment(self): raise SyntaxError('Too many end of comments.') -def unresolved(qs): +def unresolved(self): raise TypeError('Unresolved forward reference.') -def forward(qs): - qs.current_build.append([unresolved]) +def forward(self): + self.current_build.append([unresolved]) -def resolves(qs): - name = qs.get_name() - if name in qs.operators: - if qs.operators[name][0] != unresolved: +def resolves(self): + name = self.get_name() + if name in self.operators: + if self.operators[name][0] != unresolved: raise TypeError(name + ' is not a forward reference.') - qs.check_build() + self.check_build() operators[name][0] = current_build.pop() else: raise NameError('Unrecognised word: ' + name) -def char_literal(qs): - char = qs.one_char() +def char_literal(self): + char = self.one_char() if char == '': raise SyntaxError('No character found.') - qs.current_build.append(ord(char)) + self.current_build.append(ord(char)) -def string_literal(qs): +def string_literal(self): delimiter = '' result = [] while delimiter == '': - char = qs.next_char() + char = self.next_char() if char == '': raise EOFError('No string found.') if ord(char) > 32: delimiter = char char = '' while char != delimiter: - char = qs.next_char() + char = self.next_char() if char == '': raise EOFError('Endless string discovered.') if char != delimiter: result.append(ord(char)) - qs.current_build.append([[meta_literal], result]) + self.current_build.append([[meta_literal], result]) -def hexnum(qs): - word = qs.get_name() +def hexnum(self): + word = self.get_name() if not ishex(word): raise SyntaxError(word + " is not hexadecimal.") - qs.current_build.append(int(word, 16)) + self.current_build.append(int(word, 16)) predefined_builders = { 'is': qis, @@ -1645,17 +1645,17 @@ def hexnum(qs): del _qs -def quackery(source_string, qs = None): +def quackery(source_string, self = None): - if qs is None: - qs = QuackeryState() + if self is None: + self = QuackeryState() else: - if 'quackery' not in qs.operators.keys(): + if 'quackery' not in self.operators.keys(): raise NameError('QuackeryState must have word `quackery` defined.') while True: - qs.to_stack([ord(char) for char in source_string]) - try: qs.run('quackery') + self.to_stack([ord(char) for char in source_string]) + try: self.run('quackery') except QuackeryError as diagnostics: if __name__ == '__main__' and len(sys.argv) == 1: print(diagnostics) @@ -1667,8 +1667,8 @@ def quackery(source_string, qs = None): print('Python error: ' + str(diagnostics)) raise else: - qs.run('stacksize pack decimal unbuild') - the_stack = qs.from_stack() + self.run('stacksize pack decimal unbuild') + the_stack = self.from_stack() return ''.join(map(chr, the_stack[2:-2])) if __name__ == '__main__': From 62634fedbd7412dec9e315ed9ab0727d2aae474c Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Thu, 28 Apr 2022 18:06:52 -0400 Subject: [PATCH 005/121] python fix --- quackery.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/quackery.py b/quackery.py index 5fbee44..e3986f9 100644 --- a/quackery.py +++ b/quackery.py @@ -28,10 +28,7 @@ def ishex(string): hexstr = string if len(hexstr) > 1 and hexstr[0] == '-': hexstr = hexstr[1:] - for char in hexstr: - if char.lower() not in '0123456789abcdef': - return False - return True + return all(char.lower() in '0123456789abcdef' for char in hexstr): class QuackeryError(Exception): pass From baf404e7091ab2f5bd385f711636349b19dbde38 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Thu, 28 Apr 2022 18:09:16 -0400 Subject: [PATCH 006/121] rename quackery context, not `self` --- quackery.py | 610 ++++++++++++++++++++++++++-------------------------- 1 file changed, 305 insertions(+), 305 deletions(-) diff --git a/quackery.py b/quackery.py index e3986f9..f0425dc 100644 --- a/quackery.py +++ b/quackery.py @@ -33,7 +33,7 @@ def ishex(string): class QuackeryError(Exception): pass -class QuackeryState: +class QuackeryContext: def __init__(self, qstack = None, operators = None, builders = None): self.qstack = [] if qstack is None else qstack self.rstack = [] @@ -45,7 +45,7 @@ def __init__(self, qstack = None, operators = None, builders = None): self.current_build = [] def copy(self): - new = QuackeryState(self.qstack.copy(), self.operators.copy(), self.builders.copy()) + new = QuackeryContext(self.qstack.copy(), self.operators.copy(), self.builders.copy()) new.rstack = self.rstack.copy() new.program_counter = self.program_counter new.current_nest = self.current_nest.copy() @@ -229,315 +229,315 @@ def bootstrap(self): -def python(self): +def python(ctx): """For backwards compatibility only""" scope = { - "to_stack": self.to_stack, - "from_stack": self.from_stack, - "string_to_stack": self.string_to_stack, - "string_from_stack": self.string_from_stack, - "self": self, + "to_stack": ctx.to_stack, + "from_stack": ctx.from_stack, + "string_to_stack": ctx.string_to_stack, + "string_from_stack": ctx.string_from_stack, + "ctx": ctx, } try: - exec(self.string_from_stack(), scope, globals()) + exec(ctx.string_from_stack(), scope, globals()) except QuackeryError: raise except Exception as diagnostics: - self.failed('Python reported: "' + str(diagnostics) + '"') + ctx.failed('Python reported: "' + str(diagnostics) + '"') -def qfail(self): - self.failed(self.string_from_stack()) +def qfail(ctx): + ctx.failed(ctx.string_from_stack()) -def stack_size(self): - self.to_stack(len(self.qstack)) +def stack_size(ctx): + ctx.to_stack(len(ctx.qstack)) -def qreturn(self): - self.to_stack(self.rstack) +def qreturn(ctx): + ctx.to_stack(ctx.rstack) -def dup(self): - a = self.from_stack() - self.to_stack(a) - self.to_stack(a) +def dup(ctx): + a = ctx.from_stack() + ctx.to_stack(a) + ctx.to_stack(a) -def drop(self): - self.from_stack() +def drop(ctx): + ctx.from_stack() -def swap(self): - a = self.from_stack() - b = self.from_stack() - self.to_stack(a) - self.to_stack(b) +def swap(ctx): + a = ctx.from_stack() + b = ctx.from_stack() + ctx.to_stack(a) + ctx.to_stack(b) -def rot(self): # XXX @dragoncoder047 maybe simplify to [ dip swap swap ] is rot ? There are no cyclic references that would prevent this - a = self.from_stack() - swap(self) - self.to_stack(a) - swap(self) +def rot(ctx): # XXX @dragoncoder047 maybe simplify to [ dip swap swap ] is rot ? There are no cyclic references that would prevent this + a = ctx.from_stack() + swap(ctx) + ctx.to_stack(a) + swap(ctx) -def over(self): # XXX @dragoncoder047 maybe simplify to [ dip dup swap ] is over ? same reason as above - a = self.from_stack() - dup(self) - self.to_stack(a) - swap(self) +def over(ctx): # XXX @dragoncoder047 maybe simplify to [ dip dup swap ] is over ? same reason as above + a = ctx.from_stack() + dup(ctx) + ctx.to_stack(a) + swap(ctx) -def nest_depth(self): - self.to_stack(len(self.rstack) // 2) +def nest_depth(ctx): + ctx.to_stack(len(ctx.rstack) // 2) true = 1 false = 0 -def nand(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.bool_to_stack(self.from_stack() == false or a == false) - -def equal(self): - self.expect_something() - a = self.from_stack() - self.expect_something() - self.bool_to_stack(a == self.from_stack()) - -def greater(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.bool_to_stack(self.from_stack() > a) - -def inc(self): - self.expect_number() - self.to_stack(1 + self.from_stack()) - -def plus(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.to_stack(a + self.from_stack()) - -def negate(self): - self.expect_number() - self.to_stack(-self.from_stack()) - -def multiply(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.to_stack(a * self.from_stack()) - -def qdivmod(self): - self.expect_number() - a = self.from_stack() +def nand(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.bool_to_stack(ctx.from_stack() == false or a == false) + +def equal(ctx): + ctx.expect_something() + a = ctx.from_stack() + ctx.expect_something() + ctx.bool_to_stack(a == ctx.from_stack()) + +def greater(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.bool_to_stack(ctx.from_stack() > a) + +def inc(ctx): + ctx.expect_number() + ctx.to_stack(1 + ctx.from_stack()) + +def plus(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.to_stack(a + ctx.from_stack()) + +def negate(ctx): + ctx.expect_number() + ctx.to_stack(-ctx.from_stack()) + +def multiply(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.to_stack(a * ctx.from_stack()) + +def qdivmod(ctx): + ctx.expect_number() + a = ctx.from_stack() if a == 0: - self.failed('Division by zero.') - self.expect_number() - results = divmod(self.from_stack(), a) - self.to_stack(results[0]) - self.to_stack(results[1]) - -def exponentiate(self): - self.expect_number() - a = self.from_stack() + ctx.failed('Division by zero.') + ctx.expect_number() + results = divmod(ctx.from_stack(), a) + ctx.to_stack(results[0]) + ctx.to_stack(results[1]) + +def exponentiate(ctx): + ctx.expect_number() + a = ctx.from_stack() if a < 0: - self.failed('Tried to raise to a negative power: ' + str(a)) - self.expect_number() - self.to_stack(self.from_stack() ** a) + ctx.failed('Tried to raise to a negative power: ' + str(a)) + ctx.expect_number() + ctx.to_stack(ctx.from_stack() ** a) -def shift_left(self): - self.expect_number() - a = self.from_stack() +def shift_left(ctx): + ctx.expect_number() + a = ctx.from_stack() if a < 0: - self.failed('Cannot << by a negative amount: ' + str(a)) - self.expect_number() - self.to_stack(self.from_stack() << a) + ctx.failed('Cannot << by a negative amount: ' + str(a)) + ctx.expect_number() + ctx.to_stack(ctx.from_stack() << a) -def shift_right(self): - self.expect_number() - a = self.from_stack() +def shift_right(ctx): + ctx.expect_number() + a = ctx.from_stack() if a < 0: - self.failed('Cannot >> by a negative amount: ' + str(a)) - self.expect_number() - self.to_stack(self.from_stack() >> a) - -def bitwise_and(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.to_stack(a & self.from_stack()) - -def bitwise_or(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.to_stack(a | self.from_stack()) - -def bitwise_xor(self): - self.expect_number() - a = self.from_stack() - self.expect_number() - self.to_stack(a ^ self.from_stack()) - -def bitwise_not(self): - self.expect_number() - self.to_stack(~self.from_stack()) - -def qtime(self): - self.to_stack(int(time.time()*1000000)) - -def meta_done(self): - self.from_return() - self.from_return() - -def meta_again(self): - self.from_return() - self.to_return(-1) - -def meta_if(self): - self.expect_number() - if self.from_stack() == 0: - self.to_return(self.from_return() + 1) - -def meta_iff(self): - self.expect_number() - if self.from_stack() == 0: - self.to_return(self.from_return() + 2) - -def meta_else(self): - self.to_return(self.from_return() + 1) - -def meta_literal(self): - pc = self.from_return() + 1 - return_nest = self.from_return() + ctx.failed('Cannot >> by a negative amount: ' + str(a)) + ctx.expect_number() + ctx.to_stack(ctx.from_stack() >> a) + +def bitwise_and(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.to_stack(a & ctx.from_stack()) + +def bitwise_or(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.to_stack(a | ctx.from_stack()) + +def bitwise_xor(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_number() + ctx.to_stack(a ^ ctx.from_stack()) + +def bitwise_not(ctx): + ctx.expect_number() + ctx.to_stack(~ctx.from_stack()) + +def qtime(ctx): + ctx.to_stack(int(time.time()*1000000)) + +def meta_done(ctx): + ctx.from_return() + ctx.from_return() + +def meta_again(ctx): + ctx.from_return() + ctx.to_return(-1) + +def meta_if(ctx): + ctx.expect_number() + if ctx.from_stack() == 0: + ctx.to_return(ctx.from_return() + 1) + +def meta_iff(ctx): + ctx.expect_number() + if ctx.from_stack() == 0: + ctx.to_return(ctx.from_return() + 2) + +def meta_else(ctx): + ctx.to_return(ctx.from_return() + 1) + +def meta_literal(ctx): + pc = ctx.from_return() + 1 + return_nest = ctx.from_return() if len(return_nest) == pc: - self.failed('Found a "\'" at the end of a nest.') - self.to_stack(return_nest[pc]) - self.to_return(return_nest) - self.to_return(pc) - -def meta_this(self): - pc = self.from_return() - return_nest = self.from_return() - self.to_stack(return_nest) - self.to_return(return_nest) - self.to_return(pc) - -def meta_do(self): - self.expect_something() - the_thing = self.from_stack() + ctx.failed('Found a "\'" at the end of a nest.') + ctx.to_stack(return_nest[pc]) + ctx.to_return(return_nest) + ctx.to_return(pc) + +def meta_this(ctx): + pc = ctx.from_return() + return_nest = ctx.from_return() + ctx.to_stack(return_nest) + ctx.to_return(return_nest) + ctx.to_return(pc) + +def meta_do(ctx): + ctx.expect_something() + the_thing = ctx.from_stack() if not isNest(the_thing): the_thing = [the_thing] - self.to_return(the_thing) - self.to_return(-1) + ctx.to_return(the_thing) + ctx.to_return(-1) -def meta_bail_by(self): - self.expect_number() - a = 2 * self.from_stack() - if a <= len(self.rstack): +def meta_bail_by(ctx): + ctx.expect_number() + a = 2 * ctx.from_stack() + if a <= len(ctx.rstack): for _ in range(a): - self.from_return() + ctx.from_return() else: - self.failed('Bailed out of Quackery.') + ctx.failed('Bailed out of Quackery.') -def qput(self): - self.expect_nest() - a = self.from_stack() - self.expect_something() - b = self.from_stack() +def qput(ctx): + ctx.expect_nest() + a = ctx.from_stack() + ctx.expect_something() + b = ctx.from_stack() a.append(b) -def immovable(self): +def immovable(ctx): pass -def take(self): - self.expect_nest() - a = self.from_stack() +def take(ctx): + ctx.expect_nest() + a = ctx.from_stack() if len(a) == 0: - self.failed('Unexpectedly empty nest.') + ctx.failed('Unexpectedly empty nest.') if len(a) == 1: if isNest(a[0]) and len(a[0]) > 0 and a[0][0] == immovable: - self.failed('Cannot remove an immovable item.') - self.to_stack(a.pop()) - -def create_nest(self): - self.to_stack([]) - -def qsplit(self): - self.expect_number() - a = self.from_stack() - self.expect_nest() - b = self.from_stack() - self.to_stack(b[:a]) - self.to_stack(b[a:]) - -def join(self): - self.expect_something() - b = self.from_stack() + ctx.failed('Cannot remove an immovable item.') + ctx.to_stack(a.pop()) + +def create_nest(ctx): + ctx.to_stack([]) + +def qsplit(ctx): + ctx.expect_number() + a = ctx.from_stack() + ctx.expect_nest() + b = ctx.from_stack() + ctx.to_stack(b[:a]) + ctx.to_stack(b[a:]) + +def join(ctx): + ctx.expect_something() + b = ctx.from_stack() if not isNest(b): b = [b] - self.expect_something() + ctx.expect_something() a = from_stack() if not isNest(a): a = [a] - self.to_stack(a + b) + ctx.to_stack(a + b) -def qsize(self): - self.expect_nest() - self.to_stack(len(self.from_stack())) +def qsize(ctx): + ctx.expect_nest() + ctx.to_stack(len(ctx.from_stack())) -def qfind(self): - self.expect_nest() - nest = self.from_stack() - self.expect_something() - a = self.from_stack() +def qfind(ctx): + ctx.expect_nest() + nest = ctx.from_stack() + ctx.expect_something() + a = ctx.from_stack() if a in nest: - self.to_stack(nest.index(a)) + ctx.to_stack(nest.index(a)) else: - self.to_stack(len(nest)) + ctx.to_stack(len(nest)) -def peek(self): - self.expect_number() - index = self.from_stack() - self.expect_nest() - nest = self.from_stack() +def peek(ctx): + ctx.expect_number() + index = ctx.from_stack() + ctx.expect_nest() + nest = ctx.from_stack() if index >= len(nest) or ( index < 0 and len(nest) < abs(index)): failed('Cannot peek an item outside a nest.') else: to_stack(nest[index]) -def poke(self): - self.expect_number() - index = self.from_stack() - self.expect_nest() - nest = self.from_stack().copy() - self.expect_something() - value = self.from_stack() +def poke(ctx): + ctx.expect_number() + index = ctx.from_stack() + ctx.expect_nest() + nest = ctx.from_stack().copy() + ctx.expect_something() + value = ctx.from_stack() if index >= len(nest) or ( index < 0 and len(nest) < abs(index)): - self.failed('Cannot poke an item outside a nest.') + ctx.failed('Cannot poke an item outside a nest.') else: nest[index] = value - self.to_stack(nest) + ctx.to_stack(nest) -def qnest(self): - self.expect_something() - self.bool_to_stack(isNest(self.from_stack())) +def qnest(ctx): + ctx.expect_something() + ctx.bool_to_stack(isNest(ctx.from_stack())) -def qnumber(self): - self.expect_something() - self.bool_to_stack(isNumber(self.from_stack())) +def qnumber(ctx): + ctx.expect_something() + ctx.bool_to_stack(isNumber(ctx.from_stack())) -def qoperator(self): - self.expect_something() - self.bool_to_stack(isOperator(self.from_stack())) +def qoperator(ctx): + ctx.expect_something() + ctx.bool_to_stack(isOperator(ctx.from_stack())) -def quid(self): - self.expect_something() - self.to_stack(id(self.from_stack())) +def quid(ctx): + ctx.expect_something() + ctx.to_stack(id(ctx.from_stack())) -def qemit(self): - self.expect_number() - char = self.from_stack() +def qemit(ctx): + ctx.expect_number() + char = ctx.from_stack() if char == 13: sys.stdout.write('\n') elif 31 < char < 127: @@ -545,25 +545,25 @@ def qemit(self): else: sys.stdout.write('?') # XXX @dragoncoder047 maybe use \uFFFD on platforms that support unicode? -def ding(self): +def ding(ctx): sys.stdout.write('\a') -def qinput(self): - prompt = self.string_from_stack() - self.string_to_stack(input(prompt)) +def qinput(ctx): + prompt = ctx.string_from_stack() + ctx.string_to_stack(input(prompt)) filepath = [] -def putfile(self): - filename = self.string_from_stack() +def putfile(ctx): + filename = ctx.string_from_stack() if len(filepath) > 1: - self.to_stack(filepath[-1]) - filename = self.string_from_stack() + filename - filetext = self.string_from_stack() + ctx.to_stack(filepath[-1]) + filename = ctx.string_from_stack() + filename + filetext = ctx.string_from_stack() try: with open(filename, 'x'): pass except FileExistsError: - self.to_stack(false) + ctx.to_stack(false) except: raise else: @@ -572,29 +572,29 @@ def putfile(self): except: raise else: - self.to_stack(true) + ctx.to_stack(true) -def releasefile(self): +def releasefile(ctx): nonlocal filepath - filename = self.string_from_stack() + filename = ctx.string_from_stack() if len(filepath) > 1: - self.to_stack(filepath[-1]) - filename = self.string_from_stack() + filename + ctx.to_stack(filepath[-1]) + filename = ctx.string_from_stack() + filename try: os.remove(filename) except FileNotFoundError: - self.to_stack(false) + ctx.to_stack(false) except: raise else: - self.to_stack(true) + ctx.to_stack(true) -def sharefile(self): - dup(self) - filename = self.string_from_stack() +def sharefile(ctx): + dup(ctx) + filename = ctx.string_from_stack() if len(filepath) > 1: - self.to_stack(filepath[-1]) - filename = self.string_from_stack() + filename + ctx.to_stack(filepath[-1]) + filename = ctx.string_from_stack() + filename try: with open(filename) as f: filetext = f.read() except FileNotFoundError: @@ -602,9 +602,9 @@ def sharefile(self): except: raise else: - drop(self) - self.string_to_stack(filetext) - self.to_stack(true) + drop(ctx) + ctx.string_to_stack(filetext) + ctx.to_stack(true) predefined_operators = { 'python': python, # ( $ --> ) @@ -665,66 +665,66 @@ def sharefile(self): 'sharefile': sharefile # ( $ --> $ b ) } -def qis(self): - self.check_build() - name = self.get_name() - self.operators[name] = self.current_build.pop() +def qis(ctx): + ctx.check_build() + name = ctx.get_name() + ctx.operators[name] = ctx.current_build.pop() -def qcomment(self): +def qcomment(ctx): word = '' while word != ')': - word = self.next_word() + word = ctx.next_word() if word == '': raise EOFError('Unclosed comment.') -def endcomment(self): +def endcomment(ctx): raise SyntaxError('Too many end of comments.') -def unresolved(self): +def unresolved(ctx): raise TypeError('Unresolved forward reference.') -def forward(self): - self.current_build.append([unresolved]) +def forward(ctx): + ctx.current_build.append([unresolved]) -def resolves(self): - name = self.get_name() - if name in self.operators: - if self.operators[name][0] != unresolved: +def resolves(ctx): + name = ctx.get_name() + if name in ctx.operators: + if ctx.operators[name][0] != unresolved: raise TypeError(name + ' is not a forward reference.') - self.check_build() + ctx.check_build() operators[name][0] = current_build.pop() else: raise NameError('Unrecognised word: ' + name) -def char_literal(self): - char = self.one_char() +def char_literal(ctx): + char = ctx.one_char() if char == '': raise SyntaxError('No character found.') - self.current_build.append(ord(char)) + ctx.current_build.append(ord(char)) -def string_literal(self): +def string_literal(ctx): delimiter = '' result = [] while delimiter == '': - char = self.next_char() + char = ctx.next_char() if char == '': raise EOFError('No string found.') if ord(char) > 32: delimiter = char char = '' while char != delimiter: - char = self.next_char() + char = ctx.next_char() if char == '': raise EOFError('Endless string discovered.') if char != delimiter: result.append(ord(char)) - self.current_build.append([[meta_literal], result]) + ctx.current_build.append([[meta_literal], result]) -def hexnum(self): - word = self.get_name() +def hexnum(ctx): + word = ctx.get_name() if not ishex(word): raise SyntaxError(word + " is not hexadecimal.") - self.current_build.append(int(word, 16)) + ctx.current_build.append(int(word, 16)) predefined_builders = { 'is': qis, @@ -1636,23 +1636,23 @@ def hexnum(self): """ # bootstrap only once -_qs = QuackeryState() +_qs = QuackeryContext() _qs.bootstrap() predefined_operators = _qs.operators del _qs -def quackery(source_string, self = None): +def quackery(source_string, ctx = None): - if self is None: - self = QuackeryState() + if ctx is None: + ctx = QuackeryContext() else: - if 'quackery' not in self.operators.keys(): - raise NameError('QuackeryState must have word `quackery` defined.') + if 'quackery' not in ctx.operators.keys(): + raise NameError('QuackeryContext must have word `quackery` defined.') while True: - self.to_stack([ord(char) for char in source_string]) - try: self.run('quackery') + ctx.to_stack([ord(char) for char in source_string]) + try: ctx.run('quackery') except QuackeryError as diagnostics: if __name__ == '__main__' and len(sys.argv) == 1: print(diagnostics) @@ -1664,8 +1664,8 @@ def quackery(source_string, self = None): print('Python error: ' + str(diagnostics)) raise else: - self.run('stacksize pack decimal unbuild') - the_stack = self.from_stack() + ctx.run('stacksize pack decimal unbuild') + the_stack = ctx.from_stack() return ''.join(map(chr, the_stack[2:-2])) if __name__ == '__main__': From 029a297c34b389bc385b03107ba2d3fa2985690a Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 07:44:56 -0400 Subject: [PATCH 007/121] syntax error --- quackery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quackery.py b/quackery.py index f0425dc..6bde8a2 100644 --- a/quackery.py +++ b/quackery.py @@ -28,7 +28,7 @@ def ishex(string): hexstr = string if len(hexstr) > 1 and hexstr[0] == '-': hexstr = hexstr[1:] - return all(char.lower() in '0123456789abcdef' for char in hexstr): + return all(char.lower() in '0123456789abcdef' for char in hexstr) class QuackeryError(Exception): pass From ea99454f1179ee5d648949dd30025c2653153188 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 07:52:05 -0400 Subject: [PATCH 008/121] simplify --- quackery.py | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/quackery.py b/quackery.py index 6bde8a2..853cbe5 100644 --- a/quackery.py +++ b/quackery.py @@ -18,17 +18,15 @@ def isNumber(item): def isOperator(item): return isinstance(item, types.FunctionType) -def isinteger(string): - numstr = string +def isinteger(numstr): if len(numstr) > 0 and numstr[0] == '-': numstr = numstr[1:] return numstr.isdigit() -def ishex(string): - hexstr = string - if len(hexstr) > 1 and hexstr[0] == '-': - hexstr = hexstr[1:] - return all(char.lower() in '0123456789abcdef' for char in hexstr) +def ishex(hexstr): + if len(hexstr) > 1 and hexstr[0] == '-': + hexstr = hexstr[1:] + return all(char.lower() in '0123456789abcdef' for char in hexstr) class QuackeryError(Exception): pass From b1c950862650316bf4ad9e70fd8e495a5b9a082e Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 07:55:11 -0400 Subject: [PATCH 009/121] typo --- quackery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quackery.py b/quackery.py index 853cbe5..4c66280 100644 --- a/quackery.py +++ b/quackery.py @@ -104,7 +104,7 @@ def bool_to_stack(self, qbool): def to_return(self, item): self.rstack.append(item) - def from_return(self.): + def from_return(self): if len(self.rstack) == 0: self.failed('Return stack unexpectedly empty.') return self.rstack.pop() From e1364952970829ccea4ee0224cd7203878d2d222 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 08:00:29 -0400 Subject: [PATCH 010/121] stray nonlocal --- quackery.py | 1 - 1 file changed, 1 deletion(-) diff --git a/quackery.py b/quackery.py index 4c66280..fd0ce74 100644 --- a/quackery.py +++ b/quackery.py @@ -573,7 +573,6 @@ def putfile(ctx): ctx.to_stack(true) def releasefile(ctx): - nonlocal filepath filename = ctx.string_from_stack() if len(filepath) > 1: ctx.to_stack(filepath[-1]) From 12680aa9d9264118649a700aa1856a63e3fbeeb5 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 09:27:17 -0400 Subject: [PATCH 011/121] bunch of typos --- quackery.py | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/quackery.py b/quackery.py index fd0ce74..47cdaf3 100644 --- a/quackery.py +++ b/quackery.py @@ -140,9 +140,11 @@ def tick(self): def traverse(self, the_nest): + orig_depth = len(self.rstack) + self.to_return(self.current_nest) + self.to_return(self.program_counter) self.current_nest = the_nest self.program_counter = 0 - orig_depth = len(self.rstack) while len(self.rstack) > orig_depth: self.tick() @@ -176,7 +178,7 @@ def one_char(self): return char def get_name(self): - name = selfnext_word() + name = self.next_word() if name == '': raise EOFError('Unexpected end of program text.') return name @@ -204,7 +206,7 @@ def sub_build(): nesting -= 1 if nesting < 0: raise SyntaxError('Unexpected end of nest.') - return(the_nest) + return the_nest elif word in self.builders.keys(): self.builders[word](self) elif word in self.operators.keys(): @@ -222,9 +224,6 @@ def sub_build(): def run(self, source_string): self.traverse(self.build(source_string)) - def bootstrap(self): - self.run(predefined_qky) - def python(ctx): @@ -689,7 +688,7 @@ def resolves(ctx): if ctx.operators[name][0] != unresolved: raise TypeError(name + ' is not a forward reference.') ctx.check_build() - operators[name][0] = current_build.pop() + ctx.operators[name][0] = current_build.pop() else: raise NameError('Unrecognised word: ' + name) @@ -1634,7 +1633,7 @@ def hexnum(ctx): # bootstrap only once _qs = QuackeryContext() -_qs.bootstrap() +_qs.run(predefined_qky) predefined_operators = _qs.operators del _qs @@ -1644,12 +1643,14 @@ def quackery(source_string, ctx = None): if ctx is None: ctx = QuackeryContext() else: - if 'quackery' not in ctx.operators.keys(): - raise NameError('QuackeryContext must have word `quackery` defined.') + for required_word in ('stacksize', 'pack', 'decimal', 'unbuild', 'quackery'): + if required_word not in ctx.operators.keys(): + raise NameError('QuackeryContext must have word %s defined.' % required_word) while True: ctx.to_stack([ord(char) for char in source_string]) - try: ctx.run('quackery') + try: + ctx.run('quackery') except QuackeryError as diagnostics: if __name__ == '__main__' and len(sys.argv) == 1: print(diagnostics) @@ -1682,6 +1683,7 @@ def quackery(source_string, ctx = None): print('\nQuackery crashed.\n') print(diagnostics) print() + sys.exit(1) except Exception as diagnostics: print('Quackery system damage detected.') print('Python error: ' + str(diagnostics)) @@ -1689,17 +1691,15 @@ def quackery(source_string, ctx = None): else: print('\nWelcome to Quackery.') print('\nEnter "leave" to leave the shell.') - quackscript = r""" + try: + quackery(r""" $ 'extensions.qky' dup name? not dip sharefile and iff [ cr say 'Building extensions.' cr quackery ] else drop - shell """ - - try: - quackery(quackscript) + shell """) except QuackeryError as diagnostics: print('\nQuackery crashed.\n') print(diagnostics) From 89528827c179430d153a4adc7741e4cda08e136e Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 09:31:04 -0400 Subject: [PATCH 012/121] typo --- quackery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quackery.py b/quackery.py index 47cdaf3..d34947b 100644 --- a/quackery.py +++ b/quackery.py @@ -688,7 +688,7 @@ def resolves(ctx): if ctx.operators[name][0] != unresolved: raise TypeError(name + ' is not a forward reference.') ctx.check_build() - ctx.operators[name][0] = current_build.pop() + ctx.operators[name][0] = ctx.current_build.pop() else: raise NameError('Unrecognised word: ' + name) From 69b215fab346ecc223f2ef4651a7227c040391eb Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 09:42:38 -0400 Subject: [PATCH 013/121] 2 typos --- quackery.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quackery.py b/quackery.py index d34947b..8541861 100644 --- a/quackery.py +++ b/quackery.py @@ -125,8 +125,8 @@ def tick(self): return current_item = self.current_nest[self.program_counter] if isNest(current_item): - self.to_return(current_nest) - self.to_return(program_counter) + self.to_return(self.current_nest) + self.to_return(self.program_counter) self.current_nest = current_item self.program_counter = 0 elif isOperator(current_item): From 2f266ff343e75e5bde7b7799b2564f7874bee57a Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 09:50:00 -0400 Subject: [PATCH 014/121] typo!!!!!! --- quackery.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quackery.py b/quackery.py index 8541861..b613d2f 100644 --- a/quackery.py +++ b/quackery.py @@ -472,7 +472,7 @@ def join(ctx): if not isNest(b): b = [b] ctx.expect_something() - a = from_stack() + a = ctx.from_stack() if not isNest(a): a = [a] ctx.to_stack(a + b) From 81d5fd0a53ceb9897dff942f8763e6c597a2919a Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 10:23:37 -0400 Subject: [PATCH 015/121] i think I got everything --- quackery.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/quackery.py b/quackery.py index b613d2f..41e5120 100644 --- a/quackery.py +++ b/quackery.py @@ -498,9 +498,9 @@ def peek(ctx): nest = ctx.from_stack() if index >= len(nest) or ( index < 0 and len(nest) < abs(index)): - failed('Cannot peek an item outside a nest.') + ctx.failed('Cannot peek an item outside a nest.') else: - to_stack(nest[index]) + ctx.to_stack(nest[index]) def poke(ctx): ctx.expect_number() @@ -594,7 +594,7 @@ def sharefile(ctx): try: with open(filename) as f: filetext = f.read() except FileNotFoundError: - qsto_stack(false) + ctx.to_stack(false) except: raise else: From 3c0bb2411849b286aff936208693a744ff7f15cf Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Fri, 29 Apr 2022 13:13:04 -0400 Subject: [PATCH 016/121] add `__all__` --- quackery.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/quackery.py b/quackery.py index 41e5120..e551585 100644 --- a/quackery.py +++ b/quackery.py @@ -9,6 +9,8 @@ except: pass +__all__ = ['QuackeryContext', 'quackery'] + def isNest(item): return isinstance(item, list) From 893dbbe014bd651380e2a0a334281f878f7bb763 Mon Sep 17 00:00:00 2001 From: dragoncoder047 <101021094+dragoncoder047@users.noreply.github.com> Date: Sat, 30 Apr 2022 12:17:44 -0400 Subject: [PATCH 017/121] add index.html for web console --- index.html | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 index.html diff --git a/index.html b/index.html new file mode 100644 index 0000000..6497216 --- /dev/null +++ b/index.html @@ -0,0 +1,17 @@ + + +
++ The Book of Quackery + ----- + Quackery on Github +
+The Book of Quackery ----- Quackery on Github + ----- + Quackery on RosettaCode