typescript-to-lua
Version:
A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!
214 lines • 9.29 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.transformBuiltinPropertyAccessExpression = transformBuiltinPropertyAccessExpression;
exports.transformBuiltinCallExpression = transformBuiltinCallExpression;
exports.transformBuiltinIdentifierExpression = transformBuiltinIdentifierExpression;
exports.checkForLuaLibType = checkForLuaLibType;
exports.tryGetStandardLibrarySymbolOfType = tryGetStandardLibrarySymbolOfType;
const ts = require("typescript");
const lua = require("../../LuaAST");
const lua_ast_1 = require("../utils/lua-ast");
const lualib_1 = require("../utils/lualib");
const symbols_1 = require("../utils/symbols");
const typescript_1 = require("../utils/typescript");
const call_1 = require("../visitors/call");
const array_1 = require("./array");
const console_1 = require("./console");
const function_1 = require("./function");
const global_1 = require("./global");
const math_1 = require("./math");
const number_1 = require("./number");
const object_1 = require("./object");
const promise_1 = require("./promise");
const string_1 = require("./string");
const symbol_1 = require("./symbol");
const diagnostics_1 = require("../utils/diagnostics");
const CompilerOptions_1 = require("../../CompilerOptions");
const map_1 = require("./map");
function transformBuiltinPropertyAccessExpression(context, node) {
const ownerType = context.checker.getTypeAtLocation(node.expression);
if (ts.isIdentifier(node.expression) && (0, typescript_1.isStandardLibraryType)(context, ownerType, undefined)) {
switch (ownerType.symbol.name) {
case "NumberConstructor":
return (0, number_1.transformNumberProperty)(context, node);
case "Math":
return (0, math_1.transformMathProperty)(context, node);
case "SymbolConstructor":
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.Symbol);
}
}
if ((0, typescript_1.isStringType)(context, ownerType)) {
return (0, string_1.transformStringProperty)(context, node);
}
if ((0, typescript_1.isArrayType)(context, ownerType)) {
return (0, array_1.transformArrayProperty)(context, node);
}
if ((0, typescript_1.isFunctionType)(ownerType)) {
return (0, function_1.transformFunctionProperty)(context, node);
}
}
function transformBuiltinCallExpression(context, node) {
const expressionType = context.checker.getTypeAtLocation(node.expression);
if (ts.isIdentifier(node.expression) && (0, typescript_1.isStandardLibraryType)(context, expressionType, undefined)) {
checkForLuaLibType(context, expressionType);
const result = (0, global_1.tryTransformBuiltinGlobalCall)(context, node, expressionType);
if (result)
return result;
}
const calledMethod = ts.getOriginalNode((0, call_1.getCalledExpression)(node));
if (ts.isPropertyAccessExpression(calledMethod)) {
const globalResult = tryTransformBuiltinGlobalMethodCall(context, node, calledMethod);
if (globalResult)
return globalResult;
const prototypeResult = tryTransformBuiltinPropertyCall(context, node, calledMethod);
if (prototypeResult)
return prototypeResult;
// object prototype call may work even without resolved signature/type (which the other builtin calls use)
// e.g. (foo as any).toString()
// prototype methods take precedence (e.g. number.toString(2))
const objectResult = (0, object_1.tryTransformObjectPrototypeCall)(context, node, calledMethod);
if (objectResult)
return objectResult;
}
}
function tryTransformBuiltinGlobalMethodCall(context, node, calledMethod) {
const ownerType = context.checker.getTypeAtLocation(calledMethod.expression);
const ownerSymbol = tryGetStandardLibrarySymbolOfType(context, ownerType);
if (!ownerSymbol || ownerSymbol.parent)
return;
let result;
switch (ownerSymbol.name) {
case "ArrayConstructor":
result = (0, array_1.transformArrayConstructorCall)(context, node, calledMethod);
break;
case "Console":
result = (0, console_1.transformConsoleCall)(context, node, calledMethod);
break;
case "MapConstructor":
result = (0, map_1.transformMapConstructorCall)(context, node, calledMethod);
break;
case "Math":
result = (0, math_1.transformMathCall)(context, node, calledMethod);
break;
case "StringConstructor":
result = (0, string_1.transformStringConstructorMethodCall)(context, node, calledMethod);
break;
case "ObjectConstructor":
result = (0, object_1.transformObjectConstructorCall)(context, node, calledMethod);
break;
case "SymbolConstructor":
result = (0, symbol_1.transformSymbolConstructorCall)(context, node, calledMethod);
break;
case "NumberConstructor":
result = (0, number_1.transformNumberConstructorCall)(context, node, calledMethod);
break;
case "PromiseConstructor":
result = (0, promise_1.transformPromiseConstructorCall)(context, node, calledMethod);
break;
}
if (result && calledMethod.questionDotToken) {
// e.g. console?.log()
context.diagnostics.push((0, diagnostics_1.unsupportedBuiltinOptionalCall)(calledMethod));
}
return result;
}
function tryTransformBuiltinPropertyCall(context, node, calledMethod) {
const functionType = context.checker.getTypeAtLocation(node.expression);
const callSymbol = tryGetStandardLibrarySymbolOfType(context, functionType);
if (!callSymbol)
return;
const ownerSymbol = callSymbol.parent;
if (!ownerSymbol || ownerSymbol.parent)
return;
switch (ownerSymbol.name) {
case "String":
return (0, string_1.transformStringPrototypeCall)(context, node, calledMethod);
case "Number":
return (0, number_1.transformNumberPrototypeCall)(context, node, calledMethod);
case "Array":
case "ReadonlyArray":
return (0, array_1.transformArrayPrototypeCall)(context, node, calledMethod);
case "Function":
case "CallableFunction":
case "NewableFunction":
return (0, function_1.transformFunctionPrototypeCall)(context, node, calledMethod);
}
}
function transformBuiltinIdentifierExpression(context, node, symbol) {
switch (node.text) {
case "NaN":
return (0, lua_ast_1.createNaN)(node);
case "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, node);
}
case "globalThis":
return lua.createIdentifier("_G", node, (0, symbols_1.getIdentifierSymbolId)(context, node, symbol), "globalThis");
}
}
const builtinErrorTypeNames = new Set([
"Error",
"ErrorConstructor",
"RangeError",
"RangeErrorConstructor",
"ReferenceError",
"ReferenceErrorConstructor",
"SyntaxError",
"SyntaxErrorConstructor",
"TypeError",
"TypeErrorConstructor",
"URIError",
"URIErrorConstructor",
]);
function checkForLuaLibType(context, type) {
const symbol = type.symbol;
if (!symbol || symbol.parent)
return;
const name = symbol.name;
switch (name) {
case "Map":
case "MapConstructor":
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.Map);
return;
case "Set":
case "SetConstructor":
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.Set);
return;
case "WeakMap":
case "WeakMapConstructor":
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.WeakMap);
return;
case "WeakSet":
case "WeakSetConstructor":
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.WeakSet);
return;
case "Promise":
case "PromiseConstructor":
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.Promise);
return;
}
if (builtinErrorTypeNames.has(name)) {
(0, lualib_1.importLuaLibFeature)(context, lualib_1.LuaLibFeature.Error);
}
}
function tryGetStandardLibrarySymbolOfType(context, type) {
if (type.isUnionOrIntersection()) {
for (const subType of type.types) {
const symbol = tryGetStandardLibrarySymbolOfType(context, subType);
if (symbol)
return symbol;
}
}
else if ((0, typescript_1.isStandardLibraryType)(context, type, undefined)) {
return type.symbol;
}
return undefined;
}
//# sourceMappingURL=index.js.map