Indicode
Indicode is a family of somewhat-concurrent esolangs that uses a social networking service (which will be further shortened as SNS) as the medium of communication. Indicode uses social features like tagging and mentioning to function, with posts as a place to input code.
Since each SNS are different in some way (and name-snipes are a thing), most implementations of Indicode are dialects fit for the SNS the language is designed for. Because of this, you can imagine that this "reference" implementation of Indicode will be written for the SNS named PostThing (because of the writer's lack of imagination for naming things).
Required feature-set
In order for Indicode to work with a certain SNS, it must have these features:
- The SNS should have some medium to send text with. We will call this media a "post".
- Posts should support multiple lines, or at least multiple statements.
- The SNS should be able to call or notify a user from a post.
- Users should be called on replies and may call other users by @-calls.
- Note that this notify system could be done on the user-side, instead of the server notifying the callee.
- The SNS should have some ability to search a post.
- This implies that the SNS stores the post on its server somewhere.
- The searching ability will be used to search for every post bearing a tag.
- Doing this on the user-side is discouraged.
- The SNS should have an ability to reply a post.
- Some SNSes may not allow reply a reply of a post; if so some users that need to call other users must do so in another post instead of replying to the calling post.
- For SNSes that supports direct messaging to other users, that can be used instead.
- Some SNSes may not allow reply a reply of a post; if so some users that need to call other users must do so in another post instead of replying to the calling post.
Posts
Every valid Indicode post consists of multiple statements, split by lines. A statement must start with a user name to call and the rest of the statement, called the statement body. There are two types of statements:
- Statements that calls the user are called calling statements. For example,
@print Hello, world!
is a calling statement. - Statements that don't call the user are called quiet statements. For example,
print Hello, world!
is a quiet statement.
This statement type is usually executed by@exec
by calling the user name of the quiet statement.
Lines that starts with any punctuation marks are not valid statements and are ignored.
Statement bodies cannot have @-calls or anything similar. For example, this is not allowed:
@print @add 1 2
Multiple calling statements on a single post may be executed in parallel, depending on the SNS (although usually it does).
A post may have tags on them, notated by a #-tag or something similar. This is for classifying posts into different types that users like @exec
will find. Multiple posts may have the same tag; @exec
will just run them in parallel.
Here's an example of a post with a #-tag:
#hello-world print Hello, world!
Users
Every statement are controlled by "users", each doing a different task. Users may call to other users, usually on the calling post.
Replies
Once their task is done, the user must reply the calling post with either:
- The result value of an operation, either
- A number (ex:
12
) - Any other strings other than the keywords below (ex:
banana
)
- A number (ex:
- An error message prefixed with
error:
- The affirmative reply
ok
if no values are returned - Boolean values of
yes
andno
There's no concept of an array, however with the @word
user, a space separated array could be used instead.
Limits on posts
Some SNSes do not allow posts to be empty. When the text to be replied is empty, users should reply error: empty reply
instead.
Similarly, some SNSes have a limit on the message size. When the text to reply exceeds this limit, users should reply error: reply too long
instead.
Type coercion
In cases where boolean values are expected, this type coercion rule applies:
- Numbers larger than 0 are coerced to
yes
, while numbers smaller or equal to 0 are coerced tono
. ok
is coerced toyes
, and errors are coerced tono
.- Any other strings are coerced into
no
.
In cases where number values are expected, this type coercion rule applies:.
ok
andyes
is coerced to 1.no
is coerced to 0.- If any of the replies is an error, only reply the errors combined instead of doing the operation.
- If any of the replies is any other strings other than specified above, reply
error: cannot do
instead of doing the operation.
Master user
A master user (usually named @master
) may be implemented to provide non-trivial functionality like printing. When called, it may reply with the current interpreter statistics like the CPU load, amount of requests processed per second, etc.
Dealing with namesnipes
If an Indicode user name has been taken, you can work around it by adding discriminators like "{SNS name}-Indicode-", "Indicode-"or alike. Note that by adding the discriminator, all posts also have to include the discriminator to call the users:
@PostThing-Indicode-print Hello, world!
For master users, the discriminator is used as is (use @PostThing-Indicode
instead of @master
)
Standard users
These are the standard users of Indicode. An implementation of Indicode should have these users implemented.
User name | Usage | Description | Notes | |||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@print
|
@print {body...}
|
Prints the statement body to the terminal or other similar mechanism. | - | |||||||||||||||||||||||||
@echo
|
@echo {body...}
|
Replies the statement body to the calling post. | - | |||||||||||||||||||||||||
@exec
|
@exec {tag...}
|
Executes valid quiet statements in all posts tagged by the tag of the statement body in order. | Upon calling, @exec will first execute the first found statement and wait for a reply.
After it's replied, | |||||||||||||||||||||||||
@execAll
|
@execAll {tag...}
|
Executes valid quiet statements in all posts tagged by the tag of the statement body in parallel. | Upon calling, @execAll will execute all found statement and wait for a reply.
If all valid statements are executed and replied, Multiple posts with the same tag will be run in parallel. | |||||||||||||||||||||||||
@set
|
@set {name} {value...}
|
Sets the value of the variable specified by the first word to the remainder of the calling post. | - | |||||||||||||||||||||||||
@setf
|
@setf {name} {value...}
|
Sets the value of the variable specified by the first word to the formatted remainder of the calling post. | Words bounded by braces are substituted with the value of the variable with the name of that word.[note 1] | |||||||||||||||||||||||||
@setx
|
@setx {name} {value...}
|
Sets the value of the variable specified by the first word to the formatted remainder of the calling post. | Sections of the value that's bounded by braces are substituted with the reply of the execution of that section. [note 1] | |||||||||||||||||||||||||
@sets
|
@sets {name} {statement...}
|
Sets the value of the variable specified by the first word with the reply of the statement specified by the calling post. | - | |||||||||||||||||||||||||
@get
|
@get {name...}
|
Replies the calling post with the value of the variable with the name specified on the statement body. | All uninitialized variables have a blank value (i.e., the string ""). | |||||||||||||||||||||||||
@equal
|
@equal {statement1} : {statement2...}
|
Compare the replies of two statements before and after the first colon and see if they're equal. | - | |||||||||||||||||||||||||
@greater
|
@greater {statement1} : {statement2...}
|
Compare the replies of two statements before and after the first colon and see if the former is greater than the latter. | This comparison table may be used.
| |||||||||||||||||||||||||
@less
|
@less {statement1} : {statement2...}
|
Compare the replies of two statements before and after the first colon and see if the former is less than the latter. | This comparison table may be used.
| |||||||||||||||||||||||||
@add
|
@add {statement1} : {statement2...}
|
Add the replies of two statements before and after the first colon. | If two statement's reply is a boolean, coerce the reply to a boolean (making it act like an OR gate).
For other cases, concatenate the replies as a string. | |||||||||||||||||||||||||
@subt , @subtract
|
@subtract {statement1} : {statement2...}
|
Subtract the replies of two statements before and after the first colon. | If two statement's reply is a boolean, coerce the reply to a boolean.
For other cases, see type coercion. | |||||||||||||||||||||||||
@mult , @multiply
|
@multiply {statement1} : {statement2...}
|
Multiply the replies of two statements before and after the first colon. | If two statement's reply is a boolean, coerce the reply to a boolean (making it act like an AND gate).
If one statement is a string and the other is a number, repeat the string by the number. For other cases, see type coercion. | |||||||||||||||||||||||||
@div , @divide
|
@divide {statement1} : {statement2...}
|
Divide the replies of two statements before and after the first colon. | If the divisor is 0, reply error: division by zero
See type coercion for how to handle replies that isn't a number. | |||||||||||||||||||||||||
@rem , @remainder
|
@rem {statement1} : {statement2...}
|
Get the division remainder of the replies of two statements before and after the first colon. | ||||||||||||||||||||||||||
@isError
|
@isError {variable...}
|
Check if the variable's content specified by the statement body is an error. | - | |||||||||||||||||||||||||
@why
|
@why {variable...}
|
If the variable content is an error, reply the reason of the variable. | If the content is not an error, reply error: not an error .
| |||||||||||||||||||||||||
@isNumber
|
@isNumber {variable...}
|
Check if the variable's content specified by the statement body is a number. | - | |||||||||||||||||||||||||
@round
|
@round {value...}
|
Reply the rounded statement body as a number. | If the statement body is not a number, reply error: cannot do .
| |||||||||||||||||||||||||
@isBlank
|
@isBlank {variable...}
|
Check if the variable's content specified by the statement body is blank (it has no value). | This is used for SNSes that do not allow posting a post with no content. | |||||||||||||||||||||||||
@if
|
@if {statement1} then {statement2...}
|
Execute the statement before the first occurrence of the word then , and if the reply is truthy, execute the statement after the word.
|
See type coercion for how to handle replies that isn't a boolean. | |||||||||||||||||||||||||
@word
|
@word {n} of {text...}
|
Reply the n-th word of the text after the first occurrence of word of .
|
A word here is defined as some letters/glyphs and numbers surrounded by spaces. | |||||||||||||||||||||||||
@eval
|
@eval {code...}
|
Execute the formatted statement body. | Sections of the body that's bounded by braces are substituted with the reply of the execution of that section. [note 1] | |||||||||||||||||||||||||
@replace
|
@replace {pattern} : {text...}
|
Replace the pattern specified by the section of the statement body before the first colon with the text after the first colon. | - | |||||||||||||||||||||||||
@encode
|
@encode {body...}
|
Reply a space separated numbers corresponding to the Unicode codepoint of every character of the statement body. | - | |||||||||||||||||||||||||
@decode
|
@decode {body...}
|
Reply the decoding result of the statement body as many space separated numbers corresponding to a Unicode codepoint of a character. | If the statement body is not a space separated number, reply error: not a list of numbers .
If any of the numbers exceed 1114111 (0x10FFFF), reply |
More users may be added to one's liking. (see #Optional users for examples)
Optional users
Here are some users that could be implemented.
User name | Usage | Description | Notes |
---|---|---|---|
@clear
|
@clear
|
Clears the terminal. | - |
@patRep
|
@patRep {pattern} : {body...}
|
Replace the regular expression specified by the section of the statement body before the first colon with the text after the first colon. | The regular expression flavor depends on the implementation. |
@patMatch
|
@patMatch {pattern} : {body...}
|
Replies the first match of the regular expression specified by the section of the statement body before the first colon with the text after the first colon. | |
@reset
|
@reset {assertion code...}
|
Resets the interpreter. (a generated assertion code may be required to really make sure the user meant to reset the interpreter) | Note that @exec and @execAll can't call this user directly; it must be done by the user.
This could also be implemented on the master user. |
@fetch
|
@fetch {post ID}
|
Reply with the content of the post with the post ID specified by the statement body. | If no such post exists, reply error: post doesn't exist .
|
@search
|
@search {keyword}
|
Reply with a space separated post IDs matching the keywords specified by the statement body. | If no such post exists, either post a blank reply or reply error: no post found .
|
@post
|
@post {user} : {body...}
|
Make the user specified by the section of the statement body before the first colon post the section after the first colon | If the user is outside the control of the interpreter, reply error: cannot do .
|
@reply
|
@reply {user} : {post ID} : {body...}
|
Make the user specified by the section of the statement body before the first colon reply the post with the post ID specified on the section between the first and second colon with the text specified at the section after the second colon. | |
@line
|
@line {n} of {text...}
|
Reply the n-th line of the text after the first occurrence of word of .
|
A line here is defined as some letters/glyphs and numbers surrounded by new lines. |
Example posts
Here are some example posts written in PostThing Indicode. Posts may be changed to suit the dialect of the implementation.
These examples assume that the SNS database are clean; as in there are no other posts other than these.
Hello, world! program
print Hello, world!
How @exec
works
#test print Hello, world! print Hello, world!
@exec test
The first post contains only quiet statements; this makes it function like a subroutine.
The second post calls @exec
to execute the "subroutine" called "test".
Here's what the request queries might look like:
user >> POST ~ #test print Hello, world! print Hello, world! user << POST 3DBA8C3C355A9066BF35D54CDEB76418 user >> POST ~ @exec test user << POST FB905A070F8E1369B56D11992BC95653 exec << NOTIFY CALL FB905A070F8E1369B56D11992BC95653 exec >> GET FB905A070F8E1369B56D11992BC95653 exec << POST FB905A070F8E1369B56D11992BC95653 ~ user @exec test exec >> SEARCH #test exec << LIST SEARCH 3DBA8C3C355A9066BF35D54CDEB76418 exec >> GET 3DBA8C3C355A9066BF35D54CDEB76418 exec << POST 3DBA8C3C355A9066BF35D54CDEB76418 ~ user #test print Hello, world! print Hello, world! exec >> POST 3DBA8C3C355A9066BF35D54CDEB76418 @print Hello, world! exec << POST B970C7932646319ECF54B89918C41B23 print << NOTIFY CALL B970C7932646319ECF54B89918C41B23 print >> GET B970C7932646319ECF54B89918C41B23 print << POST B970C7932646319ECF54B89918C41B23 3DBA8C3C355A9066BF35D54CDEB76418 exec @print Hello, world! print >> EDIT B1015899859DF35ACF83836673D331A5[note 2] Hello, world! print << POST B1015899859DF35ACF83836673D331A5 ~ print Hello, world! exec >> POST 3DBA8C3C355A9066BF35D54CDEB76418 @print Hello, world! print >> POST B970C7932646319ECF54B89918C41B23 ok print << POST 0DC6B157A721E187B13C11C0113E81D5 exec << POST 4675BAEE398615F49AB9492227360B5C print << NOTIFY CALL 4675BAEE398615F49AB9492227360B5C print >> GET 4675BAEE398615F49AB9492227360B5C print << POST 4675BAEE398615F49AB9492227360B5C 3DBA8C3C355A9066BF35D54CDEB76418 exec @print Hello, world! print >> EDIT B1015899859DF35ACF83836673D331A5 Hello, world! Hello, world! print << POST B1015899859DF35ACF83836673D331A5 ~ print Hello, world! Hello, world! print >> POST 4675BAEE398615F49AB9492227360B5C ok print << POST 54D5059524AB76AD94058257AD195688
Fizz buzz
#fizzbuzz (set out to a blank string) set out if equal echo 0 : rem get i : 3 then setf out {out}Fizz if equal echo 0 : rem get i : 5 then setf out {out}Buzz (out is blank, change it to a number) if equal echo : get out then setf out {i} printf {out}
#fizzbuzz-loop sets i add get i : 1 exec fizzbuzz exec fizzbuzz-loop
@exec fizzbuzz-loop
Legality
The idea of dozens of accounts all controlled by a single computer, all busy sending requests to the SNS server, and potentially posting a lot of posts per seconds across all Indicode users might make you question the legality of actually implementing Indicode to a certain SNS. Indeed, if one is brave enough to implement Indicode into some SNSes like Threads, Discord, cohost!, some IRC server, or others, the SNS server will either ban their accounts for the amount of users created or the amount of posts created from one computer or rate-limit their requests for the prohibitively numerous amount of requests, thinking it's an effort of a DoS attack.
Because of this, it's perhaps better to host a server of the SNS locally if you can source one, or make a primitive one yourself. For SNSes that allows users to host their own servers like Mastodon, that can be used instead.