cluaupp 0.2.3 → 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.
Files changed (114) hide show
  1. package/CHANGELOG.md +10 -79
  2. package/README.md +42 -88
  3. package/docs/README.md +13 -21
  4. package/docs/architecture.md +13 -76
  5. package/docs/cli.md +12 -64
  6. package/docs/comparison.md +6 -24
  7. package/docs/config.md +6 -7
  8. package/docs/examples/combat.md +19 -227
  9. package/docs/examples/hud.md +13 -81
  10. package/docs/examples/index.md +9 -16
  11. package/docs/getting-started.md +20 -137
  12. package/docs/intellisense.md +5 -41
  13. package/docs/intro.md +16 -15
  14. package/docs/migration.md +38 -0
  15. package/docs/oop/file-tags.md +12 -36
  16. package/docs/oop/index.md +8 -14
  17. package/docs/syntax.md +54 -236
  18. package/editors/vscode/extension.js +1 -1
  19. package/editors/vscode/package.json +4 -4
  20. package/examples/README.md +5 -7
  21. package/examples/game/.vscode/extensions.json +0 -3
  22. package/examples/game/.vscode/settings.json +6 -14
  23. package/examples/game/src/client/hud.client.clpp +54 -0
  24. package/examples/game/src/client/init.client.clpp +6 -0
  25. package/examples/game/src/server/combat.server.clpp +85 -0
  26. package/examples/game/src/server/leaderstats.server.clpp +28 -0
  27. package/examples/game/src/shared/PlayerData.clh +20 -0
  28. package/examples/game/src/shared/config.clp +6 -0
  29. package/examples/game/src/shared/features.clp +88 -0
  30. package/generated/cli.js +40 -24
  31. package/generated/clpp/contract.js +5 -0
  32. package/generated/clpp/index.js +27 -0
  33. package/generated/clpp/paths.js +121 -0
  34. package/generated/clpp/postprocess.js +78 -0
  35. package/generated/clpp/runner.js +102 -0
  36. package/generated/compile.js +26 -138
  37. package/generated/intellisense.js +38 -157
  38. package/generated/libs.js +1 -1
  39. package/generated/lsp.js +1 -8
  40. package/generated/preprocess.js +8 -179
  41. package/generated/system-understander.js +1 -1
  42. package/generated/transpile.js +3 -50
  43. package/generated/utils/project.js +13 -28
  44. package/include/{cluaupp/datatypes.hpp → clpp/datatypes.clh} +1 -1
  45. package/include/{cluaupp/generated/instances.hpp → clpp/generated/instances.clh} +1 -1
  46. package/include/{cluaupp/libs/chrono.hpp → clpp/libs/chrono.clh} +9 -9
  47. package/include/{cluaupp/libs/cmdr.hpp → clpp/libs/cmdr.clh} +4 -4
  48. package/include/{cluaupp/libs/dataservice.hpp → clpp/libs/dataservice.clh} +8 -15
  49. package/include/{cluaupp/libs/display.hpp → clpp/libs/display.clh} +1 -2
  50. package/include/{cluaupp/libs/ezvisual.hpp → clpp/libs/ezvisual.clh} +1 -3
  51. package/include/{cluaupp/libs/formatnumber.hpp → clpp/libs/formatnumber.clh} +2 -3
  52. package/include/{cluaupp/libs/fusion.hpp → clpp/libs/fusion.clh} +5 -5
  53. package/include/{cluaupp/libs/iris.hpp → clpp/libs/iris.clh} +2 -2
  54. package/include/{cluaupp/libs/janitor.hpp → clpp/libs/janitor.clh} +1 -2
  55. package/include/{cluaupp/libs/module3d.hpp → clpp/libs/module3d.clh} +2 -4
  56. package/include/{cluaupp/libs/net.hpp → clpp/libs/net.clh} +2 -4
  57. package/include/{cluaupp/libs/promise.hpp → clpp/libs/promise.clh} +1 -4
  58. package/include/{cluaupp/libs/spring.hpp → clpp/libs/spring.clh} +1 -2
  59. package/include/{cluaupp/libs/statemachine.hpp → clpp/libs/statemachine.clh} +2 -3
  60. package/include/{cluaupp/libs/stickybillboard.hpp → clpp/libs/stickybillboard.clh} +1 -2
  61. package/include/{cluaupp/libs/topbarplus.hpp → clpp/libs/topbarplus.clh} +3 -4
  62. package/include/clpp/libs.clh +24 -0
  63. package/include/clpp/roblox.clh +31 -0
  64. package/package.json +7 -14
  65. package/src/cli.ts +39 -25
  66. package/src/clpp/contract.ts +39 -0
  67. package/src/clpp/index.ts +18 -0
  68. package/src/clpp/paths.ts +117 -0
  69. package/src/clpp/postprocess.ts +93 -0
  70. package/src/clpp/runner.ts +102 -0
  71. package/src/compile.ts +26 -149
  72. package/src/intellisense.ts +36 -165
  73. package/src/libs.ts +1 -1
  74. package/src/lsp.ts +1 -5
  75. package/src/preprocess.ts +8 -180
  76. package/src/system-understander.ts +1 -1
  77. package/src/transpile.ts +9 -52
  78. package/src/utils/project.ts +12 -28
  79. package/templates/game/.vscode/extensions.json +0 -3
  80. package/templates/game/.vscode/settings.json +6 -14
  81. package/templates/game/src/client/init.client.clpp +6 -0
  82. package/templates/game/src/server/leaderstats.server.clpp +29 -0
  83. package/templates/game/src/shared/config.clp +6 -0
  84. package/examples/game/.clangd +0 -25
  85. package/examples/game/compile_flags.txt +0 -6
  86. package/examples/game/src/client/hud.client.cpp +0 -12
  87. package/examples/game/src/client/init.client.cpp +0 -6
  88. package/examples/game/src/server/combat.server.cpp +0 -23
  89. package/examples/game/src/server/leaderstats.server.cpp +0 -29
  90. package/examples/game/src/shared/config.cpp +0 -5
  91. package/examples/game/src/shared/config.h +0 -5
  92. package/include/cluaupp/libs.hpp +0 -25
  93. package/include/cluaupp/roblox.hpp +0 -47
  94. package/src/architecture.ts +0 -500
  95. package/src/ast.ts +0 -37
  96. package/src/emit.ts +0 -609
  97. package/src/emitter/luau-codegen.ts +0 -187
  98. package/src/emitter/translators.ts +0 -168
  99. package/src/headers.ts +0 -233
  100. package/src/layout.ts +0 -114
  101. package/src/lex.ts +0 -158
  102. package/src/parse.ts +0 -729
  103. package/src/parser/collector.ts +0 -148
  104. package/src/parser/index.ts +0 -27
  105. package/src/tree-sitter-cpp.d.ts +0 -4
  106. package/src/understand.ts +0 -322
  107. package/templates/game/src/client/init.client.cpp +0 -6
  108. package/templates/game/src/server/leaderstats.server.cpp +0 -29
  109. package/templates/game/src/shared/config.cpp +0 -5
  110. package/templates/game/src/shared/config.h +0 -5
  111. /package/include/{cluaupp/generated/enums.hpp → clpp/generated/enums.clh} +0 -0
  112. /package/include/{cluaupp/libs/math.hpp → clpp/libs/math.clh} +0 -0
  113. /package/include/{cluaupp/libs/twinkle.hpp → clpp/libs/twinkle.clh} +0 -0
  114. /package/include/{cluaupp/libs/vfx.hpp → clpp/libs/vfx.clh} +0 -0
