230 lines
6.8 KiB
Markdown
230 lines
6.8 KiB
Markdown
# `.tsrc` Language Reference
|
|
|
|
`.tsrc` (Tiny Soccer Sim Rust C) is a minimal C-like DSL for scripting soccer matches in tssr. It lets you define teams, assign players, script goals, and control output format — all from a plain text file.
|
|
|
|
## Invocation
|
|
|
|
### Via `--script` flag
|
|
|
|
```bash
|
|
tssr --script match.tsrc # table output
|
|
tssr --script match.tsrc --json # JSON output
|
|
```
|
|
|
|
### Via shebang
|
|
|
|
Add this as the first line of your `.tsrc` file:
|
|
|
|
```tsrc
|
|
#!/usr/bin/env tssr
|
|
```
|
|
|
|
Then make it executable and run directly:
|
|
|
|
```bash
|
|
chmod +x match.tsrc
|
|
./match.tsrc
|
|
```
|
|
|
|
## Language Syntax
|
|
|
|
### Team Declaration
|
|
|
|
```tsrc
|
|
string var_name = "Team Name";
|
|
```
|
|
|
|
Declares a variable that holds a team name. Variables can be referenced later in `players[]`, `goal()`, and `match()`.
|
|
|
|
**Rules:**
|
|
- Variable names must be alphanumeric + underscores
|
|
- Duplicate variable names are an error
|
|
- The string value is the team's display name
|
|
|
|
### Player Assignment
|
|
|
|
```tsrc
|
|
players["Player Name"] = var_name;
|
|
players["Player Name"] = "Team Name";
|
|
```
|
|
|
|
Assigns a player to a team. The right side can be either a previously declared variable or a string literal.
|
|
|
|
**Rules:**
|
|
- The team (right side) must resolve to a team that appears in `match()`
|
|
- The same player cannot be added to the same team twice
|
|
- Variables must be declared before use (forward references are an error)
|
|
|
|
### Scripted Goals
|
|
|
|
```tsrc
|
|
goal(minute, team, player);
|
|
```
|
|
|
|
Scripts a specific goal event. When any `goal()` appears, the match score becomes deterministic.
|
|
|
|
| Argument | Type | Description |
|
|
|----------|------|-------------|
|
|
| `minute` | integer (1-90) | Minute the goal was scored |
|
|
| `team` | variable or string | The team that scored |
|
|
| `player` | string literal | The player who scored |
|
|
|
|
**Rules:**
|
|
- Minute must be between 1 and 90
|
|
- Team must be one of the two match teams
|
|
- Player must be on that team's roster
|
|
- The same player cannot score at the same minute twice
|
|
- Variables must be declared before use
|
|
|
|
### Match Selection
|
|
|
|
```tsrc
|
|
match(var_home, var_away);
|
|
```
|
|
|
|
Selects which two teams play. **Required** — every `.tsrc` script must contain exactly one `match()`.
|
|
|
|
**Rules:**
|
|
- Both variables must be previously declared
|
|
- Home and away must be different teams
|
|
- Both teams must have at least one player assigned
|
|
|
|
### Output Mode Directive
|
|
|
|
```tsrc
|
|
#define JSON
|
|
#define ASCII_TABLE
|
|
#define UNICODE_TABLE
|
|
```
|
|
|
|
Sets the output format for the match. Optional — defaults to `UNICODE_TABLE`.
|
|
|
|
**Rules:**
|
|
- Only one `#define` per script
|
|
- Must be one of the three known modes
|
|
- Unknown names produce an error
|
|
|
|
The `--json` CLI flag always overrides the script's `#define`.
|
|
|
|
## Complete Grammar
|
|
|
|
```
|
|
script = statement*
|
|
statement = define | string_decl | player_insert | goal_stmt | match_stmt
|
|
define = "#define" identifier
|
|
string_decl = "string" identifier "=" string_literal ";"
|
|
player_insert = "players" "[" string_literal "]" "=" (identifier | string_literal) ";"
|
|
goal_stmt = "goal" "(" number "," (identifier | string_literal) "," string_literal ")" ";"
|
|
match_stmt = "match" "(" identifier "," identifier ")" ";"
|
|
comment = "//" .* "\n"
|
|
shebang = "#!" .* "\n"
|
|
```
|
|
|
|
## Output Modes
|
|
|
|
| Mode | `#define` | CLI flag | Description |
|
|
|------|-----------|----------|-------------|
|
|
| Unicode table | `UNICODE_TABLE` (default) | — | Box-drawing characters (`╔`, `═`, `║`) |
|
|
| ASCII table | `ASCII_TABLE` | — | ASCII-only (`+`, `-`, `|`) |
|
|
| JSON | `JSON` | `--json` | Machine-readable JSON |
|
|
|
|
## Scripted Goals Behavior
|
|
|
|
When `goal()` is used, the match becomes deterministic:
|
|
|
|
| Field | Behavior with `goal()` | Behavior without |
|
|
|-------|------------------------|-------------------|
|
|
| Score | Count of goals per team | Random 0-5 |
|
|
| Scorers | Exact `(player, minute)` from script | Random names + minutes |
|
|
| Shots | `max(score, random(4..=18))` — floor = goals | Random 4-18 |
|
|
| Shots on target | `max(score, random(1..shots))` | Random |
|
|
| Possession | Still random | Random |
|
|
|
|
## Variable Resolution
|
|
|
|
Variables are resolved at parse time by looking up their declared value:
|
|
|
|
```tsrc
|
|
string home = "GNU United";
|
|
string away = "BSD Athletic";
|
|
|
|
players["Richard Stallman"] = home; // resolves to "GNU United"
|
|
players["Theo de Raadt"] = away; // resolves to "BSD Athletic"
|
|
|
|
goal(12, home, "Richard Stallman"); // goal for "GNU United"
|
|
goal(34, "BSD Athletic", "Theo de Raadt"); // literal also works
|
|
|
|
match(home, away); // GNU United vs BSD Athletic
|
|
```
|
|
|
|
You can mix variables and literals freely. Forward references (using a variable before its `string` declaration) are an error.
|
|
|
|
## Validation
|
|
|
|
The parser is strict. Any inconsistency produces an error and exits immediately.
|
|
|
|
### Error Conditions
|
|
|
|
| Error | Cause |
|
|
|-------|-------|
|
|
| `undefined variable 'x'` | Variable used before `string x = ...` declaration |
|
|
| `variable 'x' redefined` | Two `string x = ...` declarations |
|
|
| `players[...] = "X" which is not a match team` | Roster team isn't in `match()` |
|
|
| `duplicate player "X" on team "Y"` | Same player added to same team twice |
|
|
| `"X" has no players assigned` | A match team has zero players |
|
|
| `match() has the same team for both home and away` | Both `match()` args resolve to same team |
|
|
| `no match() directive found` | Missing `match()` |
|
|
| `goal() minute must be between 1 and 90` | Invalid minute |
|
|
| `player "X" is not on team "Y"` | Goal references unregistered player |
|
|
| `duplicate goal` | Same player scores same minute twice |
|
|
| `undefined variable 'x' in goal()` | Goal uses undeclared team variable |
|
|
| `duplicate #define` | More than one `#define` in script |
|
|
| `unknown #define 'FOO'` | Unrecognized output mode |
|
|
|
|
## Full Example
|
|
|
|
```tsrc
|
|
#!/usr/bin/env tssr
|
|
|
|
// GNU United vs BSD Athletic
|
|
#define ASCII_TABLE
|
|
|
|
string home = "GNU United";
|
|
string away = "BSD Athletic";
|
|
|
|
players["Richard Stallman"] = home;
|
|
players["Brian Fox"] = home;
|
|
players["Linus Torvalds"] = home;
|
|
players["Theo de Raadt"] = away;
|
|
players["Jordan Hubbard"] = away;
|
|
players["Ken Thompson"] = away;
|
|
|
|
goal(12, home, "Richard Stallman");
|
|
goal(34, away, "Theo de Raadt");
|
|
goal(56, home, "Brian Fox");
|
|
goal(78, "BSD Athletic", "Ken Thompson");
|
|
goal(89, home, "Linus Torvalds");
|
|
|
|
match(home, away);
|
|
```
|
|
|
|
**Output:**
|
|
```
|
|
+------------------------------------+
|
|
+ TSSR MATCH RESULT +
|
|
+------------------------------------+
|
|
+ GNU United 3-2 BSD Athletic +
|
|
+------------------------------------+
|
|
+ +
|
|
+Shots 4 5 +
|
|
+On Target 3 2 +
|
|
+Possession 48% 52% +
|
|
+ +
|
|
+Goals: +
|
|
+GNU United: Richard Stallman (12') +
|
|
+GNU United: Brian Fox (56') +
|
|
+GNU United: Linus Torvalds (89') +
|
|
+BSD Athletic: Theo de Raadt (34') +
|
|
+BSD Athletic: Ken Thompson (78') +
|
|
+------------------------------------+
|
|
```
|