From a4e2a1997a85fed9134fd4de319367995b809529 Mon Sep 17 00:00:00 2001 From: Russ Olsen Date: Thu, 23 Apr 2020 09:10:27 -0400 Subject: [PATCH] Clean up attr resolution. --- sallyforth/list.sf | 30 +++---- sallyforth/namespace.py | 2 +- sallyforth/sallyforth.py | 1 + sallyforth/startup.sf | 27 +++--- sallyforth/words.py | 181 +++++++++++++++++++++++++++++---------- 5 files changed, 164 insertions(+), 77 deletions(-) diff --git a/sallyforth/list.sf b/sallyforth/list.sf index 3f9e954..3b2c313 100644 --- a/sallyforth/list.sf +++ b/sallyforth/list.sf @@ -1,17 +1,14 @@ "List" p -: [n] (n list -- nth-item) - 2 ->list \ Make the arg list. - <. builtins.list '__getitem__ .> \ Find the getitem method. - !! \ Call! -; +\ Index into the x'th item. +: [x] (col key -- value) 1 ->list '__getitem__ .!! ; -: first (list -- first-item) 0 swap [n] ; -: second (list -- second-item) 1 swap [n] ; -: third (list -- third-item) 2 swap [n] ; -: fourth (list -- fourth-item) 3 swap [n] ; +: first (list -- first-item) 0 [x] ; +: second (list -- second-item) 1 [x] ; +: third (list -- third-item) 2 [x] ; +: fourth (list -- fourth-item) 3 [x] ; -: last (list -- last-item) -1 swap [n] ; +: last (list -- last-item) -1 [x] ; : slice (start stop -- slice-obj) swap @@ -22,15 +19,18 @@ : take (n list -- first-n-items) swap 0 swap slice \ Make the 0..n slice. - swap [n] \ Do a[0..n]. + [x] \ Do a[0..n]. ; : drop (n list -- all-but-first-n-items) swap nil slice \ Make the n..None slice. - swap [n] + [x] ; - - +: rest (list -- all-but-first) 1 swap drop ; +: rrest (list -- rest-of-rest) rest rest ; +: rrrest (list -- all-but-first) rest rest rest ; - +: first (list -- first-item) 1 swap drop ; +: ffirst (list -- first-of-first) first first ; +: fffirst (list -- fff-irst) first first first ; diff --git a/sallyforth/namespace.py b/sallyforth/namespace.py index 5d11ab1..13acbb0 100644 --- a/sallyforth/namespace.py +++ b/sallyforth/namespace.py @@ -62,7 +62,7 @@ class Namespace: return self.contents.__iter__() def __getitem__(self, key): - # print("get item", key, self.contents) + #print("get item", key, self.name) if key in self.contents: return self.contents[key] # print("not in local ns") diff --git a/sallyforth/sallyforth.py b/sallyforth/sallyforth.py index 2537978..0007aeb 100644 --- a/sallyforth/sallyforth.py +++ b/sallyforth/sallyforth.py @@ -50,6 +50,7 @@ def repl(f): line = input(p) except KeyboardInterrupt: print("<>") + f.stack.reset() line = '' except EOFError: break diff --git a/sallyforth/startup.sf b/sallyforth/startup.sf index 8c3a5d9..775df3d 100644 --- a/sallyforth/startup.sf +++ b/sallyforth/startup.sf @@ -15,11 +15,11 @@ 'dot '. alias 'colon ': alias 'semi '; alias +'thread '@@ alias 'bounded_list '[list] alias 'list '->list alias 'to_arglist '->arglist alias 'list_to_map 'list->map alias -'lookup '@@ alias 'call '!! alias 'add '+ alias 'sub '- alias @@ -59,11 +59,8 @@ : [: [ ; : :] ] ->arglist ; -: => [ ; -: >! ] arrow ; - : <. [ ; -: .> ] arrow ; +: .> ] thread ; : !!0 [] swap call ; @@ -84,26 +81,24 @@ : p . nl ; : top dup p ; -: -- -1 + ; -: ++ 1 + ; +: -- -1 + ; +: ++ 1 + ; +: *2 2 * ; : pos? 0 > ; : neg? 0 < ; : zero? 0 = ; : source-if-exists - (path --) - dup - 1 ->list os.path.exists - if source else drop then + (path --) + dup + 1 ->list os.path.exists + if source else drop then ; -: << [ ; -: >>@ ] @@ ; -: >>! ] @@ [] swap !! ; +: getattr (x 'fieldname -- field) swap 2 ->list builtins.getattr ; +: .!! (obj args method-name -- result) tbm getattr !! ; "string.sf" source "list.sf" source "init.sf" source-if-exists - - diff --git a/sallyforth/words.py b/sallyforth/words.py index a1e6007..e80a0a9 100644 --- a/sallyforth/words.py +++ b/sallyforth/words.py @@ -1,5 +1,6 @@ from inspect import isfunction, isbuiltin import importlib +import os from compiler import Compiler from arglist import Arglist @@ -16,8 +17,11 @@ def const_f(value): def native_function_handler(func): def handle(forth, i): args = forth.stack.pop() + #print(f"Native fun, calling {func}({args})") result = func(*args) + #print(f'Result: {result}') forth.stack.push(result) + #print("pushed result") return i + 1 return handle @@ -35,6 +39,11 @@ def import_native_module(forth, m, alias=None, excludes=[]): else: forth.namespace[localname] = const_f(val) +def w_eval(f, i): + token = f.stack.pop() + f.execute_token(token) + return i+1 + def w_no_op(f, i): return i+1 @@ -74,10 +83,35 @@ def w_require(f, i): import_native_module(f, m, name) return i + 1 +def source(f, path): + old_source_f = f.namespace.get('*source*', None) + old_namespace = f.namespace + try: + f.execute_file(path) + finally: + f.namespace['*source*'] = old_source_f + f.namespace = old_namespace + +def w_load(f, i): + path = f.stack.pop() + source(f, path) + return i + 1 + def w_source(f, i): path = f.stack.pop() - f.execute_file(path) - return i + 1 + if os.path.isabs(path): + source(f, path) + return i+1 + + relative_dir = os.path.dirname(f.evaluate_token('*source*')) + relative_path = f'{relative_dir}/{path}' + if os.path.exists(relative_path): + source(f, relative_path) + return i+1 + + source(f, path) + return i+1 + def execute_f(name, instructions): #print('execute_f:', name, len(instructions)) @@ -140,6 +174,43 @@ def w_unique(f, ip): # pushes a uique object. f.stack.push(Unique()) return ip+1 +def w_map(f, ip): + l = f.stack.pop() + word = f.stack.pop() + + word_f = f.namespace.get(word, None) + result = [] + + for item in l: + f.stack.push(item) + word_f(f, 0) + result.append(f.stack.pop()) + + f.stack.push(result) + return ip+1 + +def w_reduce(f, ip): + l = f.stack.pop() + word = f.stack.pop() + + word_f = f.namespace.get(word, None) + + if len(l) <= 0: + f.stack.push(None) + elif len(l) == 1: + f.stack.push(l[0]) + else: + result = l[0] + l = l[1::-1] + for item in l: + f.stack.push(result) + f.stack.push(item) + word_f(f, 0) + result = f.stack.pop() + f.stack.push(result) + + return ip+1 + def w_bounded_list(f, ip): """Create a list from delimted values on the stack. [list] @@ -168,34 +239,17 @@ def w_list(f, ip): # ->list f.stack.push(l) return ip+1 -def qqw_lookup(f, i): # @@ - l = f.stack.pop() - value = l[0] - for field in l[1::]: - value = getattr(value, field) - f.stack.push(value) - return i+1 - -def w_lookup(f, i): # -> - value = f.stack.pop() - fields = f.stack.pop() - print(f'value {value} fields {fields}') - - if not isinstance(fields, list): - fields = [fields] - - for field in fields: - print(f'value {value} field {field}') - if isinstance(field, str) and hasattr(value, field): - print("->getattr") - value = getattr(value, field) +def w_thread(f, i): # @@ + contents = f.stack.pop() + result = contents[0] + for field in contents[1::]: + if isinstance(field, str) and hasattr(result, field): + result = getattr(result, field) # result.field elif isinstance(field, Arglist): - print("->arglist") - value = value(*field) + result = result(*field) # result(*field) else: - print("index") - value = value[field] - f.stack.push(value) + result = result[field] # result[field] + f.stack.push(result) return i+1 @@ -259,23 +313,6 @@ def w_getattribute(f, i): f.stack.push(result) return i+1 -def w_arrow(f, i): # -> - contents = f.stack.pop() - result = contents[0] - for field in contents[1::]: - print(f'result {result} field {field}') - if isinstance(field, str) and hasattr(result, field): - print("->getattr") - result = getattr(result, field) - elif isinstance(field, Arglist): - print("->arglist") - result = result(*field) - else: - print("index") - result = result[field] - f.stack.push(result) - return i+1 - def w_def(f, i): value = f.stack.pop() name = f.stack.pop() @@ -351,6 +388,60 @@ def w_dup(f, i): f.stack.push(x) return i+1 +def w_tmb(f, i): # A noop + # t = f.stack.pop() + # m = f.stack.pop() + # b = f.stack.pop() + # f.stack.push(b) + # f.stack.push(m) + # f.stack.push(t) + return i+1 + +def w_tbm(f, i): + t = f.stack.pop() + m = f.stack.pop() + b = f.stack.pop() + f.stack.push(m) + f.stack.push(b) + f.stack.push(t) + return i+1 + +def w_bmt(f, i): + t = f.stack.pop() + m = f.stack.pop() + b = f.stack.pop() + f.stack.push(t) + f.stack.push(m) + f.stack.push(b) + return i+1 + +def w_btm(f, i): + t = f.stack.pop() + m = f.stack.pop() + b = f.stack.pop() + f.stack.push(m) + f.stack.push(t) + f.stack.push(b) + return i+1 + +def w_mtb(f, i): + t = f.stack.pop() + m = f.stack.pop() + b = f.stack.pop() + f.stack.push(b) + f.stack.push(t) + f.stack.push(m) + return i+1 + +def w_mbt(f, i): + t = f.stack.pop() + m = f.stack.pop() + b = f.stack.pop() + f.stack.push(t) + f.stack.push(b) + f.stack.push(m) + return i+1 + def w_rot(f, i): c = f.stack.pop() b = f.stack.pop()