Update README.md.

master
Nekojimi 1 year ago
parent dee5a39bcf
commit 97301d13f1
  1. 132
      README.md

@ -14,9 +14,9 @@ This repository contains the source for three applications:
A basic and rubbish spec for the Inner Platfom Hacking Language (IPHL)
### Concepts
### Objects & Concepts
The executable unit of IPHL code is the **program**, which lives in a .iphp file. Non-executable code (i.e libraries) is a **module** which lives in a .iphm file.
The executable unit of IPHL code is the **program**, which lives in a .iphp file. Non-executable code (i.e libraries) is a **module** which lives in a .iphm file.
These are mostly the same and so the word program will be used for both cases; maybe I'll have to come up with a generic name for both at some point.
@ -24,52 +24,39 @@ A program is made up of **nodes** and **pipes**. A node represents a function, o
Each node has a number of **ports**, which can be either input or output ports. A pipe always connects one output port to one input port. Normally, any port may have zero to many pipes connected to it, although some nodes may impose a uniqueness rule on their ports (see Ports).
### Nodes
#### Nodes
A node's purpose is to take input from it's input ports, process it, and send it to the output ports. It may also communicate with other sources it owns (such as a websocket, external process), although it should not cause side effects that are observable from other nodes, unless the programmer sets this up deliberately.
#### Representation
##### Representation
A node is visually represented by a box.
A node is visually represented by a box; at the top of the box, probably centred, is it's name. This top region may also be used for icons or buttons; the most important for editors is probably a little X button on the top-right, which can be used to remove a node from the program.
#### Properties
Below that is the node's ports (see Ports/Representation); input ports are down the left edge, and output ports are down the right edge. Next to each port (towards the inside) are port labels.
##### Properties
Things a node has:
- A name, which can be changed but defaults to a value
- A class, see below
- A type, which is one of the available node types, see below
- Zero or more input ports
- Zero or more output ports
- A reset function, which clears any internal state from a node
- A reset function, which clears any transient state from a node
- A check function, which tests if a node has enough input data for it's process function to complete
- A process function, which takes values from the input ports and turns them into values in the output ports.
Nodes should have at least one port (of either type) otherwise they're useless.
#### Node classes
### Ports
#### Properties
A port has:
Nodes should have at least one port (of either type) otherwise they're useless.
- A name
- A type
- A mode (see Ports#Modes), for output ports
- Zero or more connected pipes
#### Ports
#### Modes
Output ports can operate in one of three modes, which defines the mechanics of when and how new values are passed to a connected pipe:
Ports are part of a node, and represent an input or output of data values. All ports have a name (unique within their parent node) and a type (the data type of the values the port will accept or generate).
- **Push ports**: these push a new value into the pipes at the prompting of the node they belong to; they also signal the node at the other end of the pipe when they do. These are used for nodes that provide spontaneous input to the program, such as receiving button press or IM messages.
- **Pull ports:**: these provide a value at the prompting of the node at the other end of the pipe (the one with a connected input port). They may block while waiting for a value, or may indicate that there is no value available, which prevents the pulling node from processing. If a pull-port is connected to multiple pipes, pulling a value from one causes the same value to get pushed to all the others.
- **Static ports**: these hold a single value that is infinitely copied, and is not expected to change often. They function like push-ports in most respects, but they only push a value when the value they hold changes. They always have a value available to be pulled, and pulling this value does not change the state.
##### Representation
#### Representation
A port is visually represented by a small shape, such as a circle. This is drawn on the left or right edge of the port's node; left side for input ports, and right side for output ports. The port shape can touch or overlap the edge, or may be distant from it, whichever you'd prefer.
A port is visually represented by a small shape, such as a circle. The colour of a port represents its type, a listing of suggested colours is below:
The colour of a port represents it's type, a listing of suggested colours is below:
- Red: boolean values
- Orange: signal only (see Pipes)
@ -78,20 +65,34 @@ A port is visually represented by a small shape, such as a circle. The colour of
- Green: strings
- Yellow: complex objects
- Black/white (depending which way up your colour scheme is): any type, or unknown
If a port's type is an array (or collection, etc), it's colour is that of the array type, but the port icon is double-lined.
An output port's mode determines its shape:
The exact colours used is implementation-defined, but it is advised that suitability for colourblind persons (like me!) be considered when choosing them; ensure that colours vary in all three of hue, saturation, and lightness.
If a port's type is an array (or collection, etc), it's colour is that of the array type, but the port icon is double-lined. If it's an array of arrays, who bloody knows what happens, really (more lines?).
Next to a port's shape is the port label. Port labels show the name of a port. Input port labels are left-aligned, and vice versa.
In editor programs, port labels may be replaced with other components that represent a port in a more useful way, such as small text boxes that allow a port's value to be displayed.
##### Behaviour
Output ports give values to pipes, and input ports take values from pipes.
#### Pipes
Pipes connect output ports to input ports.
##### Representation
A pipe is represented by a continuous line, starting at the output port, ending at the input port, and drawn on top of both ports and nodes. How it gets from the start to the finish is implementation-defined.
Pipes are coloured according to their type; they have the same colour as the output port they are connected to (see Ports/Representation) They may vary their shade a little to make them easier to distinguish, or dynamically according to the value they contain, if you want.
##### Behaviour
- Push ports are circles;
- Pull ports are diamonds;
- Static ports are squares.
All input ports are circles.
Pipes need to implement at least two functions; an available function, which determines if a value can be read from the pipe (without blocking), and a read function which actually does the read.
### Pipes
Pipes connect an output port to an input port, and carry values between them.
### Program Flow
@ -99,18 +100,59 @@ Pipes connect an output port to an input port, and carry values between them.
Internally, each program thread maintains a deque of nodes. At each step of the program, the node at the front of the deque is removed, and this node is processed; it reads or takes values from its input ports, and writes new values to its output ports. When a new value is written to an output port, a signal is sent through any connected pipes.
#### Operation order
Whenever operations on nodes don't specify an order, *dependency ordering* is to be used.
Dependency ordering is a partial ordering, which is defined by example as follows;
- If the outputs of a node A are connected to the inputs of a node B, then B is dependent on A.
- If C depends on B, and B depends on A, then C depends on A, too.
- If Y depends on X, but X doesn't depend on Y, then Y is after X in dependency ordering.
- If X and Y both depend on other, they are not comparible in dependency ordering.
- If neither X nor Y depend on each other (they aren't connected at all), they're not comparible in dependency ordering.
If two nodes end up not directly comparable, they are handled in an arbitary order.
To illustrate, consider the following situation:
- A descends from nothing
- B and C both descend from A
- D descends from both B and C
- E descends from A and B
- C descends from F, and F descends from C
B
/ \
A D
\ /
C
Then dependency ordering might go like this:
A > B > E > C > D > F
All this might not be necessary but it's provided as a hedge until I can work out it's not; the signalling-and-checking process might be sufficent to prevent inconsistency.
#### Signalling
To transfer control between nodes, there is a process called **signalling**; when a node is signalled, its check function is called to determine if the node can be processed. If so, this node is added to the node deque, normally at the back.
To transfer control, nodes have a process called **signalling**; when a node is signalled, it calls its check function to see if there are enough values at the input ports to be processed (see Checking). If so, this node is added to the node deque, normally at the back.
A node is signalled under the following conditions:
- When a signal arrives at an input port from another node, indicating that a new value is available in the pipe.
- When another node wants to pull a value from a pull-port of a node. **Note that** in this case, the signalled node goes to the front of the node deque, not the back; this is so a chain of nodes with pull-ports will be processed in the reverse order that they were signalled.
- When another node wants to pull a value from a pull-port of this node. **Note that** in this case, the signalled node goes to the front of the node deque, not the back.
- Whenever a node has just finished processing, that same node is signalled again.
- A node may signal itself when an object it controls (running in another thread) receives new data. For example, a node implementing a bot on an IM program will signal itself when a new message arrives; a node representing a button will signal itself when the button is pressed.
- At the start of the program, the start nodes are signalled.
#### Checking
A node's check function returns a boolean value, indicating if there are enough input values at it's ports to allow the node to be processed. Generally, nodes will implement one of two sets of behaviour:
- **Function-like** nodes will have a checking function that requires that *all* input ports with a connected pipe must have a value ready. They may define some input ports as optional, meaning that processing can occur if there is no pipe connected to that port, but if there is a pipe then a value is needed. An optional port has its name displayed in (brackets).
- **Object-like** nodes will have a checking function that requires only a value at *any* connected input port. These will typically represent an object's getter methods or similar one-argument functions.
#### Program Start
At the start of the program, the following things happen in order:
@ -118,13 +160,17 @@ At the start of the program, the following things happen in order:
- All nodes are asked to reset; this means to clear any volatile state information they hold. Nodes may keep persistent state between runs of the program, but only if this is an obvious part of their function.
- Start nodes are signalled in an arbitrary order.
### File Types
IPHL code is stored in YAML format, although with renamed file extensions. Programs themselves are stored in .iphp files (for Inner Platform Hacking Program) while modules (parts of programs) are stored in .iphm files (Inner Platform Hacking Module). Besides their different contents, the two file types are identical.
The exact structure of these files isn't defined yet, but each one is composed of a number of sections. Most sections are optional; if a IPHL editor doesn't know what to do with an section, it should pass it through without touching it.
- shebang: files always begin with #!/bin/innerplatform, which identifies them to the shell.
- shebang: files always begin with #!/bin/innerplatform, which identifies them to the shell. This is also a YAML comment.
- `metadata:` contains metadata: what this file is, who made it, and so on.
- `name:` (string) the name of this file. It should be the same as the file name if possible.
- `author:` (string) who made the file. This is also used as the namespace. When storing module files on the disk, they are grouped into directories by author name.
- `license`: (string) the name of the license the file is distributed under. The default value is WTFPL.
- `code:` contains the actual nodes and pipes. This is the only mandatory section.
- `layout:` contains layout information: chiefly, where the nodes are positioned on screen, and what routes the pipes take.

Loading…
Cancel
Save