Indicode

From Esolang
Jump to navigation Jump to search

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.

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)
  • An error message prefixed with error:
  • The affirmative reply ok if no values are returned
  • Boolean values of yes and no

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 to no.
  • ok is coerced to yes, and errors are coerced to no.
  • Any other strings are coerced into no.

In cases where number values are expected, this type coercion rule applies:.

  • ok and yes 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, @exec will first execute the next statement until no more is found. If all valid statements are executed and replied, @exec then replies ok to the calling post. Multiple posts with the same tags will be run in parallel.

@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, @execAll then replies ok to the calling post.

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.
1\2 Numbers ok, yes error: ..., no Other strings
Numbers result1 > result2 result1 >= 1 result1 < 1 result1 > length of result2
ok, yes result2 >= 1 reply no reply yes reply no
error: ..., no result2 < 1 reply no reply no reply no
Other strings length of result1 > result1 reply no reply no ABC order of result1 > ABC order of result2
@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.
1\2 Numbers ok, yes error: ..., no Other strings
Numbers result1 < result2 result1 < 1 result1 >= 1 result1 < length of result2
ok, yes result2 < 1 reply no reply no reply no
error: ..., no result2 >= 1 reply yes reply no reply no
Other strings length of result1 < length of result2 reply no reply no ABC order of result1 < ABC order of result 1
@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 error: cannot do.

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.

Notes

  1. 1.0 1.1 1.2 Note that newlines do not "leak" to other statements, however they may leak to keywords like then. For example, if variable a has value yes then print, @eval if {get a} then set a 1 will print then set a 1!
  2. This could be done on the master user's terminal.