mirror of
https://github.com/russolsen/sallyforth
synced 2024-12-25 21:58:18 +01:00
Added builtin alias word, which means we can define most of the built-in words with non-Python comparible names (think . and +) in sallyforth instead of Python. Also added backslash comments and stack reset work.
This commit is contained in:
parent
97c3aa1fff
commit
502f120d7b
5 changed files with 102 additions and 30 deletions
|
@ -24,26 +24,7 @@ class Forth:
|
|||
'nil': const_f(None),
|
||||
'0': const_f(0),
|
||||
'1': const_f(1),
|
||||
'2': const_f(2),
|
||||
';': w_semi,
|
||||
':': w_colon,
|
||||
'->list': w_list,
|
||||
'[': w_startlist,
|
||||
']': w_endlist,
|
||||
'{': w_startmap,
|
||||
'}': w_endmap,
|
||||
'@@': w_lookup,
|
||||
'!!': w_call,
|
||||
'+': w_add,
|
||||
'+': w_add,
|
||||
'-': w_sub,
|
||||
'/': w_div,
|
||||
'>': w_gt,
|
||||
'<': w_lt,
|
||||
'<=': w_le,
|
||||
'>=': w_ge,
|
||||
'=': w_eq,
|
||||
'.': w_dot}
|
||||
'2': const_f(2) }
|
||||
|
||||
self.import_from_module(words, 'w_')
|
||||
|
||||
|
@ -75,6 +56,7 @@ class Forth:
|
|||
|
||||
def execute_tokens(self, tokens):
|
||||
for token in tokens:
|
||||
# print("token:", token)
|
||||
if not self.compiling():
|
||||
self.execute_token(token)
|
||||
else:
|
||||
|
@ -104,9 +86,7 @@ class Forth:
|
|||
if token in self.dictionary:
|
||||
word = self.dictionary[token]
|
||||
if 'immediate' in word.__dict__:
|
||||
#print('before immediate word:', self, self.dictionary)
|
||||
word(self, 0)
|
||||
#print('after immediate word:', self, self.dictionary)
|
||||
else:
|
||||
self.compiler.add_instruction(self.dictionary[token])
|
||||
return
|
||||
|
|
|
@ -16,9 +16,13 @@ def tokenize(s):
|
|||
#print(f'Loop state {state} token {token} ch {ch}')
|
||||
if state == 'start' and ch == '(':
|
||||
state = 'comment'
|
||||
elif state == 'start' and ch == '\\':
|
||||
state = 'line_comment'
|
||||
elif state == 'line_comment' and ch == '\n':
|
||||
state = 'start'
|
||||
elif state == 'comment' and ch == ')':
|
||||
state = 'start'
|
||||
elif state == 'comment':
|
||||
elif state in ['comment', 'line_comment']:
|
||||
continue
|
||||
elif state == 'start' and is_space(ch):
|
||||
continue
|
||||
|
|
|
@ -21,6 +21,9 @@ class Stack:
|
|||
def peek(self):
|
||||
return self.stack[self.top]
|
||||
|
||||
def reset(self):
|
||||
self.top = -1
|
||||
|
||||
def __str__(self):
|
||||
result = ''
|
||||
for i in range(self.top + 1):
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
"Executing " . *source* . nl
|
||||
"Executing " dot *source* dot nl
|
||||
|
||||
\ Pull in libs.
|
||||
|
||||
"builtins" require
|
||||
"time" require
|
||||
|
@ -8,10 +10,48 @@
|
|||
"os.path" require
|
||||
"io" require
|
||||
|
||||
: *prompt* "SF> " ;
|
||||
\ Basic aliases
|
||||
|
||||
'dot '. alias
|
||||
'colon ': alias
|
||||
'semi '; alias
|
||||
'bounded_list '[list] alias
|
||||
'list '->list alias
|
||||
'list_to_map 'list->map alias
|
||||
'lookup '@@ alias
|
||||
'call '!! alias
|
||||
'add '+ alias
|
||||
'sub '- alias
|
||||
'mul '* alias
|
||||
'div '/ alias
|
||||
'gt '> alias
|
||||
'lt '< alias
|
||||
'le '<= alias
|
||||
'ge '>= alias
|
||||
'eq '= alias
|
||||
|
||||
: *prompt* "Sally> " ;
|
||||
|
||||
'list-marker unique def
|
||||
: [ list-marker ;
|
||||
: ] list-marker [list] ;
|
||||
|
||||
: [] ( -- <empty list>) [ ] ;
|
||||
|
||||
'map-marker unique def
|
||||
: { map-marker ;
|
||||
: } map-marker [list] list->map ;
|
||||
|
||||
'set-marker unique def
|
||||
: {{ set-marker ;
|
||||
: }}
|
||||
set-marker [list] \ Turn elements into list
|
||||
set-marker swap set-marker [list] \ Nest list in argument list
|
||||
builtins.set !! \ Call set with 1 argument
|
||||
;
|
||||
|
||||
: type (x -- type-of-x) 1 ->list builtins.type !! ;
|
||||
|
||||
: px0 (mod fname -- result) [] px ;
|
||||
: px1 (mod fname arg -- result) 1 ->list px ;
|
||||
: px2 (mod fname arg arg -- result) 2 ->list px ;
|
||||
|
@ -25,6 +65,8 @@
|
|||
|
||||
: >0 0 > ;
|
||||
: <0 0 < ;
|
||||
: >1 1 > ;
|
||||
: <1 1 < ;
|
||||
|
||||
: p . nl ;
|
||||
: top dup p ;
|
||||
|
@ -35,7 +77,7 @@
|
|||
: neg? (n -- bool) 0 < ;
|
||||
: zero? (n -- bool) 0 = ;
|
||||
|
||||
: source-if-exists
|
||||
: source-if-exists (path --)
|
||||
dup
|
||||
1 ->list os.path.exists
|
||||
if source else drop then
|
||||
|
@ -44,8 +86,6 @@
|
|||
: << [ ;
|
||||
: >> ] @@ ;
|
||||
|
||||
: ! ( obj method args -- result ) rot stack ;
|
||||
|
||||
"init.sf" source-if-exists
|
||||
|
||||
|
||||
|
|
|
@ -2,6 +2,10 @@ from compiler import Compiler
|
|||
import importlib
|
||||
from inspect import isfunction, isbuiltin
|
||||
|
||||
class Unique:
|
||||
def __str__(self):
|
||||
return f'Unique[{id(self)}]'
|
||||
|
||||
def const_f(value):
|
||||
def x(f, i):
|
||||
f.stack.push(value)
|
||||
|
@ -30,6 +34,16 @@ def import_native_module(forth, m, alias=None, excludes=[]):
|
|||
else:
|
||||
forth.dictionary[localname] = const_f(val)
|
||||
|
||||
def w_forth(f, i):
|
||||
f.stack.push(f)
|
||||
return i+1
|
||||
|
||||
def w_alias(f, i):
|
||||
new_name = f.stack.pop()
|
||||
old_name = f.stack.pop()
|
||||
f.dictionary[new_name] = f.dictionary[old_name]
|
||||
return i + 1
|
||||
|
||||
def w_require(f, i):
|
||||
name = f.stack.pop()
|
||||
m = importlib.import_module(name)
|
||||
|
@ -81,8 +95,8 @@ def w_import(f, i):
|
|||
return i+1
|
||||
|
||||
def w_call(f, i):
|
||||
args = f.stack.pop()
|
||||
func = f.stack.pop()
|
||||
args = f.stack.pop()
|
||||
print('f', f, 'args', args)
|
||||
result = func(*args)
|
||||
print('result', result)
|
||||
|
@ -103,6 +117,25 @@ def w_px(f, i):
|
|||
f.stack.push(result)
|
||||
return i+1
|
||||
|
||||
def w_unique(f, ip): # pushes a uique object.
|
||||
f.stack.push(Unique())
|
||||
return ip+1
|
||||
|
||||
def w_bounded_list(f, ip):
|
||||
"""Create a list from delimted values on the stack.
|
||||
[list]
|
||||
(marker a b c marker -- [a b c]
|
||||
"""
|
||||
marker = f.stack.pop()
|
||||
l = []
|
||||
x = f.stack.pop()
|
||||
while x != marker:
|
||||
l.append(x)
|
||||
x = f.stack.pop()
|
||||
l.reverse()
|
||||
f.stack.push(l)
|
||||
return ip+1
|
||||
|
||||
def w_list(f, ip): # ->list
|
||||
n = f.stack.pop()
|
||||
l = []
|
||||
|
@ -158,6 +191,14 @@ def w_endmap(f, ip): # }
|
|||
f.stack.push(result)
|
||||
return ip+1
|
||||
|
||||
def w_list_to_map(f, ip): # list->map
|
||||
l = f.stack.pop()
|
||||
result = {}
|
||||
for i in range(0, len(l), 2):
|
||||
result[l[i]] = l[i+1]
|
||||
f.stack.push(result)
|
||||
return ip+1
|
||||
|
||||
def w_get(f, i):
|
||||
name = f.stack.pop()
|
||||
m = f.stack.pop()
|
||||
|
@ -176,7 +217,7 @@ def w_def(f, i):
|
|||
value = f.stack.pop()
|
||||
name = f.stack.pop()
|
||||
f.defvar(name, value)
|
||||
#print('name', name, 'value', value)
|
||||
print('name', name, 'value', value)
|
||||
return i+1
|
||||
|
||||
def w_gt(f, i):
|
||||
|
@ -233,6 +274,10 @@ def w_div(f, i):
|
|||
f.stack.push(b/a)
|
||||
return i+1
|
||||
|
||||
def w_reset(f, i):
|
||||
a = f.stack.reset()
|
||||
return i+1
|
||||
|
||||
def w_dot(f, i):
|
||||
a = f.stack.pop()
|
||||
print(a, end='')
|
||||
|
|
Loading…
Reference in a new issue