https://github.com/optimalstrategy/ppga
A scripting language that transpiles to LUA
https://github.com/optimalstrategy/ppga
Last synced: 11 months ago
JSON representation
A scripting language that transpiles to LUA
- Host: GitHub
- URL: https://github.com/optimalstrategy/ppga
- Owner: optimalstrategy
- Created: 2020-06-27T15:46:27.000Z (about 6 years ago)
- Default Branch: master
- Last Pushed: 2021-04-05T03:48:04.000Z (over 5 years ago)
- Last Synced: 2025-07-11T09:32:04.070Z (about 1 year ago)
- Language: C++
- Size: 518 KB
- Stars: 2
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# PPGA Script
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](tour.ppga) for a quick tour.
## Binary Installation
* You may clone the repo and build from source, then use the scripts `ppga.sh` and `ppga.bat`.
OR
* You may install the binary with `cargo install` from this repo:
```bash
$ cargo install --git https://github.com/OptimalStrategy/ppga/ --features=build-binary
```
## Library
There's two implementations of the transpiler, in [Rust](ppga) and [C++](./ppga-cpp/README.md).
## Syntax Highlighting
There's a syntax highlighting plugin for vscode. It can be installed from the [vscode-ppga](vscode-ppga) directory.
## Language Reference
Feature
Description
Example
Generated Lua
Literals
None.
1;
3.141592;
true;
false;
nil;
"a string";
1
3.141592
true
false
nil
"a string"
Array and Dict literals
None.
// Arrays use python-style syntax
// and are initialized from 0.
let arr = [1, 2, 3];
// Dicts are similar to Lua but
// don't require the `[]`
let dict = {1 = 2, 3 = 4};
// Indexing uses the [] syntax:
let empty = {};
empty["string"] = "hello";
local arr = {[0] = 1, [1] = 2, [2] = 3}
local dict = {
[1] = 2,
[3] = 4
}
local empty = {}
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(true and false or true);
print(true and false or true)
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.
let a;
global b = 4;
local a
b = 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.
global fn f() {}
fn g() {}
fn h(x) => x * x
function f()
end
local function g()
end
local function h(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 `...`.
fn f(a, @) {
print(a, @);
}
local function f(a, ...)
print(a, ...)
end
Ellipsis / Unpacking
Strips the parentheses and unpacks the given expression with `table.unpack`.
fn f(x) {
fn packed() {
return x, 5;
}
if not x {
// returns the result of packed
// as a single value:
// => return (packed())
return packed();
}
// unpacks the result of packed() as two values:
// => return unpack({packed()})
return ...packed();
}
local function f(x)
local function packed()
return (y), (5)
end
if not(x) then
return (packed())
end
return __PPGA_INTERNAL_UNPACK(packed())
end
For Loop (ranges)
For-range loops transpile to Lua range loops
// From 0 to 3
for i in range(3) {
print(i);
}
// From 2 to 4
for i in range(2, 4) {
print(i);
}
// From 0 to 10 with step = 2
for i in range(0, 10, 2) {
print(i);
}
for i = 0, 3, 1 do
print(i)
end
for i = 2, 4, 1 do
print(i)
end
for i = 0, 10, 2 do
print(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 pairs
for key, value in container {
print(key, value);
}
// Array iteration, uses ipairs
fori idx, value in container {
print(idx, value);
}
local container = {[0] = 1, [1] = 2, [2] = 3}
container["string"] = "hello"
for key, value in pairs(container) do
print(key, value)
end
for idx, value in ipairs(container) do
print(idx, value)
end
Error Propagation with `?` and `err` Blocks
None.
fn may_fail(fail) {
if fail {
return nil, "error";
}
return "success", nil;
}
fn main() {
// 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"First result: {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;
}
local function may_fail(fail)
if fail then
return (nil), ("error")
end
return ("success"), (nil)
end
local function main()
local ok = nil
do
local _ok_L10S283, _err_L10S283 =
__PPGA_INTERNAL_HANDLE_ERR(
__PPGA_INTERNAL_DFLT_ERR_CB,
may_fail(false)
)
if _err_L10S283 ~= nil then
return (nil), (_err_L10S283)
end
ok = _ok_L10S283
end
print("First result: " .. tostring(ok))
local ok = nil
do
local _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 ~= nil then
return (nil), (_err_L18S562)
end
ok = _ok_L18S562
end
return (ok)
end
a hack to widen the column