package/docs/intro.md CHANGED
@@ -5,33 +5,34 @@ sidebar_position: 1
5
5
 
6
6
  # Cluaupp
7
7
 
8
- **The definitive merge of C++ and modern Luau.** You write a C++ subset. Cluaupp emits [Luau](https://luau.org/getting-started) with `local` and `const` (and `--!strict` when you opt in), and calls the Roblox API the way Studio does.
8
+ **CL++ on Roblox.** You write [CL++](https://kartzrbx.github.io/CLPP/). Cluaupp runs `clpp`, maps libraries into `ReplicatedStorage.CluauppLibs`, and syncs with Rojo.
9
9
 
10
- This site is built with [Moonwave](https://eryn.io/moonwave/) for local markdown (`npm run docs`). The **public** site is generated into `site/` and deployed to [GitHub Pages](https://kartzrbx.github.io/Cluaupp/) (Learn tabs, OOP, Examples, API). The language is in the same spirit as [roblox-ts](https://roblox-ts.com): a familiar syntax, a restricted subset, readable output.
10
+ This site covers the **toolchain** (`init`, `build`, `watch`, libs). The language course is on the [CL++ site](https://kartzrbx.github.io/CLPP/).
11
11
 
12
12
  ## What you get
13
13
 
14
- 1. A compiler (`cluaupp init` / `build` / `watch`)
15
- 2. Headers for **clangd** (`#include <cluaupp/roblox.hpp>`)
16
- 3. First-party libraries in `ReplicatedStorage.CluauppLibs`
17
- 4. Wally wrappers for DataServiceV2, Fusion, Cmdr, EzVisualz, TopbarPlus, and the rest of your stack
14
+ 1. CLI: `cluaupp init` / `build` / `watch`
15
+ 2. First-party libraries in `ReplicatedStorage.CluauppLibs`
16
+ 3. Rojo project mapping (`out/server`, `out/client`, `out/shared`)
18
17
 
19
18
  ## First program
20
19
 
21
- ```cpp
22
- #include <cluaupp/roblox.hpp>
23
- #include <cluaupp/libs/janitor.hpp>
20
+ ```clpp
21
+ #include <clpp/roblox.clh>
22
+ #include <clpp/libs/janitor.clh>
24
23
 
25
24
  void OnPlayer(Player* player) {
26
- auto* janitor = new Janitor();
27
- janitor->LinkToInstance(player);
28
- janitor->Add(player->AncestryChanged.Connect(OnPlayer));
25
+ guard (player != null) else {
26
+ return;
27
+ }
28
+ Janitor* janitor = new Janitor();
29
+ janitor::LinkToInstance(player);
29
30
  }
30
31
 
31
32
  void init() {
32
- auto* players = GetService<Players>();
33
- players->PlayerAdded.Connect(OnPlayer);
33
+ Players* players = GetService<Players>();
34
+ players::PlayerAdded~>Connect(OnPlayer);
34
35
  }
35
36
  ```
36
37
 
37
- Read [Getting started](getting-started.md), then [Examples](examples/index.md), [Libraries](libraries/index.md), and [OOP structure](oop/index.md).
38
+ Read [Getting started](getting-started.md), [syntax](syntax.md), and [migration](migration.md).
@@ -0,0 +1,38 @@
1
+ # Migrate C++ games to CL++
2
+
3
+ Cluaupp 1.0 compiles **CL++**, not a C++ subset. Language docs: [kartzrbx.github.io/CLPP](https://kartzrbx.github.io/CLPP/).
4
+
5
+ ## Files
6
+
7
+ | Before | After |
8
+ | --- | --- |
9
+ | `*.server.cpp` | `*.server.clpp` |
10
+ | `*.client.cpp` | `*.client.clpp` |
11
+ | untagged `*.cpp` | `*.clp` |
12
+ | `*.h` / `*.hpp` | `*.clh` |
13
+
14
+ `#include <cluaupp/roblox.hpp>` → `#include <clpp/roblox.clh>`
15
+ `#include <cluaupp/libs/janitor.hpp>` → `#include <clpp/libs/janitor.clh>`
16
+ Quoted includes: `"leaderstats.h"` → `"leaderstats.clh"`.
17
+
18
+ ## Operators and IO
19
+
20
+ | Old C++ subset | CL++ | Luau |
21
+ | --- | --- | --- |
22
+ | `player->Name` | `player.Name` | `.` |
23
+ | `player->GetPlayers()` | `player::GetPlayers()` | `:` |
24
+ | `DataService::Server` | `DataService:Server` | `.` |
25
+ | `"hi " + name` | `"hi " .: name` | `..` |
26
+ | `signal.Connect(fn)` | `signal~>Connect(fn)` | Janitor `Add` |
27
+ | `print` / `error` | `post` / `report` | `print` / `error` |
28
+ | `nullptr` | `null` | `nil` |
29
+ | `[](Player* p) { }` | `func [](Player* p) { }` | `function` |
30
+
31
+ ## Workflow
32
+
33
+ 1. Install CL++: [github.com/KartzRbx/CLPP](https://github.com/KartzRbx/CLPP) (`cargo install --path .`).
34
+ 2. `clpp install` (editor highlighting + IntelliSense).
35
+ 3. Rename sources and apply the table above.
36
+ 4. `cluaupp build` — `clpp` must be on PATH (`CLPP_PATH` if needed).
37
+
38
+ `"architecture": true` (ForeverHD folders) is not generated in 1.0. One source file still becomes one `.luau` file.
@@ -5,44 +5,20 @@ sidebar_position: 2
5
5
 
6
6
  # File tags
7
7
 
8
- The **filename** decides the Roblox instance. This is the same key idea as roblox-ts (`*.server.ts` → Script).
8
+ The **filename** decides the Roblox instance (same idea as roblox-ts).
9
9
 
10
- | Source | Instance | RunContext |
11
- | --- | --- | --- |
12
- | `LeaderstatsServer.server.cpp` | **Script** | **Server** |
13
- | `DataBoot.client.cpp` | **LocalScript** | Client |
14
- | `Tools.plugin.cpp` | **Script** | Plugin |
15
- | `Boot.legacy.cpp` | Script | **Legacy** |
16
- | `Boot.legacy.server.cpp` | Script | **Legacy** |
17
- | `Boot.legacy.client.cpp` | LocalScript | Legacy |
18
- | `Damage.cpp` (no tag) | **ModuleScript** | — |
19
- | `LeaderstatsServer.h` | **ModuleScript** (types) | — |
20
- | `LeaderstatsServer.cpp` (sibling of `.h`) | **ModuleScript** (`*Impl`) | — |
21
-
22
- ## One file in, one file out
23
-
24
- Rojo infers the instance from the filename key: `*.server.luau` is a Script, `*.client.luau` is a LocalScript, untagged `.luau` is a ModuleScript.
10
+ | Source | Instance |
11
+ | --- | --- |
12
+ | `LeaderstatsServer.server.clpp` | Script |
13
+ | `Hud.client.clpp` | LocalScript |
14
+ | `Tools.plugin.clpp` | Plugin Script |
15
+ | `damage.clp` (no tag) | ModuleScript |
16
+ | `PlayerData.clh` | ModuleScript |
25
17
 
26
18
  ```
27
- src/server/boot/DataBoot.server.cpp → out/server/boot/DataBoot.server.luau
28
- src/client/boot/DataBoot.client.cpp → out/client/boot/DataBoot.client.luau
29
- src/shared/damage.cpp → out/shared/Damage.luau
30
- src/server/services/leaderstats/LeaderstatsServer.h → LeaderstatsServer.luau (export type)
31
- src/server/services/leaderstats/LeaderstatsServer.cpp → LeaderstatsServerImpl.luau
19
+ src/server/boot/DataBoot.server.clpp → out/server/boot/DataBoot.server.luau
20
+ src/client/hud.client.clpp → out/client/hud.client.luau
21
+ src/shared/config.clp → out/shared/config.luau
32
22
  ```
33
23
 
34
- `.legacy.server.cpp` still emits a Legacy Script (`boot.server.luau`). `.client.cpp` stays a LocalScript. Do not invent `init.meta.json` on the default 1:1 path.
35
-
36
- ## Where files live
37
-
38
- ```
39
- src/server/.../*.server.cpp → out/server (ServerScriptService.Cluaupp)
40
- src/client/.../*.client.cpp → out/client (StarterPlayerScripts.Cluaupp)
41
- src/shared/.../*.cpp → out/shared (ReplicatedStorage.Cluaupp)
42
- ```
43
-
44
- Name the **system**, not `init.server.cpp`. `LeaderstatsServer.server.cpp` and `DataBoot.server.cpp` are two files.
45
-
46
- ## Opt-in planner
47
-
48
- `"architecture": true` in `cluaupp.config.json` restores PascalCase service folders (`Main`, Controller, Types). Default is off.
24
+ Language details: [CL++ docs](https://kartzrbx.github.io/CLPP/).
package/docs/oop/index.md CHANGED
@@ -5,16 +5,14 @@ sidebar_position: 1
5
5
 
6
6
  # Structs and methods
7
7
 
8
- Live handbook: [Structs and methods](https://kartzrbx.github.io/Cluaupp/docs/structs.html). Singletons: [one table in `init()`](https://kartzrbx.github.io/Cluaupp/docs/singletons.html).
8
+ Language details: [CL++](https://kartzrbx.github.io/CLPP/). Filename tags decide Script / LocalScript / ModuleScript.
9
9
 
10
- Cluaupp does **not** emit C++ `class` metatables. You write a **type** as a `struct` in a sibling header and implement `Class::Method` in the `.cpp`. Filename tags still decide Script / LocalScript / ModuleScript.
10
+ Declare the type in a `.clh`, implement `Class::Method` in a `.clp` / `.clpp`. Capture one service table in `void init()`.
11
11
 
12
- Construct **one** `LeaderstatsServer` in `void init()`, assign `janitor = new Janitor()`, and capture it in `[&]` lambdas. Library singletons already exist (`DataService::Server`) — `Init` once from a boot script. Join strings with `string_concat` or string `+`, not Luau `..`.
13
-
14
- ```cpp
12
+ ```clpp
15
13
  #pragma once
16
- #include <cluaupp/roblox.hpp>
17
- #include <cluaupp/libs/janitor.hpp>
14
+ #include <clpp/roblox.clh>
15
+ #include <clpp/libs/janitor.clh>
18
16
 
19
17
  struct LeaderstatsServer {
20
18
  static constexpr int STARTING_COINS = 0;
@@ -24,12 +22,8 @@ struct LeaderstatsServer {
24
22
  };
25
23
  ```
26
24
 
27
- The stem must match: `LeaderstatsServer.h` next to `LeaderstatsServer.server.cpp`. `#include "leaderstats.h"` from a differently named cpp is a `require`, not the class body.
28
-
29
25
  | Page | What you learn |
30
26
  | --- | --- |
31
- | [File tags](file-tags.md) | `.server` / `.client` / `.plugin` / `.legacy` / untagged |
32
- | [Services](services.md) | One `.server.cpp` → one `.server.luau` |
33
- | [Modules](modules.md) | Untagged files, structs, named functions as methods |
34
-
35
- Planner: [Architecture](../architecture.md). Folder layout: [Organization](../cpp-organization.md). Full copy: [Leaderstats](../examples/leaderstats.md).
27
+ | [File tags](file-tags.md) | `.server.clpp` / `.client.clpp` / `.clh` |
28
+ | [Services](services.md) | `init()` singletons |
29
+ | [Modules](modules.md) | shared `.clp` |
package/docs/syntax.md CHANGED
@@ -1,262 +1,80 @@
1
- # C++ → Luau syntax
1
+ # CL++ syntax (Cluaupp)
2
2
 
3
- Cluaupp is not a full C++ compiler. It is a **subset** aimed at Roblox scripts, in the same spirit as roblox-ts (restricted TypeScript → Luau).
3
+ Cluaupp does **not** define the language. Write CL++ (`.clpp` / `.clp` / `.clh`); `clpp` emits Luau. Full course and reference: **[kartzrbx.github.io/CLPP](https://kartzrbx.github.io/CLPP/)**.
4
4
 
5
- Live grid of every construct: **[Language reference](https://kartzrbx.github.io/Cluaupp/docs/reference.html)**.
5
+ ## Files
6
6
 
7
- Generated Luau follows the current language: [`local`](https://luau.org/getting-started), `const`, and `const function`. Injected `require` / `GetService` lines are `const`. `--!strict` is emitted only when the file has `#pragma strict` (or `"strict": true` in config). `#pragma nstrict` never emits it.
8
-
9
- ## Files and includes
10
-
11
- - Extensions: `.cpp`, `.cc`, `.cxx`, `.c`, `.h`, `.hpp`, `.hh`
12
- - Tags: `*.server.cpp` → Script, `*.client.cpp` → LocalScript, `*.plugin.cpp` → Plugin, `*.legacy*` → Legacy, untagged → ModuleScript
13
- - Quoted `#include "Own.h"` (same stem as the `.cpp`) is **inlined**. Other quoted includes become `require` (Rojo path)
14
- - `#include <cluaupp/roblox.hpp>` is IntelliSense only. `#include <cluaupp/libs/janitor.hpp>` also injects `require(CluauppLibs.Janitor)`
15
- - `#pragma once` is ignored. Other macros are not expanded. `//` and `/* */` comments are stripped
16
- - `using …;` is skipped. `namespace { }` is flattened. `enum` / `template` / `typedef` / `extern` declarations are skipped
17
-
18
- ## Types
19
-
20
- | C++ | Luau |
7
+ | Source | Rojo |
21
8
  | --- | --- |
22
- | `int` / `float` / `double` | `number` |
23
- | `bool` | `boolean` |
24
- | `string` | `string` (not `std::string`) |
25
- | `void` | no return annotation |
26
- | `auto` / `auto*` | inferred from `new` / `GetService` / datatype ctor |
27
- | `Player*` / `Folder*` | `Player` / `Folder` (Instance handle, not a heap address) |
28
- | `LuaArray<T>` / `vector<T>` / `array<T>` / `span<T>` | `{T}` |
29
- | `optional<T>` | `T?` |
30
- | `const` / `static constexpr` | Luau `const` |
31
- | `nullptr` | `nil` |
32
- | `Vector3` `CFrame` `UDim2` `Color3` | same names (copied values) |
33
- | `Enum::Material::Plastic` | `Enum.Material.Plastic` |
9
+ | `*.server.clpp` | Script |
10
+ | `*.client.clpp` | LocalScript |
11
+ | `*.plugin.clpp` | Plugin Script |
12
+ | `*.clp` / untagged `.clpp` | ModuleScript |
13
+ | `*.clh` | ModuleScript (types / structs) |
34
14
 
35
- Always initialize: `int coins = 0;` not `int coins;` (uninitialized emits `nil`). There is no `delete`, no `*part`, no `&part`, no `int&`. Numbers copy; Instances mutate through `->`.
15
+ `void init()` is the script entry. There is no `int main()`.
36
16
 
37
- `auto` infers when the value is `new Class(...)`, `GetService<T>()`, or a datatype constructor. Prefer explicit types on parameters and struct fields.
17
+ ## Accessors
38
18
 
39
- ## Functions
19
+ CL++ does **not** use `->`.
40
20
 
41
- ```cpp
42
- void CreateLeaderstats(Player* player) {
43
- return;
44
- }
21
+ | Write | Meaning | Luau |
22
+ | --- | --- | --- |
23
+ | `player.Name` | property | `.` |
24
+ | `player::FindFirstChild("x")` | method | `:` |
25
+ | `DataService:Server` | table key | `.` |
26
+ | `"hi " .: name` | concat | `..` |
27
+ | `signal~>Connect(fn)` | janitor Connect | `janitor:Add(..., "Disconnect")` |
28
+ | `signal~>Once(fn)` | one-shot | `Once` + janitor |
45
29
 
46
- int doubleCoins(int coins) {
47
- return coins;
48
- }
49
- ```
30
+ `post` / `warn` / `report` → `print` / `warn` / `error`. `null` is `nil`.
50
31
 
51
- ```luau
52
- const function CreateLeaderstats(player: Player)
53
- return
54
- end
32
+ ## Exclusive CL++ (compiled by `clpp`)
55
33
 
56
- const function doubleCoins(coins: number): number
57
- return coins
58
- end
59
- ```
60
-
61
- - Only functions with a body are emitted from a `.cpp`. Prototypes in a `.h` become `export type` fields
62
- - No overloading — one name, one emit. No default arguments
63
- - If `void init()` exists, emit appends `init()` at the end of Scripts / LocalScripts. There is no `int main()`
64
- - Shared ModuleScripts should not define `init()` unless you want them to run on `require`
65
-
66
- ## Scopes
67
-
68
- - File-level decls become file `local` / `const`
69
- - Function decls become `local` from that line to the end of the block. Nested `{ }` can shadow
70
- - In `Class::Method`, `this` is `self`. Bare field names become `self.field`. Bare calls to other methods become `self:Method(...)`. Parameters and locals shadow fields
71
- - Globals stay bare: `print`, `game`, `workspace`, library types, Instance types, datatypes
72
- - Instances are not RAII. Leaving a block does not Destroy a Part — use Janitor
73
-
74
- ## Control flow
75
-
76
- ```cpp
77
- if (player->FindFirstChild("leaderstats") != nullptr) {
34
+ ```clpp
35
+ guard (player != null) else {
36
+ warn("Invalid player");
78
37
  return;
79
- } else {
80
- print("ok");
81
38
  }
82
39
 
83
- while (true) {
84
- print("tick");
85
- }
86
-
87
- for (auto* player : players->GetPlayers()) {
88
- CreateLeaderstats(player);
89
- }
90
-
91
- switch (action) {
92
- case "buy":
93
- case "purchase":
94
- Grant(player);
95
- break;
96
- case "sell":
97
- if (amount <= 0) {
98
- break;
99
- }
100
- Take(player);
101
- break;
102
- default:
103
- warn("unknown");
104
- break;
105
- }
106
- ```
107
-
108
- ```luau
109
- if player:FindFirstChild("leaderstats") ~= nil then
110
- return
111
- else
112
- print("ok")
113
- end
114
-
115
- while true do
116
- print("tick")
117
- end
118
-
119
- for _, player in players:GetPlayers() do
120
- CreateLeaderstats(player)
121
- end
122
-
123
- repeat
124
- if action == "buy" or action == "purchase" then
125
- Grant(player)
126
- elseif action == "sell" then
127
- if amount <= 0 then
128
- break
129
- end
130
- Take(player)
131
- else
132
- warn("unknown")
133
- end
134
- until true
135
- ```
136
-
137
- `switch` evaluates the discriminant **once**, then becomes `if` / `elseif` / `else` inside `repeat … until true` so `break` still exits the switch (even from inside an `if`). Stacked `case` labels share a body. There is no C-style fall-through. C-style `for (int i = 0; i < n; i++)` is not supported. No `continue`, no `do/while`, no ternary. `else if (x)` emits a nested `if` inside `else` (not Luau `elseif`).
138
-
139
- ## Expressions and operators
140
-
141
- | C++ | Luau |
142
- | --- | --- |
143
- | `nullptr` | `nil` |
144
- | `true` / `false` | `true` / `false` |
145
- | `!=` | `~=` |
146
- | `&&` | `and` |
147
- | `\|\|` | `or` |
148
- | `!` | `not` |
149
- | `==` `+` `-` `*` `/` `<` `>` `<=` `>=` | same (`*` is multiply) |
150
- | `"text"` | `"text"` |
151
- | `=` | assignment |
152
- | `obj->Prop` | `obj.Prop` |
153
- | `obj->Method(a)` | `obj:Method(a)` if the method is a Roblox / library API |
154
- | `fn(a)` | `fn(a)` |
155
- | `signal.Connect(fn)` | `signal:Connect(fn)` |
156
- | `Type { .Field = value }` | `{ Field = value }` |
157
- | unary `-` | `-` |
40
+ match (child) {
41
+ BasePart* p => BindPart(p),
42
+ Model* m => post("model spawned " .: m.Name),
43
+ _ => warn("ignored instance")
44
+ };
158
45
 
159
- No `++` `--` `+=`. Write `n = n + 1`. Binary operators in this subset are left-associative — use parentheses when mixing.
160
-
161
- Designated initializers become Luau tables:
162
-
163
- ```cpp
164
- DataService::Server.Init(DataServiceOptions {
165
- .Template = playerData,
166
- .StoreName = "PlayerData",
167
- .UseMock = true,
46
+ observable int wallet = 100;
47
+ wallet.OnChange(func [](int newValue) {
48
+ post("Coins changed to: " .: newValue);
168
49
  });
169
- ```
170
-
171
- ```luau
172
- DataService.Server:Init({
173
- Template = playerData,
174
- StoreName = "PlayerData",
175
- UseMock = true,
176
- })
177
- ```
178
-
179
- ## Strings and string_concat
180
-
181
- Luau concatenates with `..`. Do not write `..` in a `.cpp`.
182
-
183
- - If either side of `+` is a string literal, another concat, or `.Name` / `.Text` / `.DisplayName`, `+` becomes `..`
184
- - `string_concat(a, b, c)` is variadic: zero args → `""`, one arg → that value, several → `(a .. b .. c)`
185
- - Declared in `datatypes.hpp` (via `roblox.hpp`)
186
-
187
- ```cpp
188
- return player->Name + "_LeaderstatsJanitor";
189
- return string_concat(player->Name, "_", "LeaderstatsJanitor");
190
- ```
191
-
192
- ```luau
193
- return player.Name .. "_LeaderstatsJanitor"
194
- return (player.Name .. "_" .. "LeaderstatsJanitor")
195
- ```
196
-
197
- ## print / cout
198
-
199
- `print`, `warn`, and `error` work as in Luau. `cout << … << endl` is the C++ spelling — each `<<` is another argument, `endl` ends the line. `cout::warn` / `cout::error` / `cout::ping` pick the Roblox function. `cerr` is `warn`. Full table: [print and cout](print-cout.md).
200
50
 
201
- ## `new` and services
202
-
203
- ```cpp
204
- auto* coins = new IntValue(leaderstats);
205
- auto* players = GetService<Players>();
206
- auto* janitor = new Janitor();
207
- part->Size = Vector3(8, 1, 8);
208
- part->CFrame = CFrame::lookAt(from, look);
209
- part->Material = Enum::Material::Plastic;
210
- ```
211
-
212
- ```luau
213
- local coins: IntValue = Instance.new("IntValue")
214
- coins.Parent = leaderstats
215
- local players: Players = game:GetService("Players")
216
- local janitor = Janitor.new()
217
- part.Size = Vector3.new(8, 1, 8)
218
- part.CFrame = CFrame.lookAt(from, look)
219
- part.Material = Enum.Material.Plastic
220
- ```
221
-
222
- The first argument of `new Class(parent)` becomes `.Parent` for Instance classes. Libraries use `Janitor.new()`. Datatypes use `Vector3(...)`, not `new`.
223
-
224
- ## Casts
51
+ signal<Player*, int> OnHit;
52
+ OnHit~>Connect(func [](Player* player, int amount) {
53
+ post(player.Name .: " dmg " .: amount);
54
+ });
55
+ OnHit::Fire(player, 10);
225
56
 
226
- `static_cast<T>(x)`, `const_cast`, `reinterpret_cast`, `dynamic_cast` emit the argument. `(void)x;` is omitted (silences unused for clangd). Luau has no casts — they do not check ClassName.
57
+ array<string> names = {"Kartz", "Player1"};
58
+ dictionary<string, int> stats = { {"Coins", 100}, {"Gems", 50} };
227
59
 
228
- ## Callbacks (events and lambdas)
60
+ spawn { task::wait(1); post("ready"); };
61
+ parallel { post("desync"); };
229
62
 
230
- Signals use `.Connect`. Callbacks may be **named functions** or **lambdas** (`[](Player* player) { ... }`, including `[&]` / `[=]` / `[coinsValue]`). Capture lists are accepted; Luau closures do not copy C++ captures — keep Instances alive with Janitor.
63
+ async Data* FetchData(Player* player) {
64
+ return await DataService:Server::WaitFor(player);
65
+ }
231
66
 
232
- Passing a method by name from inside `Class::` binds `self`: `function(...) self:OnPlayer(...) end`.
67
+ [[server]]
68
+ void SaveData(Player* player) { post(player.Name); }
233
69
 
234
- ```cpp
235
- players->PlayerAdded.Connect([&](Player* playerEntered) {
236
- leaderstatsServer.PlayerEntered(playerEntered);
237
- });
238
- game->BindToClose([&]() {
239
- leaderstatsServer.janitor->Cleanup();
240
- });
70
+ [[client]]
71
+ void UpdateUI() { post("ui"); }
241
72
  ```
242
73
 
243
- ## OOP: structs, methods, singletons
244
-
245
- How you write a type: a `struct` (or `class`) in the sibling `.h`, `Class::Method` in the `.cpp`, `void init()` to boot.
246
-
247
- - `static constexpr` fields are `const`
248
- - Fields are `self.field`. `public:` / `private:` are ignored
249
- - Nested structs with defaults become nested tables (DataService Templates). `LuaArray<T>` fields stay on the table
250
- - `Class::` methods emit `function Class:Method(...)`
251
- - Construct **one** service table in `init()` (`LeaderstatsServer leaderstatsServer;`) and capture it in lambdas. That is the game singleton
252
- - Library singletons already exist: `DataService::Server` / `Client` — `Init` once from a boot script
253
- - Header-only field structs emit `const function Name()` returning defaults
254
- - Untagged files of only `Class::` methods `return` the table (ModuleScript)
255
-
256
- Stem must match: `LeaderstatsServer.h` next to `LeaderstatsServer.server.cpp`. A differently named include is a `require`, not the class body.
257
-
258
- ## Not supported
74
+ Fusion HUD uses `Fusion:scoped`, `Fusion:Value`, `Fusion:Computed`, `Fusion:New`. See [`examples/game`](../examples/game) (`combat.server.clpp`, `hud.client.clpp`, `features.clp`, `PlayerData.clh`).
259
75
 
260
- Custom C++ classes as metatables, generic templates besides `GetService<T>` / `static_cast<T>` / `LuaArray<T>` / `string_concat`, pointer arithmetic, `std::` (except mapped aliases), overloading, macros (except `#pragma strict` / `#pragma nstrict` / `#pragma once`), JSX / XML UI tags, C-style `for`, `++` `--` `+=`, `continue`, ternary, `do/while`, `try/catch`, `goto`, `int&` references.
76
+ ## What Cluaupp adds after `clpp`
261
77
 
262
- CLI forms: [CLI](cli.md). How to write a type: [OOP](oop/index.md). Full handbook: **[Docs](https://kartzrbx.github.io/Cluaupp/docs/)**.
78
+ - `require(ClppLibs.X)` → `require(ReplicatedStorage.CluauppLibs.X)`
79
+ - `--!strict` from `cluaupp.config.json` / `#pragma strict`
80
+ - `out/` layout for Rojo (`init`, `build`, `watch`)
@@ -55,7 +55,7 @@ function activate(context) {
55
55
  });
56
56
 
57
57
  const refreshDiagnostics = (document) => {
58
- if (!document || document.languageId !== "cpp") {
58
+ if (!document || (document.languageId !== "clpp" && document.languageId !== "cpp")) {
59
59
  return;
60
60
  }
61
61
  if (typeof loaded.engine.diagnosticsFor !== "function") {
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "cluaupp-diagnostics",
3
3
  "displayName": "Cluaupp",
4
- "description": "Cluaupp subset parse errors. C++ completion, hover, and go-to-definition come from clangd + include/cluaupp/roblox.hpp.",
5
- "version": "0.2.2",
4
+ "description": "Cluaupp project diagnostics. Language highlighting and IntelliSense come from clpp install (CL++).",
5
+ "version": "1.0.0",
6
6
  "publisher": "kartzdev",
7
7
  "engines": {
8
8
  "vscode": "^1.74.0"
@@ -11,14 +11,14 @@
11
11
  "Linters"
12
12
  ],
13
13
  "activationEvents": [
14
- "onLanguage:cpp"
14
+ "onLanguage:clpp"
15
15
  ],
16
16
  "main": "./extension.js",
17
17
  "contributes": {
18
18
  "commands": [
19
19
  {
20
20
  "command": "cluaupp.restartIntelliSense",
21
- "title": "Cluaupp: Reload subset diagnostics"
21
+ "title": "Cluaupp: Reload CL++ diagnostics"
22
22
  }
23
23
  ]
24
24
  }
@@ -1,18 +1,16 @@
1
1
  # Sample game
2
2
 
3
- This is the C++ a Cluaupp game looks like — **not** the compiler.
3
+ CL++ sources for a Cluaupp project — **not** the compiler. Language samples: [CL++ examples](https://github.com/KartzRbx/CLPP/tree/main/examples).
4
4
 
5
5
  | Folder | Rojo | Tag |
6
6
  | --- | --- | --- |
7
- | `src/server/*.server.cpp` | Script | server |
8
- | `src/client/*.client.cpp` | LocalScript | client |
9
- | `src/shared/*` | ModuleScript | none |
10
-
11
- `src/` of **this repo** is the TypeScript CLI ([roblox-ts](https://github.com/roblox-ts/roblox-ts) does the same). The sample scripts live here so they never mix with `understand.ts`.
7
+ | `src/server/*.server.clpp` | Script | server |
8
+ | `src/client/*.client.clpp` | LocalScript | client |
9
+ | `src/shared/*.clp` / `*.clh` | ModuleScript | none |
12
10
 
13
11
  ```bash
14
12
  cd examples/game
15
13
  npx cluaupp build .
16
14
  ```
17
15
 
18
- `cluaupp init` copies `templates/game` (the slim scaffold). This folder adds combat / HUD so `SystemUnderstander` has real tokens to score.
16
+ `cluaupp init` copies `templates/game`. This folder adds combat (`guard` / `match` / `signal` / `observable` / `spawn`), a Fusion HUD, `features.clp`, and `PlayerData.clh`.
@@ -1,7 +1,4 @@
1
1
  {
2
- "recommendations": [
3
- "llvm-vs-code-extensions.vscode-clangd"
4
- ],
5
2
  "unwantedRecommendations": [
6
3
  "ms-vscode.cpptools"
7
4
  ]
@@ -1,18 +1,10 @@
1
1
  {
2
- "clangd.enable": true,
3
- "clangd.arguments": [
4
- "--compile-commands-dir=${workspaceFolder}",
5
- "--header-insertion=never",
6
- "--query-driver=**/clang++*,**/clang++.exe,**/g++*,**/g++.exe"
7
- ],
8
2
  "files.associations": {
9
- "*.hpp": "cpp",
10
- "*.h": "cpp",
11
- "*.server.cpp": "cpp",
12
- "*.client.cpp": "cpp",
13
- "*.plugin.cpp": "cpp",
14
- "*.legacy.cpp": "cpp",
15
- "*.legacy.server.cpp": "cpp",
16
- "*.legacy.client.cpp": "cpp"
3
+ "*.clpp": "clpp",
4
+ "*.clp": "clpp",
5
+ "*.clh": "clpp",
6
+ "*.server.clpp": "clpp",
7
+ "*.client.clpp": "clpp",
8
+ "*.plugin.clpp": "clpp"
17
9
  }
18
10
  }
@@ -0,0 +1,54 @@
1
+ #pragma strict
2
+ #include <clpp/roblox.clh>
3
+ #include <clpp/libs/fusion.clh>
4
+
5
+ [[client]]
6
+ void init() {
7
+ Players* players = GetService<Players>();
8
+ Player* localPlayer = players.LocalPlayer;
9
+ guard (localPlayer != null) else {
10
+ report("LocalPlayer missing");
11
+ return;
12
+ }
13
+
14
+ Instance* playerGui = localPlayer::WaitForChild("PlayerGui");
15
+ auto scope = Fusion:scoped();
16
+ auto Children = Fusion:Children;
17
+
18
+ auto coins = Fusion:Value(scope, 0);
19
+ auto title = Fusion:Computed(scope, func []() {
20
+ return "Coins: " .: coins();
21
+ });
22
+
23
+ auto newScreenGui = Fusion:New(scope, "ScreenGui");
24
+ auto newFrame = Fusion:New(scope, "Frame");
25
+ auto newLabel = Fusion:New(scope, "TextLabel");
26
+
27
+ auto label = newLabel({
28
+ {"Name", "Amount"},
29
+ {"BackgroundTransparency", 1},
30
+ {"Size", UDim2.fromScale(1, 1)},
31
+ {"Text", title},
32
+ {"TextColor3", Color3.fromRGB(255, 255, 255)},
33
+ {"TextScaled", true}
34
+ });
35
+
36
+ auto frame = newFrame({
37
+ {"Name", "Hud"},
38
+ {"AnchorPoint", Vector2(0, 1)},
39
+ {"Position", UDim2.fromScale(0, 1)},
40
+ {"Size", UDim2.fromOffset(220, 64)},
41
+ {"BackgroundColor3", Color3.fromRGB(28, 18, 48)},
42
+ {Children, label}
43
+ });
44
+
45
+ newScreenGui({
46
+ {"Name", "CoinsHud"},
47
+ {"ResetOnSpawn", false},
48
+ {"Parent", playerGui},
49
+ {Children, frame}
50
+ });
51
+
52
+ coins(100);
53
+ post("hud ready");
54
+ }