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/src/transpile.ts CHANGED
@@ -1,64 +1,21 @@
1
1
  import path from "node:path";
2
- import type { CompileOptions, CompileServiceResult, TranspilerState } from "./types.js";
3
- import { ASTCollector } from "./parser/collector.js";
4
- import { parseCpp } from "./parser/index.js";
5
- import { LuauCodeEmitter } from "./emitter/luau-codegen.js";
2
+ import type { CompileOptions, CompileServiceResult } from "./types.js";
6
3
  import { compileService } from "./compile.js";
7
- import { determineArchitecture } from "./system-understander.js";
8
4
  import type { RojoMapper } from "./utils/rojo-mapper.js";
9
5
 
10
- function shouldMerge(name: string, contents: string): boolean {
11
- const file = String(name || "").replace(/\\/g, "/");
12
- if (/\.json$/i.test(file) || /\.meta\.json$/i.test(file)) {
13
- return false;
14
- }
15
- const trimmed = String(contents || "").trim();
16
- return !(trimmed.startsWith("{") || trimmed.startsWith("["));
17
- }
18
-
19
- export function collectState(source: string, mapper: RojoMapper, options: CompileOptions): TranspilerState {
20
- const tree = parseCpp(source);
21
- if (!tree) {
22
- const state = LuauCodeEmitter.emptyState(options.strict === true);
23
- return state;
24
- }
25
- const collector = new ASTCollector(mapper, {
26
- fileName: options.relativeName || options.filePath || "input.cpp",
27
- sourcePath: options.filePath,
28
- srcDir: options.srcDir,
29
- outDir: options.outDir,
30
- strict: options.strict,
31
- });
32
- const state = collector.collect(tree.rootNode);
33
- const report = determineArchitecture(options.relativeName || options.filePath || "input.cpp", null, tree.rootNode);
34
- for (const service of report.injectedServices) {
35
- state.robloxServices.add(service);
36
- }
37
- for (const line of report.reasoning) {
38
- state.headerLines.push(`-- ${line}`);
39
- }
40
- return state;
41
- }
42
-
43
- export function transpileSource(source: string, fileName: string, options: CompileOptions, mapper: RojoMapper): CompileServiceResult {
44
- const state = collectState(source, mapper, options);
45
- if (state.strict) {
46
- options.strict = true;
47
- }
48
- const compiled = compileService(source, fileName, options);
49
- return {
50
- ...compiled,
51
- files: compiled.files.map((file) => ({
52
- ...file,
53
- contents: shouldMerge(file.name, file.contents) ? LuauCodeEmitter.merge(state, file.contents) : file.contents,
54
- })),
55
- };
6
+ export function transpileSource(
7
+ source: string,
8
+ fileName: string,
9
+ options: CompileOptions,
10
+ _mapper?: RojoMapper,
11
+ ): CompileServiceResult {
12
+ return compileService(source, fileName, options);
56
13
  }
57
14
 
58
15
  export function outputNameFor(inputFile: string, outputPath: string): string {
59
16
  if (/\.luau$/i.test(outputPath)) {
60
17
  return outputPath;
61
18
  }
62
- const base = path.basename(inputFile).replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, ".luau");
19
+ const base = path.basename(inputFile).replace(/\.(clpp|clp|clh)$/i, ".luau");
63
20
  return path.join(outputPath, base);
64
21
  }
@@ -2,8 +2,8 @@ import fs from "node:fs";
2
2
  import path from "node:path";
3
3
  import type { BuildOptions, BuildResult, ProjectConfig } from "../types.js";
4
4
  import { pkg } from "../package-info.js";
5
- import { isSourceFile, toLuauPath } from "../preprocess.js";
6
- import { installEditorSupport, syncEditorSupport } from "../intellisense.js";
5
+ import { collectSources, toLuauPath } from "../clpp/paths.js";
6
+ import { syncEditorSupport } from "../intellisense.js";
7
7
  import { ProcessOrchestrator } from "./process-orchestrator.js";
8
8
  import { RojoMapper } from "./rojo-mapper.js";
9
9
  import { transpileSource } from "../transpile.js";
