gglang 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 GGLang Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,158 @@
1
+ <![CDATA[```
2
+ ██████╗ ██████╗ ██╗ █████╗ ███╗ ██╗ ██████╗
3
+ ██╔════╝ ██╔════╝ ██║ ██╔══██╗████╗ ██║██╔════╝
4
+ ██║ ███╗██║ ███╗██║ ███████║██╔██╗ ██║██║ ███╗
5
+ ██║ ██║██║ ██║██║ ██╔══██║██║╚██╗██║██║ ██║
6
+ ╚██████╔╝╚██████╔╝███████╗██║ ██║██║ ╚████║╚██████╔╝
7
+ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝
8
+ ```
9
+
10
+ # 🎮 GGLang — The Gaming-Themed Programming Language
11
+
12
+ > **GG** stands for *Good Game*. Write code like you're playing one.
13
+
14
+ [![Language](https://img.shields.io/badge/language-TypeScript-blue)]()
15
+ [![File Extension](https://img.shields.io/badge/extension-.gg-brightgreen)]()
16
+ [![License](https://img.shields.io/badge/license-MIT-yellow)]()
17
+
18
+ ---
19
+
20
+ ## 🕹️ What is GGLang?
21
+
22
+ **GGLang** is a toy programming language where every keyword is a gaming term. Variables are **equipped**, functions are **skills**, loops are **grinds**, and errors are **glitches**. It's built entirely in TypeScript and is designed to make learning about interpreters and compilers fun.
23
+
24
+ Instead of writing boring old `if / else`, you embark on a `quest` — and if things go south, you `retreat`. Instead of a `while` loop, you `grind` until you're done. Your programs don't just *start* — they `spawn`.
25
+
26
+ ---
27
+
28
+ ## ✨ Features
29
+
30
+ | Feature | Description |
31
+ |---|---|
32
+ | 🎮 **Gaming keywords** | Every keyword maps to a gaming concept |
33
+ | 🧮 **Full expressions** | Arithmetic, comparison, logical, and assignment operators |
34
+ | 🔁 **Control flow** | `quest` / `side_quest` / `retreat` (if/else if/else) |
35
+ | 🔄 **Loops** | `grind` (while) with `rage_quit` (break) and `respawn` (continue) |
36
+ | ⚔️ **Functions** | `skill` (function) with `loot` (return) and recursion support |
37
+ | 🛡️ **Error handling** | `boss_fight` / `revive` / `glitch` (try/catch/throw) |
38
+ | 📢 **I/O** | `broadcast` (print) and `interact` (input) |
39
+ | 📝 **Comments** | Single-line `//` and multi-line `/* */` |
40
+ | 🏗️ **Built with TypeScript** | Clean, hackable, and easy to extend |
41
+
42
+ ---
43
+
44
+ ## 🚀 Quick Start
45
+
46
+ ### Installation
47
+
48
+ ```bash
49
+ # Clone the repository
50
+ git clone <repo-url>
51
+ cd toy-programming-language
52
+
53
+ # Install dependencies
54
+ npm install
55
+
56
+ # Build the project
57
+ npm run build
58
+ ```
59
+
60
+ ### Hello, World!
61
+
62
+ Create a file called `hello.gg`:
63
+
64
+ ```
65
+ spawn {
66
+ broadcast("Hello, World!");
67
+ broadcast("Welcome to GGLang! 🎮");
68
+ }
69
+ ```
70
+
71
+ Run it:
72
+
73
+ ```bash
74
+ npm start -- hello.gg
75
+ ```
76
+
77
+ ### Try the REPL
78
+
79
+ ```bash
80
+ npm start
81
+ ```
82
+
83
+ ---
84
+
85
+ ## 📖 A Taste of GGLang
86
+
87
+ ```
88
+ spawn {
89
+ // Equip your variables like items in your inventory
90
+ equip playerName = interact("Enter your name, adventurer: ");
91
+ equip health = 100;
92
+ artifact maxHealth = 100; // Artifacts are constants — permanent relics
93
+
94
+ // Define a skill (function)
95
+ skill battleCry(name) {
96
+ broadcast("⚔️ " + name + " charges into battle!");
97
+ }
98
+
99
+ // Embark on a quest (if/else)
100
+ quest (health == maxHealth) {
101
+ battleCry(playerName);
102
+ } retreat {
103
+ broadcast("You need to heal first!");
104
+ }
105
+
106
+ // Grind through enemies (while loop)
107
+ equip enemiesDefeated = 0;
108
+ grind (enemiesDefeated < 5) {
109
+ broadcast("Enemy #" + (enemiesDefeated + 1) + " defeated!");
110
+ enemiesDefeated += 1;
111
+ }
112
+
113
+ broadcast("GG, " + playerName + "! 🏆");
114
+ }
115
+ ```
116
+
117
+ ---
118
+
119
+ ## 📚 Documentation
120
+
121
+ For the complete language reference, syntax guide, and example programs, see the **[Full Documentation](docs/DOCUMENTATION.md)**.
122
+
123
+ ---
124
+
125
+ ## 📂 Example Programs
126
+
127
+ | File | Description |
128
+ |---|---|
129
+ | [`hello.gg`](examples/hello.gg) | Hello World — your first spawn |
130
+ | [`fibonacci.gg`](examples/fibonacci.gg) | Recursive Fibonacci sequence |
131
+ | [`fizzbuzz.gg`](examples/fizzbuzz.gg) | Classic FizzBuzz challenge |
132
+ | [`adventure.gg`](examples/adventure.gg) | Mini text adventure game |
133
+
134
+ ---
135
+
136
+ ## 🗺️ Keyword Cheat Sheet
137
+
138
+ | Concept | GGLang | You'd normally write… |
139
+ |---|---|---|
140
+ | Start program | `spawn { }` | `main()` |
141
+ | Variable | `equip x = 5;` | `let x = 5;` |
142
+ | Constant | `artifact PI = 3.14;` | `const PI = 3.14;` |
143
+ | Print | `broadcast("hi");` | `console.log("hi");` |
144
+ | If / Else if / Else | `quest / side_quest / retreat` | `if / else if / else` |
145
+ | While loop | `grind (cond) { }` | `while (cond) { }` |
146
+ | Break / Continue | `rage_quit / respawn` | `break / continue` |
147
+ | Function / Return | `skill fn() { loot val; }` | `function fn() { return val; }` |
148
+ | True / False / Null | `victory / defeat / phantom` | `true / false / null` |
149
+ | Try / Catch | `boss_fight { } revive(e) { }` | `try { } catch(e) { }` |
150
+ | Throw error | `glitch "msg";` | `throw "msg";` |
151
+ | Input | `interact("prompt")` | `readline("prompt")` |
152
+
153
+ ---
154
+
155
+ ## 📄 License
156
+
157
+ This project is licensed under the **MIT License** — do whatever you want with it. GG! 🎮
158
+ ]]>
@@ -0,0 +1,45 @@
1
+ import { RuntimeValue } from './types';
2
+ export declare class Environment {
3
+ /** Map of variable names to their entries in the current scope */
4
+ private variables;
5
+ /** Reference to the enclosing (parent) scope, or null for global */
6
+ private parent;
7
+ /**
8
+ * Creates a new environment scope.
9
+ * @param parent - The enclosing environment. Omit for the global scope.
10
+ */
11
+ constructor(parent?: Environment);
12
+ /**
13
+ * Declares a new variable in the current scope.
14
+ * Throws if a variable with the same name already exists in this scope.
15
+ *
16
+ * @param name - The variable name
17
+ * @param value - The initial value
18
+ * @param constant - Whether this variable is a constant (artifact)
19
+ */
20
+ declare(name: string, value: RuntimeValue, constant: boolean): void;
21
+ /**
22
+ * Looks up a variable by name, walking up the parent chain.
23
+ * Throws GGRuntimeError if the variable is not found in any scope.
24
+ *
25
+ * @param name - The variable name to look up
26
+ * @returns The variable's current runtime value
27
+ */
28
+ get(name: string): RuntimeValue;
29
+ /**
30
+ * Updates an existing variable's value, walking up the parent chain.
31
+ * Throws if the variable is not found or if it's a constant (artifact).
32
+ *
33
+ * @param name - The variable name to update
34
+ * @param value - The new value to assign
35
+ */
36
+ set(name: string, value: RuntimeValue): void;
37
+ /**
38
+ * Checks whether a variable exists in the current scope or any parent scope.
39
+ *
40
+ * @param name - The variable name to check
41
+ * @returns true if the variable is declared somewhere in the scope chain
42
+ */
43
+ has(name: string): boolean;
44
+ }
45
+ //# sourceMappingURL=environment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.d.ts","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,YAAY,EAAkB,MAAM,SAAS,CAAC;AAavD,qBAAa,WAAW;IACtB,kEAAkE;IAClE,OAAO,CAAC,SAAS,CAA6B;IAE9C,oEAAoE;IACpE,OAAO,CAAC,MAAM,CAAqB;IAEnC;;;OAGG;gBACS,MAAM,CAAC,EAAE,WAAW;IAKhC;;;;;;;OAOG;IACH,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,OAAO,GAAG,IAAI;IAUnE;;;;;;OAMG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY;IAkB/B;;;;;;OAMG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,IAAI;IA2B5C;;;;;OAKG;IACH,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAW3B"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ // ============================================================
3
+ // GGLang — Environment (Scope Management)
4
+ // Manages variable declarations, lookups, and assignments
5
+ // with support for lexical scoping via parent chain traversal.
6
+ // ============================================================
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.Environment = void 0;
9
+ const types_1 = require("./types");
10
+ // ---- Environment Class ----
11
+ class Environment {
12
+ /**
13
+ * Creates a new environment scope.
14
+ * @param parent - The enclosing environment. Omit for the global scope.
15
+ */
16
+ constructor(parent) {
17
+ this.variables = new Map();
18
+ this.parent = parent ?? null;
19
+ }
20
+ /**
21
+ * Declares a new variable in the current scope.
22
+ * Throws if a variable with the same name already exists in this scope.
23
+ *
24
+ * @param name - The variable name
25
+ * @param value - The initial value
26
+ * @param constant - Whether this variable is a constant (artifact)
27
+ */
28
+ declare(name, value, constant) {
29
+ if (this.variables.has(name)) {
30
+ throw new types_1.GGRuntimeError(`Variable '${name}' is already equipped in this scope! Cannot re-declare.`);
31
+ }
32
+ this.variables.set(name, { value, constant });
33
+ }
34
+ /**
35
+ * Looks up a variable by name, walking up the parent chain.
36
+ * Throws GGRuntimeError if the variable is not found in any scope.
37
+ *
38
+ * @param name - The variable name to look up
39
+ * @returns The variable's current runtime value
40
+ */
41
+ get(name) {
42
+ const entry = this.variables.get(name);
43
+ if (entry !== undefined) {
44
+ return entry.value;
45
+ }
46
+ // Walk up the scope chain
47
+ if (this.parent) {
48
+ return this.parent.get(name);
49
+ }
50
+ // Variable not found in any scope
51
+ throw new types_1.GGRuntimeError(`Variable '${name}' is not equipped! You must equip it before using it.`);
52
+ }
53
+ /**
54
+ * Updates an existing variable's value, walking up the parent chain.
55
+ * Throws if the variable is not found or if it's a constant (artifact).
56
+ *
57
+ * @param name - The variable name to update
58
+ * @param value - The new value to assign
59
+ */
60
+ set(name, value) {
61
+ const entry = this.variables.get(name);
62
+ if (entry !== undefined) {
63
+ // Found in current scope — check if it's a constant
64
+ if (entry.constant) {
65
+ throw new types_1.GGRuntimeError(`Cannot reassign artifact '${name}'! Artifacts are immutable legendary items.`);
66
+ }
67
+ entry.value = value;
68
+ return;
69
+ }
70
+ // Walk up the scope chain
71
+ if (this.parent) {
72
+ this.parent.set(name, value);
73
+ return;
74
+ }
75
+ // Variable not found in any scope
76
+ throw new types_1.GGRuntimeError(`Variable '${name}' is not equipped! You must equip it before assigning to it.`);
77
+ }
78
+ /**
79
+ * Checks whether a variable exists in the current scope or any parent scope.
80
+ *
81
+ * @param name - The variable name to check
82
+ * @returns true if the variable is declared somewhere in the scope chain
83
+ */
84
+ has(name) {
85
+ if (this.variables.has(name)) {
86
+ return true;
87
+ }
88
+ if (this.parent) {
89
+ return this.parent.has(name);
90
+ }
91
+ return false;
92
+ }
93
+ }
94
+ exports.Environment = Environment;
95
+ //# sourceMappingURL=environment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"environment.js","sourceRoot":"","sources":["../src/environment.ts"],"names":[],"mappings":";AAAA,+DAA+D;AAC/D,0CAA0C;AAC1C,0DAA0D;AAC1D,+DAA+D;AAC/D,+DAA+D;;;AAE/D,mCAAuD;AAWvD,8BAA8B;AAE9B,MAAa,WAAW;IAOtB;;;OAGG;IACH,YAAY,MAAoB;QAC9B,IAAI,CAAC,SAAS,GAAG,IAAI,GAAG,EAAE,CAAC;QAC3B,IAAI,CAAC,MAAM,GAAG,MAAM,IAAI,IAAI,CAAC;IAC/B,CAAC;IAED;;;;;;;OAOG;IACH,OAAO,CAAC,IAAY,EAAE,KAAmB,EAAE,QAAiB;QAC1D,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,MAAM,IAAI,sBAAc,CACtB,aAAa,IAAI,yDAAyD,CAC3E,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChD,CAAC;IAED;;;;;;OAMG;IACH,GAAG,CAAC,IAAY;QACd,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,OAAO,KAAK,CAAC,KAAK,CAAC;QACrB,CAAC;QAED,0BAA0B;QAC1B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAED,kCAAkC;QAClC,MAAM,IAAI,sBAAc,CACtB,aAAa,IAAI,uDAAuD,CACzE,CAAC;IACJ,CAAC;IAED;;;;;;OAMG;IACH,GAAG,CAAC,IAAY,EAAE,KAAmB;QACnC,MAAM,KAAK,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEvC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,oDAAoD;YACpD,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;gBACnB,MAAM,IAAI,sBAAc,CACtB,6BAA6B,IAAI,6CAA6C,CAC/E,CAAC;YACJ,CAAC;YAED,KAAK,CAAC,KAAK,GAAG,KAAK,CAAC;YACpB,OAAO;QACT,CAAC;QAED,0BAA0B;QAC1B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC7B,OAAO;QACT,CAAC;QAED,kCAAkC;QAClC,MAAM,IAAI,sBAAc,CACtB,aAAa,IAAI,8DAA8D,CAChF,CAAC;IACJ,CAAC;IAED;;;;;OAKG;IACH,GAAG,CAAC,IAAY;QACd,IAAI,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC7B,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;YAChB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC/B,CAAC;QAED,OAAO,KAAK,CAAC;IACf,CAAC;CACF;AA9GD,kCA8GC"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
package/dist/index.js ADDED
@@ -0,0 +1,199 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // ============================================================
4
+ // GGLang — CLI Entry Point
5
+ // Run a .gg source file or start an interactive REPL session.
6
+ //
7
+ // Usage:
8
+ // gglang <filename.gg> — execute a source file
9
+ // gglang — start the REPL
10
+ // ============================================================
11
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ var desc = Object.getOwnPropertyDescriptor(m, k);
14
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
15
+ desc = { enumerable: true, get: function() { return m[k]; } };
16
+ }
17
+ Object.defineProperty(o, k2, desc);
18
+ }) : (function(o, m, k, k2) {
19
+ if (k2 === undefined) k2 = k;
20
+ o[k2] = m[k];
21
+ }));
22
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
23
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
24
+ }) : function(o, v) {
25
+ o["default"] = v;
26
+ });
27
+ var __importStar = (this && this.__importStar) || (function () {
28
+ var ownKeys = function(o) {
29
+ ownKeys = Object.getOwnPropertyNames || function (o) {
30
+ var ar = [];
31
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
32
+ return ar;
33
+ };
34
+ return ownKeys(o);
35
+ };
36
+ return function (mod) {
37
+ if (mod && mod.__esModule) return mod;
38
+ var result = {};
39
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
40
+ __setModuleDefault(result, mod);
41
+ return result;
42
+ };
43
+ })();
44
+ Object.defineProperty(exports, "__esModule", { value: true });
45
+ const fs = __importStar(require("fs"));
46
+ const path = __importStar(require("path"));
47
+ const readline = __importStar(require("readline"));
48
+ const lexer_1 = require("./lexer");
49
+ const parser_1 = require("./parser");
50
+ const interpreter_1 = require("./interpreter");
51
+ // ---- Constants ----
52
+ const VERSION = '1.0.0';
53
+ const VICTORY_BANNER = '\n🏆 VICTORY ROYALE! Program executed successfully.\n';
54
+ const GAME_OVER_BANNER = '\n💀 GAME OVER!\n';
55
+ // ============================================================
56
+ // File Execution Mode
57
+ // ============================================================
58
+ /**
59
+ * Reads a .gg source file, tokenizes it, parses the AST,
60
+ * and executes it through the interpreter.
61
+ *
62
+ * @param filePath - Path to the .gg source file
63
+ */
64
+ function runFile(filePath) {
65
+ // Resolve to an absolute path
66
+ const resolvedPath = path.resolve(filePath);
67
+ // Check that the file exists
68
+ if (!fs.existsSync(resolvedPath)) {
69
+ console.error(`${GAME_OVER_BANNER}❌ File not found: ${resolvedPath}`);
70
+ process.exit(1);
71
+ }
72
+ // Read the source code
73
+ const source = fs.readFileSync(resolvedPath, 'utf-8');
74
+ try {
75
+ // Pipeline: Source → Tokens → AST → Execution
76
+ const lexer = new lexer_1.Lexer();
77
+ const tokens = lexer.tokenize(source);
78
+ const parser = new parser_1.Parser();
79
+ const program = parser.parse(tokens);
80
+ const interpreter = new interpreter_1.Interpreter();
81
+ interpreter.execute(program);
82
+ console.log(VICTORY_BANNER);
83
+ }
84
+ catch (error) {
85
+ console.error(GAME_OVER_BANNER);
86
+ if (error instanceof Error) {
87
+ console.error(` ${error.message}\n`);
88
+ }
89
+ else {
90
+ console.error(` Unknown error: ${error}\n`);
91
+ }
92
+ process.exit(1);
93
+ }
94
+ }
95
+ // ============================================================
96
+ // REPL Mode (Read-Eval-Print Loop)
97
+ // ============================================================
98
+ /**
99
+ * Starts an interactive REPL session.
100
+ * Each line is independently lexed, parsed, and executed.
101
+ * State persists across lines (same interpreter instance).
102
+ *
103
+ * In REPL mode, the `spawn { }` wrapper is NOT required —
104
+ * statements are executed directly.
105
+ */
106
+ function startRepl() {
107
+ // Print the welcome banner
108
+ console.log('');
109
+ console.log('╔══════════════════════════════════════════════╗');
110
+ console.log('║ 🎮 GGLang REPL v' + VERSION + ' — Type your code, hero! ║');
111
+ console.log('║ Type "exit" or press Ctrl+C to quit. ║');
112
+ console.log('╚══════════════════════════════════════════════╝');
113
+ console.log('');
114
+ // Create readline interface for interactive input
115
+ const rl = readline.createInterface({
116
+ input: process.stdin,
117
+ output: process.stdout,
118
+ prompt: '⚔️ > ',
119
+ });
120
+ // Persistent interpreter instance — state carries across lines
121
+ const interpreter = new interpreter_1.Interpreter();
122
+ // Buffer for multi-line input (tracks unmatched braces)
123
+ let inputBuffer = '';
124
+ let braceDepth = 0;
125
+ rl.prompt();
126
+ rl.on('line', (line) => {
127
+ const trimmed = line.trim();
128
+ // ---- Exit command ----
129
+ if (trimmed === 'exit' && braceDepth === 0) {
130
+ console.log('\n👋 GG, hero! Until next time.\n');
131
+ rl.close();
132
+ process.exit(0);
133
+ }
134
+ // Accumulate input and track brace depth for multi-line blocks
135
+ inputBuffer += line + '\n';
136
+ braceDepth += countChar(line, '{') - countChar(line, '}');
137
+ // If braces are balanced, attempt to execute the buffered input
138
+ if (braceDepth <= 0) {
139
+ braceDepth = 0;
140
+ const source = inputBuffer.trim();
141
+ inputBuffer = '';
142
+ if (source.length === 0) {
143
+ rl.prompt();
144
+ return;
145
+ }
146
+ try {
147
+ // In REPL mode, we wrap the input so it doesn't need `spawn { }`
148
+ const lexer = new lexer_1.Lexer();
149
+ const tokens = lexer.tokenize(source);
150
+ const parser = new parser_1.Parser();
151
+ const program = parser.parse(tokens);
152
+ interpreter.execute(program);
153
+ }
154
+ catch (error) {
155
+ if (error instanceof Error) {
156
+ console.error(` 💥 ${error.message}`);
157
+ }
158
+ else {
159
+ console.error(` 💥 Unknown error: ${error}`);
160
+ }
161
+ }
162
+ rl.prompt();
163
+ }
164
+ else {
165
+ // Still waiting for more input — show continuation prompt
166
+ process.stdout.write('... ');
167
+ }
168
+ });
169
+ rl.on('close', () => {
170
+ console.log('\n👋 GG, hero! Until next time.\n');
171
+ process.exit(0);
172
+ });
173
+ }
174
+ // ---- Utilities ----
175
+ /**
176
+ * Counts occurrences of a character in a string.
177
+ * Used for tracking brace depth in the REPL.
178
+ */
179
+ function countChar(str, char) {
180
+ let count = 0;
181
+ for (const c of str) {
182
+ if (c === char)
183
+ count++;
184
+ }
185
+ return count;
186
+ }
187
+ // ============================================================
188
+ // Main — Parse CLI args and dispatch
189
+ // ============================================================
190
+ const filename = process.argv[2];
191
+ if (filename) {
192
+ // File execution mode
193
+ runFile(filename);
194
+ }
195
+ else {
196
+ // Interactive REPL mode
197
+ startRepl();
198
+ }
199
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ import { Program } from './types';
2
+ export declare class Interpreter {
3
+ /** The top-level global environment */
4
+ private globalEnv;
5
+ constructor();
6
+ /**
7
+ * Executes a parsed GGLang program.
8
+ * Iterates over every statement in the program body and executes it
9
+ * within the global environment.
10
+ *
11
+ * @param program - The AST root node (Program)
12
+ */
13
+ execute(program: Program): void;
14
+ /**
15
+ * Dispatches a statement to its corresponding handler based on type.
16
+ *
17
+ * @param stmt - The AST statement node
18
+ * @param env - The current environment scope
19
+ */
20
+ private executeStatement;
21
+ /**
22
+ * equip / artifact — Declare a new variable or constant.
23
+ */
24
+ private executeVariableDeclaration;
25
+ /**
26
+ * name = expr — Assign a new value to an existing variable.
27
+ */
28
+ private executeAssignment;
29
+ /**
30
+ * name += expr (and -=, *=, /=) — Compound assignment.
31
+ * Reads the current value, applies the operator, and writes back.
32
+ */
33
+ private executeCompoundAssignment;
34
+ /**
35
+ * broadcast(expr) — Print a value to stdout with GGLang formatting.
36
+ * Strings are printed without surrounding quotes.
37
+ * null → 'phantom', true → 'victory', false → 'defeat'
38
+ */
39
+ private executePrint;
40
+ /**
41
+ * quest / side_quest / retreat — Conditional branching.
42
+ */
43
+ private executeIf;
44
+ /**
45
+ * grind { ... } — While loop with break/continue support.
46
+ */
47
+ private executeWhile;
48
+ /**
49
+ * skill name(params) { ... } — Declare a function with closure capture.
50
+ * The function remembers the environment where it was declared.
51
+ */
52
+ private executeFunctionDeclaration;
53
+ /**
54
+ * loot expr — Return a value from a function.
55
+ * Throws a ReturnSignal that carries the return value up the stack.
56
+ */
57
+ private executeReturn;
58
+ /**
59
+ * glitch expr — Throw a runtime error with a user-defined message.
60
+ */
61
+ private executeThrow;
62
+ /**
63
+ * boss_fight { ... } revive(err) { ... } — Try/catch for error handling.
64
+ * Only catches GGRuntimeError (user-level errors), not internal signals.
65
+ */
66
+ private executeTryCatch;
67
+ /**
68
+ * Evaluates an expression node and returns its runtime value.
69
+ *
70
+ * @param expr - The AST expression node
71
+ * @param env - The current environment scope
72
+ * @returns The evaluated RuntimeValue
73
+ */
74
+ private evaluateExpression;
75
+ /**
76
+ * Evaluates binary expressions: arithmetic, comparison, and string concatenation.
77
+ */
78
+ private evaluateBinaryExpression;
79
+ /**
80
+ * Evaluates unary expressions: negation (-) and logical not (!).
81
+ */
82
+ private evaluateUnaryExpression;
83
+ /**
84
+ * Evaluates logical expressions with short-circuit semantics.
85
+ * && returns the first falsy value or the last value.
86
+ * || returns the first truthy value or the last value.
87
+ */
88
+ private evaluateLogicalExpression;
89
+ /**
90
+ * Evaluates a function call expression.
91
+ * Handles the built-in 'interact' function (reads user input from stdin)
92
+ * and user-defined functions (with closure support).
93
+ */
94
+ private evaluateCallExpression;
95
+ /**
96
+ * Executes a block of statements in a new child scope.
97
+ * This ensures variables declared inside the block don't leak out.
98
+ */
99
+ private executeBlock;
100
+ /**
101
+ * Determines the truthiness of a GGLang value.
102
+ * - false, null, 0, and "" are falsy
103
+ * - Everything else (including functions) is truthy
104
+ */
105
+ private isTruthy;
106
+ /**
107
+ * Asserts that a value is a number, throwing a runtime error if not.
108
+ * Used by arithmetic operators to enforce type safety.
109
+ */
110
+ private assertNumber;
111
+ /**
112
+ * Formats a RuntimeValue for display (used by broadcast and string coercion).
113
+ * - Strings are returned as-is (no surrounding quotes)
114
+ * - null → 'phantom'
115
+ * - true → 'victory', false → 'defeat'
116
+ * - Numbers are stringified normally
117
+ * - Functions show as '<skill name>'
118
+ */
119
+ private formatValue;
120
+ }
121
+ //# sourceMappingURL=interpreter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interpreter.d.ts","sourceRoot":"","sources":["../src/interpreter.ts"],"names":[],"mappings":"AAMA,OAAO,EACL,OAAO,EAqBR,MAAM,SAAS,CAAC;AA0EjB,qBAAa,WAAW;IACtB,uCAAuC;IACvC,OAAO,CAAC,SAAS,CAAc;;IAQ/B;;;;;;OAMG;IACH,OAAO,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAQ/B;;;;;OAKG;IACH,OAAO,CAAC,gBAAgB;IAiDxB;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAQlC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;;OAGG;IACH,OAAO,CAAC,yBAAyB;IAgDjC;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAKpB;;OAEG;IACH,OAAO,CAAC,SAAS;IAqBjB;;OAEG;IACH,OAAO,CAAC,YAAY;IAgBpB;;;OAGG;IACH,OAAO,CAAC,0BAA0B;IAclC;;;OAGG;IACH,OAAO,CAAC,aAAa;IAOrB;;OAEG;IACH,OAAO,CAAC,YAAY;IAKpB;;;OAGG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;;;OAMG;IACH,OAAO,CAAC,kBAAkB;IAoC1B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAqEhC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAkB/B;;;;OAIG;IACH,OAAO,CAAC,yBAAyB;IAsBjC;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IAiE9B;;;OAGG;IACH,OAAO,CAAC,YAAY;IAOpB;;;;OAIG;IACH,OAAO,CAAC,QAAQ;IAQhB;;;OAGG;IACH,OAAO,CAAC,YAAY;IAUpB;;;;;;;OAOG;IACH,OAAO,CAAC,WAAW;CAUpB"}