UNPKG

typescript-to-lua

Version:

A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!

200 lines 9.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.literalVisitors = void 0; exports.transformPropertyName = transformPropertyName; exports.createShorthandIdentifier = createShorthandIdentifier; const ts = require("typescript"); const lua = require("../../LuaAST"); const utils_1 = require("../../utils"); const diagnostics_1 = require("../utils/diagnostics"); const lualib_1 = require("../utils/lualib"); const symbols_1 = require("../utils/symbols"); const typescript_1 = require("../utils/typescript"); const function_1 = require("./function"); const expression_list_1 = require("./expression-list"); const identifier_1 = require("./identifier"); const CompilerOptions_1 = require("../../CompilerOptions"); // TODO: Move to object-literal.ts? function transformPropertyName(context, node) { if (ts.isComputedPropertyName(node)) { return context.transformExpression(node.expression); } else if (ts.isIdentifier(node)) { return lua.createStringLiteral(node.text); } else if (ts.isPrivateIdentifier(node)) { throw new Error("PrivateIdentifier is not supported"); } else { return context.transformExpression(node); } } function createShorthandIdentifier(context, valueSymbol, propertyIdentifier) { return (0, identifier_1.transformIdentifierWithSymbol)(context, propertyIdentifier, valueSymbol); } const transformNumericLiteralExpression = (expression, context) => { if (expression.text === "Infinity") { if (context.luaTarget === CompilerOptions_1.LuaTarget.Lua50) { const one = lua.createNumericLiteral(1); const zero = lua.createNumericLiteral(0); return lua.createBinaryExpression(one, zero, lua.SyntaxKind.DivisionOperator); } else { const math = lua.createIdentifier("math"); const huge = lua.createStringLiteral("huge"); return lua.createTableIndexExpression(math, huge, expression); } } return lua.createNumericLiteral(Number(expression.text), expression); }; const transformObjectLiteralExpression = (expression, context) => { const properties = []; const initializers = []; const keyPrecedingStatements = []; const valuePrecedingStatements = []; let lastPrecedingStatementsIndex = -1; for (let i = 0; i < expression.properties.length; ++i) { const element = expression.properties[i]; // Transform key and cache preceding statements context.pushPrecedingStatements(); const name = element.name ? transformPropertyName(context, element.name) : undefined; let precedingStatements = context.popPrecedingStatements(); keyPrecedingStatements.push(precedingStatements); if (precedingStatements.length > 0) { lastPrecedingStatementsIndex = i; } // Transform value and cache preceding statements context.pushPrecedingStatements(); if (ts.isPropertyAssignment(element)) { const expression = context.transformExpression(element.initializer); properties.push(lua.createTableFieldExpression(expression, name, element)); initializers.push(element.initializer); } else if (ts.isShorthandPropertyAssignment(element)) { const valueSymbol = context.checker.getShorthandAssignmentValueSymbol(element); if (valueSymbol) { (0, symbols_1.trackSymbolReference)(context, valueSymbol, element.name); } const identifier = createShorthandIdentifier(context, valueSymbol, element.name); properties.push(lua.createTableFieldExpression(identifier, name, element)); initializers.push(element); } else if (ts.isMethodDeclaration(element)) { const expression = (0, function_1.transformFunctionLikeDeclaration)(element, context); properties.push(lua.createTableFieldExpression(expression, name, element)); initializers.push(element); } else if (ts.isSpreadAssignment(element)) { const type = context.checker.getTypeAtLocation(element.expression); let tableExpression; if ((0, typescript_1.isArrayType)(context, type)) { tableExpression = (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.ArrayToObject, element.expression, context.transformExpression(element.expression)); } else { tableExpression = context.transformExpression(element.expression); } properties.push(tableExpression); initializers.push(element.expression); } else if (ts.isAccessor(element)) { context.diagnostics.push((0, diagnostics_1.unsupportedAccessorInObjectLiteral)(element)); } else { (0, utils_1.assertNever)(element); } precedingStatements = context.popPrecedingStatements(); valuePrecedingStatements.push(precedingStatements); if (precedingStatements.length > 0) { lastPrecedingStatementsIndex = i; } } // Expressions referenced before others that produced preceding statements need to be cached in temps if (lastPrecedingStatementsIndex >= 0) { for (let i = 0; i < properties.length; ++i) { const property = properties[i]; // Bubble up key's preceding statements context.addPrecedingStatements(keyPrecedingStatements[i]); // Cache computed property name in temp if before the last expression that generated preceding statements if (i <= lastPrecedingStatementsIndex && lua.isTableFieldExpression(property) && property.key) { property.key = (0, expression_list_1.moveToPrecedingTemp)(context, property.key, expression.properties[i].name); } // Bubble up value's preceding statements context.addPrecedingStatements(valuePrecedingStatements[i]); // Cache property value in temp if before the last expression that generated preceding statements if (i < lastPrecedingStatementsIndex) { if (lua.isTableFieldExpression(property)) { property.value = (0, expression_list_1.moveToPrecedingTemp)(context, property.value, initializers[i]); } else { properties[i] = (0, expression_list_1.moveToPrecedingTemp)(context, property, initializers[i]); } } } } // Sort into field expressions and tables to pass into __TS__ObjectAssign let fields = []; const tableExpressions = []; for (const property of properties) { if (lua.isTableFieldExpression(property)) { fields.push(property); } else { if (fields.length > 0) { tableExpressions.push(lua.createTableExpression(fields)); } tableExpressions.push(property); fields = []; } } if (tableExpressions.length === 0) { return lua.createTableExpression(fields, expression); } else { if (fields.length > 0) { const tableExpression = lua.createTableExpression(fields, expression); tableExpressions.push(tableExpression); } if (tableExpressions[0].kind !== lua.SyntaxKind.TableExpression) { tableExpressions.unshift(lua.createTableExpression(undefined, expression)); } return (0, lualib_1.transformLuaLibFunction)(context, lualib_1.LuaLibFeature.ObjectAssign, expression, ...tableExpressions); } }; const transformArrayLiteralExpression = (expression, context) => { // Disallow using undefined/null in array literals checkForUndefinedOrNullInArrayLiteral(expression, context); const filteredElements = expression.elements.map(e => ts.isOmittedExpression(e) ? ts.factory.createIdentifier("undefined") : e); const values = (0, expression_list_1.transformExpressionList)(context, filteredElements).map(e => lua.createTableFieldExpression(e)); return lua.createTableExpression(values, expression); }; function checkForUndefinedOrNullInArrayLiteral(array, context) { // Look for last non-nil element in literal let lastNonUndefinedIndex = array.elements.length - 1; for (; lastNonUndefinedIndex >= 0; lastNonUndefinedIndex--) { if (!isUndefinedOrNull(array.elements[lastNonUndefinedIndex])) { break; } } // Add diagnostics for non-trailing nil elements in array literal for (let i = 0; i < array.elements.length; i++) { if (i < lastNonUndefinedIndex && isUndefinedOrNull(array.elements[i])) { context.diagnostics.push((0, diagnostics_1.undefinedInArrayLiteral)(array.elements[i])); } } } function isUndefinedOrNull(node) { return (node.kind === ts.SyntaxKind.UndefinedKeyword || node.kind === ts.SyntaxKind.NullKeyword || (ts.isIdentifier(node) && node.text === "undefined")); } exports.literalVisitors = { [ts.SyntaxKind.NullKeyword]: node => lua.createNilLiteral(node), [ts.SyntaxKind.TrueKeyword]: node => lua.createBooleanLiteral(true, node), [ts.SyntaxKind.FalseKeyword]: node => lua.createBooleanLiteral(false, node), [ts.SyntaxKind.NumericLiteral]: transformNumericLiteralExpression, [ts.SyntaxKind.StringLiteral]: node => lua.createStringLiteral(node.text, node), [ts.SyntaxKind.NoSubstitutionTemplateLiteral]: node => lua.createStringLiteral(node.text, node), [ts.SyntaxKind.ObjectLiteralExpression]: transformObjectLiteralExpression, [ts.SyntaxKind.ArrayLiteralExpression]: transformArrayLiteralExpression, }; //# sourceMappingURL=literal.js.map