mirror of
https://github.com/russolsen/sallyforth
synced 2024-12-25 21:58:18 +01:00
Break up basic_words a bit,add documentation to both native and sallyforth words.
This commit is contained in:
parent
960e4b0033
commit
47554de9f4
12 changed files with 271 additions and 203 deletions
|
@ -19,6 +19,7 @@
|
||||||
: ->static { false *last-word* dynamic }
|
: ->static { false *last-word* dynamic }
|
||||||
: ->dynamic { true *last-word* dynamic }
|
: ->dynamic { true *last-word* dynamic }
|
||||||
|
|
||||||
|
|
||||||
: -- { 1 - } ->compile
|
: -- { 1 - } ->compile
|
||||||
: ++ { 1 + } ->compile
|
: ++ { 1 + } ->compile
|
||||||
: =0 { 0 = } ->compile
|
: =0 { 0 = } ->compile
|
||||||
|
@ -37,9 +38,14 @@ unique 'list-marker =!
|
||||||
: [] { [ ] } ->compile
|
: [] { [ ] } ->compile
|
||||||
|
|
||||||
unique 'map-marker =!
|
unique 'map-marker =!
|
||||||
: <<= map-marker ->compile
|
|
||||||
: =>> { map-marker [list] list->map } ->compile
|
: <<= /Start a map/ map-marker ->compile
|
||||||
: <<=>> { <<= =>> } ->compile
|
|
||||||
|
: =>> /Complete a map/ {
|
||||||
|
map-marker [list] list->map
|
||||||
|
} ->compile
|
||||||
|
|
||||||
|
: <<=>> /Push an empty map/ { <<= =>> } ->compile
|
||||||
|
|
||||||
|
|
||||||
/ Spelunk thru objects and properties.
|
/ Spelunk thru objects and properties.
|
||||||
|
@ -51,9 +57,9 @@ unique 'map-marker =!
|
||||||
|
|
||||||
/ Function calling.
|
/ Function calling.
|
||||||
|
|
||||||
: !!0 { [] swap !! }
|
: !!0 /Call a 0 arg native function/ { [] swap !! }
|
||||||
: !!1 { swap 1 ->list swap !! }
|
: !!1 /Call a 1 arg native function/ { swap 1 ->list swap !! }
|
||||||
: !!2 { mbt 2 ->list swap !! }
|
: !!2 /Call a 2 arg native function/ { mbt 2 ->list swap !! }
|
||||||
|
|
||||||
/ obj attr -- attr-value
|
/ obj attr -- attr-value
|
||||||
: getattr {
|
: getattr {
|
||||||
|
@ -109,6 +115,11 @@ unique 'map-marker =!
|
||||||
{ "Namespace " . . " loaded." p }
|
{ "Namespace " . . " loaded." p }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/ Documentartion
|
||||||
|
|
||||||
|
: ->doc { *last-word* setdoc }
|
||||||
|
: __doc__ { <. $? '__doc__ .> }
|
||||||
|
|
||||||
/ Other startup files.
|
/ Other startup files.
|
||||||
|
|
||||||
*sallyforth-dir* "/" "io.sf" + + source
|
*sallyforth-dir* "/" "io.sf" + + source
|
||||||
|
|
|
@ -1,79 +1,18 @@
|
||||||
import tokenstream as ts
|
from util import word
|
||||||
from wrappers import noop
|
|
||||||
from namespace import Namespace
|
|
||||||
from util import word, native_word
|
|
||||||
from unique import Unique
|
from unique import Unique
|
||||||
import python_compiler as pc
|
|
||||||
import inliner
|
|
||||||
import importlib
|
|
||||||
from pprint import pprint
|
from pprint import pprint
|
||||||
|
|
||||||
@word()
|
@word("!", doc='Execute the word from the stack: word -- <results>')
|
||||||
def compile(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
var = forth.ns[name]
|
|
||||||
word_f = var.value
|
|
||||||
new_f = pc.compile_word_f(word_f, name)
|
|
||||||
forth.set(name, new_f)
|
|
||||||
|
|
||||||
@word()
|
|
||||||
def inline(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
var = forth.ns[name]
|
|
||||||
word_f = var.value
|
|
||||||
new_f = inliner.compile_word_f(word_f, name)
|
|
||||||
forth.set(name, new_f)
|
|
||||||
|
|
||||||
@word()
|
|
||||||
def dynamic(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
isdyn = forth.stack.pop()
|
|
||||||
var = forth.ns[name]
|
|
||||||
var.dynamic = isdyn
|
|
||||||
|
|
||||||
@word()
|
|
||||||
def native(forth):
|
|
||||||
has_return = forth.stack.pop()
|
|
||||||
n = forth.stack.pop()
|
|
||||||
native_f = forth.stack.pop()
|
|
||||||
name = forth.stack.pop()
|
|
||||||
print('has_return', has_return)
|
|
||||||
print('n', n)
|
|
||||||
print('native_f', native_f)
|
|
||||||
print('name', name)
|
|
||||||
wrapped_f = native_word(native_f, name, n, has_return)
|
|
||||||
forth.set(name, wrapped_f)
|
|
||||||
|
|
||||||
@word("go!")
|
|
||||||
def exec_word(forth):
|
def exec_word(forth):
|
||||||
func = forth.stack.pop()
|
func = forth.stack.pop()
|
||||||
func(forth)
|
func(forth)
|
||||||
|
|
||||||
@word("function")
|
|
||||||
def function_word(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
var = forth.ns[name]
|
|
||||||
word_f = var.value
|
|
||||||
def native_f(*args):
|
|
||||||
forth.stack.push(args)
|
|
||||||
word_f(forth)
|
|
||||||
result = forth.stack.pop()
|
|
||||||
return result
|
|
||||||
forth.stack.push(native_f)
|
|
||||||
|
|
||||||
@word('raise')
|
@word('raise')
|
||||||
def w_raise(forth):
|
def w_raise(forth):
|
||||||
ex = forth.stack.pop()
|
ex = forth.stack.pop()
|
||||||
raise ex
|
raise ex
|
||||||
|
|
||||||
@word(immediate=True)
|
@word("!!", doc='Execute a raw function from the stack: func -- <results>')
|
||||||
def readtoken(forth):
|
|
||||||
t = forth.stream.get_token()
|
|
||||||
def push_token(xforth):
|
|
||||||
xforth.stack.push(t)
|
|
||||||
return push_token
|
|
||||||
|
|
||||||
@word("!!")
|
|
||||||
def w_call(forth):
|
def w_call(forth):
|
||||||
func = forth.stack.pop()
|
func = forth.stack.pop()
|
||||||
args = forth.stack.pop()
|
args = forth.stack.pop()
|
||||||
|
@ -84,129 +23,37 @@ def w_call(forth):
|
||||||
raise
|
raise
|
||||||
forth.stack.push(result)
|
forth.stack.push(result)
|
||||||
|
|
||||||
@word()
|
@word(doc='Push a new unique value onto the stack: -- unique')
|
||||||
def unique(forth):
|
def unique(forth):
|
||||||
forth.stack.push(Unique())
|
forth.stack.push(Unique())
|
||||||
|
|
||||||
@word()
|
|
||||||
def load(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
m = importlib.import_module(name)
|
|
||||||
forth.set_constant(name, m)
|
|
||||||
|
|
||||||
@word('import')
|
|
||||||
def w_import(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
m = importlib.import_module(name)
|
|
||||||
forth.ns.import_native_module(m)
|
|
||||||
|
|
||||||
@word()
|
|
||||||
def lexicon(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
forth.ns.import_from_module(name)
|
|
||||||
|
|
||||||
@word('source')
|
|
||||||
def w_source(forth):
|
|
||||||
path = forth.stack.pop()
|
|
||||||
forth.eval_file(path)
|
|
||||||
|
|
||||||
@word('alias')
|
|
||||||
def w_alias(forth):
|
|
||||||
new_name = forth.stack.pop()
|
|
||||||
old_name = forth.stack.pop()
|
|
||||||
forth.alias(new_name, old_name)
|
|
||||||
|
|
||||||
@word()
|
|
||||||
def rawdef(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
value = forth.stack.pop()
|
|
||||||
forth.set(name, value)
|
|
||||||
|
|
||||||
@word("=!")
|
|
||||||
def equal_bang(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
value = forth.stack.pop()
|
|
||||||
forth.set_constant(name, value)
|
|
||||||
|
|
||||||
@word("*prompt*")
|
@word("*prompt*")
|
||||||
def promptword(forth):
|
def promptword(forth):
|
||||||
forth.stack.push(">> ")
|
forth.stack.push(">> ")
|
||||||
|
|
||||||
@word()
|
|
||||||
def lookup(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
forth.stack.push(forth.ns[name])
|
|
||||||
|
|
||||||
@word()
|
|
||||||
def forget(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
del forth.ns[name]
|
|
||||||
|
|
||||||
@word()
|
@word()
|
||||||
def p(forth):
|
def p(forth):
|
||||||
print(forth.stack.pop())
|
print(forth.stack.pop())
|
||||||
|
|
||||||
@word()
|
@word(doc='Print a newline: - ')
|
||||||
def nl(forth):
|
def nl(forth):
|
||||||
print()
|
print()
|
||||||
|
|
||||||
@word('.')
|
@word('.', doc='Print the value on top of the stack: v --')
|
||||||
def dot(forth):
|
def dot(forth):
|
||||||
print(forth.stack.pop(), end='')
|
print(forth.stack.pop(), end='')
|
||||||
|
|
||||||
@word()
|
@word()
|
||||||
def splat(forth):
|
def splat(forth, doc='Pop a collection and push each item separately: col -- col[n]..col[0]'):
|
||||||
l = forth.stack.pop()
|
l = forth.stack.pop()
|
||||||
l.reverse()
|
l.reverse()
|
||||||
for x in l:
|
for x in l:
|
||||||
forth.stack.push(x)
|
forth.stack.push(x)
|
||||||
|
|
||||||
@word()
|
@word(doc='Print the stack: --')
|
||||||
def stack(forth):
|
def stack(forth):
|
||||||
print(forth.stack)
|
print(forth.stack)
|
||||||
|
|
||||||
@word('debug-ns')
|
|
||||||
def debug_ns(forth):
|
|
||||||
print('debug ns')
|
|
||||||
print(forth.ns.name)
|
|
||||||
pprint(forth.ns.includes)
|
|
||||||
pprint(forth.ns.contents)
|
|
||||||
|
|
||||||
@word('*ns*')
|
|
||||||
def star_ns_star(forth):
|
|
||||||
forth.stack.push(forth.ns)
|
|
||||||
|
|
||||||
@word('new-ns')
|
|
||||||
def new_ns(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
core = forth.namespaces['core']
|
|
||||||
namespace = Namespace(name, [core])
|
|
||||||
forth.namespaces[name] = namespace
|
|
||||||
|
|
||||||
@word('include')
|
|
||||||
def include_ns(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
included = forth.namespaces[name]
|
|
||||||
forth.ns.include_ns(included)
|
|
||||||
|
|
||||||
@word('set-ns')
|
|
||||||
def set_ns_word(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
forth.set_ns(name)
|
|
||||||
|
|
||||||
@word('ns?')
|
|
||||||
def ns_question(forth):
|
|
||||||
name = forth.stack.pop()
|
|
||||||
forth.stack.push(name in forth.namespaces)
|
|
||||||
|
|
||||||
@word(':', True)
|
|
||||||
def colon(forth):
|
|
||||||
name = forth.stream.get_token().value
|
|
||||||
body = forth.compile_next()
|
|
||||||
forth.set(name, body)
|
|
||||||
forth.core.set_constant('*last-word*', name)
|
|
||||||
return noop
|
|
||||||
|
|
||||||
@word()
|
@word()
|
||||||
def current_stream(forth):
|
def current_stream(forth):
|
||||||
forth.stack.push(forth.stream)
|
forth.stack.push(forth.stream)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from wrappers import inner_f
|
from wrappers import inner_f
|
||||||
|
|
||||||
def compile_f(contents, name):
|
def compile_f(contents, attributes, doc, name):
|
||||||
new_contents = []
|
new_contents = []
|
||||||
for f in contents:
|
for f in contents:
|
||||||
sub_contents = getattr(f, "contents", None)
|
sub_contents = getattr(f, "contents", None)
|
||||||
|
@ -9,11 +9,14 @@ def compile_f(contents, name):
|
||||||
else:
|
else:
|
||||||
new_contents.append(f)
|
new_contents.append(f)
|
||||||
new_func = inner_f(new_contents)
|
new_func = inner_f(new_contents)
|
||||||
|
if attributes:
|
||||||
|
new_func.__dict__ = attributes.copy()
|
||||||
|
new_func.__doc__ = doc
|
||||||
new_func.name = name
|
new_func.name = name
|
||||||
return new_func
|
return new_func
|
||||||
|
|
||||||
def compile_word_f(f, name=None):
|
def compile_word_f(f, name=None):
|
||||||
contents = getattr(f, 'contents', None)
|
contents = getattr(f, 'contents', None)
|
||||||
if contents and len(contents) > 1:
|
if contents and len(contents) > 1:
|
||||||
return compile_f(contents, name)
|
return compile_f(contents, f.__dict__, f.__doc__, name)
|
||||||
return f
|
return f
|
||||||
|
|
|
@ -2,10 +2,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
from stack import Stack
|
from stack import Stack
|
||||||
from namespace import Namespace
|
from namespace import Namespace
|
||||||
#import basic_words
|
from kword import Keyword
|
||||||
#import stack_words
|
|
||||||
#import operator_words
|
|
||||||
#import data_words
|
|
||||||
import tokenstream as ts
|
import tokenstream as ts
|
||||||
import threaded_compiler as compiler
|
import threaded_compiler as compiler
|
||||||
from wrappers import value_f
|
from wrappers import value_f
|
||||||
|
@ -54,6 +51,7 @@ class Forth:
|
||||||
sally_dir = os.path.dirname(os.path.abspath(__file__))
|
sally_dir = os.path.dirname(os.path.abspath(__file__))
|
||||||
self.set_constant('*sallyforth-dir*', sally_dir)
|
self.set_constant('*sallyforth-dir*', sally_dir)
|
||||||
self.ns.import_from_module('basic_words')
|
self.ns.import_from_module('basic_words')
|
||||||
|
self.ns.import_from_module('namespace_words')
|
||||||
self.ns.import_from_module('stack_words')
|
self.ns.import_from_module('stack_words')
|
||||||
self.ns.import_from_module('operator_words')
|
self.ns.import_from_module('operator_words')
|
||||||
self.ns.import_from_module('data_words')
|
self.ns.import_from_module('data_words')
|
||||||
|
@ -94,7 +92,8 @@ class Forth:
|
||||||
|
|
||||||
def compile_next(self, current_token=None):
|
def compile_next(self, current_token=None):
|
||||||
"""
|
"""
|
||||||
Compile the next token, either the one passed in or the next one on the current token stream.
|
Compile the next token, either the one passed in
|
||||||
|
or the next one on the current token stream.
|
||||||
"""
|
"""
|
||||||
return compiler.compile_next(self, self.stream, current_token)
|
return compiler.compile_next(self, self.stream, current_token)
|
||||||
|
|
||||||
|
@ -133,6 +132,19 @@ class Forth:
|
||||||
self.eval_string(s)
|
self.eval_string(s)
|
||||||
return self.stack.pop()
|
return self.stack.pop()
|
||||||
|
|
||||||
|
def eval_object(self, o):
|
||||||
|
if isinstance(o, [int, str, Keyword, float]):
|
||||||
|
self.stack.push(o)
|
||||||
|
elif callable(o):
|
||||||
|
o(self)
|
||||||
|
else:
|
||||||
|
print(o, "??")
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
def eval_objects(self, l):
|
||||||
|
for o in l:
|
||||||
|
self.eval_object(l)
|
||||||
|
|
||||||
def lookup(self, name):
|
def lookup(self, name):
|
||||||
"""
|
"""
|
||||||
Return the value of the given name in the current namespace.
|
Return the value of the given name in the current namespace.
|
||||||
|
|
|
@ -10,8 +10,9 @@ class Keyword(UserString):
|
||||||
value = value[1::]
|
value = value[1::]
|
||||||
UserString.__init__(self, value)
|
UserString.__init__(self, value)
|
||||||
|
|
||||||
def __call__(self, d):
|
def __call__(self, forth):
|
||||||
return d[self]
|
d = forth.stack.pop()
|
||||||
|
forth.stack.push(d[self])
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return ':' + str(self)
|
return ':' + str(self)
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
1 ->list *
|
1 ->list *
|
||||||
} ->compile
|
} ->compile
|
||||||
|
|
||||||
: len { builtins/len !!1 }
|
: len { builtins/len !!1 } builtins/len __doc__ ->doc
|
||||||
|
|
||||||
: empty? { len zero? }
|
: empty? { len zero? }
|
||||||
|
|
||||||
|
@ -38,8 +38,8 @@
|
||||||
: rrest { rest rest } ->compile
|
: rrest { rest rest } ->compile
|
||||||
: rrrest { rest rest rest } ->compile
|
: rrrest { rest rest rest } ->compile
|
||||||
|
|
||||||
: ffirst { first first } ->compile
|
: ffirst /l -- first-item-of-first-item/ { first first } ->compile
|
||||||
: fffirst { first first first } ->compile
|
: fffirst /l -- f-of-f-of-f-of-f/ { first first first } ->compile
|
||||||
|
|
||||||
: append {
|
: append {
|
||||||
dup tbm
|
dup tbm
|
||||||
|
|
|
@ -64,9 +64,7 @@ class Namespace:
|
||||||
|
|
||||||
def import_from_module(self, module_name):
|
def import_from_module(self, module_name):
|
||||||
"""
|
"""
|
||||||
Import all of the word defining functions in
|
Import all of the word defining functions in module m.
|
||||||
module m whose function names start with prefix
|
|
||||||
into this namespace. Removes the prefix.
|
|
||||||
"""
|
"""
|
||||||
m = load_module(module_name)
|
m = load_module(module_name)
|
||||||
names = dir(m)
|
names = dir(m)
|
||||||
|
@ -74,6 +72,8 @@ class Namespace:
|
||||||
value = getattr(m, name)
|
value = getattr(m, name)
|
||||||
if get_attribute(value, 'forth_word'):
|
if get_attribute(value, 'forth_word'):
|
||||||
forth_name = value.forth_name or name
|
forth_name = value.forth_name or name
|
||||||
|
if forth_name in self:
|
||||||
|
print("Warning: redefining", forth_name)
|
||||||
var = self.set(forth_name, value, False)
|
var = self.set(forth_name, value, False)
|
||||||
|
|
||||||
def import_native_module(self, m, alias=None):
|
def import_native_module(self, m, alias=None):
|
||||||
|
@ -120,8 +120,8 @@ class Namespace:
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
def __delattr__(self, key):
|
def __delitem__(self, key):
|
||||||
return self.contents.__delattr__(key)
|
return self.contents.__delitem__(key)
|
||||||
|
|
||||||
def __setitem__(self, key, x):
|
def __setitem__(self, key, x):
|
||||||
return self.set(key, x)
|
return self.set(key, x)
|
||||||
|
|
174
sallyforth/namespace_words.py
Normal file
174
sallyforth/namespace_words.py
Normal file
|
@ -0,0 +1,174 @@
|
||||||
|
from wrappers import noop
|
||||||
|
from namespace import Namespace
|
||||||
|
from util import word, native_word
|
||||||
|
import python_compiler as pc
|
||||||
|
import inliner
|
||||||
|
import importlib
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
@word(doc='Given a name or a word, return the docstring: name-or-word -- docstr')
|
||||||
|
def doc(forth):
|
||||||
|
f = forth.stack.pop()
|
||||||
|
if not callable(f):
|
||||||
|
f = forth.ns[f].value
|
||||||
|
if hasattr(f, '__doc__'):
|
||||||
|
forth.stack.push(f.__doc__)
|
||||||
|
else:
|
||||||
|
forth.stack.push('')
|
||||||
|
|
||||||
|
@word(doc='Compile forth word: name -- ')
|
||||||
|
def compile(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
var = forth.ns[name]
|
||||||
|
word_f = var.value
|
||||||
|
new_f = pc.compile_word_f(word_f, name)
|
||||||
|
forth.set(name, new_f)
|
||||||
|
|
||||||
|
@word(doc='Expand forth word: name -- ')
|
||||||
|
def inline(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
var = forth.ns[name]
|
||||||
|
word_f = var.value
|
||||||
|
new_f = inliner.compile_word_f(word_f, name)
|
||||||
|
forth.set(name, new_f)
|
||||||
|
|
||||||
|
@word()
|
||||||
|
def dynamic(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
isdyn = forth.stack.pop()
|
||||||
|
var = forth.ns[name]
|
||||||
|
var.dynamic = isdyn
|
||||||
|
|
||||||
|
@word()
|
||||||
|
def native(forth):
|
||||||
|
has_return = forth.stack.pop()
|
||||||
|
n = forth.stack.pop()
|
||||||
|
native_f = forth.stack.pop()
|
||||||
|
name = forth.stack.pop()
|
||||||
|
wrapped_f = native_word(native_f, name, n, has_return)
|
||||||
|
forth.set(name, wrapped_f)
|
||||||
|
|
||||||
|
@word("function")
|
||||||
|
def function_word(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
var = forth.ns[name]
|
||||||
|
word_f = var.value
|
||||||
|
def native_f(*args):
|
||||||
|
forth.stack.push(args)
|
||||||
|
word_f(forth)
|
||||||
|
result = forth.stack.pop()
|
||||||
|
return result
|
||||||
|
forth.stack.push(native_f)
|
||||||
|
|
||||||
|
@word(immediate=True)
|
||||||
|
def readtoken(forth):
|
||||||
|
t = forth.stream.get_token()
|
||||||
|
def push_token(xforth):
|
||||||
|
xforth.stack.push(t)
|
||||||
|
return push_token
|
||||||
|
|
||||||
|
@word(doc='Load a new native module: modname --')
|
||||||
|
def load(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
m = importlib.import_module(name)
|
||||||
|
forth.set_constant(name, m)
|
||||||
|
|
||||||
|
@word('import', doc='Import a native module, bind all of the module values: modname --')
|
||||||
|
def w_import(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
m = importlib.import_module(name)
|
||||||
|
forth.ns.import_native_module(m)
|
||||||
|
|
||||||
|
@word(doc='Import a module that defines forth words: modname -- ')
|
||||||
|
def lexicon(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
forth.ns.import_from_module(name)
|
||||||
|
|
||||||
|
@word('source', doc='Read an execute a file full of forth code: path --')
|
||||||
|
def w_source(forth):
|
||||||
|
path = forth.stack.pop()
|
||||||
|
forth.eval_file(path)
|
||||||
|
|
||||||
|
@word('alias')
|
||||||
|
def w_alias(forth):
|
||||||
|
new_name = forth.stack.pop()
|
||||||
|
old_name = forth.stack.pop()
|
||||||
|
forth.alias(new_name, old_name)
|
||||||
|
|
||||||
|
@word("=!")
|
||||||
|
def equal_bang(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
value = forth.stack.pop()
|
||||||
|
forth.set_constant(name, value)
|
||||||
|
|
||||||
|
@word()
|
||||||
|
def rawdef(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
value = forth.stack.pop()
|
||||||
|
forth.set(name, value)
|
||||||
|
|
||||||
|
@word()
|
||||||
|
def lookup(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
forth.stack.push(forth.ns[name])
|
||||||
|
|
||||||
|
@word(doc='Forget the word from the stack: wordname --')
|
||||||
|
def forget(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
del forth.ns[name]
|
||||||
|
|
||||||
|
@word('debug-ns')
|
||||||
|
def debug_ns(forth):
|
||||||
|
print('debug ns')
|
||||||
|
print(forth.ns.name)
|
||||||
|
pprint(forth.ns.includes)
|
||||||
|
pprint(forth.ns.contents)
|
||||||
|
|
||||||
|
@word('*ns*')
|
||||||
|
def star_ns_star(forth):
|
||||||
|
forth.stack.push(forth.ns)
|
||||||
|
|
||||||
|
@word('new-ns')
|
||||||
|
def new_ns(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
core = forth.namespaces['core']
|
||||||
|
namespace = Namespace(name, [core])
|
||||||
|
forth.namespaces[name] = namespace
|
||||||
|
|
||||||
|
@word('include')
|
||||||
|
def include_ns(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
included = forth.namespaces[name]
|
||||||
|
forth.ns.include_ns(included)
|
||||||
|
|
||||||
|
@word('set-ns')
|
||||||
|
def set_ns_word(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
forth.set_ns(name)
|
||||||
|
|
||||||
|
@word('ns?')
|
||||||
|
def ns_question(forth):
|
||||||
|
name = forth.stack.pop()
|
||||||
|
forth.stack.push(name in forth.namespaces)
|
||||||
|
|
||||||
|
@word(':', True)
|
||||||
|
def colon(forth):
|
||||||
|
name = forth.stream.get_token().value
|
||||||
|
tok = forth.stream.get_token(True)
|
||||||
|
docstring = None
|
||||||
|
if tok.iscomment():
|
||||||
|
docstring = tok.value
|
||||||
|
tok = None
|
||||||
|
body = forth.compile_next(tok)
|
||||||
|
if docstring:
|
||||||
|
body.__doc__ = docstring
|
||||||
|
forth.set(name, body)
|
||||||
|
forth.core.set_constant('*last-word*', name)
|
||||||
|
return noop
|
||||||
|
|
||||||
|
@word()
|
||||||
|
def setdoc(forth):
|
||||||
|
word = forth.stack.pop()
|
||||||
|
doc = forth.stack.pop()
|
||||||
|
f = forth.ns[word].value
|
||||||
|
f.__doc__ = doc
|
|
@ -26,7 +26,7 @@ def print_ast(name):
|
||||||
keywords=[]))
|
keywords=[]))
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def compile_f(contents, name):
|
def compile_f(contents, attributes, doc, name):
|
||||||
d = locals().copy()
|
d = locals().copy()
|
||||||
exprs = []
|
exprs = []
|
||||||
for i, val in enumerate(contents):
|
for i, val in enumerate(contents):
|
||||||
|
@ -39,7 +39,9 @@ def compile_f(contents, name):
|
||||||
code = compile(m, 'source', 'exec')
|
code = compile(m, 'source', 'exec')
|
||||||
exec(code, d)
|
exec(code, d)
|
||||||
f = d['generated_function']
|
f = d['generated_function']
|
||||||
f.immediate = False
|
if attributes:
|
||||||
|
f.__dict__ = attributes.copy()
|
||||||
|
f.__doc__ = doc
|
||||||
f.operation_type = 'compiled'
|
f.operation_type = 'compiled'
|
||||||
f.name = name
|
f.name = name
|
||||||
f.contents = contents
|
f.contents = contents
|
||||||
|
@ -57,5 +59,5 @@ def compile_word_f(f, name=None):
|
||||||
"""
|
"""
|
||||||
contents = getattr(f, 'contents', None)
|
contents = getattr(f, 'contents', None)
|
||||||
if contents and len(contents) > 1:
|
if contents and len(contents) > 1:
|
||||||
return compile_f(contents, name)
|
return compile_f(contents, f.__dict__, f.__doc__, name)
|
||||||
return f
|
return f
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import io
|
import io
|
||||||
|
from kword import Keyword
|
||||||
|
|
||||||
def to_number(token):
|
def to_number(token):
|
||||||
try:
|
try:
|
||||||
|
@ -41,6 +42,9 @@ class Token:
|
||||||
def isnumber(self):
|
def isnumber(self):
|
||||||
return self.kind == 'number'
|
return self.kind == 'number'
|
||||||
|
|
||||||
|
def iscomment(self):
|
||||||
|
return self.kind == 'comment'
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return str(self)
|
return str(self)
|
||||||
|
|
||||||
|
@ -90,8 +94,15 @@ class TokenStream:
|
||||||
def ender(self, ch):
|
def ender(self, ch):
|
||||||
return self.whitespace(ch) or self.special(ch)
|
return self.whitespace(ch) or self.special(ch)
|
||||||
|
|
||||||
def get_token(self):
|
def get_token(self, return_comment=False):
|
||||||
|
#print("ret comment:", return_comment)
|
||||||
|
if return_comment:
|
||||||
|
return self.do_get_token()
|
||||||
|
|
||||||
t = self.do_get_token()
|
t = self.do_get_token()
|
||||||
|
while t and t.iscomment():
|
||||||
|
t = self.do_get_token()
|
||||||
|
|
||||||
return t
|
return t
|
||||||
|
|
||||||
def next_ch(self):
|
def next_ch(self):
|
||||||
|
@ -121,24 +132,26 @@ class TokenStream:
|
||||||
return Token('string', token)
|
return Token('string', token)
|
||||||
if state in ['word']:
|
if state in ['word']:
|
||||||
return Token('word', token)
|
return Token('word', token)
|
||||||
|
if state == 'comment':
|
||||||
|
return Token('comment', token)
|
||||||
|
if state == 'keyword':
|
||||||
|
return Token('keyword', Keyword(token))
|
||||||
if state == 'number':
|
if state == 'number':
|
||||||
return self.number_or_word(token)
|
return self.number_or_word(token)
|
||||||
return None
|
return None
|
||||||
elif state == 'start' and self.special(ch):
|
elif state == 'start' and self.special(ch):
|
||||||
return Token('word', ch)
|
return Token('word', ch)
|
||||||
|
|
||||||
elif state == 'start' and ch == ':':
|
elif state == 'start' and ch == ':':
|
||||||
token = ch
|
token = ch
|
||||||
state = 'keyword'
|
state = 'keyword'
|
||||||
elif state == 'start' and ch in "+-0123456789":
|
elif state == 'start' and ch in "+-0123456789":
|
||||||
token = ch
|
token = ch
|
||||||
state = 'number'
|
state = 'number'
|
||||||
elif state == 'lcomment' and ch == '\n':
|
|
||||||
state = 'start'
|
|
||||||
elif state == 'start' and ch == '/':
|
elif state == 'start' and ch == '/':
|
||||||
state = 'icomment'
|
token = ''
|
||||||
elif state == 'icomment' and ch in ['\n', '/']:
|
state = 'comment'
|
||||||
state = 'start'
|
elif state == 'comment' and ch in ['\n', '/']:
|
||||||
|
return Token('comment', token)
|
||||||
elif state == 'start' and self.whitespace(ch):
|
elif state == 'start' and self.whitespace(ch):
|
||||||
continue
|
continue
|
||||||
elif state == 'start' and ch == '"':
|
elif state == 'start' and ch == '"':
|
||||||
|
@ -163,8 +176,8 @@ class TokenStream:
|
||||||
self.unread(ch)
|
self.unread(ch)
|
||||||
if token in [':']:
|
if token in [':']:
|
||||||
return Token('word', token)
|
return Token('word', token)
|
||||||
return Token('keyword', token)
|
return Token('keyword', Keyword(token))
|
||||||
elif state in ['word', 'dqstring', 'sqstring', 'number', 'keyword']:
|
elif state in ['word', 'dqstring', 'sqstring', 'number', 'keyword', 'comment']:
|
||||||
token += ch
|
token += ch
|
||||||
|
|
||||||
class MacroTokenStream:
|
class MacroTokenStream:
|
||||||
|
@ -177,8 +190,8 @@ class MacroTokenStream:
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
self.tokens = []
|
self.tokens = []
|
||||||
|
|
||||||
def get_more_tokens(self):
|
def get_more_tokens(self, return_comment):
|
||||||
raw_token = self.stream.get_token()
|
raw_token = self.stream.get_token(return_comment)
|
||||||
if raw_token \
|
if raw_token \
|
||||||
and raw_token.isword() \
|
and raw_token.isword() \
|
||||||
and raw_token.value[0] == '#':
|
and raw_token.value[0] == '#':
|
||||||
|
@ -192,9 +205,9 @@ class MacroTokenStream:
|
||||||
else:
|
else:
|
||||||
self.tokens.append(raw_token)
|
self.tokens.append(raw_token)
|
||||||
|
|
||||||
def get_token(self):
|
def get_token(self, return_comment=False):
|
||||||
if len(self.tokens) == 0:
|
if len(self.tokens) == 0:
|
||||||
self.get_more_tokens()
|
self.get_more_tokens(return_comment)
|
||||||
if len(self.tokens):
|
if len(self.tokens):
|
||||||
return self.tokens.pop()
|
return self.tokens.pop()
|
||||||
return None
|
return None
|
||||||
|
@ -220,7 +233,8 @@ if __name__ == "__main__":
|
||||||
pis = PromptInputStream(pmt)
|
pis = PromptInputStream(pmt)
|
||||||
ts = TokenStream(pis.getc)
|
ts = TokenStream(pis.getc)
|
||||||
|
|
||||||
result = ts.get_token()
|
result = ts.get_token(True)
|
||||||
|
#print("result", result)
|
||||||
while result:
|
while result:
|
||||||
print("result:", result)
|
print("result:", result)
|
||||||
result = ts.get_token()
|
result = ts.get_token(True)
|
||||||
|
|
|
@ -2,9 +2,10 @@ def get_attribute(x, name):
|
||||||
return getattr(x, name, None)
|
return getattr(x, name, None)
|
||||||
|
|
||||||
class word:
|
class word:
|
||||||
def __init__(self, name=None, immediate=False):
|
def __init__(self, name=None, immediate=False, doc=None):
|
||||||
self.name = name
|
self.name = name
|
||||||
self.immediate = immediate
|
self.immediate = immediate
|
||||||
|
self.doc = doc
|
||||||
|
|
||||||
def __call__(self, f):
|
def __call__(self, f):
|
||||||
f.forth_word = True
|
f.forth_word = True
|
||||||
|
@ -12,6 +13,8 @@ class word:
|
||||||
f.forth_name = self.name
|
f.forth_name = self.name
|
||||||
else:
|
else:
|
||||||
f.forth_name = f.__name__
|
f.forth_name = f.__name__
|
||||||
|
if self.doc:
|
||||||
|
f.__doc__ = self.doc
|
||||||
f.immediate = self.immediate
|
f.immediate = self.immediate
|
||||||
return f
|
return f
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ def value_f(value):
|
||||||
push_constant.immediate = False
|
push_constant.immediate = False
|
||||||
push_constant.operation_type = 'pushv'
|
push_constant.operation_type = 'pushv'
|
||||||
push_constant.value = value
|
push_constant.value = value
|
||||||
|
push_constant.__doc__ = value.__doc__
|
||||||
return push_constant
|
return push_constant
|
||||||
|
|
||||||
def inner_f(contents):
|
def inner_f(contents):
|
||||||
|
|
Loading…
Reference in a new issue