@@ -137,28 +137,19 @@ function copyRuntime(dest: string): void {
137
137
  }
138
138
 
139
139
  function copyHeaders(dest: string): void {
140
- const from = path.join(__dirname, "..", "..", "include", "cluaupp");
140
+ const from = path.join(__dirname, "..", "..", "include", "clpp");
141
141
  if (!fs.existsSync(from)) {
142
142
  return;
143
143
  }
144
- syncDir(from, path.join(dest, "include", "cluaupp"));
144
+ syncDir(from, path.join(dest, "include", "clpp"));
145
145
  }
146
146
 
147
147
  export function collectCpp(dir: string, files: string[] = []): string[] {
148
- if (!fs.existsSync(dir)) {
149
- return files;
150
- }
151
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
152
- const full = path.join(dir, entry.name);
153
- if (entry.isDirectory()) {
154
- collectCpp(full, files);
155
- } else if (isSourceFile(entry.name)) {
156
- files.push(full);
157
- }
158
- }
159
- return files;
148
+ return collectSources(dir, files);
160
149
  }
161
150
 
151
+ export const collectSourcesFiles = collectSources;
152
+
162
153
  function collectFiles(dir: string, files: string[] = []): string[] {
163
154
  if (!fs.existsSync(dir)) {
164
155
  return files;
@@ -184,7 +175,7 @@ function posixRel(from: string, file: string): string {
184
175
  }
185
176
 
186
177
  function sourcePrefixes(rel: string): string[] {
187
- const noExt = rel.replace(/\.(cpp|cc|cxx|c|h|hpp|hh)$/i, "");
178
+ const noExt = rel.replace(/\.(clpp|clp|clh)$/i, "");
188
179
  const noTag = noExt.replace(/\.(server|client)$/i, "");
189
180
  return [...new Set([noExt, noTag, toLuauPath(rel).replace(/\\/g, "/")])];
190
181
  }
@@ -256,7 +247,7 @@ function createMapper(root: string, config: ProjectConfig, rojoPath?: string): R
256
247
 
257
248
  function compileProject(root: string, config: ProjectConfig, mapper: RojoMapper) {
258
249
  const srcDir = path.join(root, config.rootDir);
259
- const files = collectCpp(srcDir);
250
+ const files = collectSources(srcDir);
260
251
  const jobs: Array<{ rel: string; files: Array<{ name: string; contents: string }>; stale: string[] }> = [];
261
252
  const errors: Array<{ rel: string; prefixes: string[]; message: string }> = [];
262
253
 
@@ -350,8 +341,8 @@ export function build(root: string, options: BuildOptions = {}): BuildResult {
350
341
  ensureVendor(root);
351
342
  }
352
343
  const srcDir = path.join(root, config.rootDir);
353
- if (!fs.existsSync(srcDir) || collectCpp(srcDir).length === 0) {
354
- console.error("no .cpp/.h/.hpp files in", config.rootDir);
344
+ if (!fs.existsSync(srcDir) || collectSources(srcDir).length === 0) {
345
+ console.error("no .clpp/.clp/.clh files in", config.rootDir);
355
346
  if (!holdOnError) {
356
347
  pruneOut(root, config, new Set(), []);
357
348
  }
@@ -412,18 +403,11 @@ export async function init(dest: string): Promise<void> {
412
403
  copyDir(include, path.join(target, "include"));
413
404
  copyRuntime(target);
414
405
  syncEditorSupport(target);
415
- const installed = await installEditorSupport();
416
406
  console.log("Cluaupp ready in", target);
407
+ console.log(" clpp install (CL++ highlighting + IntelliSense)");
417
408
  console.log(" rokit install");
418
409
  console.log(" cluaupp build");
419
410
  console.log(" rojo serve");
420
- if (
421
- installed.local.length ||
422
- (installed.clangd && (installed.clangd.status === "installed" || installed.clangd.status === "already")) ||
423
- (installed.llvm && (installed.llvm.status === "installed" || installed.llvm.status === "already"))
424
- ) {
425
- console.log(" reload Cursor (Ctrl+Shift+P → Developer: Reload Window)");
426
- }
427
411
  }
428
412
 
429
413
  function pidAlive(pid: number): boolean {
@@ -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,6 @@
1
+ #pragma strict
2
+ #include <clpp/roblox.clh>
3
+
4
+ void init() {
5
+ post("Cluaupp client ok");
6
+ }
@@ -0,0 +1,29 @@
1
+ #pragma strict
2
+ #include <clpp/roblox.clh>
3
+
4
+ void CreateLeaderstats(Player* player) {
5
+ if (player::FindFirstChild("leaderstats") != null) {
6
+ return;
7
+ }
8
+
9
+ Folder* leaderstats = new Folder(player);
10
+ leaderstats.Name = "leaderstats";
11
+
12
+ IntValue* coins = new IntValue(leaderstats);
13
+ coins.Name = "Coins";
14
+ coins.Value = 0;
15
+
16
+ IntValue* level = new IntValue(leaderstats);
17
+ level.Name = "Level";
18
+ level.Value = 0;
19
+ }
20
+
21
+ void init() {
22
+ Players* players = GetService<Players>();
23
+
24
+ for (Player* player : players::GetPlayers()) {
25
+ CreateLeaderstats(player);
26
+ }
27
+
28
+ players::PlayerAdded::Connect(CreateLeaderstats);
29
+ }
@@ -0,0 +1,6 @@
1
+ #pragma once
2
+ #include <clpp/roblox.clh>
3
+
4
+ const int STARTING_COINS = 0;
5
+ const string REMOTE_COINS = "Coins";
6
+ const string LEADERSTATS_FOLDER = "leaderstats";
@@ -1,25 +0,0 @@
1
- CompileFlags:
2
- CompilationDatabase: .
3
- Add:
4
- - -xc++
5
- - -std=c++20
6
- - -ferror-limit=0
7
- - -Iinclude
8
- - -Isrc
9
- - -I../../include
10
-
11
- Diagnostics:
12
- Suppress: '*'
13
-
14
- ---
15
- If:
16
- PathMatch: .*\.(cpp|cc|cxx|c|h|hpp|hh)$
17
- CompileFlags:
18
- Add:
19
- - -xc++
20
-
21
- ---
22
- If:
23
- PathMatch: (out|libs)/.*
24
- Index:
25
- Background: Skip
@@ -1,6 +0,0 @@
1
- -xc++
2
- -std=c++20
3
- -ferror-limit=0
4
- -Iinclude
5
- -Isrc
6
- -I../../include
@@ -1,12 +0,0 @@
1
- #pragma strict
2
- #include <cluaupp/roblox.hpp>
3
-
4
- void init() {
5
- auto* playerGui = GetService<Players>()->LocalPlayer->FindFirstChild("PlayerGui");
6
- auto* screen = new ScreenGui();
7
- screen->Name = "Hud";
8
- auto* coins = new TextLabel();
9
- coins->Name = "Coins";
10
- coins->Parent = screen;
11
- print("hud ready");
12
- }
@@ -1,6 +0,0 @@
1
- #pragma strict
2
- #include <cluaupp/roblox.hpp>
3
-
4
- void init() {
5
- print("Cluaupp client ok");
6
- }
@@ -1,23 +0,0 @@
1
- #pragma strict
2
- #include <cluaupp/roblox.hpp>
3
-
4
- void ApplyDamage(Player* player, int amount) {
5
- auto* character = player->Character;
6
- if (character == nullptr) {
7
- return;
8
- }
9
- auto* humanoid = character->FindFirstChildOfClass("Humanoid");
10
- if (humanoid == nullptr) {
11
- return;
12
- }
13
- humanoid->TakeDamage(amount);
14
- }
15
-
16
- void OnPlayer(Player* player) {
17
- ApplyDamage(player, 0);
18
- }
19
-
20
- void init() {
21
- auto* players = GetService<Players>();
22
- players->PlayerAdded.Connect(OnPlayer);
23
- }
@@ -1,29 +0,0 @@
1
- #pragma strict
2
- #include <cluaupp/roblox.hpp>
3
-
4
- void CreateLeaderstats(Player* player) {
5
- if (player->FindFirstChild("leaderstats") != nullptr) {
6
- return;
7
- }
8
-
9
- auto* leaderstats = new Folder(player);
10
- leaderstats->Name = "leaderstats";
11
-
12
- auto* coins = new IntValue(leaderstats);
13
- coins->Name = "Coins";
14
- coins->Value = 0;
15
-
16
- auto* level = new IntValue(leaderstats);
17
- level->Name = "Level";
18
- level->Value = 0;
19
- }
20
-
21
- void init() {
22
- auto* players = GetService<Players>();
23
-
24
- for (auto* player : players->GetPlayers()) {
25
- CreateLeaderstats(player);
26
- }
27
-
28
- players->PlayerAdded.Connect(CreateLeaderstats);
29
- }
@@ -1,5 +0,0 @@
1
- #include "config.h"
2
-
3
- int startingCoins() {
4
- return STARTING_COINS;
5
- }
@@ -1,5 +0,0 @@
1
- #include <cluaupp/roblox.hpp>
2
-
3
- const int STARTING_COINS = 0;
4
-
5
- int startingCoins();
@@ -1,25 +0,0 @@
1
- #pragma once
2
- // Cluaupp libraries — C++ IntelliSense. The compiler ignores these headers
3
- // and emits require(ReplicatedStorage.CluauppLibs.*). Full Luau systems live
4
- // in runtime/ (vendored from GitHub + Cluaupp originals).
5
-
6
- #include <cluaupp/generated/instances.hpp>
7
- #include <cluaupp/libs/janitor.hpp>
8
- #include <cluaupp/libs/promise.hpp>
9
- #include <cluaupp/libs/net.hpp>
10
- #include <cluaupp/libs/math.hpp>
11
- #include <cluaupp/libs/formatnumber.hpp>
12
- #include <cluaupp/libs/module3d.hpp>
13
- #include <cluaupp/libs/twinkle.hpp>
14
- #include <cluaupp/libs/dataservice.hpp>
15
- #include <cluaupp/libs/ezvisual.hpp>
16
- #include <cluaupp/libs/spring.hpp>
17
- #include <cluaupp/libs/display.hpp>
18
- #include <cluaupp/libs/stickybillboard.hpp>
19
- #include <cluaupp/libs/topbarplus.hpp>
20
- #include <cluaupp/libs/cmdr.hpp>
21
- #include <cluaupp/libs/chrono.hpp>
22
- #include <cluaupp/libs/iris.hpp>
23
- #include <cluaupp/libs/fusion.hpp>
24
- #include <cluaupp/libs/statemachine.hpp>
25
- #include <cluaupp/libs/vfx.hpp>
@@ -1,47 +0,0 @@
1
- #pragma once
2
- // Cluaupp — full Roblox API for IntelliSense.
3
- // Source: official client dump + datatypes from create.roblox.com
4
- // The compiler ignores #include and emits real Luau (Vector3.new, Instance.new, :GetPlayers, ...).
5
-
6
- #include <cluaupp/generated/enums.hpp>
7
- #include <cluaupp/datatypes.hpp>
8
- #include <cluaupp/generated/instances.hpp>
9
- #include <cluaupp/libs.hpp>
10
-
11
- template <typename T>
12
- T* GetService();
13
-
14
- template <typename T>
15
- T* GetService(Instance* game_);
16
-
17
- extern DataModel* game;
18
- extern Workspace* workspace;
19
- extern LuaSourceContainer* script;
20
-
21
- void print(string message);
22
- void warn(string message);
23
- void error(string message);
24
-
25
- struct cout {
26
- static void print(string message);
27
- static void warn(string message);
28
- static void error(string message);
29
- static void ping(string message);
30
- static void endl();
31
- cout& operator<<(string value);
32
- cout& operator<<(int value);
33
- cout& operator<<(double value);
34
- cout& operator<<(bool value);
35
- } cout;
36
-
37
- struct cerr {
38
- cerr& operator<<(string value);
39
- cerr& operator<<(int value);
40
- } cerr;
41
-
42
- const int endl = 0;
43
- double tick();
44
- double time();
45
- void wait(double seconds = 0);
46
- void spawn(void (*callback)());
47
- void delay(double seconds, void (*callback)());