UNPKG

typescript-to-lua

Version:

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

233 lines 11.2 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.literalVisitors = void 0; exports.transformPropertyName = transformPropertyName; exports.createShorthandIdentifier = createShorthandIdentifier; const ts = __importStar(require("typescript")); const lua = __importStar(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