PPGA Script is a scripting language that transpiles to Lua, original designed to be used in https://github.com/jprochazk/anikibot. It provides a more familiar C-style syntax and syntactic sugar, designed to reduce the amount of boilerplate when writing scripting commands in lua.
See tour.ppga for a quick tour.
- You may clone the repo and build from source, then use the scripts
ppga.shandppga.bat.
OR
You may install the binary with
cargo installfrom this repo:$ cargo install --git https://github.com/OptimalStrategy/ppga/ --features=build-binary
There's two implementations of the transpiler, in Rust and C++.
There's a syntax highlighting plugin for vscode. It can be installed from the vscode-ppga directory.
| Feature | Description | Example | Generated Lua |
|---|---|---|---|
| Literals | None. | 1;3.141592;true;false;nil;"a string"; | 13.141592truefalsenil"a string" |
| Array and Dict literals | None. | // Arrays use python-style syntax // and are initialized from 0.letarr=[1,2,3];// Dicts are similar to Lua but // don't require the `[]`letdict={1=2,3=4};// Indexing uses the [] syntax: letempty={};empty["string"]="hello"; | localarr= {[0] =1, [1] =2, [2] =3}
localdict= {
[1] =2,
[3] =4
}
localempty= {}
empty["string"] ="hello" |
| F-strings | An interpolated string expression that compiles to concatenation of string literals and tostring() calls. A backslash can be used to escape formatter brackets: \{}. | print(f"{a} + {b} = {a + b}");print(f"\{escaped}"); | print(tostring(a) .." + " ..tostring(b) .." = " ..tostring(a+b))
print("{escaped}") |
| Arithmetic Expressions | None. | print(1+2*3/4**5%10); | print(1+2*3/4^5%10) |
| Integer Division | Integer division operator. | print(1 \ 2); | print(1//2) |
| Comparison and Equality operators | None. | print(3<4,5<=6,8>7,9>=8,10!=11,7==7); | print(3<4, 5<=6, 8>7, 9>=8, 10~=11, 7==7) |
| Logic operators | None. | print(trueandfalseortrue); | print(trueandfalseortrue) |
| Concatenation Operator | This operator is the same as in lua. Reusing `+` for concatenation is not possible without rolling out a type system. | print("a" .."b");
| print("a" .."b")
|
| Default Operator | This operator is similar to `??` in C#. If `a` is not `nil`, its value will be returned, otherwise, the `b` value will be returned. This feature requires the PPGA internals included. | print(a??b); | print(__PPGA_INTERNAL_DEFAULT(a, b))
|
| Variable Declarations | Let bindings correspond to `local` lua variables, while `global` ones transpile to variables without a binding keyword. A `global` variable must be initialized at declaration. | leta;globalb=4; | localab=4 |
| Function Declarations | All functions are `local` by default. The `global` keyword may be used to make them global. The "fat arrow" syntax can be used if the function's body is a single expression. | globalfnf() {}
fng() {}
fnh(x) =>x*x | functionf()
endlocalfunctiong()
endlocalfunctionh(x)
return (x*x)
end |
| Lambda Expressions | Lambdas use the same syntax as named functions, except that they don't need an identifier. | print(fn(y,f){});print(fn(x)=>x*x); | print(function (y, f)
end)
print(function (x)
return (x*x)
end)
|
| Rest Arguments / Variadics | Rest arguments use the `@` symbol and transpile to `...`. | fnf(a, @) {
print(a, @);
}
| localfunctionf(a, ...)
print(a, ...)
end |
| Ellipsis / Unpacking | Strips the parentheses and unpacks the given expression with `table.unpack`. | fnf(x){fnpacked(){return x,5;}if not x {// returns the result of packed // as a single value:// => return (packed())returnpacked();}// unpacks the result of packed() as two values:// => return unpack({packed()})return ...packed();} | localfunctionf(x)
localfunctionpacked()
return (y), (5)
endifnot(x) thenreturn (packed())
endreturn__PPGA_INTERNAL_UNPACK(packed())
end |
| For Loop (ranges) | For-range loops transpile to Lua range loops | // From 0 to 3for i inrange(3){print(i);}// From 2 to 4for i inrange(2,4){print(i);}// From 0 to 10 with step = 2for i inrange(0,10,2){print(i);} | fori=0, 3, 1doprint(i)
endfori=2, 4, 1doprint(i)
endfori=0, 10, 2doprint(i)
end |
| For Loop (containers) | For-in loops transpile to `pairs` or `ipairs` depending on the keyword used. | let container = [1,2,3];
container["string"] = "hello";// Table iteration, uses pairsfor key, value in container {print(key, value);}// Array iteration, uses ipairs
fori idx, value in container{
print(idx, value);} | localcontainer= {[0] =1, [1] =2, [2] =3}
container["string"] ="hello"forkey, valueinpairs(container) doprint(key, value)
endforidx, valueinipairs(container) doprint(idx, value)
end |
| Error Propagation with `?` and `err` Blocks | None. | fnmay_fail(fail){if fail {return nil,"error";}return"success", nil;}fnmain(){// The ? operator simplifies Go-style // error handling. By default, this // will make the whole program // crash if an error is encountered.let ok = may_fail(false)?;print(f"Firstresult:{ok}");// Sometimes it is desirable to log or // try to recover from the error.// An err block may be used for this purpose:let ok = may_fail(true)err{
print(f"An error has occurred:{err}");return ...recovery();}?;return ok;} | localfunctionmay_fail(fail)
iffailthenreturn (nil), ("error")
endreturn ("success"), (nil)
endlocalfunctionmain()
localok=nildolocal_ok_L10S283, _err_L10S283=__PPGA_INTERNAL_HANDLE_ERR(
__PPGA_INTERNAL_DFLT_ERR_CB, may_fail(false)
)
if_err_L10S283~=nilthenreturn (nil), (_err_L10S283)
endok=_ok_L10S283endprint("First result: " ..tostring(ok))
localok=nildolocal_ok_L18S562, _err_L18S562=__PPGA_INTERNAL_HANDLE_ERR(
function (err) print("An error has occurred: " ..tostring(err))
return (unpack(recovery()))
end,
may_fail(true)
)
if_err_L18S562~=nilthenreturn (nil), (_err_L18S562)
endok=_ok_L18S562endreturn (ok)
end |
|