Yet Another Attempt to make a simple computer based on Joy/Thun. I'm
using Pygame & SDL2 to model the hardware interface: screen, keyboard,
mouse, and clock. Then the Python version of Joy (Thun) is used to model
a JOy interpreter (that in the real thing would be implemented in asm or
Forth.) The task is then to connect them in a simple and elegant way,
with minimal non-Joy runtime support, so that the system can be written
mostly in Joy itself.
---------------------------------------------------------------------
The event stream from Pygame is very rich, e.g. the mouse motion events
have the absolute and relative coords and the current state of three
mouse buttons.
I want the event stream to be more minimal, or even separate the keyboard
handling from the mouse.
In re: the basic design of interfacing the hardware with the (hopefully
pure) Joy system, I don't really have much of an idea, other than a very
simple (and probably too clunky) Functional Reactive style. Each event
puts some data onto a system stack and then triggers a (user-defined)
processing function to update the system in response (including any
visual operations on the screen.)
THere would have to be some kind of state saved between events, the
obvious place for that is in the system stack (or the dictionary, but
that's is to be considered a practice of last resort. Keeping state in
the dictionary is kind of a no-no, but we allow it because Forth shows us
how to use it judiciously (if you read "Thinking Forth" like you should
have before writing code in Joy.))
How much state? Different regions of the screen and their contents? A
user stack? In any event we want to be writing that stuff in Joy code,
not Python or Wirth RISC Forth or assembly (or Oberon. I should probably
write a Joy/Thun interpreter in Oberon and use that to "sculpt" a stock
Oberon OS into a Joy/Thun OS!)
SO, simplify the event stream, push events onto the stack, then call
"mousemotion" and "key" to do the thing, then develop the system in Joy.
---------------------------------------------------------------------
So far the system state is a list with the screen dimensions and a list
for buffering keyboard keys (as ints.)
[w h screen-dim]
[32 116 97 104 116 1073742049 key-buffer]
We will need more than that, of course, but it's a start.
SET_SCREEN [screen-dim] ccons [key-buffer] print_stack
KEY pop swons
The system commands are modfied, SET_SCREEN deposits the initial key
buffer list (tagged with a symbol "key-buffer", although that may turn
out to be a bad idea?), and KEY puts each key int into that list.
We could imagine a dispatch function that uses a cond combinator to
dispatch commands:
pop (to ditch the mods int)
[
[[32 =] print_stack]
[[92 =] pop [a] swoncat]
[[93 =] pop [b] swoncat]
[[...] ... ]
[swons]
] cond
And so on.
97 122 between
--------------------
This takes three integers on the stack, it will consume the top two ints.
It leaves behind the third int and a Boolean value which is true if the
third int was between the other two (inclusive.)
between == [pop >=] [popd <=] clop /\
n low high between
------------------------ w/ b = n >= low and n <= high
n b
or, since it can be destructive since it will be applied nullary...
n low high
[over] dip <= [popop false] [>=] branch
[between [over] dip <= [popop false] [>=] branch] inscribe
[lowercase? dup 97 122 between] inscribe
ANyway, that gives us the ability to classify integers into character
classes.
I guess we're going to want some way to convert lists of character codes
to and from symbols, eh? LIke they have in Prolog.
[116 97 104 116] <--> that (or maybe 'taht'?)
Do we want that? Should the runtime handle accepting bytes from the user
and dispatching whole symbols to Joy? It seems like converting between
(lists of) ints and symbols opens a door to a bunch of things we
shouldn't want to do. At least not in normal day-to-day operations.
[[100 ...] [300 ...] [100 ...]]
between == [pop >=] [popd <=] clop /\
x lo high between -> lo <= x < high
between [over] dip < [popop false] [>=] branch
between [pop >=] [popd <] cleave /\
[between [over] dip < [popop false] [>=] branch] inscribe
[r0 uncons [first +] dip] inscribe
[p0 first first [+] unary between] inscribe
[p ? [false] [p0] branch] inscribe
[wibble 0 swap [p] [? [] [first] branch popopd] [r0] tailrec] inscribe
first first [+] unary
x width [[100 ...] [300 ...] [100 ...]]
1000 [[100 ...] [300 ...] [100 ...]]
This works but it breaks if x is greater than the total width! Wah!