716 lines
17 KiB
Plaintext
716 lines
17 KiB
Plaintext
- Re: Syntax Tutorial
|
|
|
|
- Number literals
|
|
|
|
- Base literals
|
|
|
|
WriteLog(0b1011); //Binary literal, outputs 11
|
|
WriteLog(0o503); //Octal literal, outputs 323
|
|
WriteLog(0x8f62); //Hexadecimal literal, outputs 36706
|
|
|
|
Base literals default to integer type unless suffixed otherwise.
|
|
|
|
- Suffix
|
|
|
|
- "f" / "F"
|
|
Forces a number literal to a float type.
|
|
- "i" / "I"
|
|
Forces a number literal to an integer type.
|
|
|
|
Example:
|
|
WriteLog(5); //5.000000
|
|
WriteLog(5f); //5.000000
|
|
WriteLog(5i); //5
|
|
WriteLog(0x5f); //95
|
|
WriteLog(0x5fi); //95
|
|
WriteLog(7.76); //7.760000
|
|
WriteLog(7.76f); //7.760000
|
|
WriteLog(7.76i); //7
|
|
|
|
- Digit separator
|
|
|
|
The "_" character can be used in number literals to aid in visibility.
|
|
Has no effect on the resultant value.
|
|
|
|
WriteLog(5000000000i); //5000000000
|
|
WriteLog(5_000_000_000i); //still 5000000000
|
|
WriteLog(0x7f23a7e2); //2133043170
|
|
WriteLog(0x7f23_a7e2); //still 2133043170
|
|
|
|
- Variables
|
|
|
|
- Explicit types
|
|
|
|
Originally, you'd declare a variable with one of these three keywords:
|
|
- let
|
|
- var
|
|
- real
|
|
All three keywords had the same effect on the declaration.
|
|
|
|
However, with version 1.30a, the scripting language has gone through a considerable amount of changes as follows:
|
|
- "real" has been renamed to "float". (1.32a)
|
|
|
|
- You may now explicitly state the type of the variable you are declaring.
|
|
|
|
Example:
|
|
int a = 700; //typeof(a) == VAR_INT
|
|
float b = 56.243; //typeof(b) == VAR_FLOAT
|
|
char c = '0'; //typeof(c) == VAR_CHAR
|
|
bool d = false; //typeof(d) == VAR_BOOL
|
|
string e = "aubergine"; //typeof(e) == VAR_STRING
|
|
int[] f = [4i, 8]; //typeof(f) == VAR_ARRAY, ftypeof(f) == VAR_INT
|
|
|
|
- This does not change "let" and "var", they will still behave similarly to "auto" in C++.
|
|
|
|
Example:
|
|
let a = 700i; //typeof(a) == VAR_INT
|
|
let b = 56.243; //typeof(b) == VAR_FLOAT
|
|
let c = '0'; //typeof(c) == VAR_CHAR
|
|
let d = false; //typeof(d) == VAR_BOOL
|
|
let e = "aubergine"; //typeof(e) == VAR_STRING
|
|
let f = [4i, 8]; //typeof(f) == VAR_ARRAY, ftypeof(f) == VAR_INT
|
|
|
|
- You may not use "let[]" or "const[]".
|
|
|
|
An array type declaration may only be used with a non-auto type.
|
|
|
|
- Multiple variables declaration.
|
|
|
|
Example:
|
|
int a, b = 7, c = 100, d; //All will be of type "int"
|
|
const bool e = true, f = true; //All will be of type "const bool"
|
|
let g = 56, h = true, i = 6i; //g will be "float", h will be "bool", and i will be "int"
|
|
bool[][][] j, k; //All will be of type "bool[][][]" (3D bool array)
|
|
|
|
- Using "const"
|
|
|
|
"const" is used to declare constant variables.
|
|
|
|
A standalone "const" will behave like a "let".
|
|
"const" can be prefixed or suffixed by another type.
|
|
|
|
Constant variables cannot be modified.
|
|
Attempting to do so will throw a compile-time error.
|
|
|
|
Example:
|
|
const a = 1;
|
|
const let b = true;
|
|
const string c = "xolotl";
|
|
const int d;
|
|
|
|
a = 6; //ERROR
|
|
d = 10; //ERROR
|
|
|
|
- Supplement for smart people
|
|
|
|
ph3sx script type | internal C type | size in bytes |
|
|
----------------------------------------------------------
|
|
int | int64_t | 8 |
|
|
float | double | 8 |
|
|
bool | bool | 1 |
|
|
char | wchar_t | 2 |
|
|
|
|
- Scoping
|
|
|
|
- "local" has been deprecated. While they have not yet been completely removed, it is advisable to stop using it.
|
|
|
|
- But what can I use in its place?
|
|
|
|
Nothing.
|
|
Literally.
|
|
|
|
What used to be:
|
|
|
|
local {
|
|
//...
|
|
}
|
|
|
|
can now be reduced to just:
|
|
|
|
{
|
|
//...
|
|
}
|
|
|
|
Scoping rules will still apply normally, like so:
|
|
|
|
let a;
|
|
|
|
//Only a is accessible here
|
|
|
|
{
|
|
let b;
|
|
|
|
//a and b are both accessible here
|
|
|
|
{
|
|
let c;
|
|
|
|
//a, b, and c are all accessible here
|
|
}
|
|
}
|
|
|
|
- Operators
|
|
|
|
All available script operators are listed as follows.
|
|
They are arranged in order of precedence, highest-to-lowest.
|
|
|
|
1. ()
|
|
Function call
|
|
let c = SomeFunc(a, b);
|
|
1. as_x()
|
|
Type cast
|
|
let a = as_int(x);
|
|
let b = as_bool(56);
|
|
1. length()
|
|
Array length
|
|
let a = length(x);
|
|
let b = length([1, 2, 3]);
|
|
1. []
|
|
Array indexing
|
|
let a = arr[3];
|
|
let b = [10, 100, 1000][x];
|
|
1. (| |)
|
|
Absolute
|
|
let a = (|-4|); //a == 4
|
|
let b = (|a|); //b == 4
|
|
1. ()
|
|
Parentheses
|
|
2. ^
|
|
Power (Right-associative)
|
|
let a = 2 ^ 4; //a == 16
|
|
let b = 2 ^ 2 ^ 3; //b == 256
|
|
2. [..]
|
|
Array slice
|
|
let x = [9, 10, 11, 12, 13];
|
|
let a = x[0..2]; //a == [9, 10]
|
|
let b = x[2..999]; //b == [11, 12, 13]
|
|
let c = x[3..0]; //c == [11, 10, 9]
|
|
3. +
|
|
Unary plus
|
|
let a = +6;
|
|
3. -
|
|
Unary minus
|
|
let a = -10;
|
|
3. !
|
|
Unary logical not
|
|
let a = !b;
|
|
3. ~
|
|
Unary bitwise not
|
|
let a = ~312; //a == -313
|
|
let b = ~(0b1011001); //b == -90
|
|
4. *
|
|
Multiply
|
|
let a = 4 * 10; //a == 40
|
|
4. /
|
|
Divide
|
|
let a = 10 / 3; //a == 3.333333
|
|
4. ~/
|
|
Floored divide
|
|
let a = 10 ~/ 3; //a == 3
|
|
4. %
|
|
Remainder (Modulo)
|
|
let a = 7 % 4; //a == 3
|
|
5. +
|
|
Add
|
|
let a = 3 + 32; //a == 35
|
|
5. -
|
|
Subtract
|
|
let a = 9 - 12; //a == -3
|
|
5. ~
|
|
Array concatenate
|
|
let a = [8, 3] ~ [10]; //a == [8, 3, 10]
|
|
6. <<
|
|
Bitwise shift left
|
|
let a = 7 << 3; //a == 56
|
|
6. >>
|
|
Bitwise shift right
|
|
let a = 198 >> 2; //a == 49
|
|
7. ==
|
|
!=
|
|
<
|
|
<=
|
|
>
|
|
>=
|
|
Comparison
|
|
let a = 5 < 6;
|
|
let b = a != false;
|
|
let c = 10 >= 10;
|
|
8. ^^
|
|
Bitwise XOR
|
|
let a = 63 ^^ 234; //a == 213
|
|
9. |
|
|
Bitwise OR
|
|
let a = 63 | 234; //a == 255
|
|
10. &
|
|
Bitwise AND
|
|
let a = 63 & 234; //a == 42
|
|
11. ||
|
|
Logical OR
|
|
let a = true || false; //a == true
|
|
11. &&
|
|
Logical AND
|
|
let a = true || false; //a == false
|
|
12. ?:
|
|
Ternary expression
|
|
let a = x > y ? 10 : 20;
|
|
let b = z == 0 ? x * 10 : y + 4;
|
|
let c = k ? (y ? 8 : 0) : p ? 5 : 2 + x;
|
|
|
|
- Boolean expressions
|
|
|
|
- Short-circuiting
|
|
|
|
This feature was present in vanilla ph3 as well, but I have yet to see a tutorial mention it, so here it is.
|
|
|
|
Short-circuiting (short-circuit evaluation) is an optimization for boolean expressions.
|
|
|
|
Take these statements, for example:
|
|
bool c = a && b;
|
|
bool z = x || y;
|
|
|
|
This !RUN-TIME! optimization will occur when expression (a) evaluates to false,
|
|
where the evaluation of expression (b) will be completely skipped over.
|
|
Conversely, in the second statement, the evaluation of expression (y) will also be skipped over if
|
|
expression (x) evaluates to true.
|
|
|
|
Short-circuiting will take place left-to-right, so it is beneficial to format your logical expressions
|
|
in a way that more lightweight expressions get evaluated sooner rather than later.
|
|
|
|
Example:
|
|
if (bCheckHit && GetShotIdInCircleA2(...)) { /*...*/ }
|
|
|
|
would benefit more from short-circuit evaluation than
|
|
|
|
if (GetShotIdInCircleA2(...) && bCheckHit) { /*...*/ }
|
|
|
|
Short-circuiting only applies to logical expressions, not bitwise expressions.
|
|
|
|
Example:
|
|
bool c = a & b;
|
|
bool d = a | b;
|
|
|
|
Here, both expressions (a) and (b) will be evaluated regardless of the result of expression (a).
|
|
|
|
- Loops
|
|
|
|
- Ascent/Descent
|
|
|
|
Ascent and descent loops remain unchanged, but you may now assign an explicit type to the counter variable.
|
|
|
|
Example:
|
|
|
|
ascent (i in 0..3)
|
|
WriteLog(i);
|
|
|
|
Will result in the following output:
|
|
0.000000
|
|
1.000000
|
|
2.000000
|
|
|
|
//-----------------------------------------------
|
|
|
|
ascent (i in 0i..3)
|
|
WriteLog(i);
|
|
|
|
Will result in the following output:
|
|
0
|
|
1
|
|
2
|
|
|
|
//-----------------------------------------------
|
|
|
|
ascent (int i in 0..3)
|
|
WriteLog(i);
|
|
|
|
Will result in the following output:
|
|
0
|
|
1
|
|
2
|
|
|
|
- In ph3sx, two new loops are available for use.
|
|
|
|
- For loop
|
|
|
|
The for loop is the more generalized version of ascent/descent loops.
|
|
|
|
It's also the standard loop format in most programming languages,
|
|
which means I don't have to explain its usage here.
|
|
|
|
- For-each loop
|
|
|
|
The for-each loop is a quick and efficient method to iterate through arrays.
|
|
|
|
Example:
|
|
|
|
int[] arr = [10, 9, 8, 7];
|
|
for each (int i in arr)
|
|
WriteLog(i);
|
|
|
|
Will result in the following output:
|
|
10
|
|
9
|
|
8
|
|
7
|
|
|
|
//-----------------------------------------------
|
|
|
|
for each (float i in arr)
|
|
WriteLog(i);
|
|
|
|
Will result in the following output:
|
|
10.000000
|
|
9.000000
|
|
8.000000
|
|
7.000000
|
|
|
|
- The "ref" keyword
|
|
|
|
Normally, the array fed into a for-each loop will be a copy of the original array.
|
|
However, you can force the loop to directly read from the original array with the "ref" keyword.
|
|
|
|
As the array won't be copied, there would also be some performance benefits to be had,
|
|
and the loop will respond to any modifications to the array rather than being unaffected.
|
|
|
|
Example:
|
|
|
|
int[] arr = [1, 2, 3, 4];
|
|
|
|
for each (i in arr) {
|
|
if (i % 2 == 0)
|
|
arr ~= [5];
|
|
WriteLog(i);
|
|
}
|
|
WriteLog(arr);
|
|
|
|
Will result in the following output:
|
|
1
|
|
2
|
|
3
|
|
4
|
|
[1, 2, 3, 4, 5, 5]
|
|
|
|
//-----------------------------------------------
|
|
|
|
for each (i in ref arr) {
|
|
if (i % 2 == 0)
|
|
arr ~= [5];
|
|
WriteLog(i);
|
|
}
|
|
WriteLog(arr);
|
|
|
|
Will result in the following output:
|
|
1
|
|
2
|
|
3
|
|
4
|
|
5
|
|
5
|
|
[1, 2, 3, 4, 5, 5]
|
|
|
|
- Special syntaxes
|
|
|
|
- There is also another declaration syntax for the for-each loop:
|
|
|
|
{
|
|
int i = 0;
|
|
for each (itr in array) {
|
|
//...
|
|
i++;
|
|
}
|
|
}
|
|
|
|
//is equivalent to:
|
|
|
|
for each (i, itr in array) {
|
|
//...
|
|
}
|
|
|
|
- These formats are also allowed:
|
|
|
|
for each ((i, itr) in array) { /*...*/ }
|
|
for each ((int i, itr) in array) { /*...*/ }
|
|
for each (i, float itr in array) { /*...*/ }
|
|
for each ((float i, string itr) in array) { /*...*/ }
|
|
|
|
- You may use a colon(:) in place of the keyword "in"
|
|
|
|
for each (itr : array) { /*...*/ }
|
|
for each ((i, itr) : array) { /*...*/ }
|
|
|
|
- In addition, there is a new flow control statement "continue".
|
|
|
|
"continue" is used in the same manner as "break", but rather than simply ending the loop,
|
|
it will merely skip the current iteration of the loop.
|
|
|
|
Example:
|
|
|
|
ascent (int i in 0..8) {
|
|
if (i % 2 == 0) continue;
|
|
WriteLog(i);
|
|
}
|
|
|
|
Will result in the following output:
|
|
1
|
|
3
|
|
5
|
|
7
|
|
|
|
- Unlike in vanilla ph3, "break" can no longer be used outside a loop.
|
|
- Attempting to do so will throw a compile-time error.
|
|
- The same applies to "continue".
|
|
|
|
- Functions, Tasks, Subs ("Callables")
|
|
|
|
- Parameters
|
|
|
|
Parameters, like variables, can have explicit types.
|
|
|
|
Example:
|
|
|
|
function Func(int a, float b, const string[] c) {}
|
|
|
|
- Function return type
|
|
|
|
- You may explicitly specify a function's return type.
|
|
|
|
function<int> Func1(a, b) {
|
|
return a + b;
|
|
}
|
|
|
|
WriteLog(Func1(10, 4.2)); //Output: 14
|
|
WriteLog(Func1(10, "sdfs")); //ERROR: Invalid implicit casting
|
|
|
|
- Marking a function with type "void" will forbid it from returning a value.
|
|
|
|
function<void> Func1(a, b) {
|
|
return; //OK: no return value
|
|
}
|
|
|
|
function<void> Func2(a, b) {
|
|
return a + b; //ERROR: void function can't return a value
|
|
}
|
|
|
|
- Overloading
|
|
|
|
Two callables with the same name, but different argument counts, will be treated as two different, unique callables.
|
|
|
|
Example:
|
|
|
|
function<int> Func() {
|
|
return 0;
|
|
}
|
|
function<int> Func(a) {
|
|
return 100;
|
|
}
|
|
function<int> Func(a, b, c) {
|
|
return a + b + c;
|
|
}
|
|
|
|
DoStuff(); //Returns 0
|
|
DoStuff("asdf"); //Returns 100
|
|
DoStuff(1, 2, 3); //Returns 6
|
|
|
|
- Variadic argument count (varargs)
|
|
|
|
- Some default functions now allow for varargs.
|
|
|
|
Example:
|
|
|
|
NotifyEventAll(EV_USER, 0);
|
|
NotifyEventAll(EV_USER, 0, 1, 2, 3);
|
|
NotifyEventAll(EV_USER, 0, 1, 2, 3, 4, 5, 6, 7, 8);
|
|
|
|
//All of the above are valid calls to NotifyEventAll.
|
|
|
|
- You can pass a maximum of around 357900000 arguments, but please please don't actually do that.
|
|
|
|
- Scripters currently cannot define their own callables with varargs.
|
|
|
|
- Async
|
|
|
|
Async blocks can be placed anywhere in the code, they behave like inlined tasks.
|
|
|
|
Example:
|
|
|
|
function Func() {
|
|
WriteLog(0);
|
|
|
|
async {
|
|
WriteLog(1);
|
|
wait(10);
|
|
WriteLog(2);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//is equivalent to:
|
|
|
|
function Func() {
|
|
WriteLog(0);
|
|
|
|
task AsyncTask() {
|
|
WriteLog(1);
|
|
wait(10);
|
|
WriteLog(2);
|
|
}
|
|
AsyncTask();
|
|
|
|
return true;
|
|
}
|
|
|
|
- Script
|
|
|
|
- Char
|
|
|
|
- Backslash escapes (\\) is properly recognized in char/string literals.
|
|
- Hexadecimal char literals (\x[hex]) can be used in char/string literals.
|
|
Example:
|
|
"\x74" -> "t"
|
|
'\x3042' -> 'あ'
|
|
"\x042\x5f" -> "B_"
|
|
|
|
- One-lined statements
|
|
|
|
Example:
|
|
|
|
ascent (i in 0..10) WriteLog(i);
|
|
|
|
if (true) a += 10;
|
|
else a -= 4;
|
|
|
|
Can be used everywhere except in function/task/sub declarations, async blocks, @-blocks, and local{} blocks.
|
|
|
|
- Optimizations
|
|
|
|
- The script compiler will try to perform basic optimizations on maths expressions.
|
|
|
|
Examples:
|
|
|
|
a = 5 + 5 - 1; -> optimize -> a = 9;
|
|
a = 5 * 8 / 7; -> optimize -> a = 5.714286;
|
|
a = func(b) + 5 % 10; -> optimize -> a = func(b) + 5;
|
|
|
|
- Empty loops and blocks will be optimized away during script compiling.
|
|
|
|
Examples:
|
|
|
|
while (true) {}
|
|
|
|
for (let i = 0; i < 10; i++) {}
|
|
|
|
ascent (i in 0..100000000) {}
|
|
|
|
{
|
|
}
|
|
|
|
loop (1000) {
|
|
}
|
|
|
|
for each (i in "aaaaaaaaaa") {}
|
|
|
|
async {}
|
|
|
|
//All of the above examples will be optimized away
|
|
|
|
- Loops containing a single yield will be automatically transformed into a wait.
|
|
|
|
Examples:
|
|
|
|
loop (60) yield; -> optimize -> wait(60);
|
|
|
|
loop (a * 2 + 60 - 20) { -> optimize -> wait(a * 2 + 60 - 20);
|
|
yield;
|
|
}
|
|
|
|
- Text Object Tags
|
|
|
|
Text object tags are special formatting patterns that can be used to dynamically alter rendering of text objects.
|
|
|
|
Available tags:
|
|
|
|
- r
|
|
|
|
Inserts a new line. Also resets formatting from other tags.
|
|
|
|
- font / f
|
|
|
|
Modifies the font.
|
|
|
|
Available tag properties:
|
|
|
|
- reset / rs / r / clear / clr / c
|
|
|
|
Resets the text to its original settings. Present in vanilla ph3 as "clear".
|
|
|
|
- size / sz
|
|
|
|
Changes the font size. Unchanged from vanilla ph3.
|
|
|
|
- ox / oy
|
|
|
|
Changes the position offset.
|
|
|
|
- it
|
|
|
|
Toggles italic. (true/false or 1/0)
|
|
|
|
- wg
|
|
|
|
Changes the font's weight.
|
|
|
|
- br / bg / bb
|
|
|
|
Changes the font's bottom color.
|
|
|
|
- tr / tg / tb
|
|
|
|
Changes the font's top color.
|
|
|
|
- or / og / ob
|
|
|
|
Changes the font's border color.
|
|
|
|
- bc
|
|
|
|
Changes the font's bottom color as a (r, g, b) list.
|
|
|
|
- tc
|
|
|
|
Changes the font's top color as a (r, g, b) list.
|
|
|
|
- oc
|
|
|
|
Changes the font's border color as a (r, g, b) list.
|
|
|
|
Example:
|
|
|
|
ObjText_SetText(obj, "Lorem ipsum [font size=48 it=1 bc=(255, 0, 0)]dolor sit[font clr] amet");
|
|
|
|
- ruby
|
|
|
|
Creates a ruby(furigana) text.
|
|
|
|
Available tag properties:
|
|
|
|
- rb
|
|
|
|
Sets the main(bottom) text. Unchanged from vanilla ph3.
|
|
- rt
|
|
|
|
Sets the furigana(top) text. Unchanged from vanilla ph3.
|
|
- sz
|
|
|
|
Changes the furigana text's font size.
|
|
|
|
- wg
|
|
|
|
Changes the furigana text's font weight.
|
|
|
|
- ox
|
|
|
|
Changes the furigana text's left margin.
|
|
|
|
- op
|
|
|
|
Changes the furigana text's side pitch. |