Siteswap Query Language

By using the Siteswap Query Language (SsQL), you can specify the search method and the display method of results in detail. The complete syntax is:

FROM "pattern"
LET variable-definition
WHERE acquisition-condition
SELECT display-items
ORDER BY sort-condition
LIMIT number

However, you can omit everything except the FROM clause. Specify the clauses that are not omitted in this order. The LET clause can be specified multiple times.

In the FROM clause, describe the search pattern with double quotation marks. If you want to use double quotation marks in your pattern, you must escape them with \.

Only the maximum number can be specified in the LIMIT clause. The time limit can not be specified, so if you want to stop the search halfway, press the stop button. If you omit the LIMIT clause, the search continues indefinitely.

Acquisition condition

Specify the acquisition condition by combining variables, properties, methods, and operators in the WHERE clause. For example:

WHERE $0.balls == 3

If the condition is satisfied, the string is acquired, and if not, it is not acquired. If you omit the WHERE clause, you get all the generated strings.

Variables include auto-defined variables and user-defined variables. Auto-defined variables are specified by $ + numbers such as $0, $1, $2, .... User-defined variables will be described later. $0 represents the entire string, and $1, $2, etc. represent the first group, second group, and so on. You can write $ instead of $0 as an abbreviation. If the pattern specified in the FROM clause is (5+)([13]), the string are assigned to the variable as follows.

 $0$1$2
1st5151
2nd5353
3rd551551
4th553553
5th55515551
::::

Properties are specified after variable and dot.

propertyexplanationexample
patternthe string itself315315
lengthstring length6
reversereverse order513513
minminimum pattern153153
maxmaximum pattern531531
omissionabbreviation315
standardstandard form531
jugglablewhether jugglable1
validwhether valid siteswap1
ballsnumber of balls3
periodsiteswap period3
statesiteswap state19
int10base 10 value315315
int36base 36 value183315353

The value of "jugglable" is 1 if it is jugglable and 0 otherwise. "valid" is similar. "balls" and "state" will be -1 if the pattern is not jugglable. "period" will be -1 if the pattern is not a siteswap, even if it is jugglable. "int10" is a numerical value from the beginning to the position where it can be regarded as a decimal integer. "int36" is similar. Property can be omitted. If omitted, it is assumed that "pattern" is specified.

Methods are specified in the same way as properties, but with parentheses followed by arguments, such as $0.at(1). In the example in the following table, methods are applied to string "12345".

methodexplanationn = 1n = -2
at(n)character at that index24
rotate(n)rotation for n characters2345145123
skip(n)skip n characters2345123
take(n)take n characters145

All of these methods count from the left if you specify 0 or a positive number as an argument, and from the right if you specify a negative number. The leftmost position is 0 and the rightmost position is -1.

Some methods are iterative methods that take a lambda expression as an argument.

iteratorexplanation
every(lambda)whether it holds for all indexes
some(lambda)whether it holds for any one index

Lambda expressions are specified in the following format:

index => condition

or

index, whole => condition

Here, both the index variable and the variable that represents the whole are user-defined variables. User-defined variables can be specified as $ + strings, such as $index, $x1, $_, and can be used in acquisition conditions. The following is a concrete example of the former format.

$0.every($index => $0.at($index) == 1)

If the length of $0 is n, 0 to n-1 are assigned to $index in order, and the right side of => is iterated. On the right side, it is determined whether the characters from the 0th digit to the n-1th digit are 1, so throughout this example, it is determined whether all the digits of $0 are 1.

$0.take(2).some($index, $whole => $whole.at($index) == 1)

This is a concrete example of the latter form, which determines if there is a 1 in the first two digits of $0. It is the same as writing $0.take(2) instead of $whole, but more concise.

The following is a list of operators by priority.

priorityoperatormeaning
1.string on the right is a property or a method
2*multiplication
/quotient of integer division
%remainder of integer division
3+addition
-subtraction
&concatenation of strings
4==left and right values are equal
!=left and right values are different
<>
<left value is less than right value
<=left value is less than or equal to right value
>left value is more than right value
>=left value is more than or equal to right value
IN(...)left value is contained in ...
NOT IN(...)left value is not contained in ...
5NOTright condition is false
6ANDboth left and right conditions are true
7OReither left or right condition is true

If operators with the same priority are listed, they are evaluated from the left. When you want to change the priority, enclose the part in parentheses, such as 2*(3+4).

Only decimal integers are treated as numbers. When performing numerical calculation on a string, it is assumed that the "int10" property is implicitly specified. The result of the comparison operation is 1 for true and 0 for false. In the operation of NOT, AND and OR, only the number 0, the string "0", and the empty string represent false, and true otherwise.

The IN operator is used as follows:

$0.standard IN("71", "62", "53")

In this case, it will be true (or 1) if the standard form of the variable $0 is 71, 62, or 53.

Display items

