mirror of
https://github.com/russolsen/sallyforth
synced 2024-11-16 19:48:49 +01:00
Add :keywords, if-not, begin-while-repeat. Change names of values imported from native python modules from mod1.mod2.value to mod1/mod2/value.
This commit is contained in:
parent
4473e149c3
commit
e488738143
11 changed files with 186 additions and 104 deletions
|
@ -3,6 +3,7 @@ import importlib
|
||||||
import os
|
import os
|
||||||
from compiler import Compiler
|
from compiler import Compiler
|
||||||
from arglist import Arglist
|
from arglist import Arglist
|
||||||
|
from operator_words import w_not
|
||||||
|
|
||||||
def const_f(value):
|
def const_f(value):
|
||||||
def x(f, i):
|
def x(f, i):
|
||||||
|
@ -25,11 +26,15 @@ def native_function_handler(func):
|
||||||
def import_native_module(forth, m, alias=None, excludes=[]):
|
def import_native_module(forth, m, alias=None, excludes=[]):
|
||||||
if not alias:
|
if not alias:
|
||||||
alias = m.__name__
|
alias = m.__name__
|
||||||
|
alias = alias.replace(".", "/")
|
||||||
|
print(m, alias)
|
||||||
|
|
||||||
raw_names = dir(m)
|
raw_names = dir(m)
|
||||||
names = [x for x in raw_names if x not in excludes]
|
names = [x for x in raw_names if x not in excludes]
|
||||||
for name in names:
|
for name in names:
|
||||||
localname = f'{alias}.{name}'
|
localname = f'{alias}/{name}'
|
||||||
val = getattr(m, name)
|
val = getattr(m, name)
|
||||||
|
print("setting", localname)
|
||||||
forth.namespace.set(localname, const_f(val))
|
forth.namespace.set(localname, const_f(val))
|
||||||
|
|
||||||
def w_eval(f, i):
|
def w_eval(f, i):
|
||||||
|
@ -62,10 +67,18 @@ def w_ns(f, i):
|
||||||
f.namespace = new_ns
|
f.namespace = new_ns
|
||||||
return i + 1
|
return i + 1
|
||||||
|
|
||||||
|
def w_resolve(f, i):
|
||||||
|
token = f.stack.pop()
|
||||||
|
print("token", token)
|
||||||
|
resolved = f.resolve_token(token)
|
||||||
|
print("resovled:", resolved)
|
||||||
|
f.stack.push(resolved)
|
||||||
|
return i + 1
|
||||||
|
|
||||||
def w_alias(f, i):
|
def w_alias(f, i):
|
||||||
new_name = f.stack.pop()
|
new_name = f.stack.pop()
|
||||||
old_name = f.stack.pop()
|
old_name = f.stack.pop()
|
||||||
f.namespace[new_name] = f.namespace[old_name]
|
f.namespace.alias(new_name, old_name)
|
||||||
return i + 1
|
return i + 1
|
||||||
|
|
||||||
def w_require(f, i):
|
def w_require(f, i):
|
||||||
|
@ -145,11 +158,11 @@ def w_import(f, i):
|
||||||
def w_call(f, i):
|
def w_call(f, i):
|
||||||
func = f.stack.pop()
|
func = f.stack.pop()
|
||||||
args = f.stack.pop()
|
args = f.stack.pop()
|
||||||
# print('f', f, 'args', args)
|
#print('f', f, 'args', args)
|
||||||
try:
|
try:
|
||||||
result = func(*args)
|
result = func(*args)
|
||||||
except:
|
except:
|
||||||
print(f'Error executing {func}{list(args)}')
|
print(f'Error executing {func}({args})')
|
||||||
raise
|
raise
|
||||||
# print('result', result)
|
# print('result', result)
|
||||||
f.stack.push(result)
|
f.stack.push(result)
|
||||||
|
@ -189,6 +202,9 @@ def i_semi(forth, i):
|
||||||
entry = forth.defword(name, word_f)
|
entry = forth.defword(name, word_f)
|
||||||
entry.inline = forth.compiler.inline
|
entry.inline = forth.compiler.inline
|
||||||
entry.definition = forth.compiler.instructions
|
entry.definition = forth.compiler.instructions
|
||||||
|
#print(name)
|
||||||
|
#for ins in entry.definition:
|
||||||
|
# print(ins)
|
||||||
forth.compiler = None
|
forth.compiler = None
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
|
@ -223,6 +239,14 @@ def i_if(forth, i):
|
||||||
compiler.add_instruction(w_should_not_happen)
|
compiler.add_instruction(w_should_not_happen)
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
|
def i_ifnot(forth, i):
|
||||||
|
compiler = forth.compiler
|
||||||
|
compiler.add_instruction(w_not)
|
||||||
|
compiler.push_offset()
|
||||||
|
compiler.push_offset()
|
||||||
|
compiler.add_instruction(w_should_not_happen)
|
||||||
|
return i+2
|
||||||
|
|
||||||
def i_then(forth, i):
|
def i_then(forth, i):
|
||||||
compiler = forth.compiler
|
compiler = forth.compiler
|
||||||
else_offset = compiler.pop_offset()
|
else_offset = compiler.pop_offset()
|
||||||
|
@ -252,26 +276,40 @@ def i_do(forth, i):
|
||||||
compiler.add_instruction(w_should_not_happen)
|
compiler.add_instruction(w_should_not_happen)
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
def i_while(forth, i):
|
|
||||||
compiler = forth.compiler
|
|
||||||
do_offset = compiler.pop_offset()
|
|
||||||
while_offset = compiler.offset()
|
|
||||||
delta = do_offset - while_offset
|
|
||||||
compiler.instructions[if_offset] = ifnot_jump_f(delta)
|
|
||||||
return i+1
|
|
||||||
|
|
||||||
def i_begin(forth, i):
|
def i_begin(forth, i):
|
||||||
compiler = forth.compiler
|
compiler = forth.compiler
|
||||||
compiler.push_offset()
|
compiler.push_offset()
|
||||||
|
return i
|
||||||
|
|
||||||
|
def i_while(forth, i):
|
||||||
|
compiler = forth.compiler
|
||||||
|
compiler.push_offset()
|
||||||
|
compiler.add_instruction(w_should_not_happen)
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
def i_until(forth, i):
|
def i_repeat(forth, i):
|
||||||
compiler = forth.compiler
|
compiler = forth.compiler
|
||||||
|
while_offset = compiler.pop_offset()
|
||||||
begin_offset = compiler.pop_offset()
|
begin_offset = compiler.pop_offset()
|
||||||
until_offset = compiler.offset()
|
repeat_offset = compiler.offset()
|
||||||
delta = begin_offset - until_offset
|
begin_delta = begin_offset - repeat_offset
|
||||||
#print('Delta:', delta)
|
while_delta = repeat_offset - while_offset + 1
|
||||||
compiler.instructions.append(ifnot_jump_f(delta))
|
print("Begin delta", begin_delta)
|
||||||
|
print("while delta", while_delta)
|
||||||
|
compiler.instructions[while_offset] = ifnot_jump_f(while_delta)
|
||||||
|
compiler.add_instruction(jump_f(begin_delta))
|
||||||
|
return i+1
|
||||||
|
|
||||||
|
def w_marker1(f, i):
|
||||||
|
print("marker1")
|
||||||
|
return i+1
|
||||||
|
|
||||||
|
def w_marker2(f, i):
|
||||||
|
print("marker3")
|
||||||
|
return i+1
|
||||||
|
|
||||||
|
def w_marker3(f, i):
|
||||||
|
print("marker3")
|
||||||
return i+1
|
return i+1
|
||||||
|
|
||||||
def w_dump(f, i):
|
def w_dump(f, i):
|
||||||
|
|
|
@ -76,8 +76,10 @@ def w_list(f, ip): # ->list
|
||||||
|
|
||||||
def w_thread(f, i): # @@
|
def w_thread(f, i): # @@
|
||||||
contents = f.stack.pop()
|
contents = f.stack.pop()
|
||||||
|
print("Contents:", contents)
|
||||||
result = contents[0]
|
result = contents[0]
|
||||||
for field in contents[1::]:
|
for field in contents[1::]:
|
||||||
|
print("Result:", result)
|
||||||
if isinstance(field, str) and hasattr(result, field):
|
if isinstance(field, str) and hasattr(result, field):
|
||||||
result = getattr(result, field) # result.field
|
result = getattr(result, field) # result.field
|
||||||
elif isinstance(field, Arglist):
|
elif isinstance(field, Arglist):
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
|
|
||||||
'os import
|
'os import
|
||||||
|
|
||||||
: expandvars #os.path.expandvars !!1 ;
|
: expandvars #os/path/expandvars !!1 ;
|
||||||
: expanduser #os.path.expanduser !!1 ;
|
: expanduser #os/path/expanduser !!1 ;
|
||||||
: expand expanduser expandvars ;
|
: expand expanduser expandvars ;
|
||||||
|
|
||||||
: tokenize <. $? 'split .> " " swap !!1 ;
|
: tokenize <. $? 'split .> " " swap !!1 ;
|
||||||
|
@ -48,4 +48,5 @@
|
||||||
then
|
then
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|
||||||
: % "Toggle" p ;
|
: % "Toggle" p ;
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
|
|
||||||
: open builtins.open !!1 ;
|
: open builtins/open !!1 ;
|
||||||
: close <. $? 'close .> !!0 drop ;
|
: close <. $? 'close .> !!0 drop ;
|
||||||
|
|
||||||
: read-file (path -- contents) open dup <. $? 'read .> !!0 swap close ;
|
: read-file (path -- contents) open dup <. $? 'read .> !!0 swap close ;
|
||||||
: read-lines (path -- contents) open dup <. $? 'readlines .> !!0 swap close ;
|
: read-lines (path -- contents) open dup <. $? 'readlines .> !!0 swap close ;
|
||||||
|
|
||||||
: read-line (prompt -- input-line)
|
: read-line (prompt -- input-line)
|
||||||
builtins.input !!1
|
builtins/input !!1
|
||||||
;
|
;
|
||||||
|
|
||||||
\ : read-next nexttoken second ;
|
\ : read-next nexttoken second ;
|
||||||
|
|
|
@ -3,18 +3,10 @@ from os import path
|
||||||
import basic_words, data_words, operator_words, stack_words, os_words
|
import basic_words, data_words, operator_words, stack_words, os_words
|
||||||
from basic_words import const_f, w_enlist
|
from basic_words import const_f, w_enlist
|
||||||
import tokenstream as ts
|
import tokenstream as ts
|
||||||
|
from kword import Keyword
|
||||||
from stack import Stack
|
from stack import Stack
|
||||||
from namespace import Namespace
|
from namespace import Namespace
|
||||||
|
|
||||||
def to_number(token):
|
|
||||||
try:
|
|
||||||
return int(token)
|
|
||||||
except ValueError:
|
|
||||||
try:
|
|
||||||
return float(token)
|
|
||||||
except ValueError:
|
|
||||||
return None
|
|
||||||
|
|
||||||
class Forth:
|
class Forth:
|
||||||
def __init__(self, startup=None):
|
def __init__(self, startup=None):
|
||||||
self.streams = Stack()
|
self.streams = Stack()
|
||||||
|
@ -39,6 +31,7 @@ class Forth:
|
||||||
self.forth_ns.import_from_module(operator_words)
|
self.forth_ns.import_from_module(operator_words)
|
||||||
self.forth_ns.import_from_module(stack_words)
|
self.forth_ns.import_from_module(stack_words)
|
||||||
self.forth_ns.import_from_module(os_words)
|
self.forth_ns.import_from_module(os_words)
|
||||||
|
self.namespace.alias("*execute-command*", "execute")
|
||||||
|
|
||||||
self.compiler = None
|
self.compiler = None
|
||||||
|
|
||||||
|
@ -58,77 +51,71 @@ class Forth:
|
||||||
def compiling(self):
|
def compiling(self):
|
||||||
return self.compiler
|
return self.compiler
|
||||||
|
|
||||||
def _compile_token(self, kind, token):
|
def _compile_token(self, token):
|
||||||
#print(f"compile: {self.compiler.name}: {token}")
|
#print(f"compile: {self.compiler.name}: {token}")
|
||||||
if self.compiler.name == None:
|
if self.compiler.name == None:
|
||||||
#print(f'Compiling {token}')
|
#print(f'Compiling {token}')
|
||||||
self.compiler.name = token
|
self.compiler.name = token.value
|
||||||
return
|
return
|
||||||
|
|
||||||
if kind in ['dqstring', 'sqstring']:
|
if token.isnumber() or token.isstring():
|
||||||
self.compiler.add_instruction(const_f(token))
|
self.compiler.add_instruction(const_f(token.value))
|
||||||
return
|
return
|
||||||
|
|
||||||
if token in self.namespace:
|
if token.iskeyword():
|
||||||
entry = self.namespace[token]
|
self.compiler.add_instruction(Keyword(token.value))
|
||||||
#print(token, entry)
|
|
||||||
if entry.immediate:
|
|
||||||
value = entry.get_ivalue()
|
|
||||||
value(self, 0)
|
|
||||||
elif entry.inline:
|
|
||||||
self.compiler.add_instructions(entry.definition[slice(0,-1)])
|
|
||||||
else:
|
|
||||||
value = entry.get_cvalue()
|
|
||||||
self.compiler.add_instruction(value)
|
|
||||||
return
|
return
|
||||||
|
|
||||||
n = to_number(token)
|
if token.value not in self.namespace:
|
||||||
if n == None:
|
|
||||||
print(f'[{token}]?? Compile of [{self.compiler.name}] terminated.')
|
print(f'[{token}]?? Compile of [{self.compiler.name}] terminated.')
|
||||||
self.compiler = None
|
self.compiler = None
|
||||||
|
return
|
||||||
|
|
||||||
|
entry = self.namespace[token.value]
|
||||||
|
|
||||||
|
if entry.immediate:
|
||||||
|
value = entry.get_ivalue()
|
||||||
|
value(self, 0)
|
||||||
|
elif entry.inline:
|
||||||
|
self.compiler.add_instructions(entry.definition[slice(0,-1)])
|
||||||
else:
|
else:
|
||||||
self.compiler.add_instruction(const_f(n))
|
value = entry.get_cvalue()
|
||||||
|
self.compiler.add_instruction(value)
|
||||||
|
|
||||||
def _eval_token(self, kind, token):
|
def _eval_token(self, token):
|
||||||
#print(f'eval token {token} kind {kind}')
|
#print(f'***Eval token {token}')
|
||||||
if kind in ['dqstring', 'sqstring']:
|
if token == None:
|
||||||
self.stack.push(token)
|
|
||||||
return
|
|
||||||
|
|
||||||
if token in self.namespace:
|
|
||||||
#print("executing ", token)
|
|
||||||
f = self.namespace[token].get_ivalue()
|
|
||||||
#print(f)
|
|
||||||
f(self, 0)
|
|
||||||
return
|
|
||||||
|
|
||||||
n = to_number(token)
|
|
||||||
if n == None:
|
|
||||||
print(f'{token}?')
|
print(f'{token}?')
|
||||||
|
elif token.isnumber() or token.isstring():
|
||||||
|
self.stack.push(token.value)
|
||||||
|
elif token.iskeyword():
|
||||||
|
self.stack.push(Keyword(token.value))
|
||||||
|
return
|
||||||
|
elif token.value not in self.namespace:
|
||||||
|
print(f"{token.value}??")
|
||||||
else:
|
else:
|
||||||
self.stack.push(n)
|
entry = self.namespace[token.value]
|
||||||
|
f = entry.get_ivalue()
|
||||||
|
f(self, 0)
|
||||||
|
|
||||||
def execute_token(self, kind, token):
|
def execute_token(self, token):
|
||||||
#print(f'execute_token: {token}')
|
#print(f'execute_token: {token}')
|
||||||
kts = self.macro_expand_token(kind, token)
|
expanded_tokens = self.macro_expand_token(token)
|
||||||
#print(kts)
|
#print(expanded_tokens)
|
||||||
for kt in kts:
|
for expanded in expanded_tokens:
|
||||||
this_kind, this_token = kt
|
|
||||||
if not self.compiling():
|
if not self.compiling():
|
||||||
#print("interactive", this_token)
|
self._eval_token(expanded)
|
||||||
self._eval_token(this_kind, this_token)
|
|
||||||
else:
|
else:
|
||||||
#print("compiling...", this_token)
|
self._compile_token(expanded)
|
||||||
self._compile_token(this_kind, this_token)
|
|
||||||
#print("Done")
|
|
||||||
|
|
||||||
def execute_current_stream(self):
|
def execute_current_stream(self):
|
||||||
s = self.streams.peek()
|
s = self.streams.peek()
|
||||||
#print("exec current s:", s)
|
#print("exec current s:", s)
|
||||||
kind, token = s.get_token()
|
token = s.get_token()
|
||||||
while kind != 'eof':
|
while token:
|
||||||
self.execute_token(kind, token)
|
#print("Exec:", token)
|
||||||
kind, token = s.get_token()
|
self.execute_token(token)
|
||||||
|
token = s.get_token()
|
||||||
self.streams.pop()
|
self.streams.pop()
|
||||||
|
|
||||||
def execute_token_stream(self, s):
|
def execute_token_stream(self, s):
|
||||||
|
@ -140,6 +127,22 @@ class Forth:
|
||||||
token_stream = ts.string_token_stream(s)
|
token_stream = ts.string_token_stream(s)
|
||||||
return self.execute_token_stream(token_stream)
|
return self.execute_token_stream(token_stream)
|
||||||
|
|
||||||
|
def resolve_token(self, s):
|
||||||
|
token_stream = ts.string_token_stream(s)
|
||||||
|
token = token_stream.get_token()
|
||||||
|
|
||||||
|
print("token", token)
|
||||||
|
|
||||||
|
if token.isstring():
|
||||||
|
return token.value
|
||||||
|
elif token.isnumber():
|
||||||
|
return token.value
|
||||||
|
elif token.isword():
|
||||||
|
entry = self.namespace[token.value]
|
||||||
|
return entry.get_ivalue()
|
||||||
|
else:
|
||||||
|
return None
|
||||||
|
|
||||||
def evaluate_string(self, s):
|
def evaluate_string(self, s):
|
||||||
self.execute_string(s)
|
self.execute_string(s)
|
||||||
return self.stack.pop()
|
return self.stack.pop()
|
||||||
|
@ -154,24 +157,29 @@ class Forth:
|
||||||
rargs.reverse()
|
rargs.reverse()
|
||||||
if rargs:
|
if rargs:
|
||||||
for a in rargs:
|
for a in rargs:
|
||||||
# print("pushing", a);
|
#print("pushing", a);
|
||||||
self.stack.push(a)
|
self.stack.push(a)
|
||||||
#print(f'Before eval stack is {str(self.stack)}')
|
#print(f'Before eval stack is {str(self.stack)}')
|
||||||
return self.evaluate_string(s)
|
return self.evaluate_string(s)
|
||||||
|
|
||||||
|
|
||||||
def macro_expand_token(self, kind, token):
|
def macro_expand_token(self, token):
|
||||||
if len(token) <= 0 or token[0] != '#':
|
if not token.isword():
|
||||||
return [[kind, token]]
|
return [token]
|
||||||
|
elif len(token.value) <= 1:
|
||||||
|
return [token]
|
||||||
|
elif token.value[0] != '#':
|
||||||
|
return [token]
|
||||||
|
|
||||||
tag = token[1:]
|
print("Expanding token:", token)
|
||||||
|
tag = token.value[1:]
|
||||||
parts = tag.split('.')
|
parts = tag.split('.')
|
||||||
result = [ '<.', parts[0] ]
|
print("Parts", parts)
|
||||||
result = [['word', '<.'], ['word', parts[0]]]
|
result = [ ts.Token('word', '<.'), ts.Token('word', parts[0]) ]
|
||||||
for part in parts[1::]:
|
for part in parts[1::]:
|
||||||
result.append(['sqstring', part])
|
result.append(ts.Token('string', part))
|
||||||
result.append(['word', '.>'])
|
result.append(ts.Token('word', '.>'))
|
||||||
#print(result)
|
print(result)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def set_ns(self, ns_name):
|
def set_ns(self, ns_name):
|
||||||
|
|
12
sallyforth/kword.py
Normal file
12
sallyforth/kword.py
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
from collections import UserString
|
||||||
|
|
||||||
|
class Keyword(UserString):
|
||||||
|
def __init__(self, value):
|
||||||
|
value = value[1::]
|
||||||
|
UserString.__init__(self, value)
|
||||||
|
|
||||||
|
def __call__(self, d):
|
||||||
|
return d[self]
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return ':' + str(self)
|
|
@ -11,7 +11,7 @@
|
||||||
: slice (start stop -- slice-obj)
|
: slice (start stop -- slice-obj)
|
||||||
swap
|
swap
|
||||||
2 ->list
|
2 ->list
|
||||||
builtins.slice
|
builtins/slice
|
||||||
!!
|
!!
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -25,11 +25,11 @@
|
||||||
[x]
|
[x]
|
||||||
;
|
;
|
||||||
|
|
||||||
: repeat (n x -- list-of-x-repeated-n-times)
|
: n-of (n x -- list-of-x-repeated-n-times)
|
||||||
1 ->list *
|
1 ->list *
|
||||||
;
|
;
|
||||||
|
|
||||||
: len builtins.len !!1 ;
|
: len builtins/len !!1 ;
|
||||||
|
|
||||||
: empty? len zero? ;
|
: empty? len zero? ;
|
||||||
|
|
||||||
|
@ -39,3 +39,9 @@
|
||||||
|
|
||||||
: ffirst (list -- first-of-first) first first ;
|
: ffirst (list -- first-of-first) first first ;
|
||||||
: fffirst (list -- fff-irst) first first first ;
|
: fffirst (list -- fff-irst) first first first ;
|
||||||
|
|
||||||
|
: append (x list -- list-with-x-appended)
|
||||||
|
dup tbm
|
||||||
|
<. $? 'append .> !!1
|
||||||
|
drop
|
||||||
|
;
|
||||||
|
|
|
@ -24,6 +24,9 @@ class Namespace:
|
||||||
self.contents = initial_contents.copy()
|
self.contents = initial_contents.copy()
|
||||||
self.refers = refers.copy()
|
self.refers = refers.copy()
|
||||||
|
|
||||||
|
def alias(self, new_name, existing_name):
|
||||||
|
self.contents[new_name] = self.contents[existing_name]
|
||||||
|
|
||||||
def refer(self, ns):
|
def refer(self, ns):
|
||||||
"""
|
"""
|
||||||
Add the supplied namespace to the refers list.
|
Add the supplied namespace to the refers list.
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
'current_ns '*ns* alias
|
'current_ns '*ns* alias
|
||||||
|
|
||||||
: *prompt* "Sally> " ;
|
: *prompt* "Sally> " ;
|
||||||
: *execute-command* stack execute ;
|
: *execute-command* execute ;
|
||||||
|
|
||||||
\ Make a list.
|
\ Make a list.
|
||||||
'list-marker unique def
|
'list-marker unique def
|
||||||
|
@ -73,7 +73,7 @@
|
||||||
: }}
|
: }}
|
||||||
set-marker [list] \ Turn elements into list
|
set-marker [list] \ Turn elements into list
|
||||||
set-marker swap set-marker [list] \ Nest list in argument list
|
set-marker swap set-marker [list] \ Nest list in argument list
|
||||||
builtins.set !! \ Call set with 1 argument
|
builtins/set !! \ Call set with 1 argument
|
||||||
inline
|
inline
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -83,17 +83,17 @@
|
||||||
: :] ] ->arglist inline ;
|
: :] ] ->arglist inline ;
|
||||||
|
|
||||||
|
|
||||||
: str builtins.str !!1 ;
|
: str builtins/str !!1 ;
|
||||||
|
|
||||||
: type builtins.type !!1 ;
|
: type builtins/type !!1 ;
|
||||||
|
|
||||||
: type? (x class -- bool) swap type = ;
|
: type? (x class -- bool) swap type = ;
|
||||||
|
|
||||||
: ctime time.ctime !!0 ;
|
: ctime time/ctime !!0 ;
|
||||||
|
|
||||||
: sleep time.sleep !!1 drop ;
|
: sleep time/sleep !!1 drop ;
|
||||||
|
|
||||||
: callable? builtins.callable !!1 ;
|
: callable? builtins/callable !!1 ;
|
||||||
|
|
||||||
: hello "Hello" . nl ;
|
: hello "Hello" . nl ;
|
||||||
|
|
||||||
|
@ -114,16 +114,18 @@
|
||||||
: neg? 0 < inline ;
|
: neg? 0 < inline ;
|
||||||
: zero? 0 = inline ;
|
: zero? 0 = inline ;
|
||||||
|
|
||||||
: exists? os.path.exists !!1 ;
|
: exists? os/path/exists !!1 ;
|
||||||
|
|
||||||
: source-if-exists
|
: source-if-exists
|
||||||
(path -- result-of-sourcing)
|
(path -- result-of-sourcing)
|
||||||
|
"SOURCE IF EXISTS" p
|
||||||
|
stack
|
||||||
dup
|
dup
|
||||||
exists?
|
exists?
|
||||||
if source else drop then
|
if source else drop then
|
||||||
;
|
;
|
||||||
|
|
||||||
: getattr ( obj attr -- attr-value ) swap 2 ->list builtins.getattr !! ;
|
: getattr ( obj attr -- attr-value ) swap 2 ->list builtins/getattr !! ;
|
||||||
|
|
||||||
: .!! (obj args method-name -- result) tbm getattr !! ;
|
: .!! (obj args method-name -- result) tbm getattr !! ;
|
||||||
: .!!0 (obj method-name -- result ) [] swap .!! ;
|
: .!!0 (obj method-name -- result ) [] swap .!! ;
|
||||||
|
@ -132,11 +134,11 @@
|
||||||
: .!!3 (obj a1 a2 a3 method-name -- result ) swap 3 ->list swap .!! ;
|
: .!!3 (obj a1 a2 a3 method-name -- result ) swap 3 ->list swap .!! ;
|
||||||
|
|
||||||
: assert ( bool msg -- )
|
: assert ( bool msg -- )
|
||||||
swap
|
p
|
||||||
if
|
if
|
||||||
"OK " . p
|
"OK " p
|
||||||
else
|
else
|
||||||
#builtins.AssertionError !!1
|
#builtins/AssertionError !!1
|
||||||
raise
|
raise
|
||||||
then
|
then
|
||||||
;
|
;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
: split (delimit str -- tokens) 2 ->list <. builtins.str 'split .> !! ;
|
: split (delimit str -- tokens) 2 ->list <. builtins/str 'split .> !! ;
|
||||||
|
|
||||||
: dot-split (str -- tokens) "." swap split ;
|
: dot-split (str -- tokens) "." swap split ;
|
||||||
|
|
||||||
|
|
|
@ -91,3 +91,13 @@ reset false 1-or-2 2 = "False part of ifelse fires." assert
|
||||||
[ ] empty? "Empty? knows an empty list." assert
|
[ ] empty? "Empty? knows an empty list." assert
|
||||||
[ 1 ] empty? not "Empty? knows a non-empty list." assert
|
[ 1 ] empty? not "Empty? knows a non-empty list." assert
|
||||||
[ 1 2 ] empty? not "Empty? knows a non-empty list." assert
|
[ 1 2 ] empty? not "Empty? knows a non-empty list." assert
|
||||||
|
|
||||||
|
\ Loop
|
||||||
|
|
||||||
|
: test-while ( n -- ) -999 swap begin dup zero? while -- repeat -888 ;
|
||||||
|
|
||||||
|
5 test-while 3 ->list [ -999 0 -888 ] "While loop works" assert
|
||||||
|
|
||||||
|
: zero-trip-while begin false while "Should not get here." repeat ;
|
||||||
|
|
||||||
|
888 zero-trip-while 888 = "While should handle zero trip case." assert
|
||||||
|
|
Loading…
Reference in a new issue