From 388de42fe85afbfc43e5e24873cfb4f518ddd25c Mon Sep 17 00:00:00 2001 From: Wyatt McCarthy Date: Tue, 16 Jun 2026 10:07:05 -0700 Subject: [PATCH 1/4] align w/ latest lute --- foreman.toml | 2 +- .../src/benchmarks/TreeNode.bench.test.tsx | 6 +- frontend/src/tests/TreeNode.test.tsx | 54 +- frontend/src/tests/astTypeHelpers.test.ts | 48 +- .../src/tests/nodeEmphasisHelpers.test.ts | 2 +- frontend/src/tests/useTypeMetadata.test.ts | 4 +- frontend/src/utils/astTypeDefinitions.ts | 653 +++++++++--------- frontend/src/utils/astTypeHelpers.ts | 18 +- lua_helpers/astJsonToCode.luau | 6 +- lua_helpers/astParser.luau | 4 +- lua_helpers/astToJson.luau | 6 +- lua_helpers/json.lua | 10 +- lua_helpers/sortByPositionTable.lua | 5 +- lua_helpers/typeAnnotations.lua | 354 +++++----- rokit.toml | 2 +- 15 files changed, 595 insertions(+), 579 deletions(-) diff --git a/foreman.toml b/foreman.toml index 73ab4f9..bb311a1 100644 --- a/foreman.toml +++ b/foreman.toml @@ -1,3 +1,3 @@ [tools] -lute = { source = "luau-lang/lute", version = "=0.1.0-nightly.20260312" } +lute = { source = "luau-lang/lute", version = "=1.0.1-nightly.20260612" } stylua = { source = "JohnnyMorganz/StyLua", version = "2.0.2" } diff --git a/frontend/src/benchmarks/TreeNode.bench.test.tsx b/frontend/src/benchmarks/TreeNode.bench.test.tsx index e324bdc..4ac2283 100644 --- a/frontend/src/benchmarks/TreeNode.bench.test.tsx +++ b/frontend/src/benchmarks/TreeNode.bench.test.tsx @@ -5,10 +5,10 @@ import { defaultProps, MockProvider, } from "../tests/TreeNodeTestUtils"; -import { fireEvent } from "@testing-library/dom"; +import { fireEvent } from "@testing-library/react"; const root = { - _astType: "AstStatBlock", + _astType: "CstStatBlock", statements: [mockTestType(), mockTestType()], }; @@ -28,6 +28,6 @@ test("TreeNode benchmarks", () => { fireEvent.click(rootNode); }, eventName: "Toggle Collapse/Expand", - } + }, ); }); diff --git a/frontend/src/tests/TreeNode.test.tsx b/frontend/src/tests/TreeNode.test.tsx index eff52ac..3f9c600 100644 --- a/frontend/src/tests/TreeNode.test.tsx +++ b/frontend/src/tests/TreeNode.test.tsx @@ -150,7 +150,7 @@ describe("TreeNode", () => { describe("type annotations", () => { test("displays type information for AST nodes", () => { const astNode = { - _astType: "AstExpr", + _astType: "CstExpr", kind: "expression", value: "test", }; @@ -162,21 +162,21 @@ describe("TreeNode", () => { ); const nodeQuery = getQueryableNode("root"); - expect(nodeQuery.getByText(/type: AstExpr/)).toBeInTheDocument(); - expect(() => nodeQuery.getByText('_astType: "AstExpr"')).toThrow(); // should filter out _astType + expect(nodeQuery.getByText(/type: CstExpr/)).toBeInTheDocument(); + expect(() => nodeQuery.getByText('_astType: "CstExpr"')).toThrow(); // should filter out _astType }); test("extracts old types from childChanges", () => { // redundant test case, we already similar test above in "renders updated status with before/after" // this test is slightly diffe const nodeWithTypeChange = { - _astType: "AstLocal", + _astType: "CstLocal", name: "newName", childChanges: { _astType: { type: "UPDATE", - oldValue: "AstExpr", - value: "AstLocal", + oldValue: "CstExpr", + value: "CstLocal", }, }, }; @@ -194,8 +194,8 @@ describe("TreeNode", () => { // Should show both old and new type annotations const nodeQuery = getQueryableNode("root", "nodeHeader"); - expect(nodeQuery.getByText(/type: AstExpr/)).toBeInTheDocument(); // Previous type - expect(nodeQuery.getByText(/type: AstLocal/)).toBeInTheDocument(); // Current type + expect(nodeQuery.getByText(/type: CstExpr/)).toBeInTheDocument(); // Previous type + expect(nodeQuery.getByText(/type: CstLocal/)).toBeInTheDocument(); // Current type expect(nodeQuery.getByText("→")).toBeInTheDocument(); // Arrow between them }); }); @@ -239,7 +239,7 @@ describe("TreeNode", () => { test("infers types for array items from parent property definition", () => { // Test actual inference: parent has AST type with array property, children have no _astType const blockWithStatements = { - _astType: "AstStatBlock", // Parent type that has `statements: { AstStat }` property + _astType: "CstStatBlock", // Parent type that has `statements: { CstStat }` property statements: [{}, {}], }; @@ -249,19 +249,19 @@ describe("TreeNode", () => { ); - // The statements array should get inferred type from AstStatBlock definition + // The statements array should get inferred type from CstStatBlock definition const statementsQuery = getQueryableNode("root.statements", "nodeHeader"); expect( - statementsQuery.getByText(/type: { AstStat }/) + statementsQuery.getByText(/type: { CstStat }/) ).toBeInTheDocument(); }); test("fallback chain: _astType -> parentInferred -> array inference", () => { // Test actual fallback: parent type defines array property, mixed content with/without _astType const tableWithEntries = { - _astType: "AstExprTable", // Parent type that has `entries: { AstTableExprItem }` property + _astType: "CstExprTable", // Parent type that has `entries: { CstTableExprItem }` property entries: [ - { text: "filler" }, // No _astType - should infer AstTableExprItem from parent definition + { text: "filler" }, // No _astType - should infer CstTableExprItem from parent definition { _astType: "MySpecialType" }, // Has _astType - should use that directly ], }; @@ -272,15 +272,15 @@ describe("TreeNode", () => { ); - // The entries array should get inferred type from AstExprTable definition + // The entries array should get inferred type from CstExprTable definition const entriesQuery = getQueryableNode("root.entries", "nodeHeader"); expect( - entriesQuery.getByText(/type: { AstTableExprItem }/) + entriesQuery.getByText(/type: { CstTableExprItem }/) ).toBeInTheDocument(); // First item should infer type from parent array definition const item0Query = getQueryableNode("root.entries.0", "nodeHeader"); - expect(item0Query.getByText(/type: AstTableExprItem/)).toBeInTheDocument(); + expect(item0Query.getByText(/type: CstTableExprItem/)).toBeInTheDocument(); // Second item should use its explicit _astType const item1Query = getQueryableNode("root.entries.1", "nodeHeader"); @@ -335,7 +335,7 @@ describe("TreeNode", () => { describe("getChildDiffProps logic", () => { test("propagates diff props for primitive child changes", () => { const nodeWithPrimitiveChanges = { - _astType: "AstLocal", // Need a valid AST type + _astType: "CstLocal", // Need a valid AST type name: "newValue", childChanges: { name: { @@ -366,15 +366,15 @@ describe("TreeNode", () => { test("propagates diff props for object child changes", () => { const nodeWithObjectChanges = { - _astType: "AstStatFunction", // Valid parent type + _astType: "CstStatFunction", // Valid parent type expr: { - _astType: "AstExpr", + _astType: "CstExpr", name: "newExpr", }, childChanges: { expr: { type: "ADD", - value: { _astType: "AstExpr", name: "newExpr" }, + value: { _astType: "CstExpr", name: "newExpr" }, }, }, }; @@ -399,9 +399,9 @@ describe("TreeNode", () => { describe("array type inference edge cases", () => { test("handles punctuated arrays", () => { const punctuatedNode = { - _astType: "AstExprFunction", + _astType: "CstExprFunction", parameters: [ - // Use proper Punctuated structures + // Use proper Punctuated structures { node: { name: mockTypelessToken("param1") }, separator: mockTypelessToken(","), @@ -421,10 +421,10 @@ describe("TreeNode", () => { // Should handle punctuated structure correctly const parametersNode = getQueryableNode("root.parameters", "nodeHeader"); expect( - parametersNode.getByText(/type: Punctuated/) + parametersNode.getByText(/type: Punctuated/) ).toBeInTheDocument(); const param1Node = getQueryableNode("root.parameters.0", "nodeHeader"); - expect(param1Node.getByText(/type: Pair/)).toBeInTheDocument(); + expect(param1Node.getByText(/type: Pair/)).toBeInTheDocument(); }); }); @@ -453,7 +453,7 @@ describe("TreeNode", () => { // not sure if I see point in this case? will never happen in our use case const mixedArray = [ "string item", - { _astType: "AstExpr", name: "expr" }, + { _astType: "CstExpr", name: "expr" }, 123, undefined, ]; @@ -553,7 +553,7 @@ describe("TreeNode", () => { // Test that "unchanged" forces collapse even for normally expanded types test("forces collapse for unchanged nodes in diff mode", () => { const normallyExpandedNode = { - _astType: "AstExprTable", // Normally expands + _astType: "CstExprTable", // Normally expands entries: [{ item: "test" }], }; @@ -575,7 +575,7 @@ describe("TreeNode", () => { // Test that "removed" forces collapse test("forces collapse for removed nodes in diff mode", () => { const normallyExpandedNode = { - _astType: "AstExprTable", + _astType: "CstExprTable", entries: [{ item: "test" }], }; diff --git a/frontend/src/tests/astTypeHelpers.test.ts b/frontend/src/tests/astTypeHelpers.test.ts index 7a5c9e4..1b31aac 100644 --- a/frontend/src/tests/astTypeHelpers.test.ts +++ b/frontend/src/tests/astTypeHelpers.test.ts @@ -21,15 +21,15 @@ describe("astTypeHelpers", () => { expect(unpackArrayType(testArrayType)).toBe("testType"); - expect(getArrayType("statements")).toEqual(["{ AstStat }", ""]); + expect(getArrayType("statements")).toEqual(["{ CstStat }", ""]); expect(getArrayType("entries", [{ colon: ":", kind: "record" }])).toEqual([ - "{ AstTableTypeItem }", + "{ CstTableTypeItem }", "record", ]); expect(getArrayType("entries", [{ kind: "general" }])).toEqual([ - "{ AstTableExprItem }", + "{ CstTableExprItem }", "general", ]); @@ -37,34 +37,34 @@ describe("astTypeHelpers", () => { }); test("parseGenericType", () => { - expect(parseGenericType("Pair")).toEqual({ + expect(parseGenericType("Pair")).toEqual({ baseType: "Pair", - genericType: "AstExpr", + genericType: "CstExpr", }); - expect(parseGenericType("Punctuated")).toEqual({ + expect(parseGenericType("Punctuated")).toEqual({ baseType: "Punctuated", - genericType: "AstExpr", + genericType: "CstExpr", }); - expect(parseGenericType('Pair')).toEqual({ + expect(parseGenericType('Pair')).toEqual({ baseType: "Pair", - genericType: 'AstExpr, "&"', + genericType: 'CstExpr, "&"', }); - expect(parseGenericType("AstLocal")).toEqual(undefined); + expect(parseGenericType("CstLocal")).toEqual(undefined); expect(parseGenericType("randomType")).toEqual(undefined); }); test("getGenericASTTypeDefinition e2e", () => { const punctuatedType = parseGenericType( - "Punctuated" + "Punctuated" ) as GenericTypeDefinition; const punctuatedDefinition = getGenericASTTypeDefinition(punctuatedType); expect(punctuatedDefinition).toEqual({ - properties: [{ name: "", type: "{ Pair }" }], + properties: [{ name: "", type: "{ Pair }" }], }); const pairType = ( @@ -84,7 +84,7 @@ describe("astTypeHelpers", () => { expect(pairTypeDefinition).toEqual({ properties: [ - { name: "node", type: "AstExpr" }, + { name: "node", type: "CstExpr" }, { name: "separator", type: "Token<'&'>", @@ -98,41 +98,41 @@ describe("astTypeHelpers", () => { // test 3 cases: // respect existing _astType value - expect(getTypeString({ _astType: "AstStatBlock" }, "block")).toEqual([ - "AstStatBlock", + expect(getTypeString({ _astType: "CstStatBlock" }, "block")).toEqual([ + "CstStatBlock", "", ]); // leverages getArrayType expect(getTypeString([{}], "entries")).toEqual([ - "{ AstTableExprItem }", + "{ CstTableExprItem }", "", ]); // falls back on parentInferredType expect( - getTypeString({ kind: "record" }, "[0]", "AstTableExprItem") - ).toEqual(["AstTableExprItem", "record"]); + getTypeString({ kind: "record" }, "[0]", "CstTableExprItem") + ).toEqual(["CstTableExprItem", "record"]); }); test("getType", () => { // test standard case - expect(getType("AstLocal")).toEqual([ - astTypeDefinitions["AstLocal"], + expect(getType("CstLocal")).toEqual([ + astTypeDefinitions["CstLocal"], false, ]); // test array/table type - expect(getType("{ AstLocal }")).toEqual([ - astTypeDefinitions["AstLocal"], + expect(getType("{ CstLocal }")).toEqual([ + astTypeDefinitions["CstLocal"], true, ]); // test generic type - expect(getType("Pair")).toEqual([ + expect(getType("Pair")).toEqual([ { properties: [ - { name: "node", type: "AstExpr" }, + { name: "node", type: "CstExpr" }, { name: "separator", type: "Token<'&'>", diff --git a/frontend/src/tests/nodeEmphasisHelpers.test.ts b/frontend/src/tests/nodeEmphasisHelpers.test.ts index 0199fb0..3602192 100644 --- a/frontend/src/tests/nodeEmphasisHelpers.test.ts +++ b/frontend/src/tests/nodeEmphasisHelpers.test.ts @@ -20,7 +20,7 @@ describe("shouldAutoCollapse", () => { test("should return true for unions of auto-collapsable types", () => { const triviaTypeDefinition = astTypeDefinitions["Trivia"]; // example of type that is union of types that should auto-collapse - const falseUnionType = astTypeDefinitions["AstExpr"] + const falseUnionType = astTypeDefinitions["CstExpr"] expect(shouldAutoCollapse("", triviaTypeDefinition)).toBe(true); expect(shouldAutoCollapse("", falseUnionType)).toBe(false); }); diff --git a/frontend/src/tests/useTypeMetadata.test.ts b/frontend/src/tests/useTypeMetadata.test.ts index 105e16a..91b7e93 100644 --- a/frontend/src/tests/useTypeMetadata.test.ts +++ b/frontend/src/tests/useTypeMetadata.test.ts @@ -44,7 +44,7 @@ describe("useTypeMetadata test", () => { expect(result.current).toBeDefined(); const renderOneResult = result.current expect(renderOneResult).toEqual(result.current); - rerender({ value: { _astType: "AstLocal" }, ...defaultProps }); + rerender({ value: { _astType: "CstLocal" }, ...defaultProps }); expect(result.current).toBeDefined(); expect(result.current).not.toEqual(renderOneResult); }) @@ -75,7 +75,7 @@ describe("useTypeMetadata test", () => { childChanges: { _astType: { type: "UPDATE", - oldValue: "AstLocal", + oldValue: "CstLocal", value: "_testType", }, }, diff --git a/frontend/src/utils/astTypeDefinitions.ts b/frontend/src/utils/astTypeDefinitions.ts index 6402027..809b02b 100644 --- a/frontend/src/utils/astTypeDefinitions.ts +++ b/frontend/src/utils/astTypeDefinitions.ts @@ -9,7 +9,7 @@ export interface ASTTypeDefinition { properties?: PropertyDefinition[]; kinds?: Record; baseType?: string; // for intersections like "Token &" - unionMembers?: string[]; // for "AstExpr = A | B | C" + unionMembers?: string[]; // for "CstExpr = A | B | C" } export interface GenericTypeDefinition { @@ -32,10 +32,10 @@ export const astTypeDefinitions: Record = { // === UTILITY TYPES === span: { properties: [ - { name: "beginline", type: "number" }, - { name: "begincolumn", type: "number" }, - { name: "endline", type: "number" }, - { name: "endcolumn", type: "number" }, + { name: "beginLine", type: "number" }, + { name: "beginColumn", type: "number" }, + { name: "endLine", type: "number" }, + { name: "endColumn", type: "number" }, ], }, @@ -69,11 +69,11 @@ export const astTypeDefinitions: Record = { Token: { properties: [ - { name: "leadingtrivia", type: "{ Trivia }" }, + { name: "leadingTrivia", type: "{ Trivia }" }, { name: "location", type: "span" }, { name: "text", type: "string" }, - { name: "trailingtrivia", type: "{ Trivia }" }, - { name: "istoken", type: "true" }, + { name: "trailingTrivia", type: "{ Trivia }" }, + { name: "kind", type: '"token"' }, ], }, @@ -96,29 +96,29 @@ export const astTypeDefinitions: Record = { properties: [{ name: "pairs", type: "{ Pair }" }], }, - AstLocal: { + CstLocal: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"local"' }, { name: "name", type: "Token", generic: "Token" }, { name: "colon", type: "Token", generic: 'Token<":">', optional: true }, - { name: "annotation", type: "AstType", optional: true }, - { name: "shadows", type: "AstLocal", optional: true }, + { name: "annotation", type: "CstType", optional: true }, + { name: "shadows", type: "CstLocal", optional: true }, ], }, // === EXPRESSIONS === - AstExprGroup: { + CstExprGroup: { properties: [ { name: "location", type: "span" }, { name: "tag", type: '"group"' }, - { name: "openparens", type: "Token", generic: 'Token<"(">' }, - { name: "expression", type: "AstExpr" }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, + { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "expression", type: "CstExpr" }, + { name: "closeParens", type: "Token", generic: 'Token<")">' }, ], }, - AstExprConstantNil: { + CstExprConstantNil: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -128,7 +128,7 @@ export const astTypeDefinitions: Record = { ], }, - AstExprConstantBool: { + CstExprConstantBool: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -139,7 +139,7 @@ export const astTypeDefinitions: Record = { ], }, - AstExprConstantNumber: { + CstExprConstantNumber: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -150,30 +150,30 @@ export const astTypeDefinitions: Record = { ], }, - AstExprConstantString: { + CstExprConstantString: { baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"string"' }, { name: "text", type: "string" }, - { name: "quotestyle", type: ["single", "double", "block", "interp"] }, - { name: "blockdepth", type: "number" }, + { name: "quoteStyle", type: ["single", "double", "block", "interp"] }, + { name: "blockDepth", type: "number" }, ], }, - AstExprLocal: { + CstExprLocal: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"local"' }, { name: "token", type: "Token", generic: "Token" }, - { name: "local", type: "AstLocal" }, + { name: "local", type: "CstLocal" }, { name: "upvalue", type: "boolean" }, ], }, - AstExprGlobal: { + CstExprGlobal: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, @@ -182,7 +182,7 @@ export const astTypeDefinitions: Record = { ], }, - AstExprVarargs: { + CstExprVarargs: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -192,21 +192,21 @@ export const astTypeDefinitions: Record = { ], }, - AstExprCall: { + CstExprCall: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"call"' }, - { name: "func", type: "AstExpr" }, + { name: "func", type: "CstExpr" }, { - name: "openparens", + name: "openParens", type: "Token", generic: 'Token<"(">', optional: true, }, - { name: "arguments", type: "Punctuated", generic: "Punctuated" }, + { name: "arguments", type: "Punctuated", generic: "Punctuated" }, { - name: "closeparens", + name: "closeParens", type: "Token", generic: 'Token<")">', optional: true, @@ -216,57 +216,57 @@ export const astTypeDefinitions: Record = { ], }, - AstExprInstantiate: { + CstExprInstantiate: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"instantiate"' }, - { name: "expr", type: "AstExpr" }, - { name: "leftarrow1", type: "Token", generic: 'Token<"<">' }, - { name: "leftarrow2", type: "Token", generic: 'Token<"<">' }, + { name: "expr", type: "CstExpr" }, + { name: "leftArrow1", type: "Token", generic: 'Token<"<">' }, + { name: "leftArrow2", type: "Token", generic: 'Token<"<">' }, { - name: "typearguments", + name: "typeArguments", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", }, - { name: "rightarrow1", type: "Token", generic: 'Token<">">' }, - { name: "rightarrow2", type: "Token", generic: 'Token<">">' }, + { name: "rightArrow1", type: "Token", generic: 'Token<">">' }, + { name: "rightArrow2", type: "Token", generic: 'Token<">">' }, ], }, - AstExprIndexName: { + CstExprIndexName: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"indexname"' }, - { name: "expression", type: "AstExpr" }, + { name: "expression", type: "CstExpr" }, { name: "accessor", type: "Token", generic: 'Token<"." | ":">' }, { name: "index", type: "Token", generic: "Token" }, - { name: "indexlocation", type: "span" }, + { name: "indexLocation", type: "span" }, ], }, - AstExprIndexExpr: { + CstExprIndexExpr: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"index"' }, - { name: "expression", type: "AstExpr" }, - { name: "openbrackets", type: "Token", generic: 'Token<"[">' }, - { name: "index", type: "AstExpr" }, - { name: "closebrackets", type: "Token", generic: 'Token<"]">' }, + { name: "expression", type: "CstExpr" }, + { name: "openBrackets", type: "Token", generic: 'Token<"[">' }, + { name: "index", type: "CstExpr" }, + { name: "closeBrackets", type: "Token", generic: 'Token<"]">' }, ], }, - AstExprFunction: { + CstExprFunction: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"function"' }, - { name: "attributes", type: "{ AstAttribute }" }, - { name: "functionkeyword", type: "Token", generic: 'Token<"function">' }, + { name: "attributes", type: "{ CstAttribute }" }, + { name: "functionKeyword", type: "Token", generic: 'Token<"function">' }, { - name: "opengenerics", + name: "openGenerics", type: "Token", generic: 'Token<"<">', optional: true, @@ -274,27 +274,27 @@ export const astTypeDefinitions: Record = { { name: "generics", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "genericpacks", + name: "genericPacks", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "closegenerics", + name: "closeGenerics", type: "Token", generic: 'Token<">">', optional: true, }, - { name: "openparens", type: "Token", generic: 'Token<"(">' }, - { name: "self", type: "AstLocal", optional: true }, + { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "self", type: "CstLocal", optional: true }, { name: "parameters", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", }, { name: "vararg", @@ -303,262 +303,262 @@ export const astTypeDefinitions: Record = { optional: true, }, { - name: "varargcolon", + name: "varargColon", type: "Token", generic: 'Token<":">', optional: true, }, - { name: "varargannotation", type: "AstTypePack", optional: true }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, + { name: "varargAnnotation", type: "CstTypePack", optional: true }, + { name: "closeParens", type: "Token", generic: 'Token<")">' }, { - name: "returnspecifier", + name: "returnSpecifier", type: "Token", generic: 'Token<":">', optional: true, }, - { name: "returnannotation", type: "AstTypePack", optional: true }, - { name: "body", type: "AstStatBlock" }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "returnAnnotation", type: "CstTypePack", optional: true }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, ], }, - AstTableExprListItem: { + CstTableExprListItem: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"list"' }, - { name: "value", type: "AstExpr" }, + { name: "value", type: "CstExpr" }, { name: "separator", type: "Token", generic: 'Token<"," | ";">', optional: true, }, - { name: "istableitem", type: "true" }, + { name: "isTableItem", type: "true" }, ], }, - AstTableExprRecordItem: { + CstTableExprRecordItem: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"record"' }, { name: "key", type: "Token", generic: "Token" }, { name: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "value", type: "AstExpr" }, + { name: "value", type: "CstExpr" }, { name: "separator", type: "Token", generic: 'Token<"," | ";">', optional: true, }, - { name: "istableitem", type: "true" }, + { name: "isTableItem", type: "true" }, ], }, - AstTableExprGeneralItem: { + CstTableExprGeneralItem: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"general"' }, - { name: "indexeropen", type: "Token", generic: 'Token<"[">' }, - { name: "key", type: "AstExpr" }, - { name: "indexerclose", type: "Token", generic: 'Token<"]">' }, + { name: "indexerOpen", type: "Token", generic: 'Token<"[">' }, + { name: "key", type: "CstExpr" }, + { name: "indexerClose", type: "Token", generic: 'Token<"]">' }, { name: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "value", type: "AstExpr" }, + { name: "value", type: "CstExpr" }, { name: "separator", type: "Token", generic: 'Token<"," | ";">', optional: true, }, - { name: "istableitem", type: "true" }, + { name: "isTableItem", type: "true" }, ], }, - AstTableExprItem: { + CstTableExprItem: { unionMembers: [ - "AstTableExprListItem", - "AstTableExprRecordItem", - "AstTableExprGeneralItem", + "CstTableExprListItem", + "CstTableExprRecordItem", + "CstTableExprGeneralItem", ], }, - AstExprTable: { + CstExprTable: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"table"' }, - { name: "openbrace", type: "Token", generic: 'Token<"{">' }, - { name: "entries", type: "{ AstTableExprItem }" }, - { name: "closebrace", type: "Token", generic: 'Token<"}">' }, + { name: "openBrace", type: "Token", generic: 'Token<"{">' }, + { name: "entries", type: "{ CstTableExprItem }" }, + { name: "closeBrace", type: "Token", generic: 'Token<"}">' }, ], }, - AstExprUnary: { + CstExprUnary: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"unary"' }, { name: "operator", type: "Token", generic: 'Token<"not" | "-" | "#">' }, - { name: "operand", type: "AstExpr" }, + { name: "operand", type: "CstExpr" }, ], }, - AstExprBinary: { + CstExprBinary: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"binary"' }, - { name: "lhsoperand", type: "AstExpr" }, + { name: "lhsOperand", type: "CstExpr" }, { name: "operator", type: "Token" }, - { name: "rhsoperand", type: "AstExpr" }, + { name: "rhsOperand", type: "CstExpr" }, ], }, - AstExprInterpString: { + CstExprInterpString: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"interpolatedstring"' }, { name: "strings", type: "{ Token }", generic: "{ Token }" }, - { name: "expressions", type: "{ AstExpr }" }, + { name: "expressions", type: "{ CstExpr }" }, ], }, - AstExprTypeAssertion: { + CstExprTypeAssertion: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"cast"' }, - { name: "operand", type: "AstExpr" }, + { name: "operand", type: "CstExpr" }, { name: "operator", type: "Token", generic: 'Token<"::">' }, - { name: "annotation", type: "AstType" }, + { name: "annotation", type: "CstType" }, ], }, - AstElseIfExpr: { + CstElseIfExpr: { properties: [ - { name: "elseifkeyword", type: "Token", generic: 'Token<"elseif">' }, - { name: "condition", type: "AstExpr" }, - { name: "thenkeyword", type: "Token", generic: 'Token<"then">' }, - { name: "thenexpr", type: "AstExpr" }, + { name: "elseIfKeyword", type: "Token", generic: 'Token<"elseif">' }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenExpr", type: "CstExpr" }, ], }, - AstExprIfElse: { + CstExprIfElse: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"conditional"' }, - { name: "ifkeyword", type: "Token", generic: 'Token<"if">' }, - { name: "condition", type: "AstExpr" }, - { name: "thenkeyword", type: "Token", generic: 'Token<"then">' }, - { name: "thenexpr", type: "AstExpr" }, - { name: "elseifs", type: "{ AstElseIfExpr }" }, - { name: "elsekeyword", type: "Token", generic: 'Token<"else">' }, - { name: "elseexpr", type: "AstExpr" }, + { name: "ifKeyword", type: "Token", generic: 'Token<"if">' }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenExpr", type: "CstExpr" }, + { name: "elseifs", type: "{ CstElseIfExpr }" }, + { name: "elseKeyword", type: "Token", generic: 'Token<"else">' }, + { name: "elseExpr", type: "CstExpr" }, ], }, - AstExpr: { + CstExpr: { unionMembers: [ - "AstExprGroup", - "AstExprConstantNil", - "AstExprConstantBool", - "AstExprConstantNumber", - "AstExprConstantString", - "AstExprLocal", - "AstExprGlobal", - "AstExprVarargs", - "AstExprCall", - "AstExprInstantiate", - "AstExprIndexName", - "AstExprIndexExpr", - "AstExprFunction", - "AstExprTable", - "AstExprUnary", - "AstExprBinary", - "AstExprInterpString", - "AstExprTypeAssertion", - "AstExprIfElse", + "CstExprGroup", + "CstExprConstantNil", + "CstExprConstantBool", + "CstExprConstantNumber", + "CstExprConstantString", + "CstExprLocal", + "CstExprGlobal", + "CstExprVarargs", + "CstExprCall", + "CstExprInstantiate", + "CstExprIndexName", + "CstExprIndexExpr", + "CstExprFunction", + "CstExprTable", + "CstExprUnary", + "CstExprBinary", + "CstExprInterpString", + "CstExprTypeAssertion", + "CstExprIfElse", ], }, // === STATEMENTS === - AstStatBlock: { + CstStatBlock: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"block"' }, - { name: "statements", type: "{ AstStat }" }, + { name: "statements", type: "{ CstStat }" }, ], }, - AstStatDo: { + CstStatDo: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"do"' }, - { name: "dokeyword", type: "Token", generic: 'Token<"do">' }, - { name: "body", type: "AstStatBlock" }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, ], }, - AstElseIfStat: { + CstElseIfStat: { properties: [ - { name: "elseifkeyword", type: "Token", generic: 'Token<"elseif">' }, - { name: "condition", type: "AstExpr" }, - { name: "thenkeyword", type: "Token", generic: 'Token<"then">' }, - { name: "thenblock", type: "AstStatBlock" }, + { name: "elseIfKeyword", type: "Token", generic: 'Token<"elseif">' }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenBlock", type: "CstStatBlock" }, ], }, - AstStatIf: { + CstStatIf: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"conditional"' }, - { name: "ifkeyword", type: "Token", generic: 'Token<"if">' }, - { name: "condition", type: "AstExpr" }, - { name: "thenkeyword", type: "Token", generic: 'Token<"then">' }, - { name: "thenblock", type: "AstStatBlock" }, - { name: "elseifs", type: "{ AstElseIfStat }" }, + { name: "ifKeyword", type: "Token", generic: 'Token<"if">' }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenBlock", type: "CstStatBlock" }, + { name: "elseifs", type: "{ CstElseIfStat }" }, { - name: "elsekeyword", + name: "elseKeyword", type: "Token", generic: 'Token<"else">', optional: true, }, - { name: "elseblock", type: "AstStatBlock", optional: true }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "elseBlock", type: "CstStatBlock", optional: true }, + { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, ], }, - AstStatWhile: { + CstStatWhile: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"while"' }, - { name: "whilekeyword", type: "Token", generic: 'Token<"while">' }, - { name: "condition", type: "AstExpr" }, - { name: "dokeyword", type: "Token", generic: 'Token<"do">' }, - { name: "body", type: "AstStatBlock" }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "whileKeyword", type: "Token", generic: 'Token<"while">' }, + { name: "condition", type: "CstExpr" }, + { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, ], }, - AstStatRepeat: { + CstStatRepeat: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"repeat"' }, - { name: "repeatkeyword", type: "Token", generic: 'Token<"repeat">' }, - { name: "body", type: "AstStatBlock" }, - { name: "untilkeyword", type: "Token", generic: 'Token<"until">' }, - { name: "condition", type: "AstExpr" }, + { name: "repeatKeyword", type: "Token", generic: 'Token<"repeat">' }, + { name: "body", type: "CstStatBlock" }, + { name: "untilKeyword", type: "Token", generic: 'Token<"until">' }, + { name: "condition", type: "CstExpr" }, ], }, - AstStatBreak: { + CstStatBreak: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -568,7 +568,7 @@ export const astTypeDefinitions: Record = { ], }, - AstStatContinue: { + CstStatContinue: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -578,111 +578,127 @@ export const astTypeDefinitions: Record = { ], }, - AstStatReturn: { + CstStatReturn: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"return"' }, - { name: "returnkeyword", type: "Token", generic: 'Token<"return">' }, + { name: "returnKeyword", type: "Token", generic: 'Token<"return">' }, { name: "expressions", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", }, ], }, - AstStatExpr: { + CstStatExpr: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"expression"' }, - { name: "expression", type: "AstExpr" }, + { name: "expression", type: "CstExpr" }, ], }, - AstStatLocal: { + CstStatLocal: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"local"' }, - { name: "localkeyword", type: "Token", generic: 'Token<"local">' }, + { name: "localKeyword", type: "Token", generic: 'Token<"local">' }, { name: "variables", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", }, { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, + { name: "values", type: "Punctuated", generic: "Punctuated" }, ], }, - AstStatFor: { + CstStatConst: { + properties: [ + { name: "location", type: "span" }, + { name: "kind", type: '"stat"' }, + { name: "tag", type: '"const"' }, + { name: "constKeyword", type: "Token", generic: 'Token<"const">' }, + { + name: "variables", + type: "Punctuated", + generic: "Punctuated", + }, + { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, + { name: "values", type: "Punctuated", generic: "Punctuated" }, + ], + }, + + CstStatFor: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"for"' }, - { name: "forkeyword", type: "Token", generic: 'Token<"for">' }, - { name: "variable", type: "AstLocal" }, + { name: "forKeyword", type: "Token", generic: 'Token<"for">' }, + { name: "variable", type: "CstLocal" }, { name: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "from", type: "AstExpr" }, - { name: "tocomma", type: "Token", generic: 'Token<",">' }, - { name: "to", type: "AstExpr" }, + { name: "from", type: "CstExpr" }, + { name: "toComma", type: "Token", generic: 'Token<",">' }, + { name: "to", type: "CstExpr" }, { - name: "stepcomma", + name: "stepComma", type: "Token", generic: 'Token<",">', optional: true, }, - { name: "step", type: "AstExpr", optional: true }, - { name: "dokeyword", type: "Token", generic: 'Token<"do">' }, - { name: "body", type: "AstStatBlock" }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "step", type: "CstExpr", optional: true }, + { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, ], }, - AstStatForIn: { + CstStatForIn: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"forin"' }, - { name: "forkeyword", type: "Token", generic: 'Token<"for">' }, + { name: "forKeyword", type: "Token", generic: 'Token<"for">' }, { name: "variables", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", }, - { name: "inkeyword", type: "Token", generic: 'Token<"in">' }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, - { name: "dokeyword", type: "Token", generic: 'Token<"do">' }, - { name: "body", type: "AstStatBlock" }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "inKeyword", type: "Token", generic: 'Token<"in">' }, + { name: "values", type: "Punctuated", generic: "Punctuated" }, + { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, ], }, - AstStatAssign: { + CstStatAssign: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"assign"' }, - { name: "variables", type: "Punctuated", generic: "Punctuated" }, + { name: "variables", type: "Punctuated", generic: "Punctuated" }, { name: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, + { name: "values", type: "Punctuated", generic: "Punctuated" }, ], }, - AstStatCompoundAssign: { + CstStatCompoundAssign: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"compoundassign"' }, - { name: "variable", type: "AstExpr" }, + { name: "variable", type: "CstExpr" }, { name: "operand", type: "Token" }, - { name: "value", type: "AstExpr" }, + { name: "value", type: "CstExpr" }, ], }, - AstAttribute: { + CstAttribute: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -691,28 +707,28 @@ export const astTypeDefinitions: Record = { ], }, - AstStatFunction: { + CstStatFunction: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"function"' }, - { name: "name", type: "AstExpr" }, - { name: "func", type: "AstExprFunction" }, + { name: "name", type: "CstExpr" }, + { name: "func", type: "CstExprFunction" }, ], }, - AstStatLocalFunction: { + CstStatLocalFunction: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"localfunction"' }, - { name: "localkeyword", type: "Token", generic: 'Token<"local">' }, - { name: "name", type: "AstLocal" }, - { name: "func", type: "AstExprFunction" }, + { name: "localKeyword", type: "Token", generic: 'Token<"local">' }, + { name: "name", type: "CstLocal" }, + { name: "func", type: "CstExprFunction" }, ], }, - AstStatTypeAlias: { + CstStatTypeAlias: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, @@ -723,10 +739,10 @@ export const astTypeDefinitions: Record = { generic: 'Token<"export">', optional: true, }, - { name: "typetoken", type: "Token", generic: 'Token<"type">' }, + { name: "typeToken", type: "Token", generic: 'Token<"type">' }, { name: "name", type: "Token" }, { - name: "opengenerics", + name: "openGenerics", type: "Token", generic: 'Token<"<">', optional: true, @@ -734,27 +750,27 @@ export const astTypeDefinitions: Record = { { name: "generics", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "genericpacks", + name: "genericPacks", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "closegenerics", + name: "closeGenerics", type: "Token", generic: 'Token<">">', optional: true, }, { name: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "type", type: "AstType" }, + { name: "type", type: "CstType" }, ], }, - AstStatTypeFunction: { + CstStatTypeFunction: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, @@ -767,55 +783,56 @@ export const astTypeDefinitions: Record = { }, { name: "type", type: "Token", generic: 'Token<"type">' }, { name: "name", type: "Token" }, - { name: "body", type: "AstExprFunction" }, + { name: "body", type: "CstExprFunction" }, ], }, - AstStat: { + CstStat: { unionMembers: [ - "AstStatBlock", - "AstStatDo", - "AstStatIf", - "AstStatWhile", - "AstStatRepeat", - "AstStatBreak", - "AstStatContinue", - "AstStatReturn", - "AstStatExpr", - "AstStatLocal", - "AstStatFor", - "AstStatForIn", - "AstStatAssign", - "AstStatCompoundAssign", - "AstStatFunction", - "AstStatLocalFunction", - "AstStatTypeAlias", - "AstStatTypeFunction", + "CstStatBlock", + "CstStatDo", + "CstStatIf", + "CstStatWhile", + "CstStatRepeat", + "CstStatBreak", + "CstStatContinue", + "CstStatReturn", + "CstStatExpr", + "CstStatLocal", + "CstStatConst", + "CstStatFor", + "CstStatForIn", + "CstStatAssign", + "CstStatCompoundAssign", + "CstStatFunction", + "CstStatLocalFunction", + "CstStatTypeAlias", + "CstStatTypeFunction", ], }, // === GENERIC TYPES === - AstGenericType: { + CstGenericType: { properties: [ { name: "tag", type: '"generic"' }, { name: "name", type: "Token", generic: "Token" }, { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, - { name: "default", type: "AstType", optional: true }, + { name: "default", type: "CstType", optional: true }, ], }, - AstGenericTypePack: { + CstGenericTypePack: { properties: [ { name: "tag", type: '"genericpack"' }, { name: "name", type: "Token", generic: "Token" }, { name: "ellipsis", type: "Token", generic: 'Token<"...">' }, { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, - { name: "default", type: "AstTypePack", optional: true }, + { name: "default", type: "CstTypePack", optional: true }, ], }, // === TYPE SYSTEM === - AstTypeReference: { + CstTypeReference: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, @@ -827,14 +844,14 @@ export const astTypeDefinitions: Record = { optional: true, }, { - name: "prefixpoint", + name: "prefixPoint", type: "Token", generic: 'Token<".">', optional: true, }, { name: "name", type: "Token", generic: "Token" }, { - name: "openparameters", + name: "openParameters", type: "Token", generic: 'Token<"<">', optional: true, @@ -842,11 +859,11 @@ export const astTypeDefinitions: Record = { { name: "parameters", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "closeparameters", + name: "closeParameters", type: "Token", generic: 'Token<">">', optional: true, @@ -854,7 +871,7 @@ export const astTypeDefinitions: Record = { ], }, - AstTypeSingletonBool: { + CstTypeSingletonBool: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -865,41 +882,41 @@ export const astTypeDefinitions: Record = { ], }, - AstTypeSingletonString: { + CstTypeSingletonString: { baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"string"' }, { name: "text", type: "string" }, - { name: "quotestyle", type: ["single", "double"] }, + { name: "quoteStyle", type: ["single", "double"] }, ], }, - AstTypeTypeof: { + CstTypeTypeof: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"typeof"' }, { name: "typeof", type: "Token", generic: 'Token<"typeof">' }, - { name: "openparens", type: "Token", generic: 'Token<"(">' }, - { name: "expression", type: "AstExpr" }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, + { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "expression", type: "CstExpr" }, + { name: "closeParens", type: "Token", generic: 'Token<")">' }, ], }, - AstTypeGroup: { + CstTypeGroup: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"group"' }, - { name: "openparens", type: "Token", generic: 'Token<"(">' }, - { name: "type", type: "AstType" }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, + { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "type", type: "CstType" }, + { name: "closeParens", type: "Token", generic: 'Token<")">' }, ], }, - AstTypeOptional: { + CstTypeOptional: { baseType: "Token", properties: [ { name: "location", type: "span" }, @@ -909,7 +926,7 @@ export const astTypeDefinitions: Record = { ], }, - AstTypeUnion: { + CstTypeUnion: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, @@ -918,12 +935,12 @@ export const astTypeDefinitions: Record = { { name: "types", type: "Punctuated", - generic: 'Punctuated', + generic: 'Punctuated', }, ], }, - AstTypeIntersection: { + CstTypeIntersection: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, @@ -932,29 +949,29 @@ export const astTypeDefinitions: Record = { { name: "types", type: "Punctuated", - generic: 'Punctuated', + generic: 'Punctuated', }, ], }, - AstTypeArray: { + CstTypeArray: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"array"' }, - { name: "openbrace", type: "Token", generic: 'Token<"{">' }, + { name: "openBrace", type: "Token", generic: 'Token<"{">' }, { name: "access", type: "Token", generic: 'Token<"read" | "write">', optional: true, }, - { name: "type", type: "AstType" }, - { name: "closebrace", type: "Token", generic: 'Token<"}">' }, + { name: "type", type: "CstType" }, + { name: "closeBrace", type: "Token", generic: 'Token<"}">' }, ], }, - AstTableTypeItemIndexer: { + CstTableTypeItemIndexer: { properties: [ { name: "kind", type: '"indexer"' }, { @@ -963,11 +980,11 @@ export const astTypeDefinitions: Record = { generic: 'Token<"read" | "write">', optional: true, }, - { name: "indexeropen", type: "Token", generic: 'Token<"[">' }, - { name: "key", type: "AstType" }, - { name: "indexerclose", type: "Token", generic: 'Token<"]">' }, + { name: "indexerOpen", type: "Token", generic: 'Token<"[">' }, + { name: "key", type: "CstType" }, + { name: "indexerClose", type: "Token", generic: 'Token<"]">' }, { name: "colon", type: "Token", generic: 'Token<":">' }, - { name: "value", type: "AstType" }, + { name: "value", type: "CstType" }, { name: "separator", type: "Token", @@ -977,7 +994,7 @@ export const astTypeDefinitions: Record = { ], }, - AstTableTypeItemStringProperty: { + CstTableTypeItemStringProperty: { properties: [ { name: "kind", type: '"stringproperty"' }, { @@ -986,11 +1003,11 @@ export const astTypeDefinitions: Record = { generic: 'Token<"read" | "write">', optional: true, }, - { name: "indexeropen", type: "Token", generic: 'Token<"[">' }, - { name: "key", type: "AstTypeSingletonString" }, - { name: "indexerclose", type: "Token", generic: 'Token<"]">' }, + { name: "indexerOpen", type: "Token", generic: 'Token<"[">' }, + { name: "key", type: "CstTypeSingletonString" }, + { name: "indexerClose", type: "Token", generic: 'Token<"]">' }, { name: "colon", type: "Token", generic: 'Token<":">' }, - { name: "value", type: "AstType" }, + { name: "value", type: "CstType" }, { name: "separator", type: "Token", @@ -1000,7 +1017,7 @@ export const astTypeDefinitions: Record = { ], }, - AstTableTypeItemProperty: { + CstTableTypeItemProperty: { properties: [ { name: "kind", type: '"property"' }, { @@ -1011,7 +1028,7 @@ export const astTypeDefinitions: Record = { }, { name: "key", type: "Token" }, { name: "colon", type: "Token", generic: 'Token<":">' }, - { name: "value", type: "AstType" }, + { name: "value", type: "CstType" }, { name: "separator", type: "Token", @@ -1021,41 +1038,41 @@ export const astTypeDefinitions: Record = { ], }, - AstTableTypeItem: { + CstTableTypeItem: { unionMembers: [ - "AstTableTypeItemIndexer", - "AstTableTypeItemStringProperty", - "AstTableTypeItemProperty", + "CstTableTypeItemIndexer", + "CstTableTypeItemStringProperty", + "CstTableTypeItemProperty", ], }, - AstTypeTable: { + CstTypeTable: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"table"' }, - { name: "openbrace", type: "Token", generic: 'Token<"{">' }, - { name: "entries", type: "{ AstTableTypeItem }" }, - { name: "closebrace", type: "Token", generic: 'Token<"}">' }, + { name: "openBrace", type: "Token", generic: 'Token<"{">' }, + { name: "entries", type: "{ CstTableTypeItem }" }, + { name: "closeBrace", type: "Token", generic: 'Token<"}">' }, ], }, - AstFunctionTypeParameter: { + CstFunctionTypeParameter: { properties: [ { name: "location", type: "span" }, { name: "name", type: "Token", optional: true }, { name: "colon", type: "Token", generic: 'Token<":">', optional: true }, - { name: "type", type: "AstType" }, + { name: "type", type: "CstType" }, ], }, - AstTypeFunction: { + CstTypeFunction: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"function"' }, { - name: "opengenerics", + name: "openGenerics", type: "Token", generic: 'Token<"<">', optional: true, @@ -1063,66 +1080,66 @@ export const astTypeDefinitions: Record = { { name: "generics", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "genericpacks", + name: "genericPacks", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", optional: true, }, { - name: "closegenerics", + name: "closeGenerics", type: "Token", generic: 'Token<">">', optional: true, }, - { name: "openparens", type: "Token", generic: 'Token<"(">' }, + { name: "openParens", type: "Token", generic: 'Token<"(">' }, { name: "parameters", type: "Punctuated", - generic: "Punctuated", + generic: "Punctuated", }, - { name: "vararg", type: "AstTypePack", optional: true }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, - { name: "returnarrow", type: "Token", generic: 'Token<"->">' }, - { name: "returntypes", type: "AstTypePack" }, + { name: "vararg", type: "CstTypePack", optional: true }, + { name: "closeParens", type: "Token", generic: 'Token<")">' }, + { name: "returnSpecifier", type: "Token", generic: 'Token<"->">' }, + { name: "returnTypes", type: "CstTypePack" }, ], }, - AstType: { + CstType: { unionMembers: [ - "AstTypeReference", - "AstTypeSingletonBool", - "AstTypeSingletonString", - "AstTypeTypeof", - "AstTypeGroup", - "AstTypeUnion", - "AstTypeIntersection", - "AstTypeOptional", - "AstTypeArray", - "AstTypeTable", - "AstTypeFunction", + "CstTypeReference", + "CstTypeSingletonBool", + "CstTypeSingletonString", + "CstTypeTypeof", + "CstTypeGroup", + "CstTypeUnion", + "CstTypeIntersection", + "CstTypeOptional", + "CstTypeArray", + "CstTypeTable", + "CstTypeFunction", ], }, // === TYPE PACKS === - AstTypePackExplicit: { + CstTypePackExplicit: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, { name: "tag", type: '"explicit"' }, { - name: "openparens", + name: "openParens", type: "Token", generic: 'Token<"(">', optional: true, }, - { name: "types", type: "Punctuated", generic: "Punctuated" }, - { name: "tailtype", type: "AstTypePack", optional: true }, + { name: "types", type: "Punctuated", generic: "Punctuated" }, + { name: "tailType", type: "CstTypePack", optional: true }, { - name: "closeparens", + name: "closeParens", type: "Token", generic: 'Token<")">', optional: true, @@ -1130,7 +1147,7 @@ export const astTypeDefinitions: Record = { ], }, - AstTypePackGeneric: { + CstTypePackGeneric: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, @@ -1140,7 +1157,7 @@ export const astTypeDefinitions: Record = { ], }, - AstTypePackVariadic: { + CstTypePackVariadic: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, @@ -1151,15 +1168,15 @@ export const astTypeDefinitions: Record = { generic: 'Token<"...">', optional: true, }, - { name: "type", type: "AstType" }, + { name: "type", type: "CstType" }, ], }, - AstTypePack: { + CstTypePack: { unionMembers: [ - "AstTypePackExplicit", - "AstTypePackGeneric", - "AstTypePackVariadic", + "CstTypePackExplicit", + "CstTypePackGeneric", + "CstTypePackVariadic", ], }, diff --git a/frontend/src/utils/astTypeHelpers.ts b/frontend/src/utils/astTypeHelpers.ts index 4c33712..23e68df 100644 --- a/frontend/src/utils/astTypeHelpers.ts +++ b/frontend/src/utils/astTypeHelpers.ts @@ -79,10 +79,10 @@ export function getAllNodeKeys(): string[] { const resolveEntriesType = (value: any[]): string => { if (value[0] && value[0].colon) { - return "{ AstTableTypeItem }"; + return "{ CstTableTypeItem }"; } - return "{ AstTableExprItem }"; + return "{ CstTableExprItem }"; }; const resolveEntriesKind = (value: any[]): string => { @@ -90,12 +90,12 @@ const resolveEntriesKind = (value: any[]): string => { }; const arrayTypeFallbacks: Record string)> = { - statements: "{ AstStat }", - leadingtrivia: "{ Trivia }", - trailingtrivia: "{ Trivia }", - attributes: "{ AstAttribute }", - expressions: "{ AstExpr }", - elseifs: "{ AstElseIfExpr }", + statements: "{ CstStat }", + leadingTrivia: "{ Trivia }", + trailingTrivia: "{ Trivia }", + attributes: "{ CstAttribute }", + expressions: "{ CstExpr }", + elseifs: "{ CstElseIfExpr }", strings: "{ Token }", entries: resolveEntriesType, }; @@ -124,7 +124,7 @@ export const unpackArrayType = (type: string): string => { return matchAny ? matchAny[1] : type; }; -// Parse generic types like "Pair" -> { baseType: "Pair", genericType: "AstExpr" } +// Parse generic types like "Pair" -> { baseType: "Pair", genericType: "CstExpr" } export const parseGenericType = ( type: string ): GenericTypeDefinition | undefined => { diff --git a/lua_helpers/astJsonToCode.luau b/lua_helpers/astJsonToCode.luau index c9c63bc..70be7cb 100644 --- a/lua_helpers/astJsonToCode.luau +++ b/lua_helpers/astJsonToCode.luau @@ -13,7 +13,7 @@ end local sourceFilePath = args[2] -- Read the source code from file -local sourceCode = fs.readfiletostring(sourceFilePath) +local sourceCode = fs.readFileToString(sourceFilePath) local astNode = json.decode(sourceCode) @@ -21,9 +21,9 @@ local success, code = pcall(printer.printASTNode, astNode) if success then -- stylua src code for readable output - fs.writestringtofile(sourceFilePath, code :: string) + fs.writeStringToFile(sourceFilePath, code :: string) process.run({ "stylua", sourceFilePath }) - code = fs.readfiletostring(sourceFilePath) + code = fs.readFileToString(sourceFilePath) print(code) end diff --git a/lua_helpers/astParser.luau b/lua_helpers/astParser.luau index 11e5013..1aa8f76 100644 --- a/lua_helpers/astParser.luau +++ b/lua_helpers/astParser.luau @@ -12,11 +12,11 @@ end local sourceFilePath = args[2] -- Read the source code from file -local sourceCode = fs.readfiletostring(sourceFilePath) +local sourceCode = fs.readFileToString(sourceFilePath) -- Parse the AST using our custom parser local success, ast = pcall(function() - return parser.parseblock(sourceCode) + return parser.parseBlock(sourceCode) end) local result diff --git a/lua_helpers/astToJson.luau b/lua_helpers/astToJson.luau index 383ccc8..153325b 100644 --- a/lua_helpers/astToJson.luau +++ b/lua_helpers/astToJson.luau @@ -14,18 +14,18 @@ end local sourceFilePath = args[2] -- Read the source code from file -local sourceCode = fs.readfiletostring(sourceFilePath) +local sourceCode = fs.readFileToString(sourceFilePath) -- Parse the AST using our custom parser local function parseBlock(src) local success, ast = pcall(function() - return annotateWithType(parser.parseblock(sourceCode), "root") + return annotateWithType(parser.parseBlock(sourceCode), "root") end) return success, ast end local function parseExpr(src) local success, exprAST = pcall(function() - return annotateWithType(parser.parseexpr(sourceCode), "root") + return annotateWithType(parser.parseExpr(sourceCode), "root") end) return success, exprAST end diff --git a/lua_helpers/json.lua b/lua_helpers/json.lua index 02e86e0..ba56aed 100644 --- a/lua_helpers/json.lua +++ b/lua_helpers/json.lua @@ -60,12 +60,12 @@ end -- Convert span userdata to a plain table that can be JSON encoded local function serializeSpan(span) - if span.beginline then + if span.beginLine then return { - beginline = span.beginline, - begincolumn = span.begincolumn, - endline = span.endline, - endcolumn = span.endcolumn, + beginLine = span.beginLine, + beginColumn = span.beginColumn, + endLine = span.endLine, + endColumn = span.endColumn, } end return nil diff --git a/lua_helpers/sortByPositionTable.lua b/lua_helpers/sortByPositionTable.lua index 06142b4..b68754b 100644 --- a/lua_helpers/sortByPositionTable.lua +++ b/lua_helpers/sortByPositionTable.lua @@ -5,9 +5,8 @@ local function getNodePosition(node) end if node.location then - -- New span format: { beginline, begincolumn, endline, endcolumn } - if node.location.beginline then - return node.location.beginline, node.location.begincolumn + if node.location.beginLine then + return node.location.beginLine, node.location.beginColumn end end diff --git a/lua_helpers/typeAnnotations.lua b/lua_helpers/typeAnnotations.lua index f70113d..e000ad7 100644 --- a/lua_helpers/typeAnnotations.lua +++ b/lua_helpers/typeAnnotations.lua @@ -1,7 +1,7 @@ --[[ Module that serves as reference for Luau AST types so we can annotate the AST with type information This is all based directly on Luau AST type definitions from Lute - Updated to match latest Lute AST structure (lowercase property names, kind field, etc.) + Updated to match latest Lute AST structure (camelCase property names, kind field, etc.) ]] local typeDefinitions = { @@ -15,98 +15,100 @@ local typeDefinitions = { ["eof"] = "Eof", -- Expressions (kind: "expr") - ["nil"] = "AstExprConstantNil", - ["boolean"] = "AstExprConstantBool", -- also AstTypeSingletonBool - disambiguated by kind - ["number"] = "AstExprConstantNumber", - ["global"] = "AstExprGlobal", - ["vararg"] = "AstExprVarargs", - ["call"] = "AstExprCall", - ["instantiate"] = "AstExprInstantiate", - ["indexname"] = "AstExprIndexName", - ["index"] = "AstExprIndexExpr", - ["unary"] = "AstExprUnary", - ["binary"] = "AstExprBinary", - ["interpolatedstring"] = "AstExprInterpString", - ["cast"] = "AstExprTypeAssertion", + ["nil"] = "CstExprConstantNil", + ["boolean"] = "CstExprConstantBool", -- also CstTypeSingletonBool - disambiguated by kind + ["number"] = "CstExprConstantNumber", + ["global"] = "CstExprGlobal", + ["vararg"] = "CstExprVarargs", + ["call"] = "CstExprCall", + ["instantiate"] = "CstExprInstantiate", + ["indexname"] = "CstExprIndexName", + ["index"] = "CstExprIndexExpr", + ["unary"] = "CstExprUnary", + ["binary"] = "CstExprBinary", + ["interpolatedstring"] = "CstExprInterpString", + ["cast"] = "CstExprTypeAssertion", -- Statements (kind: "stat") - ["block"] = "AstStatBlock", - ["do"] = "AstStatDo", - ["while"] = "AstStatWhile", - ["repeat"] = "AstStatRepeat", - ["break"] = "AstStatBreak", - ["continue"] = "AstStatContinue", - ["return"] = "AstStatReturn", - ["expression"] = "AstStatExpr", - ["assign"] = "AstStatAssign", - ["for"] = "AstStatFor", - ["forin"] = "AstStatForIn", - ["compoundassign"] = "AstStatCompoundAssign", - ["localfunction"] = "AstStatLocalFunction", - ["typealias"] = "AstStatTypeAlias", - ["typefunction"] = "AstStatTypeFunction", + ["block"] = "CstStatBlock", + ["do"] = "CstStatDo", + ["while"] = "CstStatWhile", + ["repeat"] = "CstStatRepeat", + ["break"] = "CstStatBreak", + ["continue"] = "CstStatContinue", + ["return"] = "CstStatReturn", + ["expression"] = "CstStatExpr", + ["assign"] = "CstStatAssign", + ["for"] = "CstStatFor", + ["forin"] = "CstStatForIn", + ["compoundassign"] = "CstStatCompoundAssign", + ["const"] = "CstStatConst", + ["localfunction"] = "CstStatLocalFunction", + ["typealias"] = "CstStatTypeAlias", + ["typefunction"] = "CstStatTypeFunction", -- Types (kind: "type") - ["reference"] = "AstTypeReference", - ["typeof"] = "AstTypeTypeof", - ["union"] = "AstTypeUnion", - ["intersection"] = "AstTypeIntersection", - ["optional"] = "AstTypeOptional", - ["array"] = "AstTypeArray", + ["reference"] = "CstTypeReference", + ["typeof"] = "CstTypeTypeof", + ["union"] = "CstTypeUnion", + ["intersection"] = "CstTypeIntersection", + ["optional"] = "CstTypeOptional", + ["array"] = "CstTypeArray", -- Type packs (kind: "typepack") - ["explicit"] = "AstTypePackExplicit", - ["variadic"] = "AstTypePackVariadic", + ["explicit"] = "CstTypePackExplicit", + ["variadic"] = "CstTypePackVariadic", -- Generic types (no kind field) - ["generic"] = "AstGenericType", -- also AstTypePackGeneric - disambiguated by ellipsis - ["genericpack"] = "AstGenericTypePack", + ["generic"] = "CstGenericType", -- also CstTypePackGeneric - disambiguated by ellipsis + ["genericpack"] = "CstGenericTypePack", }, -- Key-based mappings (fallback when tag is not present) - -- Updated to use lowercase property names + -- Updated to use camelCase property names keys = { - -- Span fields (replaces Location/Position) - ["beginline"] = "number", - ["begincolumn"] = "number", - ["endline"] = "number", - ["endcolumn"] = "number", + -- Span fields + ["beginLine"] = "number", + ["beginColumn"] = "number", + ["endLine"] = "number", + ["endColumn"] = "number", ["argLocation"] = "span", - ["indexlocation"] = "span", + ["indexLocation"] = "span", -- Common token properties (fallback to Token) - ["functionkeyword"] = "Token", - ["localkeyword"] = "Token", - ["ifkeyword"] = "Token", - ["thenkeyword"] = "Token", - ["elsekeyword"] = "Token", - ["elseifkeyword"] = "Token", - ["endkeyword"] = "Token", - ["whilekeyword"] = "Token", - ["dokeyword"] = "Token", - ["forkeyword"] = "Token", - ["inkeyword"] = "Token", - ["repeatkeyword"] = "Token", - ["untilkeyword"] = "Token", - ["returnkeyword"] = "Token", + ["functionKeyword"] = "Token", + ["localKeyword"] = "Token", + ["constKeyword"] = "Token", + ["ifKeyword"] = "Token", + ["thenKeyword"] = "Token", + ["elseKeyword"] = "Token", + ["elseIfKeyword"] = "Token", + ["endKeyword"] = "Token", + ["whileKeyword"] = "Token", + ["doKeyword"] = "Token", + ["forKeyword"] = "Token", + ["inKeyword"] = "Token", + ["repeatKeyword"] = "Token", + ["untilKeyword"] = "Token", + ["returnKeyword"] = "Token", ["export"] = "Token", - ["typetoken"] = "Token", + ["typeToken"] = "Token", ["typeof"] = "Token", -- Punctuation tokens - ["openparens"] = "Token", - ["closeparens"] = "Token", - ["openbrace"] = "Token", - ["closebrace"] = "Token", - ["openbrackets"] = "Token", - ["closebrackets"] = "Token", - ["opengenerics"] = "Token", - ["closegenerics"] = "Token", - ["openparameters"] = "Token", - ["closeparameters"] = "Token", - ["indexeropen"] = "Token", - ["indexerclose"] = "Token", - ["returnarrow"] = "Token", + ["openParens"] = "Token", + ["closeParens"] = "Token", + ["openBrace"] = "Token", + ["closeBrace"] = "Token", + ["openBrackets"] = "Token", + ["closeBrackets"] = "Token", + ["openGenerics"] = "Token", + ["closeGenerics"] = "Token", + ["openParameters"] = "Token", + ["closeParameters"] = "Token", + ["indexerOpen"] = "Token", + ["indexerClose"] = "Token", + ["returnSpecifier"] = "Token", -- Operators and symbols ["equals"] = "Token", @@ -116,12 +118,11 @@ local typeDefinitions = { ["accessor"] = "Token", ["operator"] = "Token", ["ellipsis"] = "Token", - ["varargcolon"] = "Token", - ["returnspecifier"] = "Token", - ["tocomma"] = "Token", - ["stepcomma"] = "Token", - ["prefixpoint"] = "Token", - ["leading"] = "Token", + ["varargColon"] = "Token", + ["toComma"] = "Token", + ["stepComma"] = "Token", + ["prefixPoint"] = "Token", + ["leadingTrivia"] = "Token", ["access"] = "Token", ["separator"] = "Token", @@ -129,63 +130,62 @@ local typeDefinitions = { ["token"] = "Token", -- Expression/Statement specific - ["expression"] = "AstExpr", - ["func"] = "AstExprFunction", - ["condition"] = "AstExpr", - ["from"] = "AstExpr", - ["to"] = "AstExpr", - ["step"] = "AstExpr", - ["lhsoperand"] = "AstExpr", - ["rhsoperand"] = "AstExpr", - ["thenexpr"] = "AstExpr", - ["elseexpr"] = "AstExpr", + ["expression"] = "CstExpr", + ["func"] = "CstExprFunction", + ["condition"] = "CstExpr", + ["from"] = "CstExpr", + ["to"] = "CstExpr", + ["step"] = "CstExpr", + ["lhsOperand"] = "CstExpr", + ["rhsOperand"] = "CstExpr", + ["thenExpr"] = "CstExpr", + ["elseExpr"] = "CstExpr", -- Block references - ["thenblock"] = "AstStatBlock", - ["elseblock"] = "AstStatBlock", + ["thenBlock"] = "CstStatBlock", + ["elseBlock"] = "CstStatBlock", -- Variables and locals - ["local"] = "AstLocal", - ["shadows"] = "AstLocal", + ["local"] = "CstLocal", + ["shadows"] = "CstLocal", -- Type system - ["annotation"] = "AstType", - ["varargannotation"] = "AstTypePack", - ["returnannotation"] = "AstTypePack", - ["returntypes"] = "AstTypePack", - ["tailtype"] = "AstTypePack", + ["annotation"] = "CstType", + ["varargAnnotation"] = "CstTypePack", + ["returnAnnotation"] = "CstTypePack", + ["returnTypes"] = "CstTypePack", + ["tailType"] = "CstTypePack", -- Special properties ["text"] = "string", ["upvalue"] = "boolean", - ["quotestyle"] = "string", - ["blockdepth"] = "number", - ["istoken"] = "boolean", - ["istableitem"] = "boolean", + ["quoteStyle"] = "string", + ["blockDepth"] = "number", + ["isTableItem"] = "boolean", -- ParseResult specific - ["root"] = "AstStatBlock", + ["root"] = "CstStatBlock", ["eof"] = "Eof", ["lines"] = "number", }, -- Kind-based mappings for table items and other kinded structures kinds = { - -- Expression table items (istableitem: true) - ["record"] = "AstTableExprRecordItem", - ["general"] = "AstTableExprGeneralItem", - ["list"] = "AstTableExprListItem", + -- Expression table items (isTableItem: true) + ["record"] = "CstTableExprRecordItem", + ["general"] = "CstTableExprGeneralItem", + ["list"] = "CstTableExprListItem", -- Type table items - ["property"] = "AstTableTypeItemProperty", - ["indexer"] = "AstTableTypeItemIndexer", - ["stringproperty"] = "AstTableTypeItemStringProperty", + ["property"] = "CstTableTypeItemProperty", + ["indexer"] = "CstTableTypeItemIndexer", + ["stringproperty"] = "CstTableTypeItemStringProperty", - -- AstLocal - ["local"] = "AstLocal", + -- CstLocal + ["local"] = "CstLocal", -- Attribute - ["attribute"] = "AstAttribute", + ["attribute"] = "CstAttribute", }, } @@ -201,78 +201,78 @@ local function resolveAmbiguousTags(node): string? -- Handle ambiguous cases based on distinguishing properties if tag == "conditional" then - -- AstStatIf has endkeyword and kind="stat", AstExprIfElse has kind="expr" - if kind == "stat" or node.endkeyword then - return "AstStatIf" + -- CstStatIf has endKeyword and kind="stat", CstExprIfElse has kind="expr" + if kind == "stat" or node.endKeyword then + return "CstStatIf" else - return "AstExprIfElse" + return "CstExprIfElse" end elseif tag == "function" then - -- AstTypeFunction has returnarrow and kind="type" - if kind == "type" or node.returnarrow then - return "AstTypeFunction" - -- AstStatFunction has name field and kind="stat" (but not func field directly on it) + -- CstTypeFunction has returnSpecifier and kind="type" + if kind == "type" or node.returnSpecifier then + return "CstTypeFunction" + -- CstStatFunction has name field and kind="stat" (but not func field directly on it) elseif kind == "stat" then - return "AstStatFunction" + return "CstStatFunction" else - -- AstExprFunction (consolidated from old AstExprAnonymousFunction + AstFunctionBody) - return "AstExprFunction" + -- CstExprFunction (consolidated from old CstExprAnonymousFunction + CstFunctionBody) + return "CstExprFunction" end elseif tag == "group" then - -- AstExprGroup has expression and kind="expr", AstTypeGroup has type and kind="type" + -- CstExprGroup has expression and kind="expr", CstTypeGroup has type and kind="type" if kind == "type" or node.type then - return "AstTypeGroup" + return "CstTypeGroup" else - return "AstExprGroup" + return "CstExprGroup" end elseif tag == "local" then - -- AstExprLocal has token/upvalue and kind="expr", AstStatLocal has localkeyword and kind="stat" + -- CstExprLocal has token/upvalue and kind="expr", CstStatLocal has localKeyword and kind="stat" if kind == "expr" or (node.token and node.upvalue ~= nil) then - return "AstExprLocal" - elseif kind == "stat" or (node.localkeyword and node.variables) then - return "AstStatLocal" + return "CstExprLocal" + elseif kind == "stat" or (node.localKeyword and node.variables) then + return "CstStatLocal" end elseif tag == "generic" then - -- AstTypePackGeneric has ellipsis and kind="typepack", AstGenericType doesn't + -- CstTypePackGeneric has ellipsis and kind="typepack", CstGenericType doesn't if kind == "typepack" or node.ellipsis then - return "AstTypePackGeneric" + return "CstTypePackGeneric" else - return "AstGenericType" + return "CstGenericType" end elseif tag == "table" then -- AstTypeTable has kind="type", AstExprTable has kind="expr" if kind == "type" then - return "AstTypeTable" + return "CstTypeTable" elseif kind == "expr" then - return "AstExprTable" + return "CstExprTable" end -- Fallback heuristic if node.entries and #node.entries > 0 then local firstEntry = node.entries[1] - if firstEntry and firstEntry.istableitem then - return "AstExprTable" + if firstEntry and firstEntry.isTableItem then + return "CstExprTable" end end - return "AstExprTable" -- Default to expression table + return "CstExprTable" -- Default to expression table elseif tag == "string" then -- AstTypeSingletonString has kind="type", AstExprConstantString has kind="expr" if kind == "type" then - return "AstTypeSingletonString" + return "CstTypeSingletonString" elseif kind == "expr" then - return "AstExprConstantString" + return "CstExprConstantString" end - -- Fallback: expression strings can have block/interp quotestyle - if node.quotestyle == "block" or node.quotestyle == "interp" or node.blockdepth then - return "AstExprConstantString" + -- Fallback: expression strings can have block/interp quoteStyle + if node.quoteStyle == "block" or node.quoteStyle == "interp" or node.blockDepth then + return "CstExprConstantString" else - return "AstTypeSingletonString" + return "CstTypeSingletonString" end elseif tag == "boolean" then -- AstTypeSingletonBool has kind="type", AstExprConstantBool has kind="expr" if kind == "type" then - return "AstTypeSingletonBool" + return "CstTypeSingletonBool" else - return "AstExprConstantBool" + return "CstExprConstantBool" end end @@ -289,29 +289,29 @@ local function resolveAmbiguousKeys(nodeKey, node, parentNode: any?): string? -- Ambiguous keys that need context-aware resolution: if nodeKey == "body" then -- AstStatBlock vs AstExprFunction (for AstStatTypeFunction) vs { AstStat } for AstStatDo - if node.functionkeyword and node.openparens then + if node.functionKeyword and node.openParens then -- This is AstExprFunction (used in AstStatTypeFunction.body) - return "AstExprFunction" + return "CstExprFunction" elseif node.statements then - return "AstStatBlock" + return "CstStatBlock" else return nil -- Array of statements for AstStatDo end elseif nodeKey == "name" then -- Token vs AstExpr vs AstLocal - if node.istoken or node.text then + if node.kind == "token" or node.text then return "Token" elseif node.kind == "local" or node.name then - return "AstLocal" + return "CstLocal" else - return "AstExpr" + return "CstExpr" end elseif nodeKey == "value" then -- boolean vs number vs AstExpr vs AstType if parentNode.colon then - return "AstType" - elseif parentNode.istableitem or parentNode.operand then - return "AstExpr" + return "CstType" + elseif parentNode.isTableItem or parentNode.operand then + return "CstExpr" else return if parentNode.tag == "boolean" then "boolean" else "number" end @@ -321,55 +321,55 @@ local function resolveAmbiguousKeys(nodeKey, node, parentNode: any?): string? if kind == "record" then return "Token" elseif kind == "general" then - return "AstExpr" + return "CstExpr" elseif kind == "indexer" then - return "AstType" + return "CstType" elseif kind == "stringproperty" then - return "AstTypeSingletonString" + return "CstTypeSingletonString" elseif kind == "property" then return "Token" end elseif nodeKey == "operand" then -- AstExpr vs Token if parentNode.operator and parentNode.tag then - return "AstExpr" + return "CstExpr" else return "Token" end elseif nodeKey == "variable" then - -- AstLocal vs AstExpr + -- CstLocal vs AstExpr if parentNode.equals and parentNode.from then - return "AstLocal" + return "CstLocal" else - return "AstExpr" + return "CstExpr" end elseif nodeKey == "type" then -- AstType vs Token - if parentNode.functionkeyword and parentNode.tag == "typefunction" then + if parentNode.functionKeyword and parentNode.tag == "typefunction" then return "Token" else - return "AstType" + return "CstType" end elseif nodeKey == "default" then -- AstType vs AstTypePack if parentNode.ellipsis then - return "AstTypePack" + return "CstTypePack" else - return "AstType" + return "CstType" end elseif nodeKey == "self" then -- boolean vs AstLocal if parentNode.tag then return "boolean" else - return "AstLocal" + return "CstLocal" end elseif nodeKey == "index" then -- Token vs AstExpr if parentNode.accessor then return "Token" else - return "AstExpr" + return "CstExpr" end elseif nodeKey == "prefix" then -- Token @@ -393,23 +393,23 @@ local function annotateWithType(node, nodeKey: (string | number)?, parent: any?, -- Priority 1: Check for 'kind' field for direct type mapping (local, attribute) if annotatedNode.kind == "local" and not annotatedNode.tag then - astType = "AstLocal" + astType = "CstLocal" elseif annotatedNode.kind == "attribute" then - astType = "AstAttribute" + astType = "CstAttribute" -- Priority 2: Context-aware tag-based type resolution elseif annotatedNode.tag then astType = resolveAmbiguousTags(annotatedNode) -- Priority 3: Check for 'kind' field for table items - elseif annotatedNode.kind and annotatedNode.istableitem then + elseif annotatedNode.kind and annotatedNode.isTableItem then astType = typeDefinitions.kinds[annotatedNode.kind] - elseif annotatedNode.kind and (annotatedNode.key or annotatedNode.indexeropen) then + elseif annotatedNode.kind and (annotatedNode.key or annotatedNode.indexerOpen) then -- Type table items astType = typeDefinitions.kinds[annotatedNode.kind] - -- Priority 4: Check for istoken marker - elseif annotatedNode.istoken then + -- Priority 4: Check for kind="token" marker + elseif annotatedNode.kind == "token" then astType = "Token" -- Priority 5: Key-based type resolution (fallback) @@ -421,7 +421,7 @@ local function annotateWithType(node, nodeKey: (string | number)?, parent: any?, -- Any property ending in "keyword" is probably a token astType = "Token" elseif nodeKey and (nodeKey:match("^open") or nodeKey:match("^close")) then - -- Properties like openparens, closebrace, etc. + -- Properties like openParens, closeBrace, etc. astType = "Token" end diff --git a/rokit.toml b/rokit.toml index 423f218..e6d0618 100644 --- a/rokit.toml +++ b/rokit.toml @@ -1,3 +1,3 @@ [tools] -lute = "luau-lang/lute@0.1.0-nightly.20260312" +lute = "luau-lang/lute@1.0.1-nightly.20260612" stylua = "JohnnyMorganz/StyLua@2.0.2" From ad7dcd454e3798705aee6311d9cee07e652ff2bf Mon Sep 17 00:00:00 2001 From: Wyatt McCarthy Date: Tue, 16 Jun 2026 11:56:55 -0700 Subject: [PATCH 2/4] more fixes --- lua_helpers/json.lua | 467 +++--------------- lua_helpers/sortByPositionTable.lua | 29 +- lua_helpers/temp_vendor/lutePrinter.luau | 65 ++- lua_tests/astJsonToCode.spec.lua | 10 +- lua_tests/helpers/astJsonToCodeHelpers.lua | 36 +- .../helpers/typeAnnotationTestHelpers.lua | 182 ++++--- lua_tests/printASTNode.spec.lua | 4 +- lua_tests/typeAnnotations.spec.lua | 2 +- 8 files changed, 247 insertions(+), 548 deletions(-) diff --git a/lua_helpers/json.lua b/lua_helpers/json.lua index ba56aed..952af9b 100644 --- a/lua_helpers/json.lua +++ b/lua_helpers/json.lua @@ -1,409 +1,60 @@ --- --- json.lua --- --- Copyright (c) 2020 rxi --- --- Permission is hereby granted, free of charge, to any person obtaining a copy of --- this software and associated documentation files (the "Software"), to deal in --- the Software without restriction, including without limitation the rights to --- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies --- of the Software, and to permit persons to whom the Software is furnished to do --- so, subject to the following conditions: --- --- The above copyright notice and this permission notice shall be included in all --- copies or substantial portions of the Software. --- --- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR --- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, --- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE --- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER --- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, --- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE --- SOFTWARE. --- - --- Courtesy of https://github.com/rxi/json.lua - -local json = { _version = "0.1.2" } - -------------------------------------------------------------------------------- --- Encode -------------------------------------------------------------------------------- - -local encode - -local escape_char_map = { - [ "\\" ] = "\\", - [ "\"" ] = "\"", - [ "\b" ] = "b", - [ "\f" ] = "f", - [ "\n" ] = "n", - [ "\r" ] = "r", - [ "\t" ] = "t", -} - -local escape_char_map_inv = { [ "/" ] = "/" } -for k, v in pairs(escape_char_map) do - escape_char_map_inv[v] = k -end - - -local function escape_char(c) - return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte())) -end - - -local function encode_nil(val) - return "null" -end - - --- Convert span userdata to a plain table that can be JSON encoded -local function serializeSpan(span) - if span.beginLine then - return { - beginLine = span.beginLine, - beginColumn = span.beginColumn, - endLine = span.endLine, - endColumn = span.endColumn, - } - end - return nil -end - - -local function encode_table(val, stack) - local res = {} - stack = stack or {} - - -- Circular reference? - if stack[val] then error("circular reference") end - - stack[val] = true - - if rawget(val, 1) ~= nil or next(val) == nil then - -- Treat as array -- use ipairs to only get sequential numeric keys - -- This handles mixed tables (with both numeric and string keys) by only encoding the array part - for i, v in ipairs(val) do - local encodedVal = encode(v, stack) - if encodedVal ~= nil then - table.insert(res, encodedVal) - end - end - stack[val] = nil - return "[" .. table.concat(res, ",") .. "]" - - else - -- Treat as an object - for k, v in pairs(val) do - -- Only encode string keys (skip numeric, boolean, function, userdata keys, etc.) - if type(k) == "string" then - local encodedVal = encode(v, stack) - if encodedVal ~= nil then - table.insert(res, encode(k, stack) .. ":" .. encodedVal) - end - end - -- Silently skip non-string keys to handle metatables, mixed tables, etc. - end - stack[val] = nil - return "{" .. table.concat(res, ",") .. "}" - end -end - - -local function encode_string(val) - return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"' -end - - -local function encode_number(val) - -- Check for NaN, -inf and inf - if val ~= val or val <= -math.huge or val >= math.huge then - error("unexpected number value '" .. tostring(val) .. "'") - end - return string.format("%.14g", val) -end - - -local type_func_map = { - [ "nil" ] = encode_nil, - [ "table" ] = encode_table, - [ "string" ] = encode_string, - [ "number" ] = encode_number, - [ "boolean" ] = tostring, -} - - -encode = function(val, stack): string? - local t = type(val) - local f = type_func_map[t] - if t == "userdata" then - -- Try to serialize span userdata as a table - local spanTable = serializeSpan(val) - if spanTable then - return encode_table(spanTable, stack) - end - return nil :: string? - end - if f then - return f(val, stack) - end - error("unexpected type '" .. t .. "'") -end - - -function json.encode(val): string? - return ( encode(val) ) -end - - -------------------------------------------------------------------------------- --- Decode -------------------------------------------------------------------------------- - -local parse - -local function create_set(...) - local res = {} - for i = 1, select("#", ...) do - res[ select(i, ...) ] = true - end - return res -end - -local space_chars = create_set(" ", "\t", "\r", "\n") -local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",") -local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u") -local literals = create_set("true", "false", "null") - -local literal_map = { - [ "true" ] = true, - [ "false" ] = false, - [ "null" ] = nil, +local stdJson = require("@std/json") + +-- Transforms lute's new Punctuated format (array + .separators field) +-- into the frontend-compatible [{node, separator?}] Pair format before encoding. +local function transformPunctuated(node) + if type(node) ~= "table" then + return node + end + + local separators = rawget(node, "separators") + if separators and rawget(node, 1) ~= nil then + local pairs = {} + for i, item in ipairs(node) do + local pair = { node = transformPunctuated(item) } + if separators[i] then + pair.separator = transformPunctuated(separators[i]) + end + table.insert(pairs, pair) + end + return pairs + end + + local result = {} + for k, v in pairs(node) do + result[k] = transformPunctuated(v) + end + for i = 1, #node do + result[i] = transformPunctuated(node[i]) + end + return result +end + +local function encode(value) + return stdJson.serialize(transformPunctuated(value)) +end + +local function stripNulls(node) + if type(node) ~= "table" then + return node + end + local result = {} + for k, v in pairs(node) do + if type(k) == "string" and v ~= stdJson.null then + result[k] = stripNulls(v) + elseif type(k) == "number" and v ~= stdJson.null then + result[k] = stripNulls(v) + end + -- Skip userdata keys (object/array markers from @std/json) + end + return result +end + +local function decode(str) + return stripNulls(stdJson.deserialize(str)) +end + +return { + encode = encode, + decode = decode, } - - -local function next_char(str, idx, set, negate) - for i = idx, #str do - if set[str:sub(i, i)] ~= negate then - return i - end - end - return #str + 1 -end - - -local function decode_error(str, idx, msg) - local line_count = 1 - local col_count = 1 - for i = 1, idx - 1 do - col_count = col_count + 1 - if str:sub(i, i) == "\n" then - line_count = line_count + 1 - col_count = 1 - end - end - error( string.format("%s at line %d col %d", msg, line_count, col_count) ) -end - - -local function codepoint_to_utf8(n) - -- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa - local f = math.floor - if n <= 0x7f then - return string.char(n) - elseif n <= 0x7ff then - return string.char(f(n / 64) + 192, n % 64 + 128) - elseif n <= 0xffff then - return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128) - elseif n <= 0x10ffff then - return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128, - f(n % 4096 / 64) + 128, n % 64 + 128) - end - error( string.format("invalid unicode codepoint '%x'", n) ) -end - - -local function parse_unicode_escape(s) - local n1 = tonumber( s:sub(1, 4), 16 ) - local n2 = tonumber( s:sub(7, 10), 16 ) - -- Surrogate pair? - if n2 then - return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000) - else - return codepoint_to_utf8(n1) - end -end - - -local function parse_string(str, i) - local res = "" - local j = i + 1 - local k = j - - while j <= #str do - local x = str:byte(j) - - if x < 32 then - decode_error(str, j, "control character in string") - - elseif x == 92 then -- `\`: Escape - res = res .. str:sub(k, j - 1) - j = j + 1 - local c = str:sub(j, j) - if c == "u" then - local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1) - or str:match("^%x%x%x%x", j + 1) - or decode_error(str, j - 1, "invalid unicode escape in string") - res = res .. parse_unicode_escape(hex) - j = j + #hex - else - if not escape_chars[c] then - decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string") - end - res = res .. escape_char_map_inv[c] - end - k = j + 1 - - elseif x == 34 then -- `"`: End of string - res = res .. str:sub(k, j - 1) - return res, j + 1 - end - - j = j + 1 - end - - decode_error(str, i, "expected closing quote for string") -end - - -local function parse_number(str, i) - local x = next_char(str, i, delim_chars) - local s = str:sub(i, x - 1) - local n = tonumber(s) - if not n then - decode_error(str, i, "invalid number '" .. s .. "'") - end - return n, x -end - - -local function parse_literal(str, i) - local x = next_char(str, i, delim_chars) - local word = str:sub(i, x - 1) - if not literals[word] then - decode_error(str, i, "invalid literal '" .. word .. "'") - end - return literal_map[word], x -end - - -local function parse_array(str, i) - local res = {} - local n = 1 - i = i + 1 - while 1 do - local x - i = next_char(str, i, space_chars, true) - -- Empty / end of array? - if str:sub(i, i) == "]" then - i = i + 1 - break - end - -- Read token - x, i = parse(str, i) - res[n] = x - n = n + 1 - -- Next token - i = next_char(str, i, space_chars, true) - local chr = str:sub(i, i) - i = i + 1 - if chr == "]" then break end - if chr ~= "," then decode_error(str, i, "expected ']' or ','") end - end - return res, i -end - - -local function parse_object(str, i) - local res = {} - i = i + 1 - while 1 do - local key, val - i = next_char(str, i, space_chars, true) - -- Empty / end of object? - if str:sub(i, i) == "}" then - i = i + 1 - break - end - -- Read key - if str:sub(i, i) ~= '"' then - decode_error(str, i, "expected string for key") - end - key, i = parse(str, i) - -- Read ':' delimiter - i = next_char(str, i, space_chars, true) - if str:sub(i, i) ~= ":" then - decode_error(str, i, "expected ':' after key") - end - i = next_char(str, i + 1, space_chars, true) - -- Read value - val, i = parse(str, i) - -- Set - res[key] = val - -- Next token - i = next_char(str, i, space_chars, true) - local chr = str:sub(i, i) - i = i + 1 - if chr == "}" then break end - if chr ~= "," then decode_error(str, i, "expected '}' or ','") end - end - return res, i -end - - -local char_func_map = { - [ '"' ] = parse_string, - [ "0" ] = parse_number, - [ "1" ] = parse_number, - [ "2" ] = parse_number, - [ "3" ] = parse_number, - [ "4" ] = parse_number, - [ "5" ] = parse_number, - [ "6" ] = parse_number, - [ "7" ] = parse_number, - [ "8" ] = parse_number, - [ "9" ] = parse_number, - [ "-" ] = parse_number, - [ "t" ] = parse_literal, - [ "f" ] = parse_literal, - [ "n" ] = parse_literal, - [ "[" ] = parse_array, - [ "{" ] = parse_object, -} - - -parse = function(str, idx) - local chr = str:sub(idx, idx) - local f = char_func_map[chr] - if f then - return f(str, idx) - end - decode_error(str, idx, "unexpected character '" .. chr .. "'") -end - - -function json.decode(str) - if type(str) ~= "string" then - error("expected argument of type string, got " .. type(str)) - end - local res, idx = parse(str, next_char(str, 1, space_chars, true)) - idx = next_char(str, idx, space_chars, true) - if idx <= #str then - decode_error(str, idx, "trailing garbage") - end - return res -end - - -return json \ No newline at end of file diff --git a/lua_helpers/sortByPositionTable.lua b/lua_helpers/sortByPositionTable.lua index b68754b..3181a11 100644 --- a/lua_helpers/sortByPositionTable.lua +++ b/lua_helpers/sortByPositionTable.lua @@ -1,12 +1,11 @@ local function getNodePosition(node) - -- Direct location access (new span structure) if typeof(node) ~= "table" then - return nil, nil + return nil, nil, nil, nil end if node.location then if node.location.beginLine then - return node.location.beginLine, node.location.beginColumn + return node.location.beginLine, node.location.beginColumn, node.location.endLine, node.location.endColumn end end @@ -22,19 +21,33 @@ local function getNodePosition(node) end end end - return minLine, minCol + return minLine, minCol, nil, nil end local function sortByPosition(node1, node2) - local line1, col1 = getNodePosition(node1) - local line2, col2 = getNodePosition(node2) - return line1 < line2 or (line1 == line2 and col1 < col2) + local line1, col1, endLine1, endCol1 = getNodePosition(node1) + local line2, col2, endLine2, endCol2 = getNodePosition(node2) + if line1 ~= line2 then + return line1 < line2 + end + if col1 ~= col2 then + return col1 < col2 + end + -- Tiebreaker: smaller span (earlier end) comes first + if endLine1 and endLine2 then + if endLine1 ~= endLine2 then + return endLine1 < endLine2 + end + if endCol1 and endCol2 then + return endCol1 < endCol2 + end + end + return false end local function getSortedChildren(node: any) local sorted = {} for key, child in node do - -- Filter out diff metadata and nodes without position local line, col = getNodePosition(child) if line and col then table.insert(sorted, child) diff --git a/lua_helpers/temp_vendor/lutePrinter.luau b/lua_helpers/temp_vendor/lutePrinter.luau index 46ee88d..69031d9 100644 --- a/lua_helpers/temp_vendor/lutePrinter.luau +++ b/lua_helpers/temp_vendor/lutePrinter.luau @@ -1,20 +1,62 @@ local lp = require("@std/syntax/printer") local getSortedChildren = require("../sortByPositionTable") +local function printToken(token: any): string + if type(token) ~= "table" then + return "" + end + local result = "" + if token.leadingTrivia then + for _, trivia in ipairs(token.leadingTrivia) do + result ..= trivia.text or "" + end + end + result ..= token.text or "" + if token.trailingTrivia then + for _, trivia in ipairs(token.trailingTrivia) do + result ..= trivia.text or "" + end + end + return result +end + +local function isToken(node: any): boolean + return type(node) == "table" and node.kind == "token" and node.text ~= nil +end + +-- Tags where the 'func' child's contents should be merged into the parent +-- for correct position-based printing +local flattenFuncTags = { + localfunction = true, + ["function"] = true, +} + local function printFallback(node: any): string - --[[ - Function to serve as fallback when nodes are not printable with printstatement, printexpr, printtype, printlocal, printtoken - Catches array nodes and other unique cases (nodes without tag that aren't tokens); - if array node: iteratively call printASTNode (tries to printstatement, printexpr, printtype, printlocal, printtoken on a node) on children - if non-array node: sort children by position, iteratively try to print children (same way as above) - ]] local nodeSrcStr = "" if node[1] then -- handle arrays for i = 1, #node do nodeSrcStr ..= printASTNode(node[i]) or "" end else - local sortedChildren = getSortedChildren(node) + -- For nodes where 'func' should be flattened into parent + local nodeToSort = node + if node.tag and flattenFuncTags[node.tag] and node.func then + -- Merge func's children into a virtual node alongside parent's other children + nodeToSort = {} + for k, v in node do + if k ~= "func" then + nodeToSort[k] = v + end + end + -- Merge func's children (except location/tag/kind which are metadata) + for k, v in node.func do + if k ~= "location" and k ~= "tag" and k ~= "kind" and k ~= "_astType" then + nodeToSort["func_" .. k] = v + end + end + end + + local sortedChildren = getSortedChildren(nodeToSort) for key, child in sortedChildren do nodeSrcStr ..= printASTNode(child) or "" end @@ -47,14 +89,19 @@ function filterNodeForPrinting(node: any) end function printASTNode(astNode: any): string | nil - -- filter nodes lefover from diff annotations that we DONT want to print astNode = filterNodeForPrinting(astNode) - local success, defaultPrint = pcall(lp.printnode, astNode) + -- Try standard printer first (works on real CST nodes) + local success, defaultPrint = pcall(lp.printNode, astNode) if success then return defaultPrint end + -- Handle tokens directly + if isToken(astNode) then + return printToken(astNode) + end + return printFallback(astNode) end diff --git a/lua_tests/astJsonToCode.spec.lua b/lua_tests/astJsonToCode.spec.lua index e02aae8..5341deb 100644 --- a/lua_tests/astJsonToCode.spec.lua +++ b/lua_tests/astJsonToCode.spec.lua @@ -9,17 +9,17 @@ function trim(s) return s:gsub("^%s*(.-)%s*$", "%1") end -local lutePath = process.execpath() +local lutePath = process.execPath() local function ast_json_to_code_test() local tmpFilePath = "tmpastJsonPath.lua" for _, code in pairs(e2eCases) do - fs.writestringtofile(tmpFilePath, code) + fs.writeStringToFile(tmpFilePath, code) process.run({ "stylua", tmpFilePath }) - local formattedCode = trim(fs.readfiletostring(tmpFilePath)) - local ast = parser.parseblock(fs.readfiletostring(tmpFilePath)) + local formattedCode = trim(fs.readFileToString(tmpFilePath)) + local ast = parser.parseBlock(fs.readFileToString(tmpFilePath)) local astJson = json.encode(ast) - fs.writestringtofile(tmpFilePath, astJson or "nil") + fs.writeStringToFile(tmpFilePath, astJson or "nil") local cmd = process.run({ lutePath, `lua_helpers/astJsonToCode.luau`, tmpFilePath }) local formattedResult = trim(cmd.stdout) process.run({ "rm", tmpFilePath }) diff --git a/lua_tests/helpers/astJsonToCodeHelpers.lua b/lua_tests/helpers/astJsonToCodeHelpers.lua index 9126c30..a2a24ef 100644 --- a/lua_tests/helpers/astJsonToCodeHelpers.lua +++ b/lua_tests/helpers/astJsonToCodeHelpers.lua @@ -3,14 +3,14 @@ local function createMockToken(text, line, column) return { text = text, location = { - beginline = line or 1, - begincolumn = column or 1, - endline = line or 1, - endcolumn = (column or 1) + #text, + beginLine = line or 1, + beginColumn = column or 1, + endLine = line or 1, + endColumn = (column or 1) + #text, }, - leadingtrivia = {}, - trailingtrivia = {}, - istoken = true, + leadingTrivia = {}, + trailingTrivia = {}, + kind = "token", } end @@ -35,27 +35,27 @@ local cases = { kind = "local", name = createMockToken("test2", 1, 1), colon = { - leadingtrivia = {}, - trailingtrivia = { + leadingTrivia = {}, + trailingTrivia = { { tag = "whitespace", text = " ", location = { - beginline = 1, - begincolumn = 1, - endline = 1, - endcolumn = 2, + beginLine = 1, + beginColumn = 1, + endLine = 1, + endColumn = 2, }, }, }, location = { - beginline = 1, - begincolumn = 1, - endline = 1, - endcolumn = 2, + beginLine = 1, + beginColumn = 1, + endLine = 1, + endColumn = 2, }, text = ":", - istoken = true, + kind = "token", }, annotation = { kind = "type", diff --git a/lua_tests/helpers/typeAnnotationTestHelpers.lua b/lua_tests/helpers/typeAnnotationTestHelpers.lua index 6d2082f..db9ad62 100644 --- a/lua_tests/helpers/typeAnnotationTestHelpers.lua +++ b/lua_tests/helpers/typeAnnotationTestHelpers.lua @@ -9,18 +9,18 @@ local e2ecases = require("./astJsonToCodeHelpers").testCases.e2eCases ]] local validTokenTypes = { - "AstExprConstantString", - "AstExprConstantBool", - "AstExprConstantNumber", - "AstExprConstantNil", + "CstExprConstantString", + "CstExprConstantBool", + "CstExprConstantNumber", + "CstExprConstantNil", "Token", - "AstAttribute", - "AstTypeSingletonBool", - "AstTypeSingletonString", - "AstExprVarargs", - "AstStatBreak", - "AstStatContinue", - "AstTypeOptional", + "CstAttribute", + "CstTypeSingletonBool", + "CstTypeSingletonString", + "CstExprVarargs", + "CstStatBreak", + "CstStatContinue", + "CstTypeOptional", } local function verifyOutput( @@ -29,16 +29,12 @@ local function verifyOutput( verifier: ((node: luau.AstNode) -> boolean) | boolean ) if not node._astType then -- avoid failing on nodes that don't have a type - -- print(`Node has no type: {node}, in: {visitorFunction}`) - -- printTable(" ", node) - -- print("\n") return end assert( if type(verifier) == "function" then verifier(node) else verifier, `Incorrectly annotated node as {node._astType} in {visitorFunction}` ) - -- print(`✓ Correctly annotated node as {node._astType} in {visitorFunction}`) end typeAnnotationVisitor.visitToken = function(token: luau.Token) @@ -49,256 +45,251 @@ typeAnnotationVisitor.visitToken = function(token: luau.Token) end typeAnnotationVisitor.visitExprConstantString = function(token: luau.AstExprConstantString) - verifyOutput(token, "visitString", token._astType == "AstExprConstantString") + verifyOutput(token, "visitString", token._astType == "CstExprConstantString") return true end typeAnnotationVisitor.visitExprConstantBool = function(token: luau.AstExprConstantBool) - verifyOutput(token, "visitBoolean", token._astType == "AstExprConstantBool") + verifyOutput(token, "visitBoolean", token._astType == "CstExprConstantBool") return true end typeAnnotationVisitor.visitExprConstantNumber = function(token: luau.AstExprConstantNumber) - verifyOutput(token, "visitNumber", token._astType == "AstExprConstantNumber") + verifyOutput(token, "visitNumber", token._astType == "CstExprConstantNumber") return true end typeAnnotationVisitor.visitStatBlock = function(block: luau.AstStatBlock) - verifyOutput(block, "visitBlock", block._astType == "AstStatBlock") + verifyOutput(block, "visitBlock", block._astType == "CstStatBlock") return true end typeAnnotationVisitor.visitStatAssign = function(node: luau.AstStatAssign) - verifyOutput(node, "visitAssign", node._astType == "AstStatAssign") + verifyOutput(node, "visitAssign", node._astType == "CstStatAssign") return true end typeAnnotationVisitor.visitStatCompoundAssign = function(node: luau.AstStatCompoundAssign) - verifyOutput(node, "visitCompoundAssign", node._astType == "AstStatCompoundAssign") + verifyOutput(node, "visitCompoundAssign", node._astType == "CstStatCompoundAssign") return true end typeAnnotationVisitor.visitExprCall = function(node: luau.AstExprCall) - verifyOutput(node, "visitCall", node._astType == "AstExprCall") + verifyOutput(node, "visitCall", node._astType == "CstExprCall") return true end typeAnnotationVisitor.visitStatLocalFunction = function(node: luau.AstStatLocalFunction) - verifyOutput(node, "visitLocalFunction", node._astType == "AstStatLocalFunction") + verifyOutput(node, "visitLocalFunction", node._astType == "CstStatLocalFunction") return true end typeAnnotationVisitor.visitExprIfElse = function(node: luau.AstExprIfElse) - verifyOutput(node, "visitIfExpression", node._astType == "AstExprIfElse") + verifyOutput(node, "visitIfExpression", node._astType == "CstExprIfElse") return true end typeAnnotationVisitor.visitStatIf = function(node: luau.AstStatIf) - verifyOutput(node, "visitIf", node._astType == "AstStatIf") + verifyOutput(node, "visitIf", node._astType == "CstStatIf") return true end -- Add more visitors for comprehensive coverage typeAnnotationVisitor.visitLocal = function(node: luau.AstStatLocal) - verifyOutput(node, "visitLocal", node._astType == "AstStatLocal") + verifyOutput(node, "visitLocal", node._astType == "CstStatLocal") return true end typeAnnotationVisitor.visitStatFunction = function(node: luau.AstStatFunction) - verifyOutput(node, "visitFunction", node._astType == "AstStatFunction") + verifyOutput(node, "visitFunction", node._astType == "CstStatFunction") return true end typeAnnotationVisitor.visitExprFunction = function(node: luau.AstExprFunction) - verifyOutput(node, "visitExprFunction", node._astType == "AstExprFunction") + verifyOutput(node, "visitExprFunction", node._astType == "CstExprFunction") return true end typeAnnotationVisitor.visitStatReturn = function(node: luau.AstStatReturn) - verifyOutput(node, "visitReturn", node._astType == "AstStatReturn") + verifyOutput(node, "visitReturn", node._astType == "CstStatReturn") return true end typeAnnotationVisitor.visitStatBreak = function(node: luau.AstStatBreak) - verifyOutput(node, "visitBreak", node._astType == "AstStatBreak") + verifyOutput(node, "visitBreak", node._astType == "CstStatBreak") return true end typeAnnotationVisitor.visitStatContinue = function(node: luau.AstStatContinue) - verifyOutput(node, "visitContinue", node._astType == "AstStatContinue") + verifyOutput(node, "visitContinue", node._astType == "CstStatContinue") return true end typeAnnotationVisitor.visitStatWhile = function(node: luau.AstStatWhile) - verifyOutput(node, "visitWhile", node._astType == "AstStatWhile") + verifyOutput(node, "visitWhile", node._astType == "CstStatWhile") return true end typeAnnotationVisitor.visitStatRepeat = function(node: luau.AstStatRepeat) - verifyOutput(node, "visitRepeat", node._astType == "AstStatRepeat") + verifyOutput(node, "visitRepeat", node._astType == "CstStatRepeat") return true end typeAnnotationVisitor.visitStatFor = function(node: luau.AstStatFor) - verifyOutput(node, "visitFor", node._astType == "AstStatFor") + verifyOutput(node, "visitFor", node._astType == "CstStatFor") return true end typeAnnotationVisitor.visitStatDo = function(node: luau.AstStatDo) verifyOutput(node, "visitDo", function(node) - print("verifyinf do block") - return node._astType == "AstStatDo" and node.body._astType == "AstStatBlock" + return node._astType == "CstStatDo" and node.body._astType == "CstStatBlock" end) return true end typeAnnotationVisitor.visitStatForIn = function(node: luau.AstStatForIn) - verifyOutput(node, "visitForIn", node._astType == "AstStatForIn") + verifyOutput(node, "visitForIn", node._astType == "CstStatForIn") return true end -- Expression visitors typeAnnotationVisitor.visitExprGroup = function(node: luau.AstExprGroup) - verifyOutput(node, "visitGroup", node._astType == "AstExprGroup") + verifyOutput(node, "visitGroup", node._astType == "CstExprGroup") return true end typeAnnotationVisitor.visitConstantNil = function(node: luau.AstExprConstantNil) - verifyOutput(node, "visitConstantNil", node._astType == "AstExprConstantNil") + verifyOutput(node, "visitConstantNil", node._astType == "CstExprConstantNil") return true end typeAnnotationVisitor.visitExprVarargs = function(node: luau.AstExprVarargs) - verifyOutput(node, "visitVarargs", node._astType == "AstExprVarargs") + verifyOutput(node, "visitVarargs", node._astType == "CstExprVarargs") return true end typeAnnotationVisitor.visitExprGlobal = function(node: luau.AstExprGlobal) - verifyOutput(node, "visitGlobal", node._astType == "AstExprGlobal") + verifyOutput(node, "visitGlobal", node._astType == "CstExprGlobal") return true end typeAnnotationVisitor.visitLocal = function(node: luau.AstLocal) - verifyOutput(node, "visitLocal", node._astType == "AstLocal") + verifyOutput(node, "visitLocal", node._astType == "CstLocal") return true end typeAnnotationVisitor.visitExprIndexName = function(node: luau.AstExprIndexName) - verifyOutput(node, "visitIndexName", node._astType == "AstExprIndexName") + verifyOutput(node, "visitIndexName", node._astType == "CstExprIndexName") return true end typeAnnotationVisitor.visitExprIndexExpr = function(node: luau.AstExprIndexExpr) - verifyOutput(node, "visitIndexExpr", node._astType == "AstExprIndexExpr") + verifyOutput(node, "visitIndexExpr", node._astType == "CstExprIndexExpr") return true end typeAnnotationVisitor.visitExprUnary = function(node: luau.AstExprUnary) - verifyOutput(node, "visitUnary", node._astType == "AstExprUnary") + verifyOutput(node, "visitUnary", node._astType == "CstExprUnary") return true end typeAnnotationVisitor.visitExprBinary = function(node: luau.AstExprBinary) - verifyOutput(node, "visitBinary", node._astType == "AstExprBinary") + verifyOutput(node, "visitBinary", node._astType == "CstExprBinary") return true end typeAnnotationVisitor.visitExprTypeAssertion = function(node: luau.AstExprTypeAssertion) - verifyOutput(node, "visitTypeAssertion", node._astType == "AstExprTypeAssertion") + verifyOutput(node, "visitTypeAssertion", node._astType == "CstExprTypeAssertion") return true end typeAnnotationVisitor.visitExprTable = function(node: luau.AstExprTable) - verifyOutput(node, "visitTable", node._astType == "AstExprTable") + verifyOutput(node, "visitTable", node._astType == "CstExprTable") return true end typeAnnotationVisitor.visitExprInstantiate = function(node: luau.AstExprInstantiate) - verifyOutput(node, "visitExprInstantiate", node._astType == "AstExprInstantiate") + verifyOutput(node, "visitExprInstantiate", node._astType == "CstExprInstantiate") return true end -- Type visitors typeAnnotationVisitor.visitTypeReference = function(node: luau.AstTypeReference) - verifyOutput(node, "visitTypeReference", node._astType == "AstTypeReference") + verifyOutput(node, "visitTypeReference", node._astType == "CstTypeReference") return true end typeAnnotationVisitor.visitTypeTable = function(node: luau.AstTypeTable) - verifyOutput(node, "visitTypeTable", node._astType == "AstTypeTable") + verifyOutput(node, "visitTypeTable", node._astType == "CstTypeTable") return true end typeAnnotationVisitor.visitTypeFunction = function(node: luau.AstTypeFunction) - verifyOutput(node, "visitTypeFunction", node._astType == "AstTypeFunction") + verifyOutput(node, "visitTypeFunction", node._astType == "CstTypeFunction") return true end typeAnnotationVisitor.visitTypeTypeof = function(node: luau.AstTypeTypeof) - verifyOutput(node, "visitTypeTypeof", node._astType == "AstTypeTypeof") + verifyOutput(node, "visitTypeTypeof", node._astType == "CstTypeTypeof") return true end typeAnnotationVisitor.visitTypeUnion = function(node: luau.AstTypeUnion) - verifyOutput(node, "visitTypeUnion", node._astType == "AstTypeUnion") + verifyOutput(node, "visitTypeUnion", node._astType == "CstTypeUnion") return true end typeAnnotationVisitor.visitTypeIntersection = function(node: luau.AstTypeIntersection) - verifyOutput(node, "visitTypeIntersection", node._astType == "AstTypeIntersection") + verifyOutput(node, "visitTypeIntersection", node._astType == "CstTypeIntersection") return true end typeAnnotationVisitor.visitTypeError = function(node: luau.AstTypeError) - verifyOutput(node, "visitTypeError", node._astType == "AstTypeError") + verifyOutput(node, "visitTypeError", node._astType == "CstTypeError") return true end typeAnnotationVisitor.visitTypeSingletonBool = function(node: luau.AstTypeSingletonBool) - verifyOutput(node, "visitTypeSingletonBool", node._astType == "AstTypeSingletonBool") + verifyOutput(node, "visitTypeSingletonBool", node._astType == "CstTypeSingletonBool") return true end typeAnnotationVisitor.visitTypeSingletonString = function(node: luau.AstTypeSingletonString) - verifyOutput(node, "visitTypeSingletonString", node._astType == "AstTypeSingletonString") + verifyOutput(node, "visitTypeSingletonString", node._astType == "CstTypeSingletonString") return true end typeAnnotationVisitor.visitTypeOptional = function(node: luau.AstTypeOptional) - verifyOutput(node, "visitTypeOptional", node._astType == "AstTypeOptional") + verifyOutput(node, "visitTypeOptional", node._astType == "CstTypeOptional") return true end -- Type alias and generic visitors typeAnnotationVisitor.visitStatTypeAlias = function(node: luau.AstStatTypeAlias) - verifyOutput(node, "visitStatTypeAlias", node._astType == "AstStatTypeAlias") + verifyOutput(node, "visitStatTypeAlias", node._astType == "CstStatTypeAlias") return true end typeAnnotationVisitor.visitTypePackGeneric = function(node: luau.AstGenericTypePack) - verifyOutput(node, "visitTypePackGeneric", node._astType == "AstGenericTypePack") + verifyOutput(node, "visitTypePackGeneric", node._astType == "CstGenericTypePack") return true end -- Type pack visitors typeAnnotationVisitor.visitTypePackExplicit = function(node: luau.AstTypePackExplicit) - verifyOutput(node, "visitTypePackExplicit", node._astType == "AstTypePackExplicit") + verifyOutput(node, "visitTypePackExplicit", node._astType == "CstTypePackExplicit") return true end typeAnnotationVisitor.visitTypePackVariadic = function(node: luau.AstTypePackVariadic) - verifyOutput(node, "visitTypePackVariadic", node._astType == "AstTypePackVariadic") + verifyOutput(node, "visitTypePackVariadic", node._astType == "CstTypePackVariadic") return true end typeAnnotationVisitor.visitTypePackGeneric = function(node: luau.AstTypePackGeneric) - verifyOutput(node, "visitTypePackGeneric", node._astType == "AstTypePackGeneric") + verifyOutput(node, "visitTypePackGeneric", node._astType == "CstTypePackGeneric") return true end --- Table type property visitors - --- Function type parameter visitors - function printTable(indent, tbl) for k, v in pairs(tbl) do if typeof(v) == "table" then @@ -314,42 +305,41 @@ local testSrc = table.concat(e2ecases, "\n") local ambiguousTagTestCases = { -- {nodeTable, expectedType, description} - { { tag = "conditional", kind = "stat", endkeyword = {} }, "AstStatIf", "if statement" }, - { { tag = "conditional", kind = "expr" }, "AstExprIfElse", "if expression" }, - { { tag = "function", kind = "type", returnarrow = {} }, "AstTypeFunction", "type function" }, - { { tag = "function", kind = "stat", name = {} }, "AstStatFunction", "function statement" }, - { { tag = "function", kind = "expr" }, "AstExprFunction", "expression function" }, - { { tag = "group", kind = "expr", expression = {} }, "AstExprGroup", "expression group" }, - { { tag = "group", kind = "type", type = {} }, "AstTypeGroup", "type group" }, - { { tag = "local", kind = "expr", token = {}, upvalue = false }, "AstExprLocal", "local expression" }, - { { tag = "local", kind = "stat", localkeyword = {}, variables = {} }, "AstStatLocal", "local statement" }, - { { tag = "generic", kind = "typepack", ellipsis = {} }, "AstTypePackGeneric", "generic type pack" }, - { { tag = "generic" }, "AstGenericType", "generic type" }, + { { tag = "conditional", kind = "stat", endKeyword = {} }, "CstStatIf", "if statement" }, + { { tag = "conditional", kind = "expr" }, "CstExprIfElse", "if expression" }, + { { tag = "function", kind = "type", returnSpecifier = {} }, "CstTypeFunction", "type function" }, + { { tag = "function", kind = "stat", name = {} }, "CstStatFunction", "function statement" }, + { { tag = "function", kind = "expr" }, "CstExprFunction", "expression function" }, + { { tag = "group", kind = "expr", expression = {} }, "CstExprGroup", "expression group" }, + { { tag = "group", kind = "type", type = {} }, "CstTypeGroup", "type group" }, + { { tag = "local", kind = "expr", token = {}, upvalue = false }, "CstExprLocal", "local expression" }, + { { tag = "local", kind = "stat", localKeyword = {}, variables = {} }, "CstStatLocal", "local statement" }, + { { tag = "generic", kind = "typepack", ellipsis = {} }, "CstTypePackGeneric", "generic type pack" }, + { { tag = "generic" }, "CstGenericType", "generic type" }, } local ambiguousKeyTestCases = { -- {key, node, parent, expectedType, description} - { "body", { functionkeyword = {}, openparens = {} }, {}, "AstExprFunction", "function body (AstStatTypeFunction)" }, - { "body", { statements = {} }, { tag = "if" }, "AstStatBlock", "if body" }, - { "operand", { tag = "call" }, { operator = {}, tag = "unary" }, "AstExpr", "unary operand" }, - { "self", {}, {}, "AstLocal", "self parameter" }, + { "body", { functionKeyword = {}, openParens = {} }, {}, "CstExprFunction", "function body (CstStatTypeFunction)" }, + { "body", { statements = {} }, { tag = "if" }, "CstStatBlock", "if body" }, + { "operand", { tag = "call" }, { operator = {}, tag = "unary" }, "CstExpr", "unary operand" }, + { "self", {}, {}, "CstLocal", "self parameter" }, { "self", {}, { tag = "call" }, "boolean", "no self parameter" }, - { "condition", { tag = "binary" }, {}, "AstExpr", "condition expression" }, - { "expression", { tag = "call" }, {}, "AstExpr", "expression" }, - { "func", { tag = "function" }, {}, "AstExprFunction", "function expression" }, - { "key", {}, { kind = "record", istableitem = true }, "Token", "record key" }, - { "key", {}, { kind = "indexer" }, "AstType", "indexer key" }, - { "key", {}, { kind = "general", istableitem = true }, "AstExpr", "general key" }, - { "key", {}, { kind = "stringproperty" }, "AstTypeSingletonString", "string property key" }, + { "condition", { tag = "binary" }, {}, "CstExpr", "condition expression" }, + { "expression", { tag = "call" }, {}, "CstExpr", "expression" }, + { "func", { tag = "function" }, {}, "CstExprFunction", "function expression" }, + { "key", {}, { kind = "record", isTableItem = true }, "Token", "record key" }, + { "key", {}, { kind = "indexer" }, "CstType", "indexer key" }, + { "key", {}, { kind = "general", isTableItem = true }, "CstExpr", "general key" }, + { "key", {}, { kind = "stringproperty" }, "CstTypeSingletonString", "string property key" }, { "key", {}, { kind = "property" }, "Token", "property key" }, - -- we should focus on the most ambiguous case - { "value", {}, { colon = {} }, "AstType", "type value" }, - { "value", {}, { istableitem = true }, "AstExpr", "expression value" }, + { "value", {}, { colon = {} }, "CstType", "type value" }, + { "value", {}, { isTableItem = true }, "CstExpr", "expression value" }, { "value", {}, { tag = "boolean" }, "boolean", "boolean value" }, { "value", {}, { tag = "number" }, "number", "number value" }, - { "name", { text = "x", istoken = true }, {}, "Token", "token name" }, - { "name", { kind = "local", name = {} }, {}, "AstLocal", "local name" }, - { "name", {}, {}, "AstExpr", "expr name" }, + { "name", { text = "x", kind = "token" }, {}, "Token", "token name" }, + { "name", { kind = "local", name = {} }, {}, "CstLocal", "local name" }, + { "name", {}, {}, "CstExpr", "expr name" }, } return { diff --git a/lua_tests/printASTNode.spec.lua b/lua_tests/printASTNode.spec.lua index 660ffab..99e6c84 100644 --- a/lua_tests/printASTNode.spec.lua +++ b/lua_tests/printASTNode.spec.lua @@ -109,9 +109,7 @@ local function test_real_ast_integration() -- Test with valid Luau code that produces various AST structures local validCases = helpers.testCases.e2eCases for _, code in ipairs(validCases) do - local parseSuccess, ast = pcall(function() - return parser.parseblock(code) - end) + local parseSuccess, ast = pcall(parser.parseBlock, code) if parseSuccess and ast then -- Only test printing if parsing succeeded diff --git a/lua_tests/typeAnnotations.spec.lua b/lua_tests/typeAnnotations.spec.lua index 8e005d1..ae4d38e 100644 --- a/lua_tests/typeAnnotations.spec.lua +++ b/lua_tests/typeAnnotations.spec.lua @@ -8,7 +8,7 @@ local typeAnnotationHelpers = require("./helpers/typeAnnotationTestHelpers") local function annotateWithType_test() -- parse and annotate src code snippet (with large coverage of syntax constructs) - local testAST = annotateWithType(parser.parseblock(typeAnnotationHelpers.testSrc) :: any) + local testAST = annotateWithType(parser.parseBlock(typeAnnotationHelpers.testSrc) :: any) -- visit annotated tree to check for correct type assignment (using typeAnnotationVisitor) local typeAnnotationChecker = typeAnnotationHelpers.typeAnnotationVisitor visitor.visit(testAST, typeAnnotationChecker) From 168266c597c1389e02413daa3d001629ce24f733 Mon Sep 17 00:00:00 2001 From: Wyatt McCarthy Date: Tue, 16 Jun 2026 13:09:22 -0700 Subject: [PATCH 3/4] perfect alignment w/ CST types --- frontend/src/tests/TreeNode.test.tsx | 37 +- frontend/src/tests/astTypeHelpers.test.ts | 76 +-- frontend/src/utils/astTypeDefinitions.ts | 621 ++++++------------ frontend/src/utils/astTypeHelpers.ts | 35 +- lua_helpers/json.lua | 55 +- lua_helpers/temp_vendor/lutePrinter.luau | 33 +- lua_helpers/typeAnnotations.lua | 6 +- .../helpers/typeAnnotationTestHelpers.lua | 2 +- 8 files changed, 312 insertions(+), 553 deletions(-) diff --git a/frontend/src/tests/TreeNode.test.tsx b/frontend/src/tests/TreeNode.test.tsx index 3f9c600..31b87a9 100644 --- a/frontend/src/tests/TreeNode.test.tsx +++ b/frontend/src/tests/TreeNode.test.tsx @@ -233,7 +233,7 @@ describe("TreeNode", () => { const nodeQuery = getQueryableNode("root.name", "nodeHeader"); expect(nodeQuery).toBeDefined(); // Should infer from _testType that name property is of Token type - expect(nodeQuery.getByText(/type: Token/)).toBeInTheDocument(); + expect(nodeQuery.getByText(/type: CstToken/)).toBeInTheDocument(); }); test("infers types for array items from parent property definition", () => { @@ -291,7 +291,7 @@ describe("TreeNode", () => { describe("removed node handling", () => { test("correctly resolves types for removed keys", () => { const functionWithRemovedName = { - _astType: "Token", + _astType: "CstToken", ...mockTypelessToken("test"), removedName: mockTypelessToken("oldGlobalName", "removed"), // This was removed childChanges: { @@ -302,7 +302,7 @@ describe("TreeNode", () => { _astType: { type: "UPDATE", oldValue: "_testType", - value: "Token", + value: "CstToken", }, }, }; @@ -323,12 +323,12 @@ describe("TreeNode", () => { expect(removedNode.getByText("-")).toBeInTheDocument(); // The removed property should still be rendered and get proper type tooltip (inferred from parent of _testType) expect(removedNode.getByText(/removedName/)).toBeInTheDocument(); - expect(removedNode.getByText(/type: Token/)).toBeInTheDocument; + expect(removedNode.getByText(/type: CstToken/)).toBeInTheDocument; // also want to verify that root has before->after type annotation display const rootNodeHeader = getQueryableNode("root", "nodeHeader"); expect(rootNodeHeader.getByText(/type: _testType/)).toBeInTheDocument(); expect(rootNodeHeader.getByText("→")).toBeInTheDocument(); - expect(rootNodeHeader.getByText(/type: Token/)).toBeInTheDocument(); + expect(rootNodeHeader.getByText(/type: CstToken/)).toBeInTheDocument(); }); }); @@ -397,34 +397,27 @@ describe("TreeNode", () => { }); describe("array type inference edge cases", () => { - test("handles punctuated arrays", () => { - const punctuatedNode = { + test("handles punctuated parameters", () => { + const functionNode = { _astType: "CstExprFunction", - parameters: [ - // Use proper Punctuated structures - { - node: { name: mockTypelessToken("param1") }, - separator: mockTypelessToken(","), - }, - { - node: { name: mockTypelessToken("param2") }, - }, - ], + parameters: { + "1": { name: mockTypelessToken("param1") }, + "2": { name: mockTypelessToken("param2") }, + separators: [mockTypelessToken(",")], + }, }; render( - + ); - // Should handle punctuated structure correctly + // Parameters should be inferred as CstPunctuated const parametersNode = getQueryableNode("root.parameters", "nodeHeader"); expect( - parametersNode.getByText(/type: Punctuated/) + parametersNode.getByText(/type: CstPunctuated/) ).toBeInTheDocument(); - const param1Node = getQueryableNode("root.parameters.0", "nodeHeader"); - expect(param1Node.getByText(/type: Pair/)).toBeInTheDocument(); }); }); diff --git a/frontend/src/tests/astTypeHelpers.test.ts b/frontend/src/tests/astTypeHelpers.test.ts index 1b31aac..b5adc07 100644 --- a/frontend/src/tests/astTypeHelpers.test.ts +++ b/frontend/src/tests/astTypeHelpers.test.ts @@ -9,7 +9,6 @@ import { } from "../utils/astTypeHelpers"; import { GenericTypeDefinition, - PropertyDefinition, astTypeDefinitions, } from "../utils/astTypeDefinitions"; @@ -33,23 +32,20 @@ describe("astTypeHelpers", () => { "general", ]); + expect(getArrayType("separators")).toEqual(["{ CstToken }", ""]); + expect(getArrayType("invalidType")).toEqual([undefined, ""]); }); test("parseGenericType", () => { - expect(parseGenericType("Pair")).toEqual({ - baseType: "Pair", - genericType: "CstExpr", - }); - - expect(parseGenericType("Punctuated")).toEqual({ - baseType: "Punctuated", + expect(parseGenericType("CstPunctuated")).toEqual({ + baseType: "CstPunctuated", genericType: "CstExpr", }); - expect(parseGenericType('Pair')).toEqual({ - baseType: "Pair", - genericType: 'CstExpr, "&"', + expect(parseGenericType('CstPunctuated')).toEqual({ + baseType: "CstPunctuated", + genericType: 'CstType, "|"', }); expect(parseGenericType("CstLocal")).toEqual(undefined); @@ -57,46 +53,34 @@ describe("astTypeHelpers", () => { expect(parseGenericType("randomType")).toEqual(undefined); }); - test("getGenericASTTypeDefinition e2e", () => { + test("getGenericASTTypeDefinition for CstPunctuated", () => { const punctuatedType = parseGenericType( - "Punctuated" + "CstPunctuated" ) as GenericTypeDefinition; - const punctuatedDefinition = getGenericASTTypeDefinition(punctuatedType); + const definition = getGenericASTTypeDefinition(punctuatedType); - expect(punctuatedDefinition).toEqual({ - properties: [{ name: "", type: "{ Pair }" }], + expect(definition).toEqual({ + properties: [ + { name: "", type: "{ CstExpr }" }, + { name: "separators", type: "{ CstToken }" }, + ], }); - const pairType = ( - punctuatedDefinition.properties as PropertyDefinition[] - )[0].type; - - expect(typeof pairType).toBe("string"); - - const pairTypeGenericDefinition = parseGenericType( - unpackArrayType(pairType as string) - ); - - expect(pairTypeGenericDefinition).toBeDefined(); - const pairTypeDefinition = getGenericASTTypeDefinition( - pairTypeGenericDefinition as GenericTypeDefinition - ); + // With separator type specified + const unionPunctuated = parseGenericType( + 'CstPunctuated' + ) as GenericTypeDefinition; + const unionDef = getGenericASTTypeDefinition(unionPunctuated); - expect(pairTypeDefinition).toEqual({ + expect(unionDef).toEqual({ properties: [ - { name: "node", type: "CstExpr" }, - { - name: "separator", - type: "Token<'&'>", - optional: true, - }, + { name: "", type: "{ CstType }" }, + { name: "separators", type: "{ CstToken }" }, ], }); }); test("getTypeString", () => { - // test 3 cases: - // respect existing _astType value expect(getTypeString({ _astType: "CstStatBlock" }, "block")).toEqual([ "CstStatBlock", @@ -121,23 +105,19 @@ describe("astTypeHelpers", () => { astTypeDefinitions["CstLocal"], false, ]); - + // test array/table type expect(getType("{ CstLocal }")).toEqual([ astTypeDefinitions["CstLocal"], true, ]); - // test generic type - expect(getType("Pair")).toEqual([ + // test CstPunctuated generic type + expect(getType("CstPunctuated")).toEqual([ { properties: [ - { name: "node", type: "CstExpr" }, - { - name: "separator", - type: "Token<'&'>", - optional: true, - }, + { name: "", type: "{ CstExpr }" }, + { name: "separators", type: "{ CstToken }" }, ], }, false, diff --git a/frontend/src/utils/astTypeDefinitions.ts b/frontend/src/utils/astTypeDefinitions.ts index 809b02b..1103757 100644 --- a/frontend/src/utils/astTypeDefinitions.ts +++ b/frontend/src/utils/astTypeDefinitions.ts @@ -1,15 +1,15 @@ export interface PropertyDefinition { name: string; - type: string | string[]; // string[] for unions like "true" | "false" + type: string | string[]; optional?: boolean; - generic?: string; // for Token<"specific"> types + generic?: string; } export interface ASTTypeDefinition { properties?: PropertyDefinition[]; kinds?: Record; - baseType?: string; // for intersections like "Token &" - unionMembers?: string[]; // for "CstExpr = A | B | C" + baseType?: string; + unionMembers?: string[]; } export interface GenericTypeDefinition { @@ -28,6 +28,7 @@ export interface TypeMetadata { prevKind: string; } +// Aligned with ~/.lute/typedefs/1.0.1/lute/syntax/cst.luau export const astTypeDefinitions: Record = { // === UTILITY TYPES === span: { @@ -67,7 +68,7 @@ export const astTypeDefinitions: Record = { unionMembers: ["Whitespace", "SingleLineComment", "MultiLineComment"], }, - Token: { + CstToken: { properties: [ { name: "leadingTrivia", type: "{ Trivia }" }, { name: "location", type: "span" }, @@ -77,31 +78,24 @@ export const astTypeDefinitions: Record = { ], }, - Eof: { - baseType: "Token", - properties: [ - { name: "tag", type: '"eof"' }, - { name: "text", type: '""' }, - ], + CstEof: { + baseType: "CstToken", + properties: [{ name: "tag", type: '"eof"' }], }, - Pair: { + CstPunctuated: { properties: [ - { name: "node", type: "any" }, - { name: "separator", type: "Token", optional: true }, + { name: "", type: "{ T }" }, + { name: "separators", type: "{ CstToken }" }, ], }, - Punctuated: { - properties: [{ name: "pairs", type: "{ Pair }" }], - }, - CstLocal: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"local"' }, - { name: "name", type: "Token", generic: "Token" }, - { name: "colon", type: "Token", generic: 'Token<":">', optional: true }, + { name: "name", type: "CstToken" }, + { name: "colon", type: "CstToken", optional: true }, { name: "annotation", type: "CstType", optional: true }, { name: "shadows", type: "CstLocal", optional: true }, ], @@ -111,54 +105,61 @@ export const astTypeDefinitions: Record = { CstExprGroup: { properties: [ { name: "location", type: "span" }, + { name: "kind", type: '"expr"' }, { name: "tag", type: '"group"' }, - { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "openParens", type: "CstToken" }, { name: "expression", type: "CstExpr" }, - { name: "closeParens", type: "Token", generic: 'Token<")">' }, + { name: "closeParens", type: "CstToken" }, ], }, CstExprConstantNil: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"nil"' }, - { name: "text", type: '"nil"' }, + { name: "token", type: "CstToken" }, ], }, CstExprConstantBool: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"boolean"' }, - { name: "text", type: ["true", "false"] }, { name: "value", type: "boolean" }, + { name: "token", type: "CstToken" }, ], }, CstExprConstantNumber: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"number"' }, - { name: "text", type: "string" }, { name: "value", type: "number" }, + { name: "token", type: "CstToken" }, + ], + }, + + CstExprConstantInteger: { + properties: [ + { name: "location", type: "span" }, + { name: "kind", type: '"expr"' }, + { name: "tag", type: '"integer"' }, + { name: "value", type: "number" }, + { name: "token", type: "CstToken" }, ], }, CstExprConstantString: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"string"' }, - { name: "text", type: "string" }, { name: "quoteStyle", type: ["single", "double", "block", "interp"] }, { name: "blockDepth", type: "number" }, + { name: "value", type: "CstToken" }, ], }, @@ -167,7 +168,7 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"local"' }, - { name: "token", type: "Token", generic: "Token" }, + { name: "token", type: "CstToken" }, { name: "local", type: "CstLocal" }, { name: "upvalue", type: "boolean" }, ], @@ -178,17 +179,16 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"global"' }, - { name: "name", type: "Token" }, + { name: "name", type: "CstToken" }, ], }, CstExprVarargs: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"vararg"' }, - { name: "text", type: '"..."' }, + { name: "token", type: "CstToken" }, ], }, @@ -198,19 +198,9 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"call"' }, { name: "func", type: "CstExpr" }, - { - name: "openParens", - type: "Token", - generic: 'Token<"(">', - optional: true, - }, - { name: "arguments", type: "Punctuated", generic: "Punctuated" }, - { - name: "closeParens", - type: "Token", - generic: 'Token<")">', - optional: true, - }, + { name: "openParens", type: "CstToken", optional: true }, + { name: "arguments", type: "CstPunctuated" }, + { name: "closeParens", type: "CstToken", optional: true }, { name: "self", type: "boolean" }, { name: "argLocation", type: "span" }, ], @@ -222,15 +212,11 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"instantiate"' }, { name: "expr", type: "CstExpr" }, - { name: "leftArrow1", type: "Token", generic: 'Token<"<">' }, - { name: "leftArrow2", type: "Token", generic: 'Token<"<">' }, - { - name: "typeArguments", - type: "Punctuated", - generic: "Punctuated", - }, - { name: "rightArrow1", type: "Token", generic: 'Token<">">' }, - { name: "rightArrow2", type: "Token", generic: 'Token<">">' }, + { name: "leftArrow1", type: "CstToken" }, + { name: "leftArrow2", type: "CstToken" }, + { name: "typeArguments", type: "CstPunctuated" }, + { name: "rightArrow1", type: "CstToken" }, + { name: "rightArrow2", type: "CstToken" }, ], }, @@ -240,8 +226,8 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"indexname"' }, { name: "expression", type: "CstExpr" }, - { name: "accessor", type: "Token", generic: 'Token<"." | ":">' }, - { name: "index", type: "Token", generic: "Token" }, + { name: "accessor", type: "CstToken" }, + { name: "index", type: "CstToken" }, { name: "indexLocation", type: "span" }, ], }, @@ -252,9 +238,9 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"index"' }, { name: "expression", type: "CstExpr" }, - { name: "openBrackets", type: "Token", generic: 'Token<"[">' }, + { name: "openBrackets", type: "CstToken" }, { name: "index", type: "CstExpr" }, - { name: "closeBrackets", type: "Token", generic: 'Token<"]">' }, + { name: "closeBrackets", type: "CstToken" }, ], }, @@ -264,61 +250,22 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"function"' }, { name: "attributes", type: "{ CstAttribute }" }, - { name: "functionKeyword", type: "Token", generic: 'Token<"function">' }, - { - name: "openGenerics", - type: "Token", - generic: 'Token<"<">', - optional: true, - }, - { - name: "generics", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "genericPacks", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "closeGenerics", - type: "Token", - generic: 'Token<">">', - optional: true, - }, - { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "functionKeyword", type: "CstToken" }, + { name: "openGenerics", type: "CstToken", optional: true }, + { name: "generics", type: "CstPunctuated", optional: true }, + { name: "genericPacks", type: "CstPunctuated", optional: true }, + { name: "closeGenerics", type: "CstToken", optional: true }, + { name: "openParens", type: "CstToken" }, { name: "self", type: "CstLocal", optional: true }, - { - name: "parameters", - type: "Punctuated", - generic: "Punctuated", - }, - { - name: "vararg", - type: "Token", - generic: 'Token<"...">', - optional: true, - }, - { - name: "varargColon", - type: "Token", - generic: 'Token<":">', - optional: true, - }, + { name: "parameters", type: "CstPunctuated" }, + { name: "vararg", type: "CstToken", optional: true }, + { name: "varargColon", type: "CstToken", optional: true }, { name: "varargAnnotation", type: "CstTypePack", optional: true }, - { name: "closeParens", type: "Token", generic: 'Token<")">' }, - { - name: "returnSpecifier", - type: "Token", - generic: 'Token<":">', - optional: true, - }, + { name: "closeParens", type: "CstToken" }, + { name: "returnSpecifier", type: "CstToken", optional: true }, { name: "returnAnnotation", type: "CstTypePack", optional: true }, { name: "body", type: "CstStatBlock" }, - { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, + { name: "endKeyword", type: "CstToken" }, ], }, @@ -327,12 +274,7 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"list"' }, { name: "value", type: "CstExpr" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, + { name: "separator", type: "CstToken", optional: true }, { name: "isTableItem", type: "true" }, ], }, @@ -341,15 +283,10 @@ export const astTypeDefinitions: Record = { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"record"' }, - { name: "key", type: "Token", generic: "Token" }, - { name: "equals", type: "Token", generic: 'Token<"=">' }, + { name: "key", type: "CstToken" }, + { name: "equals", type: "CstToken" }, { name: "value", type: "CstExpr" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, + { name: "separator", type: "CstToken", optional: true }, { name: "isTableItem", type: "true" }, ], }, @@ -358,17 +295,12 @@ export const astTypeDefinitions: Record = { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"general"' }, - { name: "indexerOpen", type: "Token", generic: 'Token<"[">' }, + { name: "indexerOpen", type: "CstToken" }, { name: "key", type: "CstExpr" }, - { name: "indexerClose", type: "Token", generic: 'Token<"]">' }, - { name: "equals", type: "Token", generic: 'Token<"=">' }, + { name: "indexerClose", type: "CstToken" }, + { name: "equals", type: "CstToken" }, { name: "value", type: "CstExpr" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, + { name: "separator", type: "CstToken", optional: true }, { name: "isTableItem", type: "true" }, ], }, @@ -386,9 +318,9 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"table"' }, - { name: "openBrace", type: "Token", generic: 'Token<"{">' }, + { name: "openBrace", type: "CstToken" }, { name: "entries", type: "{ CstTableExprItem }" }, - { name: "closeBrace", type: "Token", generic: 'Token<"}">' }, + { name: "closeBrace", type: "CstToken" }, ], }, @@ -397,7 +329,7 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"unary"' }, - { name: "operator", type: "Token", generic: 'Token<"not" | "-" | "#">' }, + { name: "operator", type: "CstToken" }, { name: "operand", type: "CstExpr" }, ], }, @@ -408,7 +340,7 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"binary"' }, { name: "lhsOperand", type: "CstExpr" }, - { name: "operator", type: "Token" }, + { name: "operator", type: "CstToken" }, { name: "rhsOperand", type: "CstExpr" }, ], }, @@ -418,7 +350,7 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"interpolatedstring"' }, - { name: "strings", type: "{ Token }", generic: "{ Token }" }, + { name: "strings", type: "{ CstToken }" }, { name: "expressions", type: "{ CstExpr }" }, ], }, @@ -429,16 +361,16 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"expr"' }, { name: "tag", type: '"cast"' }, { name: "operand", type: "CstExpr" }, - { name: "operator", type: "Token", generic: 'Token<"::">' }, + { name: "operator", type: "CstToken" }, { name: "annotation", type: "CstType" }, ], }, CstElseIfExpr: { properties: [ - { name: "elseIfKeyword", type: "Token", generic: 'Token<"elseif">' }, + { name: "elseIfKeyword", type: "CstToken" }, { name: "condition", type: "CstExpr" }, - { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenKeyword", type: "CstToken" }, { name: "thenExpr", type: "CstExpr" }, ], }, @@ -448,12 +380,12 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"conditional"' }, - { name: "ifKeyword", type: "Token", generic: 'Token<"if">' }, + { name: "ifKeyword", type: "CstToken" }, { name: "condition", type: "CstExpr" }, - { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenKeyword", type: "CstToken" }, { name: "thenExpr", type: "CstExpr" }, { name: "elseifs", type: "{ CstElseIfExpr }" }, - { name: "elseKeyword", type: "Token", generic: 'Token<"else">' }, + { name: "elseKeyword", type: "CstToken" }, { name: "elseExpr", type: "CstExpr" }, ], }, @@ -464,6 +396,7 @@ export const astTypeDefinitions: Record = { "CstExprConstantNil", "CstExprConstantBool", "CstExprConstantNumber", + "CstExprConstantInteger", "CstExprConstantString", "CstExprLocal", "CstExprGlobal", @@ -497,17 +430,17 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"do"' }, - { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "doKeyword", type: "CstToken" }, { name: "body", type: "CstStatBlock" }, - { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, + { name: "endKeyword", type: "CstToken" }, ], }, CstElseIfStat: { properties: [ - { name: "elseIfKeyword", type: "Token", generic: 'Token<"elseif">' }, + { name: "elseIfKeyword", type: "CstToken" }, { name: "condition", type: "CstExpr" }, - { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenKeyword", type: "CstToken" }, { name: "thenBlock", type: "CstStatBlock" }, ], }, @@ -517,19 +450,14 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"conditional"' }, - { name: "ifKeyword", type: "Token", generic: 'Token<"if">' }, + { name: "ifKeyword", type: "CstToken" }, { name: "condition", type: "CstExpr" }, - { name: "thenKeyword", type: "Token", generic: 'Token<"then">' }, + { name: "thenKeyword", type: "CstToken" }, { name: "thenBlock", type: "CstStatBlock" }, { name: "elseifs", type: "{ CstElseIfStat }" }, - { - name: "elseKeyword", - type: "Token", - generic: 'Token<"else">', - optional: true, - }, + { name: "elseKeyword", type: "CstToken", optional: true }, { name: "elseBlock", type: "CstStatBlock", optional: true }, - { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, + { name: "endKeyword", type: "CstToken" }, ], }, @@ -538,11 +466,11 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"while"' }, - { name: "whileKeyword", type: "Token", generic: 'Token<"while">' }, + { name: "whileKeyword", type: "CstToken" }, { name: "condition", type: "CstExpr" }, - { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "doKeyword", type: "CstToken" }, { name: "body", type: "CstStatBlock" }, - { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, + { name: "endKeyword", type: "CstToken" }, ], }, @@ -551,30 +479,28 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"repeat"' }, - { name: "repeatKeyword", type: "Token", generic: 'Token<"repeat">' }, + { name: "repeatKeyword", type: "CstToken" }, { name: "body", type: "CstStatBlock" }, - { name: "untilKeyword", type: "Token", generic: 'Token<"until">' }, + { name: "untilKeyword", type: "CstToken" }, { name: "condition", type: "CstExpr" }, ], }, CstStatBreak: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"break"' }, - { name: "text", type: '"break"' }, + { name: "token", type: "CstToken" }, ], }, CstStatContinue: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"continue"' }, - { name: "text", type: '"continue"' }, + { name: "token", type: "CstToken" }, ], }, @@ -583,12 +509,8 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"return"' }, - { name: "returnKeyword", type: "Token", generic: 'Token<"return">' }, - { - name: "expressions", - type: "Punctuated", - generic: "Punctuated", - }, + { name: "returnKeyword", type: "CstToken" }, + { name: "expressions", type: "CstPunctuated" }, ], }, @@ -606,14 +528,10 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"local"' }, - { name: "localKeyword", type: "Token", generic: 'Token<"local">' }, - { - name: "variables", - type: "Punctuated", - generic: "Punctuated", - }, - { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, + { name: "localKeyword", type: "CstToken" }, + { name: "variables", type: "CstPunctuated" }, + { name: "equals", type: "CstToken", optional: true }, + { name: "values", type: "CstPunctuated" }, ], }, @@ -622,14 +540,10 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"const"' }, - { name: "constKeyword", type: "Token", generic: 'Token<"const">' }, - { - name: "variables", - type: "Punctuated", - generic: "Punctuated", - }, - { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, + { name: "constKeyword", type: "CstToken" }, + { name: "variables", type: "CstPunctuated" }, + { name: "equals", type: "CstToken", optional: true }, + { name: "values", type: "CstPunctuated" }, ], }, @@ -638,22 +552,17 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"for"' }, - { name: "forKeyword", type: "Token", generic: 'Token<"for">' }, + { name: "forKeyword", type: "CstToken" }, { name: "variable", type: "CstLocal" }, - { name: "equals", type: "Token", generic: 'Token<"=">' }, + { name: "equals", type: "CstToken" }, { name: "from", type: "CstExpr" }, - { name: "toComma", type: "Token", generic: 'Token<",">' }, + { name: "toComma", type: "CstToken" }, { name: "to", type: "CstExpr" }, - { - name: "stepComma", - type: "Token", - generic: 'Token<",">', - optional: true, - }, + { name: "stepComma", type: "CstToken", optional: true }, { name: "step", type: "CstExpr", optional: true }, - { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "doKeyword", type: "CstToken" }, { name: "body", type: "CstStatBlock" }, - { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, + { name: "endKeyword", type: "CstToken" }, ], }, @@ -662,17 +571,13 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"forin"' }, - { name: "forKeyword", type: "Token", generic: 'Token<"for">' }, - { - name: "variables", - type: "Punctuated", - generic: "Punctuated", - }, - { name: "inKeyword", type: "Token", generic: 'Token<"in">' }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, - { name: "doKeyword", type: "Token", generic: 'Token<"do">' }, + { name: "forKeyword", type: "CstToken" }, + { name: "variables", type: "CstPunctuated" }, + { name: "inKeyword", type: "CstToken" }, + { name: "values", type: "CstPunctuated" }, + { name: "doKeyword", type: "CstToken" }, { name: "body", type: "CstStatBlock" }, - { name: "endKeyword", type: "Token", generic: 'Token<"end">' }, + { name: "endKeyword", type: "CstToken" }, ], }, @@ -681,9 +586,9 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"assign"' }, - { name: "variables", type: "Punctuated", generic: "Punctuated" }, - { name: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "values", type: "Punctuated", generic: "Punctuated" }, + { name: "variables", type: "CstPunctuated" }, + { name: "equals", type: "CstToken" }, + { name: "values", type: "CstPunctuated" }, ], }, @@ -693,17 +598,16 @@ export const astTypeDefinitions: Record = { { name: "kind", type: '"stat"' }, { name: "tag", type: '"compoundassign"' }, { name: "variable", type: "CstExpr" }, - { name: "operand", type: "Token" }, + { name: "operand", type: "CstToken" }, { name: "value", type: "CstExpr" }, ], }, CstAttribute: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"attribute"' }, - { name: "text", type: ["@checked", "@native", "@deprecated"] }, + { name: "name", type: "CstToken" }, ], }, @@ -722,7 +626,7 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"localfunction"' }, - { name: "localKeyword", type: "Token", generic: 'Token<"local">' }, + { name: "localKeyword", type: "CstToken" }, { name: "name", type: "CstLocal" }, { name: "func", type: "CstExprFunction" }, ], @@ -733,39 +637,14 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"typealias"' }, - { - name: "export", - type: "Token", - generic: 'Token<"export">', - optional: true, - }, - { name: "typeToken", type: "Token", generic: 'Token<"type">' }, - { name: "name", type: "Token" }, - { - name: "openGenerics", - type: "Token", - generic: 'Token<"<">', - optional: true, - }, - { - name: "generics", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "genericPacks", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "closeGenerics", - type: "Token", - generic: 'Token<">">', - optional: true, - }, - { name: "equals", type: "Token", generic: 'Token<"=">' }, + { name: "export", type: "CstToken", optional: true }, + { name: "typeToken", type: "CstToken" }, + { name: "name", type: "CstToken" }, + { name: "openGenerics", type: "CstToken", optional: true }, + { name: "generics", type: "CstPunctuated", optional: true }, + { name: "genericPacks", type: "CstPunctuated", optional: true }, + { name: "closeGenerics", type: "CstToken", optional: true }, + { name: "equals", type: "CstToken" }, { name: "type", type: "CstType" }, ], }, @@ -775,14 +654,9 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"typefunction"' }, - { - name: "export", - type: "Token", - generic: 'Token<"export">', - optional: true, - }, - { name: "type", type: "Token", generic: 'Token<"type">' }, - { name: "name", type: "Token" }, + { name: "export", type: "CstToken", optional: true }, + { name: "type", type: "CstToken" }, + { name: "name", type: "CstToken" }, { name: "body", type: "CstExprFunction" }, ], }, @@ -815,8 +689,8 @@ export const astTypeDefinitions: Record = { CstGenericType: { properties: [ { name: "tag", type: '"generic"' }, - { name: "name", type: "Token", generic: "Token" }, - { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, + { name: "name", type: "CstToken" }, + { name: "equals", type: "CstToken", optional: true }, { name: "default", type: "CstType", optional: true }, ], }, @@ -824,9 +698,9 @@ export const astTypeDefinitions: Record = { CstGenericTypePack: { properties: [ { name: "tag", type: '"genericpack"' }, - { name: "name", type: "Token", generic: "Token" }, - { name: "ellipsis", type: "Token", generic: 'Token<"...">' }, - { name: "equals", type: "Token", generic: 'Token<"=">', optional: true }, + { name: "name", type: "CstToken" }, + { name: "ellipsis", type: "CstToken" }, + { name: "equals", type: "CstToken", optional: true }, { name: "default", type: "CstTypePack", optional: true }, ], }, @@ -837,59 +711,32 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"reference"' }, - { - name: "prefix", - type: "Token", - generic: "Token", - optional: true, - }, - { - name: "prefixPoint", - type: "Token", - generic: 'Token<".">', - optional: true, - }, - { name: "name", type: "Token", generic: "Token" }, - { - name: "openParameters", - type: "Token", - generic: 'Token<"<">', - optional: true, - }, - { - name: "parameters", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "closeParameters", - type: "Token", - generic: 'Token<">">', - optional: true, - }, + { name: "prefix", type: "CstToken", optional: true }, + { name: "prefixPoint", type: "CstToken", optional: true }, + { name: "name", type: "CstToken" }, + { name: "openParameters", type: "CstToken", optional: true }, + { name: "parameters", type: "CstPunctuated", optional: true }, + { name: "closeParameters", type: "CstToken", optional: true }, ], }, CstTypeSingletonBool: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"boolean"' }, - { name: "text", type: ["true", "false"] }, { name: "value", type: "boolean" }, + { name: "token", type: "CstToken" }, ], }, CstTypeSingletonString: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"string"' }, - { name: "text", type: "string" }, { name: "quoteStyle", type: ["single", "double"] }, + { name: "value", type: "CstToken" }, ], }, @@ -898,10 +745,10 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"typeof"' }, - { name: "typeof", type: "Token", generic: 'Token<"typeof">' }, - { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "typeof", type: "CstToken" }, + { name: "openParens", type: "CstToken" }, { name: "expression", type: "CstExpr" }, - { name: "closeParens", type: "Token", generic: 'Token<")">' }, + { name: "closeParens", type: "CstToken" }, ], }, @@ -910,19 +757,18 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"group"' }, - { name: "openParens", type: "Token", generic: 'Token<"(">' }, + { name: "openParens", type: "CstToken" }, { name: "type", type: "CstType" }, - { name: "closeParens", type: "Token", generic: 'Token<")">' }, + { name: "closeParens", type: "CstToken" }, ], }, CstTypeOptional: { - baseType: "Token", properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"optional"' }, - { name: "text", type: '"?"' }, + { name: "token", type: "CstToken" }, ], }, @@ -931,12 +777,8 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"union"' }, - { name: "leading", type: "Token", generic: 'Token<"|">', optional: true }, - { - name: "types", - type: "Punctuated", - generic: 'Punctuated', - }, + { name: "leading", type: "CstToken", optional: true }, + { name: "types", type: 'CstPunctuated' }, ], }, @@ -945,12 +787,8 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"intersection"' }, - { name: "leading", type: "Token", generic: 'Token<"&">', optional: true }, - { - name: "types", - type: "Punctuated", - generic: 'Punctuated', - }, + { name: "leading", type: "CstToken", optional: true }, + { name: "types", type: 'CstPunctuated' }, ], }, @@ -959,82 +797,47 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"array"' }, - { name: "openBrace", type: "Token", generic: 'Token<"{">' }, - { - name: "access", - type: "Token", - generic: 'Token<"read" | "write">', - optional: true, - }, + { name: "openBrace", type: "CstToken" }, + { name: "access", type: "CstToken", optional: true }, { name: "type", type: "CstType" }, - { name: "closeBrace", type: "Token", generic: 'Token<"}">' }, + { name: "closeBrace", type: "CstToken" }, ], }, CstTableTypeItemIndexer: { properties: [ { name: "kind", type: '"indexer"' }, - { - name: "access", - type: "Token", - generic: 'Token<"read" | "write">', - optional: true, - }, - { name: "indexerOpen", type: "Token", generic: 'Token<"[">' }, + { name: "access", type: "CstToken", optional: true }, + { name: "indexerOpen", type: "CstToken" }, { name: "key", type: "CstType" }, - { name: "indexerClose", type: "Token", generic: 'Token<"]">' }, - { name: "colon", type: "Token", generic: 'Token<":">' }, + { name: "indexerClose", type: "CstToken" }, + { name: "colon", type: "CstToken" }, { name: "value", type: "CstType" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, + { name: "separator", type: "CstToken", optional: true }, ], }, CstTableTypeItemStringProperty: { properties: [ { name: "kind", type: '"stringproperty"' }, - { - name: "access", - type: "Token", - generic: 'Token<"read" | "write">', - optional: true, - }, - { name: "indexerOpen", type: "Token", generic: 'Token<"[">' }, + { name: "access", type: "CstToken", optional: true }, + { name: "indexerOpen", type: "CstToken" }, { name: "key", type: "CstTypeSingletonString" }, - { name: "indexerClose", type: "Token", generic: 'Token<"]">' }, - { name: "colon", type: "Token", generic: 'Token<":">' }, + { name: "indexerClose", type: "CstToken" }, + { name: "colon", type: "CstToken" }, { name: "value", type: "CstType" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, + { name: "separator", type: "CstToken", optional: true }, ], }, CstTableTypeItemProperty: { properties: [ { name: "kind", type: '"property"' }, - { - name: "access", - type: "Token", - generic: 'Token<"read" | "write">', - optional: true, - }, - { name: "key", type: "Token" }, - { name: "colon", type: "Token", generic: 'Token<":">' }, + { name: "access", type: "CstToken", optional: true }, + { name: "key", type: "CstToken" }, + { name: "colon", type: "CstToken" }, { name: "value", type: "CstType" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, + { name: "separator", type: "CstToken", optional: true }, ], }, @@ -1051,17 +854,16 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"table"' }, - { name: "openBrace", type: "Token", generic: 'Token<"{">' }, + { name: "openBrace", type: "CstToken" }, { name: "entries", type: "{ CstTableTypeItem }" }, - { name: "closeBrace", type: "Token", generic: 'Token<"}">' }, + { name: "closeBrace", type: "CstToken" }, ], }, CstFunctionTypeParameter: { properties: [ - { name: "location", type: "span" }, - { name: "name", type: "Token", optional: true }, - { name: "colon", type: "Token", generic: 'Token<":">', optional: true }, + { name: "name", type: "CstToken", optional: true }, + { name: "colon", type: "CstToken", optional: true }, { name: "type", type: "CstType" }, ], }, @@ -1071,39 +873,15 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"function"' }, - { - name: "openGenerics", - type: "Token", - generic: 'Token<"<">', - optional: true, - }, - { - name: "generics", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "genericPacks", - type: "Punctuated", - generic: "Punctuated", - optional: true, - }, - { - name: "closeGenerics", - type: "Token", - generic: 'Token<">">', - optional: true, - }, - { name: "openParens", type: "Token", generic: 'Token<"(">' }, - { - name: "parameters", - type: "Punctuated", - generic: "Punctuated", - }, + { name: "openGenerics", type: "CstToken", optional: true }, + { name: "generics", type: "CstPunctuated", optional: true }, + { name: "genericPacks", type: "CstPunctuated", optional: true }, + { name: "closeGenerics", type: "CstToken", optional: true }, + { name: "openParens", type: "CstToken" }, + { name: "parameters", type: "CstPunctuated" }, { name: "vararg", type: "CstTypePack", optional: true }, - { name: "closeParens", type: "Token", generic: 'Token<")">' }, - { name: "returnSpecifier", type: "Token", generic: 'Token<"->">' }, + { name: "closeParens", type: "CstToken" }, + { name: "returnArrow", type: "CstToken" }, { name: "returnTypes", type: "CstTypePack" }, ], }, @@ -1130,20 +908,10 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, { name: "tag", type: '"explicit"' }, - { - name: "openParens", - type: "Token", - generic: 'Token<"(">', - optional: true, - }, - { name: "types", type: "Punctuated", generic: "Punctuated" }, + { name: "openParens", type: "CstToken", optional: true }, + { name: "types", type: "CstPunctuated" }, { name: "tailType", type: "CstTypePack", optional: true }, - { - name: "closeParens", - type: "Token", - generic: 'Token<")">', - optional: true, - }, + { name: "closeParens", type: "CstToken", optional: true }, ], }, @@ -1152,8 +920,8 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, { name: "tag", type: '"generic"' }, - { name: "name", type: "Token" }, - { name: "ellipsis", type: "Token", generic: 'Token<"...">' }, + { name: "name", type: "CstToken" }, + { name: "ellipsis", type: "CstToken" }, ], }, @@ -1162,12 +930,7 @@ export const astTypeDefinitions: Record = { { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, { name: "tag", type: '"variadic"' }, - { - name: "ellipsis", - type: "Token", - generic: 'Token<"...">', - optional: true, - }, + { name: "ellipsis", type: "CstToken", optional: true }, { name: "type", type: "CstType" }, ], }, @@ -1182,8 +945,8 @@ export const astTypeDefinitions: Record = { _testType: { properties: [ - { name: "removedName", type: "Token", optional: true }, - { name: "name", type: "Token", optional: true }, + { name: "removedName", type: "CstToken", optional: true }, + { name: "name", type: "CstToken", optional: true }, ], }, }; diff --git a/frontend/src/utils/astTypeHelpers.ts b/frontend/src/utils/astTypeHelpers.ts index 23e68df..ee2dac2 100644 --- a/frontend/src/utils/astTypeHelpers.ts +++ b/frontend/src/utils/astTypeHelpers.ts @@ -20,30 +20,16 @@ export function getTypeDefinition( export function getGenericASTTypeDefinition( genericType: GenericTypeDefinition ): ASTTypeDefinition { - switch (genericType.baseType) { - case "Pair": - const splitGenericType = genericType.genericType.split(","); - return { - properties: [ - { name: "node", type: splitGenericType[0] }, - { - name: "separator", - type: `Token${ - splitGenericType[1] ? `<${splitGenericType[1].trim()}>` : "" - }`, - optional: true, - }, - ], - }; - case "Punctuated": - return { - properties: [ - { name: "", type: `{ Pair<${genericType.genericType}> }` }, - ], - }; - default: - return { properties: [] }; + if (genericType.baseType === "CstPunctuated") { + const itemType = genericType.genericType.split(",")[0].trim(); + return { + properties: [ + { name: "", type: `{ ${itemType} }` }, + { name: "separators", type: "{ CstToken }" }, + ], + }; } + return { properties: [] }; } export function getAllTypes(): string[] { @@ -96,8 +82,9 @@ const arrayTypeFallbacks: Record string)> = { attributes: "{ CstAttribute }", expressions: "{ CstExpr }", elseifs: "{ CstElseIfExpr }", - strings: "{ Token }", + strings: "{ CstToken }", entries: resolveEntriesType, + separators: "{ CstToken }", }; export const getArrayType = ( diff --git a/lua_helpers/json.lua b/lua_helpers/json.lua index 952af9b..25feac6 100644 --- a/lua_helpers/json.lua +++ b/lua_helpers/json.lua @@ -1,57 +1,66 @@ local stdJson = require("@std/json") --- Transforms lute's new Punctuated format (array + .separators field) --- into the frontend-compatible [{node, separator?}] Pair format before encoding. -local function transformPunctuated(node) +-- Lute represents punctuated lists as arrays with a .separators sibling field. +-- JSON arrays can't have named properties, so we serialize these as objects +-- with numeric string keys for items and a "separators" key — matching lute's +-- actual data shape as closely as JSON allows. +local function prepareForJson(node) if type(node) ~= "table" then return node end local separators = rawget(node, "separators") if separators and rawget(node, 1) ~= nil then - local pairs = {} + local result = {} for i, item in ipairs(node) do - local pair = { node = transformPunctuated(item) } - if separators[i] then - pair.separator = transformPunctuated(separators[i]) - end - table.insert(pairs, pair) + result[tostring(i)] = prepareForJson(item) end - return pairs + local preparedSeparators = {} + for i, sep in ipairs(separators) do + preparedSeparators[i] = prepareForJson(sep) + end + result.separators = preparedSeparators + return result + end + + if rawget(node, 1) ~= nil then + local result = {} + for i, v in ipairs(node) do + result[i] = prepareForJson(v) + end + return result end local result = {} for k, v in pairs(node) do - result[k] = transformPunctuated(v) - end - for i = 1, #node do - result[i] = transformPunctuated(node[i]) + if type(k) == "string" then + result[k] = prepareForJson(v) + end end return result end -local function encode(value) - return stdJson.serialize(transformPunctuated(value)) -end - -local function stripNulls(node) +local function stripMarkers(node) if type(node) ~= "table" then return node end local result = {} for k, v in pairs(node) do if type(k) == "string" and v ~= stdJson.null then - result[k] = stripNulls(v) + result[k] = stripMarkers(v) elseif type(k) == "number" and v ~= stdJson.null then - result[k] = stripNulls(v) + result[k] = stripMarkers(v) end - -- Skip userdata keys (object/array markers from @std/json) end return result end +local function encode(value) + return stdJson.serialize(prepareForJson(value)) +end + local function decode(str) - return stripNulls(stdJson.deserialize(str)) + return stripMarkers(stdJson.deserialize(str)) end return { diff --git a/lua_helpers/temp_vendor/lutePrinter.luau b/lua_helpers/temp_vendor/lutePrinter.luau index 69031d9..b1ae479 100644 --- a/lua_helpers/temp_vendor/lutePrinter.luau +++ b/lua_helpers/temp_vendor/lutePrinter.luau @@ -25,30 +25,55 @@ local function isToken(node: any): boolean end -- Tags where the 'func' child's contents should be merged into the parent --- for correct position-based printing local flattenFuncTags = { localfunction = true, ["function"] = true, } +-- Checks if a table represents a punctuated list (has numeric string keys + separators) +local function isPunctuated(node: any): boolean + return type(node) == "table" and node.separators ~= nil and node["1"] ~= nil +end + +-- Flattens a punctuated object into a list of items and separators for sorting +local function flattenPunctuated(node: any): any + local flat = {} + local i = 1 + while node[tostring(i)] do + flat["item_" .. i] = node[tostring(i)] + i += 1 + end + if node.separators then + for j, sep in ipairs(node.separators) do + flat["sep_" .. j] = sep + end + end + return flat +end + local function printFallback(node: any): string local nodeSrcStr = "" if node[1] then -- handle arrays for i = 1, #node do nodeSrcStr ..= printASTNode(node[i]) or "" end + elseif isPunctuated(node) then + -- Flatten items and separators, sort by position + local flat = flattenPunctuated(node) + local sortedChildren = getSortedChildren(flat) + for _, child in sortedChildren do + nodeSrcStr ..= printASTNode(child) or "" + end else -- For nodes where 'func' should be flattened into parent local nodeToSort = node if node.tag and flattenFuncTags[node.tag] and node.func then - -- Merge func's children into a virtual node alongside parent's other children nodeToSort = {} for k, v in node do if k ~= "func" then nodeToSort[k] = v end end - -- Merge func's children (except location/tag/kind which are metadata) for k, v in node.func do if k ~= "location" and k ~= "tag" and k ~= "kind" and k ~= "_astType" then nodeToSort["func_" .. k] = v @@ -57,7 +82,7 @@ local function printFallback(node: any): string end local sortedChildren = getSortedChildren(nodeToSort) - for key, child in sortedChildren do + for _, child in sortedChildren do nodeSrcStr ..= printASTNode(child) or "" end end diff --git a/lua_helpers/typeAnnotations.lua b/lua_helpers/typeAnnotations.lua index e000ad7..fc7e783 100644 --- a/lua_helpers/typeAnnotations.lua +++ b/lua_helpers/typeAnnotations.lua @@ -18,6 +18,7 @@ local typeDefinitions = { ["nil"] = "CstExprConstantNil", ["boolean"] = "CstExprConstantBool", -- also CstTypeSingletonBool - disambiguated by kind ["number"] = "CstExprConstantNumber", + ["integer"] = "CstExprConstantInteger", ["global"] = "CstExprGlobal", ["vararg"] = "CstExprVarargs", ["call"] = "CstExprCall", @@ -109,6 +110,7 @@ local typeDefinitions = { ["indexerOpen"] = "Token", ["indexerClose"] = "Token", ["returnSpecifier"] = "Token", + ["returnArrow"] = "Token", -- Operators and symbols ["equals"] = "Token", @@ -208,8 +210,8 @@ local function resolveAmbiguousTags(node): string? return "CstExprIfElse" end elseif tag == "function" then - -- CstTypeFunction has returnSpecifier and kind="type" - if kind == "type" or node.returnSpecifier then + -- CstTypeFunction has returnArrow and kind="type" + if kind == "type" or node.returnArrow then return "CstTypeFunction" -- CstStatFunction has name field and kind="stat" (but not func field directly on it) elseif kind == "stat" then diff --git a/lua_tests/helpers/typeAnnotationTestHelpers.lua b/lua_tests/helpers/typeAnnotationTestHelpers.lua index db9ad62..c76dabb 100644 --- a/lua_tests/helpers/typeAnnotationTestHelpers.lua +++ b/lua_tests/helpers/typeAnnotationTestHelpers.lua @@ -307,7 +307,7 @@ local ambiguousTagTestCases = { -- {nodeTable, expectedType, description} { { tag = "conditional", kind = "stat", endKeyword = {} }, "CstStatIf", "if statement" }, { { tag = "conditional", kind = "expr" }, "CstExprIfElse", "if expression" }, - { { tag = "function", kind = "type", returnSpecifier = {} }, "CstTypeFunction", "type function" }, + { { tag = "function", kind = "type", returnArrow = {} }, "CstTypeFunction", "type function" }, { { tag = "function", kind = "stat", name = {} }, "CstStatFunction", "function statement" }, { { tag = "function", kind = "expr" }, "CstExprFunction", "expression function" }, { { tag = "group", kind = "expr", expression = {} }, "CstExprGroup", "expression group" }, From 53363269079faa9ec38ef78510d93ece7180b145 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Tue, 16 Jun 2026 20:09:57 +0000 Subject: [PATCH 4/4] Add changelog file for PR #72 --- .changes/72-bug.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 .changes/72-bug.md diff --git a/.changes/72-bug.md b/.changes/72-bug.md new file mode 100644 index 0000000..276885b --- /dev/null +++ b/.changes/72-bug.md @@ -0,0 +1 @@ +Align w/ latest lute