cluaupp 1.5.2 → 2.0.0-beta.2
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/CHANGELOG.md +8 -0
- package/README.md +29 -41
- package/api/generated/bench-latest.json +43 -21
- package/api/generated/lsp-index.json +1 -1
- package/api/manifests/roblox-target.manifest.json +5 -5
- package/api/normalized/roblox-target.profile.json +8729 -267
- package/api/roblox/luau-builtins.d.luau +185 -0
- package/api/roblox/surface.json +1 -0
- package/api/roblox-api.lock.json +11 -2
- package/bin/cluaupp.js +38 -0
- package/editors/vscode/README.md +1 -1
- package/editors/vscode/package.json +50 -15
- package/editors/vscode/snippets/flare.json +1 -1
- package/editors/vscode/snippets/hive.json +1 -1
- package/editors/vscode/syntaxes/clpp.tmLanguage.json +211 -0
- package/examples/README.md +9 -9
- package/examples/game/cluaupp.config.json +2 -2
- package/examples/game/default.project.json +4 -15
- package/examples/game/out/ReplicatedStorage/Shared/GameInfo.luau +8 -0
- package/examples/game/out/ReplicatedStorage/Shared/GameInfo.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Leaderstats.server.luau +26 -0
- package/examples/game/out/ServerScriptService/Leaderstats.server.luau.map.json +13 -0
- package/examples/game/out/ServerScriptService/Main.server.luau +15 -0
- package/examples/game/out/ServerScriptService/Main.server.luau.map.json +13 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Main.client.luau +10 -0
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Main.client.luau.map.json +13 -0
- package/examples/game/src/ReplicatedStorage/Shared/GameInfo.clp +1 -0
- package/examples/game/src/ServerScriptService/Leaderstats.server.clp +18 -0
- package/examples/game/src/ServerScriptService/Main.server.clp +9 -0
- package/examples/game/src/StarterPlayer/StarterPlayerScripts/Main.client.clp +4 -0
- package/generated/api/build-profile.js +1 -1
- package/generated/api/loader.js +2 -2
- package/generated/api/surface/build.js +328 -0
- package/generated/api/surface/luau-defs.js +595 -0
- package/generated/api/surface/model.js +8 -0
- package/generated/api-cli.js +2 -2
- package/generated/cli.js +18 -17
- package/generated/clpp/contract.js +6 -3
- package/generated/clpp/handshake.js +36 -0
- package/generated/clpp/modules.js +20 -9
- package/generated/clpp/runner.js +62 -31
- package/generated/compile.js +18 -1
- package/generated/compiler/ast.js +3 -0
- package/generated/compiler/checker/calls.js +999 -0
- package/generated/compiler/checker/checker.js +1215 -0
- package/generated/compiler/checker/exprs.js +791 -0
- package/generated/compiler/checker/flow.js +168 -0
- package/generated/compiler/checker/members.js +763 -0
- package/generated/compiler/checker/statements.js +792 -0
- package/generated/compiler/checker/symbols.js +90 -0
- package/generated/compiler/checker/typeops.js +348 -0
- package/generated/compiler/checker/yields.js +115 -0
- package/generated/compiler/diagnostics.js +138 -0
- package/generated/compiler/emit/emitter.js +2356 -0
- package/generated/compiler/emit/luau-types.js +137 -0
- package/generated/compiler/emit/names.js +130 -0
- package/generated/compiler/emit/runtime.js +432 -0
- package/generated/compiler/lexer.js +403 -0
- package/generated/compiler/parser.js +1881 -0
- package/generated/compiler/project.js +332 -0
- package/generated/compiler/roblox/api.js +388 -0
- package/generated/compiler/roblox/context.js +100 -0
- package/generated/compiler/source.js +59 -0
- package/generated/compiler/stdlib.js +232 -0
- package/generated/compiler/types.js +250 -0
- package/generated/intellisense.js +1 -15
- package/generated/lsp.js +1 -1
- package/generated/target/build-cache.js +4 -4
- package/generated/target/datamodel-generate.js +12 -0
- package/generated/target/gen-rojo-tree.js +15 -0
- package/generated/target/source-map.js +61 -8
- package/generated/target/studio-bridge.js +1 -0
- package/generated/utils/project.js +104 -31
- package/include/README.md +5 -0
- package/native/bin/.gitkeep +1 -0
- package/package.json +17 -6
- package/plugins/CluauppNav/Plugin.luau +28 -4
- package/rust/cluaupp/Cargo.lock +795 -0
- package/rust/cluaupp/Cargo.toml +17 -0
- package/rust/cluaupp/src/main.rs +717 -0
- package/scripts/postinstall-native.js +56 -0
- package/skills/README.md +3 -3
- package/skills/clpp-hive-flare/SKILL.md +30 -26
- package/skills/clpp-language/SKILL.md +67 -74
- package/skills/clpp-language/compiler.md +24 -36
- package/skills/clpp-style/SKILL.md +31 -44
- package/src/api/build-profile.ts +1 -1
- package/src/api/loader.ts +2 -2
- package/src/api/surface/build.ts +374 -0
- package/src/api/surface/luau-defs.ts +635 -0
- package/src/api/surface/model.ts +96 -0
- package/src/api-cli.ts +2 -2
- package/src/cli.ts +19 -18
- package/src/clpp/contract.ts +20 -3
- package/src/clpp/handshake.ts +25 -0
- package/src/clpp/modules.ts +17 -10
- package/src/clpp/runner.ts +52 -34
- package/src/compile.ts +20 -2
- package/src/compiler/ast.ts +336 -0
- package/src/compiler/checker/calls.ts +1025 -0
- package/src/compiler/checker/checker.ts +1352 -0
- package/src/compiler/checker/exprs.ts +805 -0
- package/src/compiler/checker/flow.ts +174 -0
- package/src/compiler/checker/members.ts +793 -0
- package/src/compiler/checker/statements.ts +802 -0
- package/src/compiler/checker/symbols.ts +219 -0
- package/src/compiler/checker/typeops.ts +355 -0
- package/src/compiler/checker/yields.ts +120 -0
- package/src/compiler/diagnostics.ts +163 -0
- package/src/compiler/emit/emitter.ts +2486 -0
- package/src/compiler/emit/luau-types.ts +143 -0
- package/src/compiler/emit/names.ts +130 -0
- package/src/compiler/emit/runtime.ts +438 -0
- package/src/compiler/lexer.ts +444 -0
- package/src/compiler/parser.ts +1943 -0
- package/src/compiler/project.ts +354 -0
- package/src/compiler/roblox/api.ts +408 -0
- package/src/compiler/roblox/context.ts +108 -0
- package/src/compiler/source.ts +67 -0
- package/src/compiler/stdlib.ts +256 -0
- package/src/compiler/types.ts +313 -0
- package/src/intellisense.ts +1 -13
- package/src/lsp.ts +1 -1
- package/src/target/build-cache.ts +5 -8
- package/src/target/datamodel-generate.ts +12 -1
- package/src/target/gen-rojo-tree.ts +15 -0
- package/src/target/source-map.ts +65 -27
- package/src/target/studio-bridge.ts +3 -0
- package/src/types.ts +3 -0
- package/src/utils/project.ts +99 -37
- package/templates/README.md +7 -0
- package/templates/{game → game-modern}/cluaupp.config.json +2 -2
- package/templates/{game → game-modern}/package.json +1 -2
- package/templates/game-modern/rokit.toml +2 -0
- package/templates/game-modern/src/ReplicatedStorage/Shared/GameInfo.clp +1 -0
- package/templates/game-modern/src/ServerScriptService/Handlers/Guard.server.clp +4 -0
- package/templates/game-modern/src/ServerScriptService/Main.server.clp +8 -0
- package/templates/game-modern/src/StarterPlayer/StarterPlayerScripts/Main.client.clp +4 -0
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau +0 -29
- package/examples/game/out/ReplicatedStorage/Shared/Constants/Datas/TemplateData.luau.map.json +0 -13
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau +0 -83
- package/examples/game/out/ReplicatedStorage/Shared/Net/Net.luau.map.json +0 -13
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau +0 -18
- package/examples/game/out/ServerScriptService/Boot/DataBoot.server.luau.map.json +0 -13
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau +0 -14
- package/examples/game/out/ServerScriptService/Configuration/ServerConfig.luau.map.json +0 -13
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau +0 -15
- package/examples/game/out/ServerScriptService/Handlers/Guard.server.luau.map.json +0 -13
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau +0 -50
- package/examples/game/out/ServerScriptService/Handlers/PlayerHandler.server.luau.map.json +0 -13
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau +0 -12
- package/examples/game/out/StarterPlayer/StarterCharacterScripts/Character/CharacterReady.client.luau.map.json +0 -13
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau +0 -16
- package/examples/game/out/StarterPlayer/StarterPlayerScripts/Controllers/DataController.client.luau.map.json +0 -13
- package/examples/game/src/Client/Controllers/DataController.client.clpp +0 -7
- package/examples/game/src/Client/Main.client.clpp +0 -4
- package/examples/game/src/Declarations/Net.flare +0 -5
- package/examples/game/src/Include/GameTypes.clh +0 -40
- package/examples/game/src/Modules/Core/Guard.server.clpp +0 -7
- package/examples/game/src/Modules/Core/PlayerHandler.server.clpp +0 -23
- package/examples/game/src/Server/Boot/DataBoot.server.clpp +0 -13
- package/examples/game/src/Server/Main.server.clpp +0 -4
- package/templates/game/.clangd +0 -25
- package/templates/game/.vscode/extensions.json +0 -8
- package/templates/game/.vscode/settings.json +0 -17
- package/templates/game/Packages/.gitkeep +0 -0
- package/templates/game/compile_flags.txt +0 -6
- package/templates/game/default.project.json +0 -41
- package/templates/game/include/clpp/datatypes.clh +0 -575
- package/templates/game/include/clpp/generated/enums.clh +0 -4920
- package/templates/game/include/clpp/generated/instances.clh +0 -87182
- package/templates/game/include/clpp/libs/arrayindexer.clh +0 -12
- package/templates/game/include/clpp/libs/axiom.clh +0 -154
- package/templates/game/include/clpp/libs/bloom.clh +0 -58
- package/templates/game/include/clpp/libs/coil.clh +0 -37
- package/templates/game/include/clpp/libs/crest.clh +0 -22
- package/templates/game/include/clpp/libs/echo.clh +0 -52
- package/templates/game/include/clpp/libs/ember.clh +0 -17
- package/templates/game/include/clpp/libs/flare.clh +0 -65
- package/templates/game/include/clpp/libs/gleam.clh +0 -111
- package/templates/game/include/clpp/libs/guide.clh +0 -42
- package/templates/game/include/clpp/libs/helm.clh +0 -31
- package/templates/game/include/clpp/libs/hive.clh +0 -20
- package/templates/game/include/clpp/libs/keep.clh +0 -158
- package/templates/game/include/clpp/libs/lens.clh +0 -24
- package/templates/game/include/clpp/libs/mint.clh +0 -28
- package/templates/game/include/clpp/libs/net.clh +0 -31
- package/templates/game/include/clpp/libs/occlude.clh +0 -15
- package/templates/game/include/clpp/libs/pin.clh +0 -28
- package/templates/game/include/clpp/libs/promise.clh +0 -24
- package/templates/game/include/clpp/libs/roster.clh +0 -123
- package/templates/game/include/clpp/libs/shift.clh +0 -22
- package/templates/game/include/clpp/libs/spark.clh +0 -28
- package/templates/game/include/clpp/libs/stage.clh +0 -23
- package/templates/game/include/clpp/libs/sweep.clh +0 -23
- package/templates/game/include/clpp/libs/trace.clh +0 -18
- package/templates/game/include/clpp/libs/ward.clh +0 -19
- package/templates/game/include/clpp/libs.clh +0 -31
- package/templates/game/include/clpp/roblox.clh +0 -41
- package/templates/game/rokit.toml +0 -5
- package/templates/game/src/Client/Controllers/DataController.client.clpp +0 -7
- package/templates/game/src/Client/Main.client.clpp +0 -4
- package/templates/game/src/Declarations/Net.flare +0 -5
- package/templates/game/src/Include/GameTypes.clh +0 -40
- package/templates/game/src/Modules/Core/Guard.server.clpp +0 -7
- package/templates/game/src/Modules/Core/PlayerHandler.server.clpp +0 -24
- package/templates/game/src/Server/Boot/DataBoot.server.clpp +0 -13
- package/templates/game/src/Server/Main.server.clpp +0 -4
- package/templates/game/stylua.toml +0 -9
- package/templates/game/wally.toml +0 -12
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CL++ standard library modules (`@clpp.axiom`, `@clpp.text`, `@clpp.math`, `@clpp.http`) on the
|
|
3
|
+
* Roblox target. Each function has a CL++ signature and a lowering: an inline Luau template using
|
|
4
|
+
* fast built-ins, or a call into the CluauppLibs runtime (`Axiom`) / a file-local helper.
|
|
5
|
+
*
|
|
6
|
+
* Templates use `$1…$n` for arguments; `@n` marks arguments that are evaluated more than once,
|
|
7
|
+
* so the emitter only inlines when those arguments are side-effect free.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { T, type FnParam, type Type } from "./types.js";
|
|
11
|
+
|
|
12
|
+
export type StdModule = "axiom" | "text" | "math" | "http" | "json" | "time";
|
|
13
|
+
|
|
14
|
+
export interface StdFunction {
|
|
15
|
+
name: string;
|
|
16
|
+
params: FnParam[];
|
|
17
|
+
ret: Type;
|
|
18
|
+
/** Inline Luau template, or null to call the runtime / helper. */
|
|
19
|
+
inline: string | null;
|
|
20
|
+
/** Helper (from runtime.ts) the lowering needs. */
|
|
21
|
+
helper?: string;
|
|
22
|
+
/** Runtime library member to call when not inlined. */
|
|
23
|
+
runtime?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const typeOf: Record<string, Type> = {
|
|
27
|
+
float: T.float,
|
|
28
|
+
int: T.int,
|
|
29
|
+
bool: T.bool,
|
|
30
|
+
string: T.string,
|
|
31
|
+
Vector2: T.datatype("Vector2"),
|
|
32
|
+
Vector3: T.datatype("Vector3"),
|
|
33
|
+
Color3: T.datatype("Color3"),
|
|
34
|
+
CFrame: T.datatype("CFrame"),
|
|
35
|
+
UDim2: T.datatype("UDim2"),
|
|
36
|
+
floats: T.list(T.float),
|
|
37
|
+
strings: T.list(T.string),
|
|
38
|
+
list: T.list(T.any, false),
|
|
39
|
+
any: T.any,
|
|
40
|
+
strings2: T.list(T.string),
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
function sig(spec: string, inline: string | null, extra: Partial<StdFunction> = {}): StdFunction {
|
|
44
|
+
const m = /^(\w+)\(([^)]*)\)\s*->\s*(\w+)$/.exec(spec);
|
|
45
|
+
if (!m) {
|
|
46
|
+
throw new Error(`bad std signature ${spec}`);
|
|
47
|
+
}
|
|
48
|
+
const params = m[2]
|
|
49
|
+
.split(",")
|
|
50
|
+
.map((p) => p.trim())
|
|
51
|
+
.filter(Boolean)
|
|
52
|
+
.map((p, i) => {
|
|
53
|
+
const optional = p.endsWith("?");
|
|
54
|
+
const [tname, pname] = p.replace("?", "").split(/\s+/);
|
|
55
|
+
return { name: pname || `p${i}`, type: typeOf[tname] ?? T.any, optional };
|
|
56
|
+
});
|
|
57
|
+
return { name: m[1], params, ret: typeOf[m[3]] ?? T.void, inline, ...extra };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const AXIOM: StdFunction[] = [
|
|
61
|
+
sig("Clamp(float value, float min, float max) -> float", "math.min(math.max($1, $2), $3)"),
|
|
62
|
+
sig("Map(float value, float inMin, float inMax, float outMin, float outMax) -> float", null),
|
|
63
|
+
sig("Wrap(float value, float min, float max) -> float", null),
|
|
64
|
+
sig("Sign(float value) -> float", "math.sign($1)"),
|
|
65
|
+
sig("Round(float value, float places?) -> float", null),
|
|
66
|
+
sig("Snap(float value, float step) -> float", null),
|
|
67
|
+
sig("PingPong(float t, float length) -> float", null),
|
|
68
|
+
sig("Saturate(float value) -> float", "math.min(math.max($1, 0), 1)"),
|
|
69
|
+
sig("Fract(float value) -> float", "@1 - math.floor(@1)"),
|
|
70
|
+
sig("InvLerp(float from, float to, float value) -> float", null),
|
|
71
|
+
sig("Approach(float current, float target, float maxDelta) -> float", null),
|
|
72
|
+
sig("IsFinite(float value) -> bool", "@1 == @1 and @1 ~= math.huge and @1 ~= -math.huge"),
|
|
73
|
+
sig("Abs(float value) -> float", "math.abs($1)"),
|
|
74
|
+
sig("Min(float a, float b) -> float", "math.min($1, $2)"),
|
|
75
|
+
sig("Max(float a, float b) -> float", "math.max($1, $2)"),
|
|
76
|
+
sig("Pow(float base, float exp) -> float", "$1 ^ $2"),
|
|
77
|
+
sig("Sqrt(float value) -> float", "math.sqrt($1)"),
|
|
78
|
+
sig("Cbrt(float value) -> float", null),
|
|
79
|
+
sig("Hypot(float a, float b) -> float", "math.sqrt(@1 * @1 + @2 * @2)"),
|
|
80
|
+
sig("Log(float value) -> float", "math.log($1)"),
|
|
81
|
+
sig("Log2(float value) -> float", "math.log($1, 2)"),
|
|
82
|
+
sig("Log10(float value) -> float", "math.log10($1)"),
|
|
83
|
+
sig("Exp(float value) -> float", "math.exp($1)"),
|
|
84
|
+
sig("Smoothstep(float edge0, float edge1, float x) -> float", null),
|
|
85
|
+
sig("Smootherstep(float edge0, float edge1, float x) -> float", null),
|
|
86
|
+
sig("Gcd(float a, float b) -> float", null),
|
|
87
|
+
sig("Lcm(float a, float b) -> float", null),
|
|
88
|
+
sig("IsEven(float value) -> bool", "$1 % 2 == 0"),
|
|
89
|
+
sig("IsOdd(float value) -> bool", "$1 % 2 == 1"),
|
|
90
|
+
sig("IsNaN(float value) -> bool", "@1 ~= @1"),
|
|
91
|
+
sig("Factorial(float n) -> float", null),
|
|
92
|
+
sig("Scale(float value, float index) -> float", null),
|
|
93
|
+
sig("Lerp(float from, float to, float alpha) -> float", "@1 + (@2 - @1) * $3"),
|
|
94
|
+
sig("LerpClamped(float from, float to, float alpha) -> float", "@1 + (@2 - @1) * math.min(math.max($3, 0), 1)"),
|
|
95
|
+
sig("LerpVector2(Vector2 from, Vector2 to, float alpha) -> Vector2", "$1:Lerp($2, $3)"),
|
|
96
|
+
sig("LerpVector3(Vector3 from, Vector3 to, float alpha) -> Vector3", "$1:Lerp($2, $3)"),
|
|
97
|
+
sig("LerpVector(Vector3 from, Vector3 to, float alpha) -> Vector3", "$1:Lerp($2, $3)"),
|
|
98
|
+
sig("LerpColor3(Color3 from, Color3 to, float alpha) -> Color3", "$1:Lerp($2, $3)"),
|
|
99
|
+
sig("LerpCFrame(CFrame from, CFrame to, float alpha) -> CFrame", "$1:Lerp($2, $3)"),
|
|
100
|
+
sig("SlerpCFrame(CFrame from, CFrame to, float alpha) -> CFrame", "$1:Lerp($2, $3)"),
|
|
101
|
+
sig("LerpUDim2(UDim2 from, UDim2 to, float alpha) -> UDim2", "$1:Lerp($2, $3)"),
|
|
102
|
+
sig("LerpAngle(float from, float to, float alpha) -> float", null),
|
|
103
|
+
sig("Inverse(float from, float to, float value) -> float", null),
|
|
104
|
+
sig("Project(Vector3 a, Vector3 b) -> Vector3", null),
|
|
105
|
+
sig("Reject(Vector3 a, Vector3 b) -> Vector3", null),
|
|
106
|
+
sig("Reflect(Vector3 incident, Vector3 normal) -> Vector3", null),
|
|
107
|
+
sig("Angle(Vector3 a, Vector3 b) -> float", "$1:Angle($2)"),
|
|
108
|
+
sig("Distance(Vector3 a, Vector3 b) -> float", "($2 - $1).Magnitude"),
|
|
109
|
+
sig("Distance2(Vector2 a, Vector2 b) -> float", "($2 - $1).Magnitude"),
|
|
110
|
+
sig("Orthonormal(Vector3 forward, Vector3 up?) -> Vector3", null),
|
|
111
|
+
sig("Slerp(Vector3 a, Vector3 b, float t) -> Vector3", null),
|
|
112
|
+
sig("LookAt(Vector3 from, Vector3 target) -> Vector3", null),
|
|
113
|
+
sig("Flat(Vector3 value) -> Vector3", null),
|
|
114
|
+
sig("Dot(Vector3 a, Vector3 b) -> float", "$1:Dot($2)"),
|
|
115
|
+
sig("Cross(Vector3 a, Vector3 b) -> Vector3", "$1:Cross($2)"),
|
|
116
|
+
sig("Length(Vector3 v) -> float", "$1.Magnitude"),
|
|
117
|
+
sig("Normalize(Vector3 v) -> Vector3", null),
|
|
118
|
+
sig("CubicBezier(float t, Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3) -> Vector3", null),
|
|
119
|
+
sig("QuadraticBezier(float t, Vector3 p0, Vector3 p1, Vector3 p2) -> Vector3", null),
|
|
120
|
+
sig("Hover(float t, Vector3 base, Vector3 amplitude) -> Vector3", null),
|
|
121
|
+
sig("Float(float t, Vector3 base, Vector3 amplitude) -> Vector3", null),
|
|
122
|
+
sig("FloatSpin(float t, Vector3 base) -> Vector3", null),
|
|
123
|
+
sig("AabbContains(Vector3 point, Vector3 min, Vector3 max) -> bool", null),
|
|
124
|
+
sig("SphereContains(Vector3 point, Vector3 center, float radius) -> bool", "($1 - $2).Magnitude <= $3"),
|
|
125
|
+
sig("RayPlane(Vector3 origin, Vector3 dir, Vector3 point, Vector3 normal) -> Vector3", null),
|
|
126
|
+
sig("Barycentric(Vector3 p, Vector3 a, Vector3 b, Vector3 c) -> Vector3", null),
|
|
127
|
+
sig("ClosestPointOnSegment(Vector3 p, Vector3 a, Vector3 b) -> Vector3", null),
|
|
128
|
+
sig("Deg(float rad) -> float", "math.deg($1)"),
|
|
129
|
+
sig("Rad(float deg) -> float", "math.rad($1)"),
|
|
130
|
+
sig("DeltaAngle(float from, float to) -> float", null),
|
|
131
|
+
sig("AngleDiff(float from, float to) -> float", null),
|
|
132
|
+
sig("DeltaAngleDegrees(float from, float to) -> float", null),
|
|
133
|
+
sig("NormalizeAngle(float angle) -> float", null),
|
|
134
|
+
sig("Sin(float x) -> float", "math.sin($1)"),
|
|
135
|
+
sig("Cos(float x) -> float", "math.cos($1)"),
|
|
136
|
+
sig("Tan(float x) -> float", "math.tan($1)"),
|
|
137
|
+
sig("Asin(float x) -> float", "math.asin($1)"),
|
|
138
|
+
sig("Acos(float x) -> float", "math.acos($1)"),
|
|
139
|
+
sig("Atan2(float y, float x) -> float", "math.atan2($1, $2)"),
|
|
140
|
+
sig("RandomRange(float min, float max) -> float", null),
|
|
141
|
+
sig("Random(float min, float max) -> float", null),
|
|
142
|
+
sig("Weighted(floats weights) -> int", null),
|
|
143
|
+
sig("Gaussian(float mean?, float std?) -> float", null),
|
|
144
|
+
sig("Average(floats values) -> float", null),
|
|
145
|
+
sig("Sum(floats values) -> float", null),
|
|
146
|
+
sig("HashU32(float n) -> int", null),
|
|
147
|
+
sig("Value1(float x) -> float", null),
|
|
148
|
+
sig("Value2(float x, float y) -> float", null),
|
|
149
|
+
sig("Value3(float x, float y, float z) -> float", null),
|
|
150
|
+
sig("FromHSV(float h, float s, float v) -> Color3", "Color3.fromHSV($1, $2, $3)"),
|
|
151
|
+
sig("Contrast(Color3 color, float amount) -> Color3", null),
|
|
152
|
+
sig("LerpHSV(Color3 a, Color3 b, float t) -> Color3", null),
|
|
153
|
+
sig("Floor(float value) -> float", "math.floor($1)"),
|
|
154
|
+
sig("Ceil(float value) -> float", "math.ceil($1)"),
|
|
155
|
+
sig("Trunc(float value) -> float", null),
|
|
156
|
+
sig("Pi() -> float", "math.pi"),
|
|
157
|
+
];
|
|
158
|
+
|
|
159
|
+
const TEXT: StdFunction[] = [
|
|
160
|
+
sig("trim(string text) -> string", null, { helper: "trim" }),
|
|
161
|
+
sig("lower(string text) -> string", "string.lower($1)"),
|
|
162
|
+
sig("upper(string text) -> string", "string.upper($1)"),
|
|
163
|
+
sig("contains(string text, string part) -> bool", "string.find($1, $2, 1, true) ~= nil"),
|
|
164
|
+
sig("split(string text, string separator) -> strings", "string.split($1, $2)"),
|
|
165
|
+
sig("replace(string text, string target, string replacement) -> string", null, { helper: "replace" }),
|
|
166
|
+
sig("startsWith(string text, string part) -> bool", "string.sub($1, 1, #@2) == @2"),
|
|
167
|
+
sig("endsWith(string text, string part) -> bool", null, { helper: "endsWith" }),
|
|
168
|
+
sig("repeat(string text, int count) -> string", "string.rep($1, $2)"),
|
|
169
|
+
sig("toNumber(string text) -> float", null, { helper: "toNumber" }),
|
|
170
|
+
sig("indexOf(string text, string part) -> int", null, { helper: "indexOf" }),
|
|
171
|
+
sig("joinAll(list parts, string separator) -> string", null, { helper: "joinAll" }),
|
|
172
|
+
];
|
|
173
|
+
|
|
174
|
+
const MATH: StdFunction[] = [sig("abs(float n) -> float", "math.abs($1)")];
|
|
175
|
+
|
|
176
|
+
const HTTP: StdFunction[] = [sig("host(string url) -> string", null, { helper: "urlHost" })];
|
|
177
|
+
|
|
178
|
+
/** @clpp.json on Roblox: HttpService JSONEncode/JSONDecode plus dotted-path helpers. */
|
|
179
|
+
const JSON_FNS: StdFunction[] = [
|
|
180
|
+
sig("Parse(string text) -> any", null, { helper: "jsonParse" }),
|
|
181
|
+
sig("Valid(string text) -> bool", null, { helper: "jsonValid" }),
|
|
182
|
+
sig("Stringify(any value) -> string", null, { helper: "jsonStringify" }),
|
|
183
|
+
sig("Pretty(any value) -> string", null, { helper: "jsonPretty" }),
|
|
184
|
+
sig("Get(any value, string path) -> any", null, { helper: "jsonGet" }),
|
|
185
|
+
sig("Has(any value, string path) -> bool", null, { helper: "jsonHas" }),
|
|
186
|
+
sig("Set(any target, string key, any value) -> any", null, { helper: "jsonSet" }),
|
|
187
|
+
sig("Object() -> any", "{}"),
|
|
188
|
+
sig("Keys(any object) -> strings", null, { helper: "jsonKeys" }),
|
|
189
|
+
];
|
|
190
|
+
|
|
191
|
+
/** @clpp.time on Roblox: os.clock / DateTime / os.date / task.wait. */
|
|
192
|
+
const TIME: StdFunction[] = [
|
|
193
|
+
sig("Now() -> float", "DateTime.now().UnixTimestampMillis / 1000"),
|
|
194
|
+
sig("Clock() -> float", "os.clock()"),
|
|
195
|
+
sig("Sleep(float ms) -> void", "task.wait($1 / 1000)"),
|
|
196
|
+
sig("Date() -> string", 'os.date("%Y-%m-%d")'),
|
|
197
|
+
sig("TimeOfDay() -> string", 'os.date("%H:%M:%S")'),
|
|
198
|
+
sig("Format(string pattern) -> string", "os.date($1)"),
|
|
199
|
+
sig("Year() -> int", 'os.date("*t").year'),
|
|
200
|
+
sig("Month() -> int", 'os.date("*t").month'),
|
|
201
|
+
sig("Day() -> int", 'os.date("*t").day'),
|
|
202
|
+
sig("Hour() -> int", 'os.date("*t").hour'),
|
|
203
|
+
sig("Minute() -> int", 'os.date("*t").min'),
|
|
204
|
+
sig("Second() -> int", 'os.date("*t").sec'),
|
|
205
|
+
sig("Weekday() -> int", 'os.date("*t").wday - 1'),
|
|
206
|
+
sig("DayOfYear() -> int", 'os.date("*t").yday'),
|
|
207
|
+
];
|
|
208
|
+
|
|
209
|
+
const MODULES: Record<StdModule, Map<string, StdFunction>> = {
|
|
210
|
+
axiom: new Map(AXIOM.map((f) => [f.name, f])),
|
|
211
|
+
text: new Map(TEXT.map((f) => [f.name, f])),
|
|
212
|
+
math: new Map(MATH.map((f) => [f.name, f])),
|
|
213
|
+
http: new Map(HTTP.map((f) => [f.name, f])),
|
|
214
|
+
json: new Map(JSON_FNS.map((f) => [f.name, f])),
|
|
215
|
+
time: new Map(TIME.map((f) => [f.name, f])),
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
for (const f of AXIOM) {
|
|
219
|
+
if (!f.inline) {
|
|
220
|
+
f.runtime = f.name;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
/** Desktop-only CL++ modules and what to use on Roblox instead. */
|
|
225
|
+
export const DESKTOP_ONLY: Record<string, string> = {
|
|
226
|
+
"@clpp.fs": "Roblox games have no file system; persist data with DataStoreService (or CluauppLibs Keep)",
|
|
227
|
+
"@clpp.os": "Roblox games have no process environment; use attributes or a config module",
|
|
228
|
+
"@clpp.window": "the Roblox client owns the window; use RunService.RenderStepped and UserInputService",
|
|
229
|
+
"@clpp.gfx": "draw with GUI objects (Frame, ImageLabel) or EditableImage",
|
|
230
|
+
"@clpp.ui": "build UI with ScreenGui/Frame/TextButton, or CluauppLibs Gleam",
|
|
231
|
+
"@clpp.gui": "build UI with ScreenGui instances, or the declarative CluauppLibs Gleam",
|
|
232
|
+
"@clpp.audio": "play Sound instances (SoundService) instead",
|
|
233
|
+
"@clpp.input": "read input with UserInputService/ContextActionService (scripts cannot drive the mouse)",
|
|
234
|
+
"@clpp.io": "there is no console input on Roblox; use print/warn",
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
export const STD_PATHS: Record<string, StdModule | "unsupported"> = {
|
|
238
|
+
"@clpp.axiom": "axiom",
|
|
239
|
+
"@clpp.Axion": "axiom",
|
|
240
|
+
"@clpp.mathutils": "axiom",
|
|
241
|
+
"@clpp.text": "text",
|
|
242
|
+
"@clpp.math": "math",
|
|
243
|
+
"@clpp.http": "http",
|
|
244
|
+
"@clpp.json": "json",
|
|
245
|
+
"@clpp.time": "time",
|
|
246
|
+
"@clpp.fs": "unsupported",
|
|
247
|
+
"@clpp.os": "unsupported",
|
|
248
|
+
};
|
|
249
|
+
|
|
250
|
+
export function stdModule(name: StdModule): Map<string, StdFunction> {
|
|
251
|
+
return MODULES[name];
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
export function stdFunctionType(f: StdFunction): Type {
|
|
255
|
+
return T.func(f.params, f.ret);
|
|
256
|
+
}
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CL++ type model for the Roblox host: the CL++ core types plus Roblox classes, datatypes,
|
|
3
|
+
* enums and signals. Types are plain immutable objects; struct/enum details live in registries
|
|
4
|
+
* keyed by `id` (`<moduleId>::<Name>`).
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
export interface FnParam {
|
|
8
|
+
name: string;
|
|
9
|
+
type: Type;
|
|
10
|
+
optional: boolean;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export type Type =
|
|
14
|
+
| { k: "any" }
|
|
15
|
+
| { k: "unknown" }
|
|
16
|
+
| { k: "never" }
|
|
17
|
+
| { k: "void" }
|
|
18
|
+
| { k: "null" }
|
|
19
|
+
| { k: "int" }
|
|
20
|
+
| { k: "float" }
|
|
21
|
+
| { k: "bool" }
|
|
22
|
+
| { k: "string" }
|
|
23
|
+
| { k: "buffer" }
|
|
24
|
+
| { k: "thread" }
|
|
25
|
+
| { k: "lit"; value: string | number | boolean }
|
|
26
|
+
| { k: "list"; elem: Type; typed: boolean }
|
|
27
|
+
| { k: "dict"; key: Type; value: Type }
|
|
28
|
+
| { k: "tuple"; elems: Type[] }
|
|
29
|
+
| { k: "table"; fields: Record<string, Type> }
|
|
30
|
+
| { k: "struct"; id: string; name: string; args: Type[] }
|
|
31
|
+
| { k: "enum"; id: string; name: string }
|
|
32
|
+
| { k: "variant"; id: string; name: string; alternatives: Type[] }
|
|
33
|
+
| { k: "option"; inner: Type }
|
|
34
|
+
| { k: "result"; ok: Type; err: Type }
|
|
35
|
+
| { k: "task"; result: Type }
|
|
36
|
+
| { k: "func"; params: FnParam[]; ret: Type; variadic: Type | null; generics?: string[]; overloads?: Type[] }
|
|
37
|
+
| { k: "union"; members: Type[] }
|
|
38
|
+
| { k: "param"; name: string }
|
|
39
|
+
| { k: "instance"; cls: string; dm?: DataModelNode }
|
|
40
|
+
| { k: "datatype"; name: string }
|
|
41
|
+
| { k: "rbxEnumItem"; enumName: string }
|
|
42
|
+
| { k: "rbxEnum"; enumName: string }
|
|
43
|
+
| { k: "rbxEnums" }
|
|
44
|
+
| { k: "rbxSignal"; args: Type[] }
|
|
45
|
+
| { k: "clSignal"; params: Type[] | null }
|
|
46
|
+
| { k: "namespace"; ns: Namespace }
|
|
47
|
+
| { k: "infer"; resolved: Type | null };
|
|
48
|
+
|
|
49
|
+
export type Namespace =
|
|
50
|
+
| { kind: "module"; moduleId: string; alias: string }
|
|
51
|
+
| { kind: "luauModule"; alias: string }
|
|
52
|
+
| { kind: "library"; name: string }
|
|
53
|
+
| { kind: "datatype"; name: string }
|
|
54
|
+
| { kind: "instanceStatic" }
|
|
55
|
+
| { kind: "struct"; id: string; name: string }
|
|
56
|
+
| { kind: "enum"; id: string; name: string }
|
|
57
|
+
| { kind: "clNamespace"; name: string; moduleId: string }
|
|
58
|
+
| { kind: "stdlib"; module: "axiom" | "text" | "math" | "http" | "json" | "time"; alias: string }
|
|
59
|
+
| { kind: "result" };
|
|
60
|
+
|
|
61
|
+
/** A node of the typed DataModel (from the project layout): `game.ReplicatedStorage.Shared.Combat`. */
|
|
62
|
+
export interface DataModelNode {
|
|
63
|
+
name: string;
|
|
64
|
+
className: string;
|
|
65
|
+
path: string[];
|
|
66
|
+
children: Map<string, DataModelNode>;
|
|
67
|
+
/** Absolute path of the `.clp` that compiles to this ModuleScript/Script, when known. */
|
|
68
|
+
sourceFile?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export const T = {
|
|
72
|
+
any: { k: "any" } as Type,
|
|
73
|
+
unknown: { k: "unknown" } as Type,
|
|
74
|
+
never: { k: "never" } as Type,
|
|
75
|
+
void: { k: "void" } as Type,
|
|
76
|
+
null: { k: "null" } as Type,
|
|
77
|
+
int: { k: "int" } as Type,
|
|
78
|
+
float: { k: "float" } as Type,
|
|
79
|
+
bool: { k: "bool" } as Type,
|
|
80
|
+
string: { k: "string" } as Type,
|
|
81
|
+
buffer: { k: "buffer" } as Type,
|
|
82
|
+
thread: { k: "thread" } as Type,
|
|
83
|
+
instance: (cls: string): Type => ({ k: "instance", cls }),
|
|
84
|
+
datatype: (name: string): Type => ({ k: "datatype", name }),
|
|
85
|
+
list: (elem: Type, typed = true): Type => ({ k: "list", elem, typed }),
|
|
86
|
+
dict: (key: Type, value: Type): Type => ({ k: "dict", key, value }),
|
|
87
|
+
option: (inner: Type): Type => (inner.k === "option" || inner.k === "any" || inner.k === "unknown" || inner.k === "null" ? inner : { k: "option", inner }),
|
|
88
|
+
func: (params: FnParam[], ret: Type, variadic: Type | null = null): Type => ({ k: "func", params, ret, variadic }),
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
/** Follow solved inference slots. */
|
|
92
|
+
export function prune(t: Type): Type {
|
|
93
|
+
let cur = t;
|
|
94
|
+
while (cur.k === "infer" && cur.resolved) {
|
|
95
|
+
cur = cur.resolved;
|
|
96
|
+
}
|
|
97
|
+
return cur;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export function isNumeric(t: Type): boolean {
|
|
101
|
+
const p = prune(t);
|
|
102
|
+
return p.k === "int" || p.k === "float" || (p.k === "lit" && typeof p.value === "number");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function isIntLike(t: Type): boolean {
|
|
106
|
+
const p = prune(t);
|
|
107
|
+
return p.k === "int" || (p.k === "lit" && typeof p.value === "number" && Number.isInteger(p.value)) || p.k === "enum";
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export function isDynamic(t: Type): boolean {
|
|
111
|
+
const p = prune(t);
|
|
112
|
+
return p.k === "any" || p.k === "unknown" || (p.k === "infer" && !p.resolved);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function isStringLike(t: Type): boolean {
|
|
116
|
+
const p = prune(t);
|
|
117
|
+
return p.k === "string" || (p.k === "lit" && typeof p.value === "string");
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export function isBoolLike(t: Type): boolean {
|
|
121
|
+
const p = prune(t);
|
|
122
|
+
return p.k === "bool" || (p.k === "lit" && typeof p.value === "boolean");
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/** Widen literal types: `"Idle"` → string, `3` → int. */
|
|
126
|
+
export function widen(t: Type): Type {
|
|
127
|
+
const p = prune(t);
|
|
128
|
+
if (p.k === "lit") {
|
|
129
|
+
if (typeof p.value === "string") {
|
|
130
|
+
return T.string;
|
|
131
|
+
}
|
|
132
|
+
if (typeof p.value === "boolean") {
|
|
133
|
+
return T.bool;
|
|
134
|
+
}
|
|
135
|
+
return Number.isInteger(p.value) ? T.int : T.float;
|
|
136
|
+
}
|
|
137
|
+
return p;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** Remove `null`/option wrappers. */
|
|
141
|
+
export function nonNull(t: Type): Type {
|
|
142
|
+
const p = prune(t);
|
|
143
|
+
if (p.k === "option") {
|
|
144
|
+
return p.inner;
|
|
145
|
+
}
|
|
146
|
+
if (p.k === "union") {
|
|
147
|
+
const members = p.members.filter((m) => prune(m).k !== "null");
|
|
148
|
+
return members.length === 1 ? members[0] : { k: "union", members };
|
|
149
|
+
}
|
|
150
|
+
return p;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function isNullable(t: Type): boolean {
|
|
154
|
+
const p = prune(t);
|
|
155
|
+
return p.k === "option" || p.k === "null" || (p.k === "union" && p.members.some((m) => prune(m).k === "null"));
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/** Tables that CL++ treats as values (copied on assignment). */
|
|
159
|
+
export function isValueTable(t: Type): boolean {
|
|
160
|
+
const p = prune(t);
|
|
161
|
+
return p.k === "struct" || p.k === "list" || p.k === "dict" || p.k === "result";
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export function sameType(a: Type, b: Type): boolean {
|
|
165
|
+
const x = prune(a);
|
|
166
|
+
const y = prune(b);
|
|
167
|
+
if (x === y) {
|
|
168
|
+
return true;
|
|
169
|
+
}
|
|
170
|
+
if (x.k !== y.k) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
switch (x.k) {
|
|
174
|
+
case "lit":
|
|
175
|
+
return x.value === (y as typeof x).value;
|
|
176
|
+
case "list":
|
|
177
|
+
return sameType(x.elem, (y as typeof x).elem);
|
|
178
|
+
case "dict":
|
|
179
|
+
return sameType(x.key, (y as typeof x).key) && sameType(x.value, (y as typeof x).value);
|
|
180
|
+
case "struct":
|
|
181
|
+
return x.id === (y as typeof x).id && x.args.length === (y as typeof x).args.length && x.args.every((a2, i) => sameType(a2, (y as typeof x).args[i]));
|
|
182
|
+
case "enum":
|
|
183
|
+
case "variant":
|
|
184
|
+
return x.id === (y as typeof x).id;
|
|
185
|
+
case "option":
|
|
186
|
+
return sameType(x.inner, (y as typeof x).inner);
|
|
187
|
+
case "result":
|
|
188
|
+
return sameType(x.ok, (y as typeof x).ok) && sameType(x.err, (y as typeof x).err);
|
|
189
|
+
case "task":
|
|
190
|
+
return sameType(x.result, (y as typeof x).result);
|
|
191
|
+
case "instance":
|
|
192
|
+
return x.cls === (y as typeof x).cls;
|
|
193
|
+
case "datatype":
|
|
194
|
+
return x.name === (y as typeof x).name;
|
|
195
|
+
case "rbxEnumItem":
|
|
196
|
+
case "rbxEnum":
|
|
197
|
+
return x.enumName === (y as typeof x).enumName;
|
|
198
|
+
case "param":
|
|
199
|
+
return x.name === (y as typeof x).name;
|
|
200
|
+
case "tuple":
|
|
201
|
+
return x.elems.length === (y as typeof x).elems.length && x.elems.every((e, i) => sameType(e, (y as typeof x).elems[i]));
|
|
202
|
+
case "union":
|
|
203
|
+
return x.members.length === (y as typeof x).members.length && x.members.every((m) => (y as typeof x).members.some((n) => sameType(m, n)));
|
|
204
|
+
default:
|
|
205
|
+
return true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/** CL++ notation, for diagnostics and hover. */
|
|
210
|
+
export function typeToString(t: Type, depth = 0): string {
|
|
211
|
+
const p = prune(t);
|
|
212
|
+
if (depth > 6) {
|
|
213
|
+
return "…";
|
|
214
|
+
}
|
|
215
|
+
const s = (x: Type) => typeToString(x, depth + 1);
|
|
216
|
+
switch (p.k) {
|
|
217
|
+
case "any":
|
|
218
|
+
return "any";
|
|
219
|
+
case "unknown":
|
|
220
|
+
return "unknown";
|
|
221
|
+
case "never":
|
|
222
|
+
return "never";
|
|
223
|
+
case "void":
|
|
224
|
+
return "void";
|
|
225
|
+
case "null":
|
|
226
|
+
return "null";
|
|
227
|
+
case "int":
|
|
228
|
+
case "float":
|
|
229
|
+
case "bool":
|
|
230
|
+
case "string":
|
|
231
|
+
case "buffer":
|
|
232
|
+
case "thread":
|
|
233
|
+
return p.k;
|
|
234
|
+
case "lit":
|
|
235
|
+
return typeof p.value === "string" ? JSON.stringify(p.value) : String(p.value);
|
|
236
|
+
case "list":
|
|
237
|
+
return p.typed ? `array<${s(p.elem)}>` : "list";
|
|
238
|
+
case "dict":
|
|
239
|
+
return `dictionary<${s(p.key)}, ${s(p.value)}>`;
|
|
240
|
+
case "tuple":
|
|
241
|
+
return `(${p.elems.map(s).join(", ")})`;
|
|
242
|
+
case "table":
|
|
243
|
+
return `{ ${Object.entries(p.fields).slice(0, 6).map(([k, v]) => `${k}: ${s(v)}`).join(", ")} }`;
|
|
244
|
+
case "struct":
|
|
245
|
+
return p.args.length ? `${p.name}<${p.args.map(s).join(", ")}>` : p.name;
|
|
246
|
+
case "enum":
|
|
247
|
+
case "variant":
|
|
248
|
+
return p.name;
|
|
249
|
+
case "option":
|
|
250
|
+
return `${s(p.inner)}?`;
|
|
251
|
+
case "result":
|
|
252
|
+
return `Result<${s(p.ok)}, ${s(p.err)}>`;
|
|
253
|
+
case "task":
|
|
254
|
+
return isDynamic(p.result) || p.result.k === "void" ? "task" : `task<${s(p.result)}>`;
|
|
255
|
+
case "func": {
|
|
256
|
+
const params = p.params.map((x) => `${s(x.type)}${x.optional ? "?" : ""}`);
|
|
257
|
+
if (p.variadic) {
|
|
258
|
+
params.push(`...${s(p.variadic)}`);
|
|
259
|
+
}
|
|
260
|
+
return `func(${params.join(", ")}) -> ${s(p.ret)}`;
|
|
261
|
+
}
|
|
262
|
+
case "union":
|
|
263
|
+
return p.members.map(s).join(" | ");
|
|
264
|
+
case "param":
|
|
265
|
+
return p.name;
|
|
266
|
+
case "instance":
|
|
267
|
+
return p.cls;
|
|
268
|
+
case "datatype":
|
|
269
|
+
return p.name;
|
|
270
|
+
case "rbxEnumItem":
|
|
271
|
+
return `Enum.${p.enumName}`;
|
|
272
|
+
case "rbxEnum":
|
|
273
|
+
return `Enum.${p.enumName} (enum)`;
|
|
274
|
+
case "rbxEnums":
|
|
275
|
+
return "Enum";
|
|
276
|
+
case "rbxSignal":
|
|
277
|
+
return `RBXScriptSignal<${p.args.map(s).join(", ")}>`;
|
|
278
|
+
case "clSignal":
|
|
279
|
+
return p.params ? `signal(${p.params.map(s).join(", ")})` : "signal";
|
|
280
|
+
case "namespace":
|
|
281
|
+
return nsToString(p.ns);
|
|
282
|
+
case "infer":
|
|
283
|
+
return "unknown";
|
|
284
|
+
default:
|
|
285
|
+
return "unknown";
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function nsToString(ns: Namespace): string {
|
|
290
|
+
switch (ns.kind) {
|
|
291
|
+
case "module":
|
|
292
|
+
case "luauModule":
|
|
293
|
+
return `module ${ns.alias}`;
|
|
294
|
+
case "library":
|
|
295
|
+
return `library ${ns.name}`;
|
|
296
|
+
case "datatype":
|
|
297
|
+
return `${ns.name} (datatype)`;
|
|
298
|
+
case "instanceStatic":
|
|
299
|
+
return "Instance";
|
|
300
|
+
case "struct":
|
|
301
|
+
return `struct ${ns.name}`;
|
|
302
|
+
case "enum":
|
|
303
|
+
return `enum ${ns.name}`;
|
|
304
|
+
case "clNamespace":
|
|
305
|
+
return `namespace ${ns.name}`;
|
|
306
|
+
case "stdlib":
|
|
307
|
+
return `module ${ns.alias}`;
|
|
308
|
+
case "result":
|
|
309
|
+
return "Result";
|
|
310
|
+
default:
|
|
311
|
+
return "namespace";
|
|
312
|
+
}
|
|
313
|
+
}
|
package/src/intellisense.ts
CHANGED
|
@@ -4,8 +4,6 @@ import path from "node:path";
|
|
|
4
4
|
import { spawnSync } from "node:child_process";
|
|
5
5
|
import { pkg, projectRoot as PACKAGE_ROOT } from "./package-info.js";
|
|
6
6
|
import type { ProjectConfig } from "./types.js";
|
|
7
|
-
import { CLPP_INSTALL_HINT } from "./clpp/contract.js";
|
|
8
|
-
import { hasClpp } from "./clpp/runner.js";
|
|
9
7
|
import { isSourceFile } from "./clpp/paths.js";
|
|
10
8
|
import { editorBin } from "./editor-install.js";
|
|
11
9
|
|
|
@@ -114,7 +112,7 @@ function writeVscode(root: string): void {
|
|
|
114
112
|
}
|
|
115
113
|
|
|
116
114
|
export function diagnosticsFor(_source?: string, _fileName?: string): CluauppDiagnostic[] {
|
|
117
|
-
//
|
|
115
|
+
// CL++ diagnostics are reported by the compiler during build. Do not spawn a compiler
|
|
118
116
|
// from the editor — that duplicates source=clpp and freezes on every keystroke.
|
|
119
117
|
return [];
|
|
120
118
|
}
|
|
@@ -204,16 +202,6 @@ export async function installEditorSupport() {
|
|
|
204
202
|
console.log(" ", dest);
|
|
205
203
|
}
|
|
206
204
|
}
|
|
207
|
-
if (hasClpp()) {
|
|
208
|
-
const result = spawnSync("clpp", ["install"], { encoding: "utf8", windowsHide: true });
|
|
209
|
-
if (result.status === 0) {
|
|
210
|
-
console.log(String(result.stderr || result.stdout || "clpp install ok").trim());
|
|
211
|
-
} else {
|
|
212
|
-
console.log("cluaupp:", CLPP_INSTALL_HINT);
|
|
213
|
-
}
|
|
214
|
-
} else {
|
|
215
|
-
console.log("cluaupp:", CLPP_INSTALL_HINT);
|
|
216
|
-
}
|
|
217
205
|
return { local };
|
|
218
206
|
}
|
|
219
207
|
|
package/src/lsp.ts
CHANGED
|
@@ -61,7 +61,7 @@ function flareDiagnostics(document: TextDocument): Diagnostic[] {
|
|
|
61
61
|
}
|
|
62
62
|
|
|
63
63
|
export function start(_options: { projectRoot?: string } = {}): void {
|
|
64
|
-
const connection = createConnection(ProposedFeatures.all);
|
|
64
|
+
const connection = createConnection(ProposedFeatures.all, process.stdin, process.stdout);
|
|
65
65
|
const documents = new TextDocuments(TextDocument);
|
|
66
66
|
|
|
67
67
|
connection.onInitialize(() => ({
|
|
@@ -8,12 +8,9 @@ import fs from "node:fs";
|
|
|
8
8
|
import os from "node:os";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
|
|
11
|
-
export const COMPILE_CACHE_SCHEMA =
|
|
11
|
+
export const COMPILE_CACHE_SCHEMA = 2 as const;
|
|
12
12
|
|
|
13
|
-
export
|
|
14
|
-
name: string;
|
|
15
|
-
contents: string;
|
|
16
|
-
}
|
|
13
|
+
export type CachedArtifact = import("../types.js").CompiledArtifact;
|
|
17
14
|
|
|
18
15
|
export interface CachedJob {
|
|
19
16
|
rel: string;
|
|
@@ -45,7 +42,7 @@ function indexPath(projectRoot: string): string {
|
|
|
45
42
|
}
|
|
46
43
|
|
|
47
44
|
function jobPath(projectRoot: string, rel: string): string {
|
|
48
|
-
const safe = rel
|
|
45
|
+
const safe = hashText(rel);
|
|
49
46
|
return path.join(compileCacheDir(projectRoot), `${safe}.json`);
|
|
50
47
|
}
|
|
51
48
|
|
|
@@ -56,7 +53,7 @@ export function loadCompileCacheIndex(projectRoot: string): CompileCacheIndex {
|
|
|
56
53
|
}
|
|
57
54
|
try {
|
|
58
55
|
const raw = JSON.parse(fs.readFileSync(file, "utf8")) as CompileCacheIndex;
|
|
59
|
-
if (!raw || typeof raw.entries !== "object") {
|
|
56
|
+
if (!raw || raw.schemaVersion !== COMPILE_CACHE_SCHEMA || !raw.entries || typeof raw.entries !== "object" || Array.isArray(raw.entries)) {
|
|
60
57
|
return { schemaVersion: COMPILE_CACHE_SCHEMA, entries: {} };
|
|
61
58
|
}
|
|
62
59
|
return { schemaVersion: COMPILE_CACHE_SCHEMA, entries: raw.entries };
|
|
@@ -82,7 +79,7 @@ export function readCachedJob(projectRoot: string, rel: string, sourceHash: stri
|
|
|
82
79
|
}
|
|
83
80
|
try {
|
|
84
81
|
const job = JSON.parse(fs.readFileSync(file, "utf8")) as CachedJob;
|
|
85
|
-
if (!job || job.sourceHash !== sourceHash || !Array.isArray(job.files)) {
|
|
82
|
+
if (!job || job.rel !== rel || job.sourceHash !== sourceHash || !Array.isArray(job.files) || !job.files.every(f => typeof f.name === "string" && typeof f.contents === "string")) {
|
|
86
83
|
return null;
|
|
87
84
|
}
|
|
88
85
|
return job;
|