From 724da5ed8f825e273ba8c754563d67247e87cda6 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sun, 5 Jan 2025 01:15:35 +0800 Subject: [PATCH] Updated TSTL to 1.29.0. [skip CI] --- Assets/Script/Lib/Dora/en/es6-subset.d.ts | 3 ++ .../Script/Lib/Dora/zh-Hans/es6-subset.d.ts | 3 ++ .../src/3rdParty/tstl/CompilerOptions.ts | 1 + Tools/dora-dora/src/3rdParty/tstl/LuaAST.ts | 37 +++++++++++++++++++ .../dora-dora/src/3rdParty/tstl/LuaPrinter.ts | 19 ++++++++++ .../tstl/transformation/builtins/index.ts | 5 ++- .../tstl/transformation/utils/diagnostics.ts | 4 ++ .../tstl/transformation/utils/scope.ts | 1 + .../transformation/utils/typescript/types.ts | 18 +++++++-- .../transformation/visitors/break-continue.ts | 20 +++++++--- .../tstl/transformation/visitors/class/new.ts | 28 +++++++++++++- .../transformation/visitors/conditional.ts | 11 ++++++ .../transformation/visitors/loops/utils.ts | 1 + 13 files changed, 139 insertions(+), 12 deletions(-) diff --git a/Assets/Script/Lib/Dora/en/es6-subset.d.ts b/Assets/Script/Lib/Dora/en/es6-subset.d.ts index ffd61857a..714e6ee06 100644 --- a/Assets/Script/Lib/Dora/en/es6-subset.d.ts +++ b/Assets/Script/Lib/Dora/en/es6-subset.d.ts @@ -908,6 +908,9 @@ interface Array { } interface ArrayConstructor { + new (): any[]; + new (): T[]; + new (...items: T[]): T[]; isArray(arg: any): arg is any[]; } diff --git a/Assets/Script/Lib/Dora/zh-Hans/es6-subset.d.ts b/Assets/Script/Lib/Dora/zh-Hans/es6-subset.d.ts index 4cfa3a4dd..08e88e32d 100644 --- a/Assets/Script/Lib/Dora/zh-Hans/es6-subset.d.ts +++ b/Assets/Script/Lib/Dora/zh-Hans/es6-subset.d.ts @@ -907,6 +907,9 @@ interface Array { } interface ArrayConstructor { + new (): any[]; + new (): T[]; + new (...items: T[]): T[]; isArray(arg: any): arg is any[]; } diff --git a/Tools/dora-dora/src/3rdParty/tstl/CompilerOptions.ts b/Tools/dora-dora/src/3rdParty/tstl/CompilerOptions.ts index aef21f9d7..4029ae584 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/CompilerOptions.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/CompilerOptions.ts @@ -48,6 +48,7 @@ export enum LuaTarget { Lua53 = "5.3", Lua54 = "5.4", LuaJIT = "JIT", + Luau = "Luau", } export enum BuildMode { diff --git a/Tools/dora-dora/src/3rdParty/tstl/LuaAST.ts b/Tools/dora-dora/src/3rdParty/tstl/LuaAST.ts index 994755617..ad4a7e06b 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/LuaAST.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/LuaAST.ts @@ -25,6 +25,7 @@ export enum SyntaxKind { LabelStatement, ReturnStatement, BreakStatement, + ContinueStatement, // Luau only. ExpressionStatement, // Expression @@ -45,6 +46,7 @@ export enum SyntaxKind { Identifier, TableIndexExpression, ParenthesizedExpression, + ConditionalExpression, // Luau only // Operators @@ -488,6 +490,18 @@ export function createBreakStatement(tsOriginal?: ts.Node): BreakStatement { return createNode(SyntaxKind.BreakStatement, tsOriginal) as BreakStatement; } +export interface ContinueStatement extends Statement { + kind: SyntaxKind.ContinueStatement; +} + +export function isContinueStatement(node: Node): node is ContinueStatement { + return node.kind === SyntaxKind.ContinueStatement; +} + +export function createContinueStatement(tsOriginal?: ts.Node): ContinueStatement { + return createNode(SyntaxKind.ContinueStatement, tsOriginal) as ContinueStatement; +} + export interface ExpressionStatement extends Statement { kind: SyntaxKind.ExpressionStatement; expression: Expression; @@ -861,3 +875,26 @@ export function createParenthesizedExpression(expression: Expression, tsOriginal parenthesizedExpression.expression = expression; return parenthesizedExpression; } + +export type ConditionalExpression = Expression & { + condition: Expression; + whenTrue: Expression; + whenFalse: Expression; +}; + +export function isConditionalExpression(node: Node): node is ConditionalExpression { + return node.kind === SyntaxKind.ConditionalExpression; +} + +export function createConditionalExpression( + condition: Expression, + whenTrue: Expression, + whenFalse: Expression, + tsOriginal?: ts.Node +): ConditionalExpression { + const conditionalExpression = createNode(SyntaxKind.ConditionalExpression, tsOriginal) as ConditionalExpression; + conditionalExpression.condition = condition; + conditionalExpression.whenTrue = whenTrue; + conditionalExpression.whenFalse = whenFalse; + return conditionalExpression; +} diff --git a/Tools/dora-dora/src/3rdParty/tstl/LuaPrinter.ts b/Tools/dora-dora/src/3rdParty/tstl/LuaPrinter.ts index 8a60a19bc..08c2ec91f 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/LuaPrinter.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/LuaPrinter.ts @@ -400,6 +400,8 @@ export class LuaPrinter { return this.printReturnStatement(statement as lua.ReturnStatement); case lua.SyntaxKind.BreakStatement: return this.printBreakStatement(statement as lua.BreakStatement); + case lua.SyntaxKind.ContinueStatement: + return this.printContinueStatement(statement as lua.ContinueStatement); case lua.SyntaxKind.ExpressionStatement: return this.printExpressionStatement(statement as lua.ExpressionStatement); default: @@ -578,6 +580,10 @@ export class LuaPrinter { return this.createSourceNode(statement, this.indent("break")); } + public printContinueStatement(statement: lua.ContinueStatement): SourceNode { + return this.createSourceNode(statement, this.indent("continue")); + } + public printExpressionStatement(statement: lua.ExpressionStatement): SourceNode { return this.createSourceNode(statement, [this.indent(), this.printExpression(statement.expression)]); } @@ -618,6 +624,8 @@ export class LuaPrinter { return this.printTableIndexExpression(expression as lua.TableIndexExpression); case lua.SyntaxKind.ParenthesizedExpression: return this.printParenthesizedExpression(expression as lua.ParenthesizedExpression); + case lua.SyntaxKind.ConditionalExpression: + return this.printConditionalExpression(expression as lua.ConditionalExpression); default: throw new Error(`Tried to print unknown statement kind: ${lua.SyntaxKind[expression.kind]}`); } @@ -832,6 +840,17 @@ export class LuaPrinter { return this.createSourceNode(expression, ["(", this.printExpression(expression.expression), ")"]); } + public printConditionalExpression(expression: lua.ConditionalExpression): SourceNode { + return this.createSourceNode(expression, [ + "if ", + this.printExpression(expression.condition), + " then ", + this.printExpression(expression.whenTrue), + " else ", + this.printExpression(expression.whenFalse), + ]); + } + public printOperator(kind: lua.Operator): SourceNode { return new SourceNode(null, null, this.relativeSourcePath, LuaPrinter.operatorMap[kind]); } diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/builtins/index.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/builtins/index.ts index 85a4c9802..3eefd64c9 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/builtins/index.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/builtins/index.ts @@ -221,7 +221,10 @@ export function checkForLuaLibType(context: TransformationContext, type: ts.Type } } -function tryGetStandardLibrarySymbolOfType(context: TransformationContext, type: ts.Type): ts.Symbol | undefined { +export function tryGetStandardLibrarySymbolOfType( + context: TransformationContext, + type: ts.Type +): ts.Symbol | undefined { if (type.isUnionOrIntersection()) { for (const subType of type.types) { const symbol = tryGetStandardLibrarySymbolOfType(context, subType); diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/diagnostics.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/diagnostics.ts index 137bd15b8..5fb1bf15e 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/diagnostics.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/diagnostics.ts @@ -172,3 +172,7 @@ export const cannotAssignToNodeOfKind = createErrorDiagnosticFactory( export const incompleteFieldDecoratorWarning = createWarningDiagnosticFactory( "You are using a class field decorator, note that tstl ignores returned value initializers!" ); + +export const unsupportedArrayWithLengthConstructor = createErrorDiagnosticFactory( + `Constructing new Array with length is not supported.` +); diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/scope.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/scope.ts index 87f431162..2b0351e4f 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/scope.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/scope.ts @@ -25,6 +25,7 @@ interface FunctionDefinitionInfo { export enum LoopContinued { WithGoto, WithRepeatBreak, + WithContinue, } export interface Scope { diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/typescript/types.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/typescript/types.ts index 5ba2a013c..4a356b972 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/typescript/types.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/utils/typescript/types.ts @@ -56,6 +56,20 @@ export function isNumberType(context: TransformationContext, type: ts.Type): boo function isExplicitArrayType(context: TransformationContext, type: ts.Type): boolean { if (context.checker.isArrayType(type) || context.checker.isTupleType(type)) return true; + + if (type.isUnionOrIntersection()) { + if (type.types.some(t => isExplicitArrayType(context, t))) { + return true; + } + } + + const baseTypes = type.getBaseTypes(); + if (baseTypes) { + if (baseTypes.some(t => isExplicitArrayType(context, t))) { + return true; + } + } + if (type.symbol) { const baseConstraint = context.checker.getBaseConstraintOfType(type); if (baseConstraint && baseConstraint !== type) { @@ -63,10 +77,6 @@ function isExplicitArrayType(context: TransformationContext, type: ts.Type): boo } } - if (type.isUnionOrIntersection()) { - return type.types.some(t => isExplicitArrayType(context, t)); - } - return false; } diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/break-continue.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/break-continue.ts index cfc411439..87487475d 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/break-continue.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/break-continue.ts @@ -11,12 +11,17 @@ export const transformBreakStatement: FunctionVisitor = (brea export const transformContinueStatement: FunctionVisitor = (statement, context) => { const scope = findScope(context, ScopeType.Loop); - const continuedWith = - context.luaTarget === LuaTarget.Universal || - context.luaTarget === LuaTarget.Lua50 || - context.luaTarget === LuaTarget.Lua51 - ? LoopContinued.WithRepeatBreak - : LoopContinued.WithGoto; + + const continuedWith = { + [LuaTarget.Universal]: LoopContinued.WithRepeatBreak, + [LuaTarget.Lua50]: LoopContinued.WithRepeatBreak, + [LuaTarget.Lua51]: LoopContinued.WithRepeatBreak, + [LuaTarget.Lua52]: LoopContinued.WithGoto, + [LuaTarget.Lua53]: LoopContinued.WithGoto, + [LuaTarget.Lua54]: LoopContinued.WithGoto, + [LuaTarget.LuaJIT]: LoopContinued.WithGoto, + [LuaTarget.Luau]: LoopContinued.WithContinue, + }[context.luaTarget]; if (scope) { scope.loopContinued = continuedWith; @@ -28,6 +33,9 @@ export const transformContinueStatement: FunctionVisitor = case LoopContinued.WithGoto: return lua.createGotoStatement(label, statement); + case LoopContinued.WithContinue: + return lua.createContinueStatement(statement); + case LoopContinued.WithRepeatBreak: return [ lua.createAssignmentStatement(lua.createIdentifier(label), lua.createBooleanLiteral(true), statement), diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/class/new.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/class/new.ts index 7c608bc65..0c5733451 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/class/new.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/class/new.ts @@ -2,16 +2,42 @@ import * as ts from "typescript"; import * as lua from "../../../LuaAST"; import { FunctionVisitor } from "../../context"; import { AnnotationKind, getTypeAnnotations } from "../../utils/annotations"; -import { annotationInvalidArgumentCount } from "../../utils/diagnostics"; +import { annotationInvalidArgumentCount, unsupportedArrayWithLengthConstructor } from "../../utils/diagnostics"; import { LuaLibFeature, transformLuaLibFunction } from "../../utils/lualib"; import { transformArguments, transformCallAndArguments } from "../call"; import { isTableNewCall } from "../language-extensions/table"; +import { tryGetStandardLibrarySymbolOfType } from "../../builtins"; export const transformNewExpression: FunctionVisitor = (node, context) => { if (isTableNewCall(context, node)) { return lua.createTableExpression(undefined, node); } + const constructorType = context.checker.getTypeAtLocation(node.expression); + if (tryGetStandardLibrarySymbolOfType(context, constructorType)?.name === "ArrayConstructor") { + if (node.arguments === undefined || node.arguments.length === 0) { + // turn new Array<>() into a simple {} + return lua.createTableExpression([], node); + } else { + // More than one argument, check if items constructor + const signature = context.checker.getResolvedSignature(node); + const signatureDeclaration = signature?.getDeclaration(); + if ( + signatureDeclaration?.parameters.length === 1 && + signatureDeclaration.parameters[0].dotDotDotToken === undefined + ) { + context.diagnostics.push(unsupportedArrayWithLengthConstructor(node)); + return lua.createTableExpression([], node); + } else { + const callArguments = transformArguments(context, node.arguments, signature); + return lua.createTableExpression( + callArguments.map(e => lua.createTableFieldExpression(e)), + node + ); + } + } + } + const signature = context.checker.getResolvedSignature(node); const [name, params] = transformCallAndArguments(context, node.expression, node.arguments ?? [], signature); diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/conditional.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/conditional.ts index 178f6ac2d..b90c7e2db 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/conditional.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/conditional.ts @@ -6,6 +6,7 @@ import { performHoisting, ScopeType } from "../utils/scope"; import { transformBlockOrStatement } from "./block"; import { canBeFalsy } from "../utils/typescript"; import { truthyOnlyConditionalValue } from "../utils/diagnostics"; +import { LuaTarget } from "../../CompilerOptions"; function transformProtectedConditionalExpression( context: TransformationContext, @@ -38,6 +39,16 @@ function transformProtectedConditionalExpression( } export const transformConditionalExpression: FunctionVisitor = (expression, context) => { + if (context.luaTarget === LuaTarget.Luau) { + // Luau's ternary operator doesn't have these issues + return lua.createConditionalExpression( + context.transformExpression(expression.condition), + context.transformExpression(expression.whenTrue), + context.transformExpression(expression.whenFalse), + expression + ); + } + // Check if we need to add diagnostic about Lua truthiness checkOnlyTruthyCondition(expression.condition, context); diff --git a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/loops/utils.ts b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/loops/utils.ts index f34b35245..01466b450 100644 --- a/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/loops/utils.ts +++ b/Tools/dora-dora/src/3rdParty/tstl/transformation/visitors/loops/utils.ts @@ -21,6 +21,7 @@ export function transformLoopBody( switch (scope.loopContinued) { case undefined: + case LoopContinued.WithContinue: return body; case LoopContinued.WithGoto: