Overview


Noisett is probably an esoteric programming language.

Basically it's a minimalistic multi-agent middleware, where agents are tiny pattern-triggered peers. These agents are named "Nuts". When they receive a message, they can send other messages, if they're so inclined.

Each Nut is defined in its own text file (extension .nut), that looks like an INI file. A ".nut" file contains sections. Sections start with a name in square brackets, like this:


example00.nut
	
	[MAIL]
	 ...
	 
	[LINK]
	 ...
	 
	[COPY]
	 ...
	 
	[PROG]	
	 ...
		
	

The MAIL section contains incoming messages, it is the Nut's inbox. The LINK section keeps parts of the network topology, we'll get to that later. The COPY section is just a clipboard. The PROG section is where the behavior of the Nut is defined. It is possible to create additional sections programmatically.

If the PROG section of a Nut contains the following code...


example01.nut
	
	[MAIL]
	[LINK]
	[COPY]
	[PROG]	
	 * hey * > Hello world
		
	

... then this Nut will send "Hello world" every time it receives a message with "hey" in it. It's pretty straightforward. Triggers are simple glob patterns, and messages are public: this "Hello world" will always be sent to every Nut connected to this one.

There are no keywords in Noisett, only the following characters have special meanings:


Noisett special characters list
	
	*	Wildcard
	|	End of line
	+	Check whether message matches an additional pattern
	-	Check whether message does not match a pattern
	
	>	Send a message
	<	Send a message to myself
	^	Send a message to my Tables
	
	.	Rename myself
	
	[	Choose the current section (create it if needed)
	&	Add something to the current section
	?	Check whether anything in current section matches a pattern
	!	Check whether nothing in current section matches a pattern
	%	Copy from current section everything that matches a pattern
	]	Delete from current section everything that matches a pattern
	
	{	Create a topological link
	}	Delete every link matching a pattern
	
	_	Set vector filter pattern
	
	$x	Insert wildcard number x
	=	Insert my name
	@	Insert name of message sender
	€	Insert a pattern that matches everything in current section
	#	Insert name of next section
	§	Insert current section (in message) or clipboard (in section)
	~	Insert a random element from current section
	"	Insert the following characters (escape)
	|	Insert an End of line
	
	

These special characters are either standalone or followed by their "arguments".

Some of them are conditions (namely + - ? and !) while some others express actions.

Code lines in the PROG section always start with a pattern. If the current message matches it, we just keep reading the line and executing actions until a condition fails (or until the end of line). Incoming messages are matched against every code line.



Basic message handling


During the execution of a code line, when writing text we can insert portions of text captured by wildcards. For example, if a Nut is like...


example02.nut
	
	[MAIL]
	 I'm a Noisett agent
	 
	[PROG]
	 I'm * > He's $1
		
	

... then when reacting to the message in its MAIL section, it will send "He's a Noisett Agent". $1 gets the first wildcard, $2 gets the second wildcard, and so on.


We can test the message against several patterns with the "+" character:


example03.nut
	
	[MAIL]	
	 I'm a Noisett agent
	 I like Noisett
	 I'm glad
	 	 
	[PROG]
	 I'm * + * Noisett * > Received $1
		
	

Receiving 3 messages, this Nut will only send "Received a Noisett agent", and nothing else, because the first message is the only one matching both "I'm *" and "* Noisett *".

Now, if instead of $1 we ask for $2...


example04.nut
	
	[MAIL]	
	 I'm a Noisett agent
	 I like Noisett
	 I'm glad
	 	 
	[PROG]
	 I'm * + * Noisett * > Received $2
		
	

... then we'll get "Received I'm a", because that's what was captured by the 2nd wildcard of this code line. No matter where the wildcard is on the code line, we always start at $1 and keep counting. So here, $3 would be "agent".


We can also check that a message doesn't match a pattern, with the "-" character.


example05.nut
	
	[MAIL]	
	 I'm a Noisett agent
	 I like Noisett
	 I'm ok
	 	 
	[PROG]
	 I'm * - * Noisett * > $1

	

This one would send "ok", because that's the only message that matches "I'm *" and that doesn't match "* Noisett *". Obviously, asking for $2 or $3 here wouldn't make sense since they're not supposed to be captured. Hence here $2 and $3 would evaluate to an empty string, if inserted in a message.


Nuts can send messages to themselves, using the "<" character, like this:


