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 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..31b87a9 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 }); }); @@ -233,13 +233,13 @@ 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", () => { // 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"); @@ -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,19 +323,19 @@ 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(); }); }); 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" }, }, }, }; @@ -397,34 +397,27 @@ describe("TreeNode", () => { }); describe("array type inference edge cases", () => { - test("handles punctuated arrays", () => { - const punctuatedNode = { - _astType: "AstExprFunction", - parameters: [ - // Use proper Punctuated structures - { - node: { name: mockTypelessToken("param1") }, - separator: mockTypelessToken(","), - }, - { - node: { name: mockTypelessToken("param2") }, - }, - ], + test("handles punctuated parameters", () => { + const functionNode = { + _astType: "CstExprFunction", + 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(); }); }); @@ -453,7 +446,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 +546,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 +568,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..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"; @@ -21,123 +20,104 @@ 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", ]); + expect(getArrayType("separators")).toEqual(["{ CstToken }", ""]); + expect(getArrayType("invalidType")).toEqual([undefined, ""]); }); test("parseGenericType", () => { - expect(parseGenericType("Pair")).toEqual({ - baseType: "Pair", - genericType: "AstExpr", - }); - - expect(parseGenericType("Punctuated")).toEqual({ - baseType: "Punctuated", - genericType: "AstExpr", + expect(parseGenericType("CstPunctuated")).toEqual({ + baseType: "CstPunctuated", + genericType: "CstExpr", }); - expect(parseGenericType('Pair')).toEqual({ - baseType: "Pair", - genericType: 'AstExpr, "&"', + expect(parseGenericType('CstPunctuated')).toEqual({ + baseType: "CstPunctuated", + genericType: 'CstType, "|"', }); - expect(parseGenericType("AstLocal")).toEqual(undefined); + expect(parseGenericType("CstLocal")).toEqual(undefined); 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: "AstExpr" }, - { - 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: "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([ + // test CstPunctuated generic type + expect(getType("CstPunctuated")).toEqual([ { properties: [ - { name: "node", type: "AstExpr" }, - { - name: "separator", - type: "Token<'&'>", - optional: true, - }, + { name: "", type: "{ CstExpr }" }, + { name: "separators", type: "{ CstToken }" }, ], }, false, 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..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 "AstExpr = A | B | C" + baseType?: string; + unionMembers?: string[]; } export interface GenericTypeDefinition { @@ -28,14 +28,15 @@ export interface TypeMetadata { prevKind: string; } +// Aligned with ~/.lute/typedefs/1.0.1/lute/syntax/cst.luau 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" }, ], }, @@ -67,1106 +68,885 @@ export const astTypeDefinitions: Record = { unionMembers: ["Whitespace", "SingleLineComment", "MultiLineComment"], }, - Token: { + CstToken: { 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"' }, ], }, - 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 }" }], - }, - - 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: "name", type: "CstToken" }, + { name: "colon", type: "CstToken", optional: true }, + { name: "annotation", type: "CstType", optional: true }, + { name: "shadows", type: "CstLocal", optional: true }, ], }, // === EXPRESSIONS === - AstExprGroup: { + CstExprGroup: { properties: [ { name: "location", type: "span" }, + { name: "kind", type: '"expr"' }, { name: "tag", type: '"group"' }, - { name: "openparens", type: "Token", generic: 'Token<"(">' }, - { name: "expression", type: "AstExpr" }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, + { name: "openParens", type: "CstToken" }, + { name: "expression", type: "CstExpr" }, + { name: "closeParens", type: "CstToken" }, ], }, - AstExprConstantNil: { - baseType: "Token", + CstExprConstantNil: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"nil"' }, - { name: "text", type: '"nil"' }, + { name: "token", type: "CstToken" }, ], }, - AstExprConstantBool: { - baseType: "Token", + CstExprConstantBool: { 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" }, ], }, - AstExprConstantNumber: { - baseType: "Token", + CstExprConstantNumber: { 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" }, ], }, - AstExprConstantString: { - baseType: "Token", + CstExprConstantString: { 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" }, + { name: "value", type: "CstToken" }, ], }, - 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: "token", type: "CstToken" }, + { name: "local", type: "CstLocal" }, { name: "upvalue", type: "boolean" }, ], }, - AstExprGlobal: { + CstExprGlobal: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"global"' }, - { name: "name", type: "Token" }, + { name: "name", type: "CstToken" }, ], }, - AstExprVarargs: { - baseType: "Token", + CstExprVarargs: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"vararg"' }, - { name: "text", type: '"..."' }, + { name: "token", type: "CstToken" }, ], }, - AstExprCall: { + CstExprCall: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"call"' }, - { name: "func", type: "AstExpr" }, - { - name: "openparens", - type: "Token", - generic: 'Token<"(">', - optional: true, - }, - { name: "arguments", type: "Punctuated", generic: "Punctuated" }, - { - name: "closeparens", - type: "Token", - generic: 'Token<")">', - optional: true, - }, + { name: "func", type: "CstExpr" }, + { name: "openParens", type: "CstToken", optional: true }, + { name: "arguments", type: "CstPunctuated" }, + { name: "closeParens", type: "CstToken", optional: true }, { name: "self", type: "boolean" }, { name: "argLocation", type: "span" }, ], }, - 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: "typearguments", - type: "Punctuated", - generic: "Punctuated", - }, - { name: "rightarrow1", type: "Token", generic: 'Token<">">' }, - { name: "rightarrow2", type: "Token", generic: 'Token<">">' }, + { name: "expr", type: "CstExpr" }, + { name: "leftArrow1", type: "CstToken" }, + { name: "leftArrow2", type: "CstToken" }, + { name: "typeArguments", type: "CstPunctuated" }, + { name: "rightArrow1", type: "CstToken" }, + { name: "rightArrow2", type: "CstToken" }, ], }, - AstExprIndexName: { + CstExprIndexName: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"indexname"' }, - { name: "expression", type: "AstExpr" }, - { name: "accessor", type: "Token", generic: 'Token<"." | ":">' }, - { name: "index", type: "Token", generic: "Token" }, - { name: "indexlocation", type: "span" }, + { name: "expression", type: "CstExpr" }, + { name: "accessor", type: "CstToken" }, + { name: "index", type: "CstToken" }, + { 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: "CstToken" }, + { name: "index", type: "CstExpr" }, + { name: "closeBrackets", type: "CstToken" }, ], }, - 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: "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: "self", type: "AstLocal", 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: "varargannotation", type: "AstTypePack", optional: true }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, - { - 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">' }, - ], - }, - - AstTableExprListItem: { + { name: "attributes", type: "{ CstAttribute }" }, + { 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: "CstPunctuated" }, + { name: "vararg", type: "CstToken", optional: true }, + { name: "varargColon", type: "CstToken", optional: true }, + { name: "varargAnnotation", type: "CstTypePack", 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: "CstToken" }, + ], + }, + + CstTableExprListItem: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"list"' }, - { name: "value", type: "AstExpr" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, - { name: "istableitem", type: "true" }, + { name: "value", type: "CstExpr" }, + { name: "separator", type: "CstToken", optional: 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: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, - { name: "istableitem", type: "true" }, + { name: "key", type: "CstToken" }, + { name: "equals", type: "CstToken" }, + { name: "value", type: "CstExpr" }, + { name: "separator", type: "CstToken", optional: 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: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "value", type: "AstExpr" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, - { name: "istableitem", type: "true" }, - ], - }, - - AstTableExprItem: { + { name: "indexerOpen", type: "CstToken" }, + { name: "key", type: "CstExpr" }, + { name: "indexerClose", type: "CstToken" }, + { name: "equals", type: "CstToken" }, + { name: "value", type: "CstExpr" }, + { name: "separator", type: "CstToken", optional: true }, + { name: "isTableItem", type: "true" }, + ], + }, + + 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: "CstToken" }, + { name: "entries", type: "{ CstTableExprItem }" }, + { name: "closeBrace", type: "CstToken" }, ], }, - 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: "operator", type: "CstToken" }, + { name: "operand", type: "CstExpr" }, ], }, - AstExprBinary: { + CstExprBinary: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"binary"' }, - { name: "lhsoperand", type: "AstExpr" }, - { name: "operator", type: "Token" }, - { name: "rhsoperand", type: "AstExpr" }, + { name: "lhsOperand", type: "CstExpr" }, + { name: "operator", type: "CstToken" }, + { 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: "strings", type: "{ CstToken }" }, + { name: "expressions", type: "{ CstExpr }" }, ], }, - AstExprTypeAssertion: { + CstExprTypeAssertion: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"expr"' }, { name: "tag", type: '"cast"' }, - { name: "operand", type: "AstExpr" }, - { name: "operator", type: "Token", generic: 'Token<"::">' }, - { name: "annotation", type: "AstType" }, + { name: "operand", type: "CstExpr" }, + { name: "operator", type: "CstToken" }, + { 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: "CstToken" }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "CstToken" }, + { 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: "CstToken" }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "CstToken" }, + { name: "thenExpr", type: "CstExpr" }, + { name: "elseifs", type: "{ CstElseIfExpr }" }, + { name: "elseKeyword", type: "CstToken" }, + { 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", + "CstExprConstantInteger", + "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: "CstToken" }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "CstToken" }, ], }, - 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: "CstToken" }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "CstToken" }, + { 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: "elsekeyword", - type: "Token", - generic: 'Token<"else">', - optional: true, - }, - { name: "elseblock", type: "AstStatBlock", optional: true }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { name: "ifKeyword", type: "CstToken" }, + { name: "condition", type: "CstExpr" }, + { name: "thenKeyword", type: "CstToken" }, + { name: "thenBlock", type: "CstStatBlock" }, + { name: "elseifs", type: "{ CstElseIfStat }" }, + { name: "elseKeyword", type: "CstToken", optional: true }, + { name: "elseBlock", type: "CstStatBlock", optional: true }, + { name: "endKeyword", type: "CstToken" }, ], }, - 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: "CstToken" }, + { name: "condition", type: "CstExpr" }, + { name: "doKeyword", type: "CstToken" }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "CstToken" }, ], }, - 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: "CstToken" }, + { name: "body", type: "CstStatBlock" }, + { name: "untilKeyword", type: "CstToken" }, + { name: "condition", type: "CstExpr" }, ], }, - AstStatBreak: { - baseType: "Token", + CstStatBreak: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"break"' }, - { name: "text", type: '"break"' }, + { name: "token", type: "CstToken" }, ], }, - AstStatContinue: { - baseType: "Token", + CstStatContinue: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"continue"' }, - { name: "text", type: '"continue"' }, + { name: "token", type: "CstToken" }, ], }, - AstStatReturn: { + CstStatReturn: { properties: [ { 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" }, ], }, - 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: "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" }, ], }, - AstStatFor: { + CstStatConst: { + properties: [ + { name: "location", type: "span" }, + { name: "kind", type: '"stat"' }, + { name: "tag", type: '"const"' }, + { name: "constKeyword", type: "CstToken" }, + { name: "variables", type: "CstPunctuated" }, + { name: "equals", type: "CstToken", optional: true }, + { name: "values", type: "CstPunctuated" }, + ], + }, + + 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: "equals", type: "Token", generic: 'Token<"=">' }, - { name: "from", type: "AstExpr" }, - { name: "tocomma", type: "Token", generic: 'Token<",">' }, - { name: "to", type: "AstExpr" }, - { - 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">' }, - ], - }, - - AstStatForIn: { + { name: "forKeyword", type: "CstToken" }, + { name: "variable", type: "CstLocal" }, + { name: "equals", type: "CstToken" }, + { name: "from", type: "CstExpr" }, + { name: "toComma", type: "CstToken" }, + { name: "to", type: "CstExpr" }, + { name: "stepComma", type: "CstToken", optional: true }, + { name: "step", type: "CstExpr", optional: true }, + { name: "doKeyword", type: "CstToken" }, + { name: "body", type: "CstStatBlock" }, + { name: "endKeyword", type: "CstToken" }, + ], + }, + + CstStatForIn: { properties: [ { 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: "body", type: "AstStatBlock" }, - { name: "endkeyword", type: "Token", generic: 'Token<"end">' }, + { 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: "CstToken" }, ], }, - AstStatAssign: { + CstStatAssign: { properties: [ { 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" }, ], }, - AstStatCompoundAssign: { + CstStatCompoundAssign: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"stat"' }, { name: "tag", type: '"compoundassign"' }, - { name: "variable", type: "AstExpr" }, - { name: "operand", type: "Token" }, - { name: "value", type: "AstExpr" }, + { name: "variable", type: "CstExpr" }, + { name: "operand", type: "CstToken" }, + { name: "value", type: "CstExpr" }, ], }, - AstAttribute: { - baseType: "Token", + CstAttribute: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"attribute"' }, - { name: "text", type: ["@checked", "@native", "@deprecated"] }, + { name: "name", type: "CstToken" }, ], }, - 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: "CstToken" }, + { name: "name", type: "CstLocal" }, + { name: "func", type: "CstExprFunction" }, ], }, - AstStatTypeAlias: { + CstStatTypeAlias: { properties: [ { 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: "type", type: "AstType" }, - ], - }, - - AstStatTypeFunction: { + { 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" }, + ], + }, + + CstStatTypeFunction: { properties: [ { 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: "body", type: "AstExprFunction" }, + { name: "export", type: "CstToken", optional: true }, + { name: "type", type: "CstToken" }, + { name: "name", type: "CstToken" }, + { 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: "name", type: "CstToken" }, + { name: "equals", type: "CstToken", 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: "name", type: "CstToken" }, + { name: "ellipsis", type: "CstToken" }, + { name: "equals", type: "CstToken", optional: true }, + { name: "default", type: "CstTypePack", optional: true }, ], }, // === TYPE SYSTEM === - AstTypeReference: { + CstTypeReference: { properties: [ { 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, - }, - ], - }, - - AstTypeSingletonBool: { - baseType: "Token", + { 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: { 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" }, ], }, - AstTypeSingletonString: { - baseType: "Token", + CstTypeSingletonString: { 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"] }, + { name: "value", type: "CstToken" }, ], }, - 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: "typeof", type: "CstToken" }, + { name: "openParens", type: "CstToken" }, + { name: "expression", type: "CstExpr" }, + { name: "closeParens", type: "CstToken" }, ], }, - 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: "CstToken" }, + { name: "type", type: "CstType" }, + { name: "closeParens", type: "CstToken" }, ], }, - AstTypeOptional: { - baseType: "Token", + CstTypeOptional: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"type"' }, { name: "tag", type: '"optional"' }, - { name: "text", type: '"?"' }, + { name: "token", type: "CstToken" }, ], }, - AstTypeUnion: { + CstTypeUnion: { properties: [ { 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' }, ], }, - AstTypeIntersection: { + CstTypeIntersection: { properties: [ { 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' }, ], }, - AstTypeArray: { + CstTypeArray: { properties: [ { 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: "type", type: "AstType" }, - { name: "closebrace", type: "Token", generic: 'Token<"}">' }, + { name: "openBrace", type: "CstToken" }, + { name: "access", type: "CstToken", optional: true }, + { name: "type", type: "CstType" }, + { name: "closeBrace", type: "CstToken" }, ], }, - AstTableTypeItemIndexer: { + CstTableTypeItemIndexer: { properties: [ { name: "kind", type: '"indexer"' }, - { - name: "access", - type: "Token", - generic: 'Token<"read" | "write">', - optional: true, - }, - { name: "indexeropen", type: "Token", generic: 'Token<"[">' }, - { name: "key", type: "AstType" }, - { name: "indexerclose", type: "Token", generic: 'Token<"]">' }, - { name: "colon", type: "Token", generic: 'Token<":">' }, - { name: "value", type: "AstType" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, - ], - }, - - AstTableTypeItemStringProperty: { + { name: "access", type: "CstToken", optional: true }, + { name: "indexerOpen", type: "CstToken" }, + { name: "key", type: "CstType" }, + { name: "indexerClose", type: "CstToken" }, + { name: "colon", type: "CstToken" }, + { name: "value", type: "CstType" }, + { 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: "key", type: "AstTypeSingletonString" }, - { name: "indexerclose", type: "Token", generic: 'Token<"]">' }, - { name: "colon", type: "Token", generic: 'Token<":">' }, - { name: "value", type: "AstType" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, - ], - }, - - AstTableTypeItemProperty: { + { name: "access", type: "CstToken", optional: true }, + { name: "indexerOpen", type: "CstToken" }, + { name: "key", type: "CstTypeSingletonString" }, + { name: "indexerClose", type: "CstToken" }, + { name: "colon", type: "CstToken" }, + { name: "value", type: "CstType" }, + { 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: "value", type: "AstType" }, - { - name: "separator", - type: "Token", - generic: 'Token<"," | ";">', - optional: true, - }, - ], - }, - - AstTableTypeItem: { + { name: "access", type: "CstToken", optional: true }, + { name: "key", type: "CstToken" }, + { name: "colon", type: "CstToken" }, + { name: "value", type: "CstType" }, + { name: "separator", type: "CstToken", optional: true }, + ], + }, + + 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: "CstToken" }, + { name: "entries", type: "{ CstTableTypeItem }" }, + { name: "closeBrace", type: "CstToken" }, ], }, - 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: "name", type: "CstToken", optional: true }, + { name: "colon", type: "CstToken", optional: true }, + { name: "type", type: "CstType" }, ], }, - AstTypeFunction: { + CstTypeFunction: { properties: [ { 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: "vararg", type: "AstTypePack", optional: true }, - { name: "closeparens", type: "Token", generic: 'Token<")">' }, - { name: "returnarrow", type: "Token", generic: 'Token<"->">' }, - { name: "returntypes", type: "AstTypePack" }, - ], - }, - - AstType: { + { 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: "CstToken" }, + { name: "returnArrow", type: "CstToken" }, + { name: "returnTypes", type: "CstTypePack" }, + ], + }, + + 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", - type: "Token", - generic: 'Token<"(">', - optional: true, - }, - { name: "types", type: "Punctuated", generic: "Punctuated" }, - { name: "tailtype", type: "AstTypePack", optional: true }, - { - name: "closeparens", - type: "Token", - generic: 'Token<")">', - optional: true, - }, + { name: "openParens", type: "CstToken", optional: true }, + { name: "types", type: "CstPunctuated" }, + { name: "tailType", type: "CstTypePack", optional: true }, + { name: "closeParens", type: "CstToken", optional: true }, ], }, - AstTypePackGeneric: { + CstTypePackGeneric: { properties: [ { 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" }, ], }, - AstTypePackVariadic: { + CstTypePackVariadic: { properties: [ { name: "location", type: "span" }, { name: "kind", type: '"typepack"' }, { name: "tag", type: '"variadic"' }, - { - name: "ellipsis", - type: "Token", - generic: 'Token<"...">', - optional: true, - }, - { name: "type", type: "AstType" }, + { name: "ellipsis", type: "CstToken", optional: true }, + { name: "type", type: "CstType" }, ], }, - AstTypePack: { + CstTypePack: { unionMembers: [ - "AstTypePackExplicit", - "AstTypePackGeneric", - "AstTypePackVariadic", + "CstTypePackExplicit", + "CstTypePackGeneric", + "CstTypePackVariadic", ], }, _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 4c33712..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[] { @@ -79,10 +65,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,14 +76,15 @@ const resolveEntriesKind = (value: any[]): string => { }; const arrayTypeFallbacks: Record string)> = { - statements: "{ AstStat }", - leadingtrivia: "{ Trivia }", - trailingtrivia: "{ Trivia }", - attributes: "{ AstAttribute }", - expressions: "{ AstExpr }", - elseifs: "{ AstElseIfExpr }", - strings: "{ Token }", + statements: "{ CstStat }", + leadingTrivia: "{ Trivia }", + trailingTrivia: "{ Trivia }", + attributes: "{ CstAttribute }", + expressions: "{ CstExpr }", + elseifs: "{ CstElseIfExpr }", + strings: "{ CstToken }", entries: resolveEntriesType, + separators: "{ CstToken }", }; export const getArrayType = ( @@ -124,7 +111,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..25feac6 100644 --- a/lua_helpers/json.lua +++ b/lua_helpers/json.lua @@ -1,409 +1,69 @@ --- --- 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") + +-- 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 result = {} + for i, item in ipairs(node) do + result[tostring(i)] = prepareForJson(item) + end + 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 + if type(k) == "string" then + result[k] = prepareForJson(v) + end + end + return result +end + +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] = stripMarkers(v) + elseif type(k) == "number" and v ~= stdJson.null then + result[k] = stripMarkers(v) + end + end + return result +end + +local function encode(value) + return stdJson.serialize(prepareForJson(value)) +end + +local function decode(str) + return stripMarkers(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 06142b4..3181a11 100644 --- a/lua_helpers/sortByPositionTable.lua +++ b/lua_helpers/sortByPositionTable.lua @@ -1,13 +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 - -- 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, node.location.endLine, node.location.endColumn end end @@ -23,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..b1ae479 100644 --- a/lua_helpers/temp_vendor/lutePrinter.luau +++ b/lua_helpers/temp_vendor/lutePrinter.luau @@ -1,21 +1,88 @@ 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 +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 - --[[ - 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 + 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 - local sortedChildren = getSortedChildren(node) - for key, child in sortedChildren do + -- For nodes where 'func' should be flattened into parent + local nodeToSort = node + if node.tag and flattenFuncTags[node.tag] and node.func then + nodeToSort = {} + for k, v in node do + if k ~= "func" then + nodeToSort[k] = v + end + end + 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 _, child in sortedChildren do nodeSrcStr ..= printASTNode(child) or "" end end @@ -47,14 +114,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_helpers/typeAnnotations.lua b/lua_helpers/typeAnnotations.lua index f70113d..fc7e783 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,102 @@ 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", + ["integer"] = "CstExprConstantInteger", + ["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", + ["returnArrow"] = "Token", -- Operators and symbols ["equals"] = "Token", @@ -116,12 +120,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 +132,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 +203,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 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 - 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 +291,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 +323,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 +395,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 +423,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/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..c76dabb 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", 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" }, + { { 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) 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"