Some integration with Type Checking.
Now the UI highlights commands and numbers as you move the mouse, numbers are blue, commands that type-check are green, commands that fail to type-check are orange and will not be interpreted, and if there is no stack effect information available for a command it is grey but you can still attempt to execute it. You can still evaluate whole expressions by selceting them and right-inter-clicking before you release the left button, or by putting the cursor on a line and typing ctrl-enter, which will run the whole line. These expressions are NOT (yet) type-checked.
This commit is contained in:
parent
0292e8a297
commit
e169c6aae2
|
|
@ -19,10 +19,10 @@ from joy.utils.stack import stack_to_string
|
||||||
|
|
||||||
tb = TEXT_BINDINGS.copy()
|
tb = TEXT_BINDINGS.copy()
|
||||||
tb.update({
|
tb.update({
|
||||||
'<F4>': lambda tv: tv.cut,
|
|
||||||
'<F3>': lambda tv: tv.copy_selection_to_stack,
|
'<F3>': lambda tv: tv.copy_selection_to_stack,
|
||||||
|
'<F4>': lambda tv: tv.cut,
|
||||||
# '<F-->': lambda tv: tv.pastecut,
|
# '<F-->': lambda tv: tv.pastecut,
|
||||||
'<F6>': lambda tv: tv.copyto,
|
# '<F6>': lambda tv: tv.copyto,
|
||||||
})
|
})
|
||||||
defaults = dict(text_bindings=tb, width=80, height=25)
|
defaults = dict(text_bindings=tb, width=80, height=25)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,7 @@ class MouseBindingsMixin:
|
||||||
self.bind("<ButtonRelease-3>", self.B3r)
|
self.bind("<ButtonRelease-3>", self.B3r)
|
||||||
|
|
||||||
self.bind("<Any-Leave>", self.leave)
|
self.bind("<Any-Leave>", self.leave)
|
||||||
|
self.bind("<Motion>", self.scan_command)
|
||||||
|
|
||||||
def B1d(self, event):
|
def B1d(self, event):
|
||||||
'''button one pressed'''
|
'''button one pressed'''
|
||||||
|
|
@ -167,6 +168,9 @@ class MouseBindingsMixin:
|
||||||
|
|
||||||
return "break"
|
return "break"
|
||||||
|
|
||||||
|
def scan_command(self, event):
|
||||||
|
self.update_command_word(event)
|
||||||
|
|
||||||
def B1r(self, event):
|
def B1r(self, event):
|
||||||
'''button one released'''
|
'''button one released'''
|
||||||
self.B1_DOWN = False
|
self.B1_DOWN = False
|
||||||
|
|
|
||||||
|
|
@ -164,10 +164,11 @@ class TextViewerWidget(tk.Text, MouseBindingsMixin, SavingMixin):
|
||||||
|
|
||||||
#These are the config tags for command text when it's highlighted.
|
#These are the config tags for command text when it's highlighted.
|
||||||
command_tags = dict(
|
command_tags = dict(
|
||||||
underline = 1,
|
#underline = 1,
|
||||||
bgstipple = "gray50",
|
#bgstipple = "gray50",
|
||||||
borderwidth = "1",
|
borderwidth = 2,
|
||||||
foreground = "orange"
|
relief=tk.RIDGE,
|
||||||
|
foreground = "green"
|
||||||
)
|
)
|
||||||
|
|
||||||
def __init__(self, world, master=None, **kw):
|
def __init__(self, world, master=None, **kw):
|
||||||
|
|
@ -196,6 +197,9 @@ class TextViewerWidget(tk.Text, MouseBindingsMixin, SavingMixin):
|
||||||
|
|
||||||
#Add tag config for command highlighting.
|
#Add tag config for command highlighting.
|
||||||
self.tag_config('command', **self.command_tags)
|
self.tag_config('command', **self.command_tags)
|
||||||
|
self.tag_config('bzzt', foreground = "orange")
|
||||||
|
self.tag_config('huh', foreground = "grey")
|
||||||
|
self.tag_config('number', foreground = "blue")
|
||||||
|
|
||||||
#Create us a command instance variable
|
#Create us a command instance variable
|
||||||
self.command = ''
|
self.command = ''
|
||||||
|
|
@ -246,18 +250,28 @@ class TextViewerWidget(tk.Text, MouseBindingsMixin, SavingMixin):
|
||||||
return
|
return
|
||||||
|
|
||||||
cmd, b, e = cmd
|
cmd, b, e = cmd
|
||||||
if self.world.has(cmd) or is_numerical(cmd):
|
if is_numerical(cmd):
|
||||||
self.command = cmd
|
extra_tags = 'number',
|
||||||
self.highlight_command(
|
elif self.world.has(cmd):
|
||||||
'%d.%d' % (row, b),
|
check = self.world.check(cmd)
|
||||||
'%d.%d' % (row, e),
|
if check: extra_tags = ()
|
||||||
)
|
elif check is None: extra_tags = 'huh',
|
||||||
|
else: extra_tags = 'bzzt',
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
self.command = cmd
|
||||||
|
self.highlight_command(
|
||||||
|
'%d.%d' % (row, b),
|
||||||
|
'%d.%d' % (row, e),
|
||||||
|
*extra_tags)
|
||||||
|
|
||||||
def highlight_command(self, from_, to):
|
def highlight_command(self, from_, to, *extra_tags):
|
||||||
'''Apply command style from from_ to to.'''
|
'''Apply command style from from_ to to.'''
|
||||||
cmdstart = self.index(from_)
|
cmdstart = self.index(from_)
|
||||||
cmdend = self.index(to)
|
cmdend = self.index(to)
|
||||||
self.tag_add('command', cmdstart, cmdend)
|
self.tag_add('command', cmdstart, cmdend)
|
||||||
|
for tag in extra_tags:
|
||||||
|
self.tag_add(tag, cmdstart, cmdend)
|
||||||
|
|
||||||
def do_command(self, event):
|
def do_command(self, event):
|
||||||
'''Do the currently highlighted command.'''
|
'''Do the currently highlighted command.'''
|
||||||
|
|
@ -288,6 +302,9 @@ class TextViewerWidget(tk.Text, MouseBindingsMixin, SavingMixin):
|
||||||
|
|
||||||
def unhighlight_command(self):
|
def unhighlight_command(self):
|
||||||
'''Remove any command highlighting.'''
|
'''Remove any command highlighting.'''
|
||||||
|
self.tag_remove('number', 1.0, tk.END)
|
||||||
|
self.tag_remove('huh', 1.0, tk.END)
|
||||||
|
self.tag_remove('bzzt', 1.0, tk.END)
|
||||||
self.tag_remove('command', 1.0, tk.END)
|
self.tag_remove('command', 1.0, tk.END)
|
||||||
|
|
||||||
def set_insertion_point(self, event):
|
def set_insertion_point(self, event):
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,7 @@ from inspect import getdoc
|
||||||
from joy.joy import run
|
from joy.joy import run
|
||||||
from joy.parser import Symbol
|
from joy.parser import Symbol
|
||||||
from joy.utils.stack import stack_to_string
|
from joy.utils.stack import stack_to_string
|
||||||
|
from joy.utils.polytypes import type_check
|
||||||
|
|
||||||
|
|
||||||
def is_numerical(s):
|
def is_numerical(s):
|
||||||
|
|
@ -40,6 +41,9 @@ class World(object):
|
||||||
self.dictionary = dictionary or {}
|
self.dictionary = dictionary or {}
|
||||||
self.text_widget = text_widget
|
self.text_widget = text_widget
|
||||||
|
|
||||||
|
def check(self, name):
|
||||||
|
return type_check(name, self.stack)
|
||||||
|
|
||||||
def do_lookup(self, name):
|
def do_lookup(self, name):
|
||||||
if name in self.dictionary:
|
if name in self.dictionary:
|
||||||
self.stack = (Symbol(name), ()), self.stack
|
self.stack = (Symbol(name), ()), self.stack
|
||||||
|
|
@ -75,6 +79,10 @@ class World(object):
|
||||||
return self.stack[0]
|
return self.stack[0]
|
||||||
|
|
||||||
def interpret(self, command):
|
def interpret(self, command):
|
||||||
|
if len(command.split()) == 1 and not is_numerical(command):
|
||||||
|
assert self.has(command), repr(command)
|
||||||
|
if self.check(command) == False: # not in {True, None}:
|
||||||
|
return
|
||||||
try:
|
try:
|
||||||
self.stack, _, self.dictionary = run(
|
self.stack, _, self.dictionary = run(
|
||||||
command,
|
command,
|
||||||
|
|
@ -109,8 +117,14 @@ class StackDisplayWorld(World):
|
||||||
self.relative_STACK_FN = rel_filename
|
self.relative_STACK_FN = rel_filename
|
||||||
|
|
||||||
def interpret(self, command):
|
def interpret(self, command):
|
||||||
print '\njoy?', command
|
if (
|
||||||
super(StackDisplayWorld, self).interpret(command)
|
is_numerical(command)
|
||||||
|
or len(command.split()) > 1
|
||||||
|
or self.has(command)
|
||||||
|
and self.check(command) in {True, None}
|
||||||
|
):
|
||||||
|
print '\njoy?', command
|
||||||
|
super(StackDisplayWorld, self).interpret(command)
|
||||||
|
|
||||||
def print_stack(self):
|
def print_stack(self):
|
||||||
print '\n%s <-' % stack_to_string(self.stack)
|
print '\n%s <-' % stack_to_string(self.stack)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ and we can introduce a kind of Kleene Star or sequence type that can stand for
|
||||||
an unbounded sequence of other types.
|
an unbounded sequence of other types.
|
||||||
|
|
||||||
'''
|
'''
|
||||||
|
import sys
|
||||||
from inspect import stack as inspect_stack
|
from inspect import stack as inspect_stack
|
||||||
from itertools import chain, product
|
from itertools import chain, product
|
||||||
from logging import getLogger
|
from logging import getLogger
|
||||||
|
|
@ -343,6 +344,31 @@ def infer(*expression):
|
||||||
return sorted(set(_infer(list_to_stack(expression))))
|
return sorted(set(_infer(list_to_stack(expression))))
|
||||||
|
|
||||||
|
|
||||||
|
def type_check(name, stack):
|
||||||
|
'''
|
||||||
|
Trinary predicate. True if named function type-checks, False if it
|
||||||
|
fails, None if it's indeterminate (because I haven't entered it into
|
||||||
|
the FUNCTIONS dict yet.)
|
||||||
|
'''
|
||||||
|
try:
|
||||||
|
func = FUNCTIONS[name]
|
||||||
|
except KeyError:
|
||||||
|
return # None, indicating unknown
|
||||||
|
|
||||||
|
for fi, fo in infer(func):
|
||||||
|
try:
|
||||||
|
U = unify(fi, stack)
|
||||||
|
except JoyTypeError, e:
|
||||||
|
#print e
|
||||||
|
continue
|
||||||
|
except ValueError, e:
|
||||||
|
#print >> sys.stderr, name, e, stack
|
||||||
|
continue
|
||||||
|
#print U
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = A
|
a0, a1, a2, a3, a4, a5, a6, a7, a8, a9 = A
|
||||||
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = B
|
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9 = B
|
||||||
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = N
|
n0, n1, n2, n3, n4, n5, n6, n7, n8, n9 = N
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue