roblox-ts
Version:
<div align="center"><img width=25% src="https://i.imgur.com/yCjHmng.png"></div> <h1 align="center"><a href="https://roblox-ts.github.io/">roblox-ts</a></h1> <div align="center">A TypeScript-to-Lua Compiler for Roblox</div> <br> <div align="center"> <a hr
160 lines • 8.2 kB
JavaScript
;
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k];
result["default"] = mod;
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
const ts = __importStar(require("ts-morph"));
const _1 = require(".");
const CompilerError_1 = require("../errors/CompilerError");
const typeUtilities_1 = require("../typeUtilities");
const utility_1 = require("../utility");
function compileMapElement(state, element) {
if (ts.TypeGuards.isArrayLiteralExpression(element)) {
const [key, value] = _1.compileCallArguments(state, element.getElements().map(e => utility_1.skipNodesDownwards(e)));
return `[${key}] = ${value};\n`;
}
else if (ts.TypeGuards.isCallExpression(element) && typeUtilities_1.isTupleType(element.getReturnType())) {
const key = state.getNewId();
const value = state.getNewId();
state.pushPrecedingStatementToNewId(element, _1.compileExpression(state, element).slice(2, -2), `${key}, ${value}`);
return `[${key}] = ${value};\n`;
}
else {
const id = _1.getReadableExpressionName(state, element, _1.compileExpression(state, element));
return `[${id}[1]] = ${id}[2];\n`;
}
}
function compileSetElement(state, element) {
const [key] = _1.compileCallArguments(state, [element]);
return `[${key}] = true;\n`;
}
const compileMapSetElement = new Map([
["map", { compile: compileMapElement, addMethodName: "set" }],
["set", { compile: compileSetElement, addMethodName: "add" }],
]);
function compileSetMapConstructorHelper(state, node, args, type, mode = "") {
const preDeclaration = mode ? "setmetatable(" : "";
const postDeclaration = mode ? `, { __mode = "${mode}" })` : "";
const typeArgument = typeUtilities_1.getType(node).getTypeArguments()[0];
if (typeArgument.isNullable() || typeArgument.isUndefined()) {
throw new CompilerError_1.CompilerError(`Cannot create a ${type} with a nullable index!`, node, CompilerError_1.CompilerErrorType.NullableIndexOnMapOrSet);
}
const firstParam = utility_1.skipNodesDownwards(args[0]);
let exp = node;
let parent = utility_1.skipNodesUpwards(node.getParent());
const { compile: compileElement, addMethodName: addMethodName } = compileMapSetElement.get(type);
while (ts.TypeGuards.isPropertyAccessExpression(parent) && addMethodName === parent.getName()) {
const grandparent = utility_1.skipNodesUpwards(parent.getParent());
if (ts.TypeGuards.isCallExpression(grandparent)) {
exp = grandparent;
parent = utility_1.skipNodesUpwards(grandparent.getParent());
}
else {
break;
}
}
const pushCondition = ts.TypeGuards.isNewExpression(exp)
? () => true
: (declaration) => declaration.isIdentifier;
if (firstParam &&
(!ts.TypeGuards.isArrayLiteralExpression(firstParam) ||
firstParam.getChildrenOfKind(ts.SyntaxKind.SpreadElement).length > 0)) {
state.usesTSLibrary = true;
const id = state.pushToDeclarationOrNewId(exp, preDeclaration + `TS.${type}_new(${_1.compileCallArgumentsAndJoin(state, args)})` + postDeclaration, pushCondition);
return id;
}
else {
let id = "";
const lines = new Array();
let hasContext = false;
if (firstParam) {
for (let element of firstParam.getElements()) {
element = utility_1.skipNodesDownwards(element);
if (hasContext) {
state.pushPrecedingStatements(exp, id + compileElement(state, element));
}
else {
state.enterPrecedingStatementContext();
const line = compileElement(state, element);
const context = state.exitPrecedingStatementContext();
if (context.length > 0) {
hasContext = true;
id = state.pushToDeclarationOrNewId(exp, preDeclaration + "{}" + postDeclaration, declaration => declaration.isIdentifier);
state.pushPrecedingStatements(exp, ...lines.map(current => state.indent + id + current), ...context, state.indent + id + line);
}
else {
lines.push(line);
}
}
}
}
if (!hasContext) {
id = state.pushToDeclarationOrNewId(exp, lines.length === 0
? preDeclaration + "{}" + postDeclaration
: preDeclaration +
lines.reduce((result, line) => result + state.indent + utility_1.joinIndentedLines([line], 1), "{\n") +
state.indent +
"}" +
postDeclaration, pushCondition);
}
return id;
}
}
const ARRAY_NIL_LIMIT = 200;
function compileNewExpression(state, node) {
const expNode = utility_1.skipNodesDownwards(node.getExpression());
const expressionType = typeUtilities_1.getType(expNode);
const name = _1.compileExpression(state, expNode);
const args = node.getFirstChildByKind(ts.SyntaxKind.OpenParenToken)
? node.getArguments().map(arg => utility_1.skipNodesDownwards(arg))
: [];
if (_1.inheritsFromRoact(expressionType)) {
throw new CompilerError_1.CompilerError(`Roact components cannot be created using new\n` +
utility_1.suggest(`Proper usage: Roact.createElement(${name}), <${name}></${name}> or <${name}/>`), node, CompilerError_1.CompilerErrorType.RoactNoNewComponentAllowed);
}
if (typeUtilities_1.inheritsFrom(expressionType, "ArrayConstructor")) {
if (args.length === 0) {
return "{}";
}
let result = `{`;
if (args.length === 1) {
const arg = args[0];
if (ts.TypeGuards.isNumericLiteral(arg) &&
arg.getText().match(/^\d+$/) &&
arg.getLiteralValue() <= ARRAY_NIL_LIMIT) {
const literalValue = arg.getLiteralValue();
if (literalValue !== 0) {
result += ", nil".repeat(literalValue).substring(1) + " ";
}
}
else {
throw new CompilerError_1.CompilerError("Invalid argument #1 passed into ArrayConstructor. Expected a simple integer fewer or equal to " +
ARRAY_NIL_LIMIT +
".", node, CompilerError_1.CompilerErrorType.BadBuiltinConstructorCall);
}
}
else if (args.length !== 0) {
throw new CompilerError_1.CompilerError("Invalid arguments passed into ArrayConstructor!", node, CompilerError_1.CompilerErrorType.BadBuiltinConstructorCall);
}
return _1.appendDeclarationIfMissing(state, utility_1.skipNodesUpwards(node.getParent()), result + `}`);
}
if (typeUtilities_1.inheritsFrom(expressionType, "MapConstructor")) {
return _1.appendDeclarationIfMissing(state, utility_1.skipNodesUpwards(node.getParent()), compileSetMapConstructorHelper(state, node, args, "map"));
}
if (typeUtilities_1.inheritsFrom(expressionType, "SetConstructor")) {
return _1.appendDeclarationIfMissing(state, utility_1.skipNodesUpwards(node.getParent()), compileSetMapConstructorHelper(state, node, args, "set"));
}
if (typeUtilities_1.inheritsFrom(expressionType, "WeakMapConstructor")) {
return _1.appendDeclarationIfMissing(state, utility_1.skipNodesUpwards(node.getParent()), compileSetMapConstructorHelper(state, node, args, "map", "k"));
}
if (typeUtilities_1.inheritsFrom(expressionType, "WeakSetConstructor")) {
return _1.appendDeclarationIfMissing(state, utility_1.skipNodesUpwards(node.getParent()), compileSetMapConstructorHelper(state, node, args, "set", "k"));
}
return `${name}.new(${_1.compileCallArgumentsAndJoin(state, args)})`;
}
exports.compileNewExpression = compileNewExpression;
//# sourceMappingURL=new.js.map