Handmade Network»paultarvydas

Recent Activity

update Oct. 24, 2022

This diagram:

Hello World

is transpiled to this JSON:

      "children": [ {"kind":"Hello", "name":"cell_7"},  {"kind":"World", "name":"cell_8"} ],
      "connections": [
	  "receivers": [ {"receiver": {"component":"cell_7", "port":"stdin"}} ],
	  "senders": [ {"sender": {"component":"cell_6", "port":"stdin"}} ]
	  "receivers": [ {"receiver": {"component":"cell_8", "port":"stdin"}} ],
	  "senders": [ {"sender": {"component":"cell_7", "port":"stdout"}} ]
	  "receivers": [ {"receiver": {"component":"cell_6", "port":"stdout"}} ],
	  "senders": [ {"sender": {"component":"cell_8", "port":"stdout"}} ]
      "inputs": ["cell_17" ],
      "outputs": ["cell_15" ],
      "children": [],
      "connections": [],
      "inputs": ["cell_12" ],
      "outputs": ["cell_10" ],
      "children": [],
      "connections": [],
      "inputs": ["cell_11" ],
      "outputs": ["cell_14" ],

and the above JSON is transpiled to this Python:

from message import Message
from sender import Sender
from selfsender import SelfSender
from receiver import Receiver
from selfreceiver import SelfReceiver
from upconnect import UpConnect
from downconnect import DownConnect
from routeconnect import RouteConnect
from passthroughconnect import PassThroughConnect
from container import Container
from Hello import Hello
from World import World
class HelloWorld (Container): 
  def __init__ (self, parent, name):
    cell_7 = Hello (self, f'{name}-Hello-cell_7');
    cell_8 = World (self, f'{name}-World-cell_8');
    self._children = [cell_7,cell_8]
    self._connections = [
      DownConnect (SelfSender (self,'stdin'), Receiver (cell_7,'stdin')),
      RouteConnect (Sender (cell_7,'stdout'), Receiver (cell_8,'stdin')),
      UpConnect (Sender (cell_8,'stdout'), SelfReceiver (self,'stdout'))
    super ().__init__ (parent, name, self._children, self._connections)

and is transpiled to Common Lisp

(in-package "EH")
(defun new-HelloWorld (parent name)
  (let ((self (make-instance 'Container :parent parent :name name)))
    (let ((cell_7 (make-instance 'Hello :parent self :name (format nil "~a-~a-~a" name "Hello" "cell_7"))))
      (let ((cell_8 (make-instance 'World :parent self :name (format nil "~a-~a-~a" name "World" "cell_8"))))
	(let ((children (list cell_7 cell_8 )))
	  (let ((connections (list  
			      (make-instance 'DownConnect :sender (make-instance 'SelfSender :component self :port "stdin") :receiver (make-instance 'Receiver :component cell_7 :port "stdin")) 
			      (make-instance 'RouteConnect :sender (make-instance 'Sender :component cell_7 :port "stdout") :receiver (make-instance 'Receiver :component cell_8 :port "stdin")) 
			      (make-instance 'UpConnect :sender (make-instance 'Sender :component cell_8 :port "stdout") :receiver (make-instance 'SelfReceiver :component self :port "stdout"))  )))
	    (setf (children self) children)
	    (setf (connections self) connections)


Branch master has a wart - a hard-coded path (see README.md). This will be fixed in branch dev.

Next Steps

Cleave ė into multiple parts

  • diagram to JSON component descriptors
  • JSON component descriptors to Python
  • JSON component descriptors to Common Lisp

Create spin-off which enables manual creation of ė and HSM and 0D code in Python.

  • diagram transpiler - copied das as subdirectory into project

  • hw.drawio -> hw.json transpile helloworld diagram

  • hwhw.drawio -> hwhw.json transpile re-architected diagram

  • wart: das does not transpile simple hello.drawio diagram -> just use hw.drawio and hand-carve the generated json out of it (or just continue ignoring the issue, since hello.drawio is very, very simple and not worth any trouble)

  • diagram parser: das.ohm parses output hw.json and hwhw.json

  • next

    • create .fmt for diagram parser and emit same .py code that was written manually

git (same place as before)

update: 2022-08-24

make all now runs 4 tests.

Test 4 contains 2 world.pys and produces {'stdout': ['hello', 'world', 'hello', 'world']}

Test 4 shows off some deep technical aspects: fan-out, fan-in, punting messge from Container to Child, Child output routed to other Chidren.

Test 3 is test2 wrapped in another layer, just to test whether it can be done.

Also fixed Hello.py->hello.py case insensitivity in MacOS. Make was failing because it could not find hello.py, whereas other tools (like vscode) did not fail on this.

Next: create .drawio diagrams and transpile them to the above .py code (diagrams as shown in the documentation. [Intend to use https://github.com/guitarvydas/das]

branch: master

(day-after jam, added Usage and Makefile to branch "master")



This runs run.bash which runs a single 0D Leaf component echo.py and prints its output queue at the command-line.

Test.py invokes hello.py and feeds it a trigger message (True).

Then test.py invokes world.py and feeds it the above output.

World.py is almost like hello.py except that hello.py does not echo its input whereas world.py does echo its input. World.py emits 2 outputs for each input it receives.

Both components - hello.py and world.py send outputs to their respective output queues.

The final result is:

  1. hello.py outputs ['hello'] on output port 'stdout'
  2. world.py inputs 'hello' on its input port, then outputs ['hello', 'world'] on its output port 'stdout'.

Test.py invokes the two components and sends them messages in sequence. This process can be generalized to what I call a Container component, but, I didn't get there before the jam ended.

Note that the .outputs () method returns a dictionary of stacks (LIFO) of values for each port. This was a conscious decision. LIFOs, Alists are what original McCarthy FP-style code used. Sector Lisp continues the tradition of using LIFOs. I think that this is one of the secret ingredients for the anti-bloatwareness of Sector Lisp. No RAM, therefore, no heaps, therefore, no mutation, therefore, simplified data access via push/pop/lambda-binding. Lambda-binding and LIFO call-stacks fit together to make small code and no-fuss structure-sharing.

Sequencing in this paradigm is explicit and caused by the order of the sends. Sequencing in most textual programming languages is implicit and is controlled by the syntax of the language (lines of code are ordered sequences).

End of Jam

The jam ended before test.py worked correctly, but, today - 1 day after the jam - test.py is working.

Post Jam

Next, would be to make a Container (Composite) component - helloworld.py that contained two components that can be chained together. Chaining is not necessary in this paradigm and I keep it only to make the examples look more familiar.

After that would come a rearrangement of helloworld.py that would contain one hello.py and two world.pys, resulting in "['hello', 'world', 'hello', 'world']"