example06.nut
	
	[MAIL]
	 I'm a Noisett agent
	 
	[PROG]
	 I'm * < I think $0
		
	

This Nut would send "I think I'm a Noisett agent" to itself, because "$0" captures the entire message. Then it would send "I think I think I'm a Noisett agent" to itself. Then it would send "I think I think I think I'm a Noisett agent" to itself. You get the idea.


We can insert the name of the sender of the received message using the "@" character. If a Nut named "Foo" sends a message "Hey buddy" to the following Nut...


example07.nut
	
	[MAIL]
	 Hey buddy
	 
	[PROG]
	 * > @ said : $1
		
	

... then this Nut will send "Foo said : Hey buddy". The "=" character works the same way, except that it inserts the name of the Nut executing the code line.



Working with sections


Inside a code line, square brackets and curly braces don't work in pairs, they don't have to be balanced. Each character "[", "]", "{", and "}" is independent and has its own meaning.

The purpose of the openning square "[" is to decide which section is now the "current" section. The "current" section is the one we're currently working with. For example, we can insert the current section with the "§" character:


example08.nut
	
	[MAIL]
	 Hello!
	 
	[PROG]
	 * [ TEST > Giving § $1
	
	[TEST]
	 one two three

	

Here, first we capture the message in a wildcard, then we choose TEST as the current section, and finally we send "Giving one two three Hello!".

If a section doesn't exist yet when we choose it with an opening square bracket "[", then it is created.


The "&" character appends a string to the current section, and the "?" character checks whether the current section contains at least one string matching a pattern.


example09-a.nut
	
	[MAIL]
	 Go
	 Check it
	 
	[PROG]
	 Check it [ TEST ? Got * > I need $1
	 * [ TEST & Got to $1
	 
example09-b.nut
	
	[MAIL]
	 Check it
	 
	[PROG]
	 Check it [ TEST ? Got * > I need $1
	 * [ TEST & Got to $1

	[TEST]
	 Got to Go

	

In step "a", the Nut receives two messages "Go" and "Check it". Handling "Go", a TEST section is created (since it doesn't exists) and a "Got to Go" is put inside it. Then in step "b", handling "Check it", we check whether there's a string matching "Got *" in the TEST section, and since there's "Got to Go", we send a "I need to Go" message.

Note that in step "c", there would be a "Got to Check it" at the end of TEST, because "Check it" also triggers the 2nd code line in PROG. Indeed, every code line in PROG is tested for every incoming message.


While "?" succeeds if there's a match in the current section, "!" succeeds if there's no match in the current section.


We can delete elements from the current section with the closing square "]" followed by the pattern of things we want to delete:


example10-a.nut
	
	[MAIL]
	 Clean TEST

	[PROG]
	 Clean * [ $1 ] * def *
	 CleanAll * [ $1 ] *
	 
	[TEST]
	 abc def
	 def ghi
	 ghi jkl
	 
example10-b.nut
	
	[MAIL]

	[PROG]
	 Clean * [ $1 ] * def *
	 CleanAll * [ $1 ] *
	 
	[TEST]
	 ghi jkl

	

First with "[ $1" we choose TEST as current section, then we delete anything matching "* def *". Since a single wildcard "*" matches everything, "CleanAll TEST" would delete everything in TEST. Empty sections are automatically suppressed, so TEST would then simply disappear.



Network topology


Nuts are connected to one another by pipe links. Links are associations of 4 Nuts.



In a link, normal messages flow from a Sender Nut, through a Vector Nut, to a Target Nut. Each link is created, modified and destroyed by its Table Nut. The same Nut can be involved simultaneously in different links as Sender, Vector, Target, and Table.


Links are described in the LINK section, as CSV:


example11.nut
	
	[LINK]
	
	 Sender , Vector , Target , Table
	 
	

The LINK section of a Nut contains every link involving this Nut. The Nut itself is denoted "=" (me) in these links. For example:

example12.nut
	
	[LINK]
	
	 =, Tom, Jane, Family
	 =, Tom, Bob, Family
	 Jane, Tom, =, Family
	 
	

Here, according to the Family table, this Nut sends its messages to Jane and Bob through Tom, and it receives messages from Jane through Tom.


A Nut can be involved several times in the same link:


example13.nut
	
	[LINK]
	
	 Family, Family, =, Family
	 
	

Here, according to the Family table, Family sends messages through itself (as a vector) to this Nut.


When a Nut creates a link with the "{" character, it always becomes the table of this link. So, after "{" in a code line, we never specify the "table" part of the link we want to create:


example14-a.nut
	
	[MAIL]
	 Please connect A to C through B
	 
	[PROG]
	 Please connect * to * through * { $1 , $3 , $2
	
	[LINK]
	 
example14-b.nut
	
	[MAIL]
	 
	[PROG]
	 Please connect * to * through * { $1 , $3 , $2
	
	[LINK]
	 A , B , C , =
	
	

The LINK section is the only one that can't be modified with "&" or "]", we have to use "{" to add links and "}" to delete links. The reason is simple: when links are modified, the LINK section of every Nut involved will be modified accordingly.

When Noisett detects inconsistencies in LINK sections (if a ".nut" file is wildly modified by an external program for instance), the LINK section of the table Nut of a link is considered to be the right one. Also, when a ".nut" file cannot be found, links it was involved in are deleted.


Only table Nuts can delete links, with the "}" character followed by the pattern of links they want to delete. Again, we don't specify the "table" part of links, since a Nut can only delete its own links.


example15.nut
	
	[MAIL]
	 Please free A
	 
	[PROG]
	 Please free * } * $1 *
	
	

This Nut would delete every link where "A" is involved.


Vector Nuts are able to filter messages that flow through them, with the "_" character followed by a filter pattern. If we want to block every message, we use a double underscore "_ _". For example:


example16.nut
	
	[MAIL]
	 Allow Only * ok *
	
	[PROG]
	 Block All _ _
	 Allow Only * _ $1
	 Allow All _ *
	
	

This vector Nut would allow messages containing "ok".


With the "^" character, Nuts can send messages to the tables of links they're involved in. Messages sent with "^" won't be received by target Nuts, only table Nuts will receive them.


example17.nut
	
	[MAIL]
	 Free your mind
	
	[PROG]
	 Free your mind ^ Please free = 
	
	

When it receives a "Free your mind" message, this Nut sends a "Please free me" request to table Nuts of every link it's involved in.



Copy and paste


Every Nut has a COPY section which can be used as a clipboard. The "%" character stands for "copy", and the "§" stands for "paste".


example18.nut
	
	[MAIL]
	 From ORIG keep foo
	 Put it in DEST 
	
	[PROG]
	 From * keep * [ $1 % * $2 *
	 Put it in * [ $1 & §
	
	

This Nut will copy everything matching "* foo *" from its ORIG section, and then paste all in its DEST section

We must be careful with "§", since it has two meaning, depending on the context where it is used. When used in a "&" context, writing sections, it means "paste". But when used in a ">" or "<" or "^" context, sending messages, it means "insert the current section".



Meta programming


To do some meta programming, we must be able to insert special characters in messages. This is the purpose of the double-quote character """, which will escape characters that follow it (without spaces):


example19-a.nut
	
	[MAIL]
	 When foo say bar
	
	[PROG]
	 When * say * [ PROG & "* $1 "* "> $2
	 
example19-b.nut
	
	[MAIL]
	
	[PROG]
	 When * say * [ PROG & "* $1 "* "> $2
	 * foo * > bar
	 
	

Here, the Nut learn a simple new rule "* foo * > bar".

In fact, this is exactly how new Nuts are created: they're almost empty, with only one rule in their PROG section:


example20.nut
	
	[MAIL]
	[LINK]
	[COPY]
	[PROG]
	 * [ PROG & $1	 
	 
	

A new Nut always takes whatever you tell it and put it in its PROG section. Typically, you create a Nut, you give it rules, and then you connect it to the nutwork.

To create a new Nut, you just send a message to it. There's no way to delete Nuts programmatically, because there's no need to do it. However, Nut files can be organised in folders. Slash and backslash have no special meaning in Noisett, so they can be part of a Nut's name.


A Nut can choose a new name with the "." character:


example21.nut
	
	[MAIL]
	 Become yet another nut

	[PROG]
	 Become * . $1
	 
	

This Nut will rename itself "yet another nut", in a file named "yet another nut.nut" (the file extension is appended automatically). If a Nut with this name already exists, it will be replaced by this one.


Patterns can be created automatically with the "€" character, which finds the Longest Common Subsequence of every element in the current section, makes a pattern out of it, and inserts this pattern.


Finally, the "#" character can be used to insert the name of the section that immediately follows the current section. Using it, we can explore the entire Nut, one section at a time.



Implementation


No public implementation of Noisett is known.