Tags in 42 include a custom scripting language called Yonni na or yna for short. You are free to pronunce this how you want. I personally say "why en ay", but I've heard it pronunced "yonna" and even "nya" before.
yna is a very powerful mechamism, however it can be intimidating to write or read scripts for.
It is usually a good idea to start simple and work up from there, and when you start writing larger scope tags, Make liberal use of {func}
. It will save a lot of headache with nested elements.
If you instead want to write code using Notepad++, you can install and edit this shader.
There are a few limitations to tags to prevent them from having errors or infinite loops, and an additional one limiting the size of tags for memory considerations.
Tags have a limit of 32,000 characters (~31.5kB). To upload tags this long, you should create a text file with the .yna
extension and upload it with the create call as the caption.
Tags consisting of 5 or fewer yna objects (e.g. 1 or 2 {choose} objects) have a considerably higher limit of 256,000 characters (~250kB).
Patreon supporters also get this higher limit on all their tags.
yna evaluation objects work on a stack. While one object is processing its children, the next object is appended to the stack.
When the stack exceeds 32 objects, a nesting depth reached
error will be returned.
Even if you are not using debugging, 42 has a hard limit of how much she can execute in a single tag.
This limit is ~32k lines of debug log. Each object adds between 2 and 6 lines to the log, though some may add more.
The debug file also shows the stack height down the left hand side by the number of vertical lines, as well as how long the tag took to execute (note, this will be slightly faster without debug.)
When this limit is reached, the tag is returned in its unfinished state, no errors are thrown.
Assuming your tag calls are within the other limits too, there is a hard cap to how many times you can use the {call}
function.
Right now, there are 3 distinct limits
already used
error.out of calls
error.no access
error.There are several important tools and structures that are used in yna tags.
42 defines two constructs for adding a description to your tag.
Long Description
This one is used in a tag's info page:
{!!description <Description content here>!}
Short Description
This one is only used on generic tags, but is absolutely required to have a generic tag approved.
This should be no longer than 8 to 10 words.
{!!descshort <Description content here>!}
42 provides a way to add comments to yna code or to comment code out completely.
She will not close a comment until all internal brackets are matched up.
{!<Comment content here>!}
Some users have set up their shaders to display commented content anything between {!
and !}
. While this is not strictly neccissary, it is still a good gesture if you are intending your code to be read by other people.
This style however is used on this site to aid with highlighting.
42 has 2 ways of escaping objects and special characters.
To escape individual characters, you can precede the character by a backslash.
\{
, \}
, \;
and \\
To escape entire objects, you can insert a >
inside the opening brace.
e.g. {>choose:foo;bar;baz;}
Format objects are one of the 2 kinds of objects in 42. These directly insert a value into the tag without doing anything special.
They are notable by the fact they do not end with a semicolon.
New format objects can be created using set, func and save
Here is a list of default format objects:
{tag}
The name of the tag{me}
The Member object of the tag's creator*{meid}
The ID of the tag's creator{caller}
The Member object of the caller*{callerid}
The ID of the caller{channel}
The Channel object of the current channel**{channelid}
The ID of the channel{server}
The Guild object of the server***{serverid}
The ID of the server{time}
The DateTime that the tag was called****{uses}
The number of times the tag has been called{arglen}
The number of args{arg1} {arg2} ...
The individual numbered args (1 indexed){args}
All the args as a single string{mentionlen}
The number of user mentions{mention1} ...
The individual Member objects* (1 indexed){newrep}
How {rep}
will work{generic}
Whether the tag is generic{base}
true
until {call}
is used, then false
***Guild docs
You can access the different attributes of each object by using Python's attribute access syntax, but in short...
To access the name of a Member, Channel or Server
{me.name}
-> squaswin
To pad a string
{arg1:<10}
-> Hello
{arg2:^10}
-> World!
To print a date
{time:%Y-%m-%d}
-> 2017-05-31
missing semicolon
General formatting exception. This is usually caused by forgetting the semicolon from an evaluation object, however, it may also be caused by a broken template.does not have x
General attribute exception. Usually caused by trying to access a member variable that does not exist.bad slice
General type exception. Usually caused by using invalid slicesout of range
General index exception. Usually caused by accessing an array index that doesn't exist (e.g. {caller.roles[501]}
)
Evaluation objects are the other kind of objects in yna, and they are much more powerful than format objects.
These objects generally do a lot of various things, such as flow control, variable storage, and recursion.
Evaluation objects are differentiated by the training semicolon inside the closing brace.
Keys
Keys are special shortcuts for saving the output of some functions.
While this is a holdover from yna4, it is still useful to save something without a set function.
For example, {chooseanimal:cat;dog;horse;}
will save whatever it chooses to {chooseanimal}
mismatched brackets
Failed to find a closing bracket for an object.Case functions change the case of a block of evaluated content, either to UPPER, lower or Title case.
{upper:<content>;}
{lower:<content>;}
{title:<content>;}
content
The content to edit.no content
No content was given.Gets the length of the given evaluated content.
{len:<content>;}
content
The content to measure.no content
No content was given.Slices a piece of evaluated content.
{slice:<c>;<content>;}
{slice:[<b=None>],[<e=None>][,<s=1>];<content>;}
content
The content to slice.c
A specific character index.b
The beginning of a slice.e
The end value of a slice.s
The step of a slice.no args
No arguments were given.bad content
Either not enough or too many args were given.too many nums
More than 3 values were given for the slice.bad index
String index was out of range.non int index
Values could not be casted to int.zero step
A step value of 0 was given.
Gets the current time and either stores or posts it.
Template options
{time[<k>][:<offset=0>[;<template=%H:%M>]];}
{time<k>:<offset>;;}
k
A key to store the DateTime object under.offset
The integer hours offest to add to the time.template
The template to match the time into. If omitted and a key is given, then no output will be posted.invalid offset
The offset given could not be casted to int.invalid format
The template given was invalid.Converts characters into a string into a format that can be used in URLs.
{parse:<quote>;}
quote
The content to parse.no content
No content was given.Chooses a random element from a given list.
{choose[<k>]:<option>;<option>[;<...>];}
option
One of the choices....
Options list can extend indefinately.no options
No options were given.Chooses an element with regards to given weightings.
{wchoose[<k>]:<option1>;<weight1>;<option2>;<weight2>[;<...>;<...>];}
option
The available choices.weight
The corresponding weightings for each option....
Options list can extend indefinately.no options
No options were givenmismatched weightings
Not every option could be matched with a weighting.invalid weight
A weighting could not be casted to int or float.Chooses a random member from the server. Can choose any member, not just online/active/in the channel members.
{user[:<attrs=None>];}
{user<k>;}
attrs
Attribute path for the member. Equal to {_.attrs}
k
Key value to store the member with.type clash
User brackets cannot have a key and an attribute path.too many args
More than 1 argument was given.has no attrs
The attribute path is not valid.
Fetches a members name from their ID.
This can be paired with {member}
to get an object.
{nameof:<ID>[;<attrs=None>];}
ID
ID to search for.attrs
Attribute path for the member. Equal to {_.attrs}
no id
No ID was given.too many args
More than 1 arg was given.not found
The ID did not match a user on the server.has no attrs
The attribute path is not valid.Gets a random number between a given range.
{num[<k>][:[<min=0>];<max=100>[;<step=1>]];}
k
Key value to store the number with.min
The inclusive minimum.max
The inclusive maximum.step
The step value.no args
Args were expected, but none were given. Caused by {num:;}
invalid args
Could not cast args to int.invalid range
Given range was negative or empty, or step was 0.
Variables can be stored using the set
command and then recalled like any other Format Object.
All objects saved this way are strings.
Example: calling {set:foo;Hello World;}
means that you can now use {foo}
{set:<key>;<value>;}
{set:<key>;}
key
The key value (variable name.)value
The evaluated contents to store.no args
No args were given.invalid args
Either too many or not enough args were given.invalid key
The key value is not a valid identifier name.
Functions are declared using the func
command. This is similar to the set
command but does not evaluate the contents.
This means that when you recall it, it executes the code again instead of just regurgitating the results.
You can use recursion this way, but if you start an infinite loop, I will find you and kill you she will eventually reach a point and stop executing.
While not strictly required, some syntax highlighters will mark functions starting with f_
. This makes it easier to see what is a function. e.g. {f_recurse}
.
{func:<key>;<code>;}
key
The key value (function name.)code
The script to store.no args
No args were given.invalid args
Either too many or not enough args were given.invalid key
The key value is not a valid identifier name.
You have the option of passing "Template Arguments" into your function calls.
These are a comma seperated list that are placed in the template of the function call.
{f_myfunc:foo,bar,baz}
The above code will run f_myfunc
with these additional format objects.
Note: Once the function call has completed, these format objects will be deleted.
{targs}
The full template string ("foo,bar,baz"){ta1}
The first arg ("foo"){ta2}
The second arg ("bar"){ta3}
The third arg ("baz"){talen}
The number of template args (3)Nested function calls will also override these variables in a stack fashion, so if they are required as part of another function call, they should be set to global variables or passed explicitly as arguments.
Fetches a Member object from the server and stores it to a variable.
Fetches a member by either name, nickname or Discord Tag.
{member:<key>;<name>;}
key
The key value (variable name.)name
The username, nickname or Discord Tag of the target.no args
No args were given.no query
No name was given.invalid key
The key value is not a valid identifier name.not found
There was no user with the given name on the server.
Conditionals, similar to if statements.
Unlike the old version of yna, only the path chosen will be executed instead of the when block deciding just what output to post.
{when:<a>;<op>;<b>;<true>[;<false=None>];}
a
b
The 2 arguments.op
The operation.true
Code to execute if true.false
Code to execute if false.eq
Checks that a
and b
are the same.ne
Checks that a
and b
are different.lt
Checks that a
is strictly less than b
.le
Checks that a
is less than or equal to b
.gt
Checks that a
is strictly greater than b
.ge
Checks that a
is greater than or equal to b
.in
Checks that a
is a substring of b
.in
Checks that a
matches an element in the comma seperated list in b
.is
Checks that a
is of the type defined in b
word
Checks if a
is a single word.letter
Checks if a
is a single letter.number
Checks if a
is castable to int.decimal
Checks if a
is castable to float.error
Checks if a
is a yna exception./regex/
Checks if a
matches the regex.invalid args
Either too few or too many args were given.invalid op
The operation could not be recognised.args must be numbers
Comparison operators were attempted between non-number inputsargs do not support in
A generic type error occured while performing in
checks.invalid type name
The type name in is
could not be recognised.invalid regex
The regex could not be compiled
Flow control, similar to "for" loops.
Whilst inside the loop, your current loopcount will be stored in the {iter}
variable. Note: This will be deleted when a loop is exited.
When loops are nested, only the current loop value is stored in {iter}
. Once the loop finishes, the loop value of the outside loop will be copied back again.
If you want to access the loop variable inside nested loops, you will need to {set}
it to a new variable.
{loop:[<b=1>,]<e>[,<s=1>;<content>;}
b
The inclusive loop beginning.e
The inclusive loop ending.s
The loop step.content
The content to loop through.no args
No arguments were given.invalid args
Either too few or too many args were given.invalid range
invalid values for the range of the loop.
Works like a find and replace function in a text editor.
This command has 2 different syntaxes. The old and depreciated one and a new one.
Switching between the two is done by setting the {newrep}
variable.
{rep:<var>;<in>;<with>;}
{rep:<var>;<with>;<in>;}
{set:newrep;true;}
.
var
The search variable. This can be a regex string by wrapping it in /swith
The evaluated replace value.in
The string to search and replace.no args
No arguments were given.invalid args
Too few or too many args were given.
Splits a string based on a given separator, generating a set of variables with the split values.
Each element of the output will be saved in a variable with a given prefix, and counting up from 1.
This function returns the total number of elements (which is by definition the highest valid output index.)
{split:<var>;<content>[;<sep=,>];}
var
The output variable prefix. Must be a valid variable name.content
The content to split.sep
The string to split on.no args
No arguments were given.invalid args
Too few or too many args were given.invalid key
Output parameter is not a valid valid name.
All arithmetic is done through a single function.
Each method takes a specific number of arguments and has a specific resolution.
The resolution is either int or float, the args are either exactly 1, exactly 2 or 2 and more.
You can use aliases, e.e. add
and +
, not
and ~
{math:<op>;<arg1>[[;<arg2>];<...>];}
op
The operator to use.arg1
The first arg.arg2
The second arg. Omitted in = 1
operators....
Any aditional args. Only used in ≥ 2
operators.Operation | Aliases | Arguments | Resolution | Description |
---|---|---|---|---|
add | + | ≥ 2 | float | Addition |
sub | - | = 2 | float | Subtraction |
mul | * | ≥ 2 | float | Multiplication |
div | /, /f | = 2 | float | Division |
idiv | // | = 2 | int | Integer Division |
mod | % | = 2 | int | Modulo Function |
pow | ** | = 2 | float | Exponent |
and | & | ≥ 2 | int | Bitwise AND |
or | | | ≥ 2 | int | Bitwise OR |
xor | ^ | = 2 | int | Bitwise XOR |
not | ~ | = 1 | int | Bitwise NOT |
max | ≥ 2 | float | Maximum Number | |
min | ≥ 2 | float | Minimum Number | |
floor | = 1 | float | Floor Function | |
ceil | = 1 | float | Ceiling Function | |
round | = 1 | float | Round Function |
no args
No arguments were given.unknon op
The operator was not recognised.invalid args
The number of args doesn't match the operator.non-int args
, non-float args
The args could not be cast properly.inf
, -inf
The result is too large or small.divide by 0
Attempted to divide by 0.
This strips all the newlines and leading whitespace from code, allowing it to be formatted in a readable way without leaving a lot of newlines.
A backslash at the end of a line will make the newline remain, but not preserve the next line's leading whitespace.
A "\n" anywhere inside the block will insert a newline.
Using a empty comment {!}
will force the start of the line, allowing for leading whitespace.
{oneline:<content>;}
content
The content to condense.no content
No content was given.
This evaluates its internal code and then swallows the output.
The output will be printed to the debug log, accessable through +tag debug
{void:<content>;}
content
The content to evaluate.
Tags have access to a set of state variables. These are similar to variables created using {set}
, but with 1 very big difference:
State variables aren't deleted when a tag call ends!
This allows you to create tags that can remember things, like when they were called, or who called them, or things like that.
There is a small list of restrictions with state variables however:
There is only 1 command that you can use to save variables to the state.
This function takes an evaluated value and saves it to the tags state dictionary.
While not strictly required, some syntax highlighters will mark functions starting with s_
. This makes it easier to see what is a state variable. e.g. {s_lastcall}
.
{save:<name>;<content>;}
{save:<name>;}
name
The state variable name.content
The content to store.no args
No args were given.invalid args
Either too many or not enough args were given.invalid key
The key value is not a valid identifier name.too many variables
There are already 16 state variables.invalid name
A reserved key was used or the name was too long.content too long
The content was too long.You can set up some initial state variables when you create a tag. These defaults are actually stored and used when a tag is cloned or reset.
{init} <initialisation code> {endinit}
42 will read this as its own short script and then immediately comment the
entire section out to prevent it being shown in a regular call.
init and endinit are not yna objects. They are more
akin to preprocessor instructions.
In the same vein, 42 does not care if you have commented the init block already.
She will still find it and execute it when the tag is created.
Tags have the ability to import other tags within some reason.
If you wish to create a library tag for anyone to use, you must mark it as such.
Add this line to your code to mark a tag as library:
{!!library}
This function is how you import tags. The content of the tag will replace this call in its relative position to your script.
{call:<tagname>;}
tagname
The tag to call.no tag
You did not supply a tag name.not found
The tag was not found.no access
You do not own the tag and it is not public.already used
The tag has already been imported.out of calls
You have already used call 3 times.
If you are a Supporter or the server owner, you can create tags that post rich embeds as well as text.
Note that when you stop supporting, your embed tags will no longer embed. Also, this is checked off the tag's owner, not off of {meid}
.
Editing is done using the {embed}
object. You cannot unset an element once you have set it though.
{embed:<attribute>;<args...>;}
attribute
The part of the embed to edit.args...
The list of args for that attribute.{embed:author;<name>;}
{embed:author;name;<name>;}
{embed:author;url;<url>;}
{embed:author;icon_url;<url>;}
{embed:author;<name>;<url>;<icon_url>;}
{embed:title;<title>;}
{embed:url;<title-url>;}
{embed:description;<content>;}
{embed:footer;<text>;}
{embed:footer;text;<text>;}
{embed:footer;icon_url;<url>;}
{embed:footer;<text>;<icon_url>;}
{embed:thumbnail;<url>;}
{embed:image;<url>;}
{embed:colour;<0xRRGGBB>;}
{embed:colour;<red>;<green>;<blue>;}
{embed:field;<label>;<content>;}
{embed:timestamp;<args>;}
{embed:timestamp;;<time;>;
;
, the date will be set to UTC Today and only the time is defined.
no args
You did not specify an attribute,invalid field
The embed field was not validattrib invalid args
The field was passed invalid args. See debug for details.no author name
Author requires a name to be specifiedinvalid timestamp
Could not parse timestamp, either invalid values (33 days) or too many values (9 args).invalid colour
Could not map colour values into a colour.
Here is a list of relatively simple tags created by either myself or the community.
If you want your tag here, let me know over on Kiwi Hangout.
Credit will be given where it is due.