Specify display items such as variables and constants separated by white space in the SELECT clause. For example:

SELECT $0 "(" $0.balls ")"

White spaces are not included in the displayed string, so specify the spaces in double quotation marks if necessary. The string enclosed in double quotation marks is output as is. If you omit the SELECT clause, you get the entire generated string (assuming $0.pattern was specified).

You can also use operators. For example:

SELECT $0.int10 "+1=" $0.int10 + 1

genarates 3+1=4 etc.

To suppress the output of the same string, specify DISTINCT after SELECT. If you want to generate only unique strings, describe as follows.

SELECT DISTINCT $0

DISTINCT is similar to the WHERE clause in that it limits the number of strings displayed, but WHERE covers the conditions that the generated string satisfies, whereas DISTINCT only covers whether the entire string processed by SELECT already exists.

Sort condition

Specify sorting conditions separated by commas in the ORDER BY clause.

ORDER BY $0.period DESC, $0

If you specify DESC after the condition, the order will be descending. If you specify ASC or nothing, the order will be ascending. The above example means "descending by siteswap period, then ascending by string itself". If the strings generated are 3, 441, 531, then the longer siteswap periods 441 and 531 come first and the shorter period 3 comes later. In 441 and 531, 441 is smaller as a string, so it comes earlier, and finally 441 531 3 is output.

If you omit the ORDER BY clause, they are displayed in the order they were generated.

Variable definition

The LET clause defines a variable that can be used throughout the statement.

LET $const = "123"

The left side of equal is the variable name, and the right side is the definition. Like user-defined variables that appear in lambda expressions, variable names are specified with the $ + string. The first character of the variable name can be an alphabet or an underscore, and numbers can be used in addition to that after the second character. Case is ignored and $name and $Name and $NAME are treated as the same name. You can not define multiple variables with the same name.

Any number of LET clauses can be written for one SsQL statement. You can use variables as well as constants in definitions.

LET $var1 = $1
LET $var2 = $var1 + 3
LET $var3 = $0.at($index)

Using an undefined variable will result in an error, but the order of definition does not matter, so there is no problem if you use $var3 as follows.

WHERE $0.every($index => $var3 < 3)

Comments and other

You can also write a comment in SsQL.

-- 1 line comment
/* Multi-
line
comment */

Line comments are from -- to the end of the line, block comments are from /* to */. Only one line comment can be specified per line, and it can not span multiple lines. On the other hand, a block comment can be written over multiple lines, or multiple block comments can be written in the middle of a line. However, you can not nest comments.

You can write SsQL in free format. That is spaces, line breaks, and comments between keywords are ignored.

Uppercase letters are converted to lowercase. The message when there is an error is also displayed as a string converted to lowercase letters.

Language specifications

For reference, I describe the specifications of the accepted SsQL in HABA format.

Query ::= From Let* Where? Select? Order? Limit? ;
From ::= 'FROM' String ;
String ::= """(\\""|[^""])*""" ;
Let ::= 'LET' User '=' Term ;
Where ::= 'WHERE' Condition ;
Condition ::= Part ('OR' Part)* ;
Part ::= Unit ('AND' Unit)* ;
Unit ::= 'NOT'? Expression ;
Expression ::= Term (Compare Term | Clause)? ;
Term ::= Factor (('+' | '-' | '&') Factor)* ;
Factor ::= Value (('*' | '/' | '%') Value)* ;
Value ::= Element ('.' (Property | Method | Iterator))* ;
Element ::= Auto | User | Literal | '(' Condition ')' ;
Auto ::= "\$[0-9]*" ;
User ::= "\$[a-z_][a-z_0-9]*" ;
Literal ::= String | Integer ;
Integer ::= "[0-9]+" ;
Property ::= 'pattern' | 'length' | 'reverse' | 'min' | 'max' | 'omission' | 'standard' | 'jugglable' | 'valid' | 'balls' | 'period' | 'state' | 'int10' | 'int36' ;
Method ::= ('at' | 'rotate' | 'skip' | 'take') '(' Parameter ')' ;
Parameter ::= Term | '-' Value ;
Iterator ::=  ('every' | 'some') '(' Lambda ')' ;
Lambda ::= User (',' User)? '=>' Condition ;
Compare ::= '==' | '!=' | '<>' | '<' | '<=' | '>' | '>=' ;
Clause ::= 'NOT'? 'IN' '(' List ')' ;
List ::= Literal (',' Literal)* ;
Select ::= 'SELECT' 'DISTINCT'? View ;
View ::= Term+ ;
Order ::= 'ORDER' 'BY' Multiple ;
Multiple ::= Single (',' Single)* ;
Single ::= Value ('ASC' | 'DESC')? ;
Limit ::= 'LIMIT' Term ;
Space ::= "\s+" ;
Line ::= "--[^\n]*(\n|$)" ;
Block ::= "/\*((?!\*/)[\s\S])*\*/" ;