UNPKG

typescript-to-lua

Version:

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

752 lines 34.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.LuaPrinter = exports.tstlHeader = exports.escapeString = void 0; exports.createPrinter = createPrinter; const path = require("path"); const source_map_1 = require("source-map"); const CompilerOptions_1 = require("./CompilerOptions"); const lua = require("./LuaAST"); const LuaLib_1 = require("./LuaLib"); const safe_names_1 = require("./transformation/utils/safe-names"); const transpilation_1 = require("./transpilation"); const utils_1 = require("./utils"); // https://www.lua.org/pil/2.4.html // https://www.ecma-international.org/ecma-262/10.0/index.html#table-34 const escapeStringRegExp = /[\b\f\n\r\t\v\\"\0]/g; const escapeStringMap = { "\b": "\\b", "\f": "\\f", "\n": "\\n", "\r": "\\r", "\t": "\\t", "\v": "\\v", "\\": "\\\\", '"': '\\"', "\0": "\\0", }; const escapeString = (value) => `"${value.replace(escapeStringRegExp, char => escapeStringMap[char])}"`; exports.escapeString = escapeString; exports.tstlHeader = "--[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]\n"; /** * Checks that a name is valid for use in lua function declaration syntax: * * `foo.bar` => passes (`function foo.bar()` is valid) * `getFoo().bar` => fails (`function getFoo().bar()` would be illegal) */ const isValidLuaFunctionDeclarationName = (str, options) => ((0, safe_names_1.shouldAllowUnicode)(options) ? /^[a-zA-Z0-9_\u00FF-\uFFFD.]+$/ : /^[a-zA-Z0-9_.]+$/).test(str); /** * Returns true if expression contains no function calls. */ function isSimpleExpression(expression) { switch (expression.kind) { case lua.SyntaxKind.CallExpression: case lua.SyntaxKind.MethodCallExpression: case lua.SyntaxKind.FunctionExpression: return false; case lua.SyntaxKind.TableExpression: const tableExpression = expression; return tableExpression.fields.every(e => isSimpleExpression(e)); case lua.SyntaxKind.TableFieldExpression: const fieldExpression = expression; return ((!fieldExpression.key || isSimpleExpression(fieldExpression.key)) && isSimpleExpression(fieldExpression.value)); case lua.SyntaxKind.TableIndexExpression: const indexExpression = expression; return isSimpleExpression(indexExpression.table) && isSimpleExpression(indexExpression.index); case lua.SyntaxKind.UnaryExpression: return isSimpleExpression(expression.operand); case lua.SyntaxKind.BinaryExpression: const binaryExpression = expression; return isSimpleExpression(binaryExpression.left) && isSimpleExpression(binaryExpression.right); } return true; } function createPrinter(printers) { if (printers.length === 0) { return (program, emitHost, fileName, file) => new LuaPrinter(emitHost, program, fileName).print(file); } else if (printers.length === 1) { return printers[0]; } else { throw new Error("Only one plugin can specify 'printer'"); } } class LuaPrinter { constructor(emitHost, program, sourceFile) { this.emitHost = emitHost; this.program = program; this.sourceFile = sourceFile; this.currentIndent = ""; this.options = program.getCompilerOptions(); this.luaFile = (0, utils_1.normalizeSlashes)((0, transpilation_1.getEmitPath)(this.sourceFile, this.program)); // Source nodes contain relative path from mapped lua file to original TS source file this.relativeSourcePath = (0, utils_1.normalizeSlashes)(path.relative(path.dirname(this.luaFile), this.sourceFile)); } print(file) { // Add traceback lualib if sourcemap traceback option is enabled if (this.options.sourceMapTraceback) { file.luaLibFeatures.add(LuaLib_1.LuaLibFeature.SourceMapTraceBack); } const sourceRoot = this.options.sourceRoot ? // According to spec, sourceRoot is simply prepended to the source name, so the slash should be included `${this.options.sourceRoot.replace(/[\\/]+$/, "")}/` : ""; const rootSourceNode = this.printFile(file); const sourceMap = this.buildSourceMap(sourceRoot, rootSourceNode); let code = rootSourceNode.toString(); if (this.options.inlineSourceMap) { code += "\n" + this.printInlineSourceMap(sourceMap); } if (this.options.sourceMapTraceback) { const stackTraceOverride = this.printStackTraceOverride(rootSourceNode); code = code.replace(LuaPrinter.sourceMapTracebackPlaceholder, stackTraceOverride); } return { code, sourceMap: sourceMap.toString(), sourceMapNode: rootSourceNode }; } printInlineSourceMap(sourceMap) { const map = sourceMap.toString(); const base64Map = Buffer.from(map).toString("base64"); return `--# sourceMappingURL=data:application/json;base64,${base64Map}\n`; } printStackTraceOverride(rootNode) { let currentLine = 1; const map = {}; rootNode.walk((chunk, mappedPosition) => { if (mappedPosition.line !== undefined && mappedPosition.line > 0) { if (map[currentLine] === undefined) { map[currentLine] = mappedPosition.line; } else { map[currentLine] = Math.min(map[currentLine], mappedPosition.line); } } currentLine += chunk.split("\n").length - 1; }); const mapItems = Object.entries(map).map(([line, original]) => `["${line}"] = ${original}`); const mapString = "{" + mapItems.join(",") + "}"; return `__TS__SourceMapTraceBack(debug.getinfo(1).short_src, ${mapString});`; } printFile(file) { var _a, _b; let sourceChunks = [file.trivia]; if (!this.options.noHeader) { sourceChunks.push(exports.tstlHeader); } const luaTarget = (_a = this.options.luaTarget) !== null && _a !== void 0 ? _a : CompilerOptions_1.LuaTarget.Universal; const luaLibImport = (_b = this.options.luaLibImport) !== null && _b !== void 0 ? _b : CompilerOptions_1.LuaLibImportKind.Require; if ((luaLibImport === CompilerOptions_1.LuaLibImportKind.Require || luaLibImport === CompilerOptions_1.LuaLibImportKind.RequireMinimal) && file.luaLibFeatures.size > 0) { // Import lualib features sourceChunks = this.printStatementArray((0, LuaLib_1.loadImportedLualibFeatures)(file.luaLibFeatures, luaTarget, this.emitHost)); } else if (luaLibImport === CompilerOptions_1.LuaLibImportKind.Inline && file.luaLibFeatures.size > 0) { // Inline lualib features sourceChunks.push("-- Lua Library inline imports\n"); sourceChunks.push((0, LuaLib_1.loadInlineLualibFeatures)(file.luaLibFeatures, luaTarget, this.emitHost)); sourceChunks.push("-- End of Lua Library inline imports\n"); } if (this.options.sourceMapTraceback && !(0, CompilerOptions_1.isBundleEnabled)(this.options)) { // In bundle mode the traceback is being generated for the entire file in getBundleResult // Otherwise, traceback is being generated locally sourceChunks.push(`${LuaPrinter.sourceMapTracebackPlaceholder}\n`); } // Print reest of the statements in file sourceChunks.push(...this.printStatementArray(file.statements)); return this.concatNodes(...sourceChunks); } pushIndent() { this.currentIndent += " "; } popIndent() { this.currentIndent = this.currentIndent.slice(4); } indent(input = "") { return this.concatNodes(this.currentIndent, input); } createSourceNode(node, chunks, name) { const { line, column } = lua.getOriginalPos(node); return line !== undefined && column !== undefined ? new source_map_1.SourceNode(line + 1, column, this.relativeSourcePath, chunks, name) : new source_map_1.SourceNode(null, null, this.relativeSourcePath, chunks, name); } concatNodes(...chunks) { return new source_map_1.SourceNode(null, null, this.relativeSourcePath, chunks); } printBlock(block) { return this.concatNodes(...this.printStatementArray(block.statements)); } statementMayRequireSemiColon(statement) { // Types of statements that could create ambiguous syntax if followed by parenthesis return (lua.isVariableDeclarationStatement(statement) || lua.isAssignmentStatement(statement) || lua.isExpressionStatement(statement)); } nodeStartsWithParenthesis(sourceNode) { let result; sourceNode.walk(chunk => { if (result === undefined) { chunk = chunk.trimLeft(); // Ignore leading whitespace if (chunk.length > 0) { result = chunk.startsWith("("); } } }); return result !== null && result !== void 0 ? result : false; } printStatementArray(statements) { const statementNodes = []; for (const [index, statement] of statements.entries()) { const node = this.printStatement(statement); if (index > 0 && this.statementMayRequireSemiColon(statements[index - 1]) && this.nodeStartsWithParenthesis(node)) { statementNodes[index - 1].add(";"); } statementNodes.push(node); if (lua.isReturnStatement(statement)) break; } return statementNodes.length > 0 ? [...(0, utils_1.intersperse)(statementNodes, "\n"), "\n"] : []; } printStatement(statement) { let resultNode = this.printStatementExcludingComments(statement); if (statement.leadingComments) { resultNode = this.concatNodes(statement.leadingComments.map(c => this.printComment(c)).join("\n"), "\n", resultNode); } if (statement.trailingComments) { resultNode = this.concatNodes(resultNode, "\n", statement.trailingComments.map(c => this.printComment(c)).join("\n")); } return resultNode; } printComment(comment) { if (Array.isArray(comment)) { if (comment.length === 0) { return this.indent("--[[]]"); } else { const [firstLine, ...restLines] = comment; const commentLines = this.concatNodes(...restLines.map(c => this.concatNodes("\n", this.indent(c)))); return this.concatNodes(this.indent("--[["), firstLine, commentLines, "]]"); } } else { return this.indent(`--${comment}`); } } printStatementExcludingComments(statement) { switch (statement.kind) { case lua.SyntaxKind.DoStatement: return this.printDoStatement(statement); case lua.SyntaxKind.VariableDeclarationStatement: return this.printVariableDeclarationStatement(statement); case lua.SyntaxKind.AssignmentStatement: return this.printVariableAssignmentStatement(statement); case lua.SyntaxKind.IfStatement: return this.printIfStatement(statement); case lua.SyntaxKind.WhileStatement: return this.printWhileStatement(statement); case lua.SyntaxKind.RepeatStatement: return this.printRepeatStatement(statement); case lua.SyntaxKind.ForStatement: return this.printForStatement(statement); case lua.SyntaxKind.ForInStatement: return this.printForInStatement(statement); case lua.SyntaxKind.GotoStatement: return this.printGotoStatement(statement); case lua.SyntaxKind.LabelStatement: return this.printLabelStatement(statement); case lua.SyntaxKind.ReturnStatement: return this.printReturnStatement(statement); case lua.SyntaxKind.BreakStatement: return this.printBreakStatement(statement); case lua.SyntaxKind.ContinueStatement: return this.printContinueStatement(statement); case lua.SyntaxKind.ExpressionStatement: return this.printExpressionStatement(statement); default: throw new Error(`Tried to print unknown statement kind: ${lua.SyntaxKind[statement.kind]}`); } } printDoStatement(statement) { const chunks = []; chunks.push(this.indent("do\n")); this.pushIndent(); chunks.push(...this.printStatementArray(statement.statements)); this.popIndent(); chunks.push(this.indent("end")); return this.concatNodes(...chunks); } printVariableDeclarationStatement(statement) { const chunks = []; chunks.push(this.indent("local ")); if (lua.isFunctionDefinition(statement)) { // Print all local functions as `local function foo()` instead of `local foo = function` to allow recursion chunks.push(this.printFunctionDefinition(statement)); } else { chunks.push(...this.joinChunksWithComma(statement.left.map(e => this.printExpression(e)))); if (statement.right) { chunks.push(" = "); chunks.push(...this.joinChunksWithComma(statement.right.map(e => this.printExpression(e)))); } } return this.createSourceNode(statement, chunks); } printVariableAssignmentStatement(statement) { const chunks = []; chunks.push(this.indent()); if (lua.isFunctionDefinition(statement) && (statement.right[0].flags & lua.NodeFlags.Declaration) !== 0) { // Use `function foo()` instead of `foo = function()` const name = this.printExpression(statement.left[0]); if (isValidLuaFunctionDeclarationName(name.toString(), this.options)) { chunks.push(this.printFunctionDefinition(statement)); return this.createSourceNode(statement, chunks); } } chunks.push(...this.joinChunksWithComma(statement.left.map(e => this.printExpression(e)))); chunks.push(" = "); chunks.push(...this.joinChunksWithComma(statement.right.map(e => this.printExpression(e)))); return this.createSourceNode(statement, chunks); } printIfStatement(statement, isElseIf = false) { const chunks = []; const prefix = isElseIf ? "elseif" : "if"; chunks.push(this.indent(prefix + " "), this.printExpression(statement.condition), " then\n"); this.pushIndent(); chunks.push(this.printBlock(statement.ifBlock)); this.popIndent(); if (statement.elseBlock) { if (lua.isIfStatement(statement.elseBlock)) { chunks.push(this.printIfStatement(statement.elseBlock, true)); } else { chunks.push(this.indent("else\n")); this.pushIndent(); chunks.push(this.printBlock(statement.elseBlock)); this.popIndent(); chunks.push(this.indent("end")); } } else { chunks.push(this.indent("end")); } return this.concatNodes(...chunks); } printWhileStatement(statement) { const chunks = []; chunks.push(this.indent("while "), this.printExpression(statement.condition), " do\n"); this.pushIndent(); chunks.push(this.printBlock(statement.body)); this.popIndent(); chunks.push(this.indent("end")); return this.concatNodes(...chunks); } printRepeatStatement(statement) { const chunks = []; chunks.push(this.indent("repeat\n")); this.pushIndent(); chunks.push(this.printBlock(statement.body)); this.popIndent(); chunks.push(this.indent("until "), this.printExpression(statement.condition)); return this.concatNodes(...chunks); } printForStatement(statement) { const ctrlVar = this.printExpression(statement.controlVariable); const ctrlVarInit = this.printExpression(statement.controlVariableInitializer); const limit = this.printExpression(statement.limitExpression); const chunks = []; chunks.push(this.indent("for "), ctrlVar, " = ", ctrlVarInit, ", ", limit); if (statement.stepExpression) { chunks.push(", ", this.printExpression(statement.stepExpression)); } chunks.push(" do\n"); this.pushIndent(); chunks.push(this.printBlock(statement.body)); this.popIndent(); chunks.push(this.indent("end")); return this.concatNodes(...chunks); } printForInStatement(statement) { const names = this.joinChunksWithComma(statement.names.map(i => this.printIdentifier(i))); const expressions = this.joinChunksWithComma(statement.expressions.map(e => this.printExpression(e))); const chunks = []; chunks.push(this.indent("for "), ...names, " in ", ...expressions, " do\n"); this.pushIndent(); chunks.push(this.printBlock(statement.body)); this.popIndent(); chunks.push(this.indent("end")); return this.createSourceNode(statement, chunks); } printGotoStatement(statement) { return this.createSourceNode(statement, [this.indent("goto "), statement.label]); } printLabelStatement(statement) { return this.createSourceNode(statement, [this.indent("::"), statement.name, "::"]); } printReturnStatement(statement) { if (statement.expressions.length === 0) { return this.createSourceNode(statement, this.indent("return")); } const chunks = []; chunks.push(...this.joinChunksWithComma(statement.expressions.map(e => this.printExpression(e)))); return this.createSourceNode(statement, [this.indent(), "return ", ...chunks]); } printBreakStatement(statement) { return this.createSourceNode(statement, this.indent("break")); } printContinueStatement(statement) { return this.createSourceNode(statement, this.indent("continue")); } printExpressionStatement(statement) { return this.createSourceNode(statement, [this.indent(), this.printExpression(statement.expression)]); } // Expressions printExpression(expression) { switch (expression.kind) { case lua.SyntaxKind.StringLiteral: return this.printStringLiteral(expression); case lua.SyntaxKind.NumericLiteral: return this.printNumericLiteral(expression); case lua.SyntaxKind.NilKeyword: return this.printNilLiteral(expression); case lua.SyntaxKind.DotsKeyword: return this.printDotsLiteral(expression); case lua.SyntaxKind.ArgKeyword: return this.printArgLiteral(expression); case lua.SyntaxKind.TrueKeyword: case lua.SyntaxKind.FalseKeyword: return this.printBooleanLiteral(expression); case lua.SyntaxKind.FunctionExpression: return this.printFunctionExpression(expression); case lua.SyntaxKind.TableFieldExpression: return this.printTableFieldExpression(expression); case lua.SyntaxKind.TableExpression: return this.printTableExpression(expression); case lua.SyntaxKind.UnaryExpression: return this.printUnaryExpression(expression); case lua.SyntaxKind.BinaryExpression: return this.printBinaryExpression(expression); case lua.SyntaxKind.CallExpression: return this.printCallExpression(expression); case lua.SyntaxKind.MethodCallExpression: return this.printMethodCallExpression(expression); case lua.SyntaxKind.Identifier: return this.printIdentifier(expression); case lua.SyntaxKind.TableIndexExpression: return this.printTableIndexExpression(expression); case lua.SyntaxKind.ParenthesizedExpression: return this.printParenthesizedExpression(expression); case lua.SyntaxKind.ConditionalExpression: return this.printConditionalExpression(expression); default: throw new Error(`Tried to print unknown statement kind: ${lua.SyntaxKind[expression.kind]}`); } } printStringLiteral(expression) { return this.createSourceNode(expression, (0, exports.escapeString)(expression.value)); } printNumericLiteral(expression) { return this.createSourceNode(expression, String(expression.value)); } printNilLiteral(expression) { return this.createSourceNode(expression, "nil"); } printDotsLiteral(expression) { return this.createSourceNode(expression, "..."); } printArgLiteral(expression) { return this.createSourceNode(expression, "arg"); } printBooleanLiteral(expression) { return this.createSourceNode(expression, expression.kind === lua.SyntaxKind.TrueKeyword ? "true" : "false"); } printFunctionParameters(expression) { var _a; const parameterChunks = ((_a = expression.params) !== null && _a !== void 0 ? _a : []).map(i => this.printIdentifier(i)); if (expression.dots) { parameterChunks.push(this.printDotsLiteral(expression.dots)); } return this.joinChunksWithComma(parameterChunks); } printFunctionExpression(expression) { const chunks = []; chunks.push("function("); chunks.push(...this.printFunctionParameters(expression)); chunks.push(")"); if (lua.isInlineFunctionExpression(expression)) { const returnStatement = expression.body.statements[0]; chunks.push(" "); const returnNode = [ "return ", ...this.joinChunksWithComma(returnStatement.expressions.map(e => this.printExpression(e))), ]; chunks.push(this.createSourceNode(returnStatement, returnNode)); chunks.push(this.createSourceNode(expression, " end")); } else { chunks.push("\n"); this.pushIndent(); chunks.push(this.printBlock(expression.body)); this.popIndent(); chunks.push(this.indent(this.createSourceNode(expression, "end"))); } return this.createSourceNode(expression, chunks); } printFunctionDefinition(statement) { const expression = statement.right[0]; const chunks = []; chunks.push("function "); chunks.push(this.printExpression(statement.left[0])); chunks.push("("); chunks.push(...this.printFunctionParameters(expression)); chunks.push(")\n"); this.pushIndent(); chunks.push(this.printBlock(expression.body)); this.popIndent(); chunks.push(this.indent(this.createSourceNode(statement, "end"))); return this.createSourceNode(expression, chunks); } printTableFieldExpression(expression) { const chunks = []; const value = this.printExpression(expression.value); if (expression.key) { if (lua.isStringLiteral(expression.key) && (0, safe_names_1.isValidLuaIdentifier)(expression.key.value, this.options)) { chunks.push(expression.key.value, " = ", value); } else { chunks.push("[", this.printExpression(expression.key), "] = ", value); } } else { chunks.push(value); } return this.createSourceNode(expression, chunks); } printTableExpression(expression) { return this.createSourceNode(expression, ["{", ...this.printExpressionList(expression.fields), "}"]); } printUnaryExpression(expression) { const chunks = []; chunks.push(this.printOperator(expression.operator)); chunks.push(this.printExpressionInParenthesesIfNeeded(expression.operand, LuaPrinter.operatorPrecedence[expression.operator])); return this.createSourceNode(expression, chunks); } printBinaryExpression(expression) { const chunks = []; const isRightAssociative = LuaPrinter.rightAssociativeOperators.has(expression.operator); const precedence = LuaPrinter.operatorPrecedence[expression.operator]; chunks.push(this.printExpressionInParenthesesIfNeeded(expression.left, isRightAssociative ? precedence + 1 : precedence)); chunks.push(" ", this.printOperator(expression.operator), " "); chunks.push(this.printExpressionInParenthesesIfNeeded(expression.right, isRightAssociative ? precedence : precedence + 1)); return this.createSourceNode(expression, chunks); } printExpressionInParenthesesIfNeeded(expression, minPrecedenceToOmit) { return this.needsParenthesis(expression, minPrecedenceToOmit) ? this.createSourceNode(expression, ["(", this.printExpression(expression), ")"]) : this.printExpression(expression); } needsParenthesis(expression, minPrecedenceToOmit) { if (lua.isBinaryExpression(expression) || lua.isUnaryExpression(expression)) { return (minPrecedenceToOmit === undefined || LuaPrinter.operatorPrecedence[expression.operator] < minPrecedenceToOmit); } else { return lua.isFunctionExpression(expression) || lua.isTableExpression(expression); } } printCallExpression(expression) { const chunks = []; chunks.push(this.printExpressionInParenthesesIfNeeded(expression.expression), "("); if (expression.params) { chunks.push(...this.printExpressionList(expression.params)); } chunks.push(")"); return this.createSourceNode(expression, chunks); } printMethodCallExpression(expression) { const chunks = []; const prefix = this.needsParenthesis(expression.prefixExpression) || lua.isStringLiteral(expression.prefixExpression) ? ["(", this.printExpression(expression.prefixExpression), ")"] : [this.printExpression(expression.prefixExpression)]; const name = this.printIdentifier(expression.name); chunks.push(...prefix, ":", name, "("); if (expression.params) { chunks.push(...this.printExpressionList(expression.params)); } chunks.push(")"); return this.createSourceNode(expression, chunks); } printIdentifier(expression) { return this.createSourceNode(expression, expression.text, expression.originalName !== expression.text ? expression.originalName : undefined); } printTableIndexExpression(expression) { const chunks = []; chunks.push(this.printExpressionInParenthesesIfNeeded(expression.table)); if (lua.isStringLiteral(expression.index) && (0, safe_names_1.isValidLuaIdentifier)(expression.index.value, this.options)) { chunks.push(".", this.createSourceNode(expression.index, expression.index.value)); } else { chunks.push("[", this.printExpression(expression.index), "]"); } return this.createSourceNode(expression, chunks); } printParenthesizedExpression(expression) { return this.createSourceNode(expression, ["(", this.printExpression(expression.expression), ")"]); } printConditionalExpression(expression) { return this.createSourceNode(expression, [ "if ", this.printExpression(expression.condition), " then ", this.printExpression(expression.whenTrue), " else ", this.printExpression(expression.whenFalse), ]); } printOperator(kind) { return new source_map_1.SourceNode(null, null, this.relativeSourcePath, LuaPrinter.operatorMap[kind]); } joinChunksWithComma(chunks) { return (0, utils_1.intersperse)(chunks, ", "); } /** * Returns true if the expression list (table field or parameters) should be printed on one line. */ isSimpleExpressionList(expressions) { if (expressions.length <= 1) return true; if (expressions.length > 4) return false; return expressions.every(isSimpleExpression); } printExpressionList(expressions) { const chunks = []; if (this.isSimpleExpressionList(expressions)) { chunks.push(...this.joinChunksWithComma(expressions.map(e => this.printExpression(e)))); } else { chunks.push("\n"); this.pushIndent(); for (const [index, expression] of expressions.entries()) { const tail = index < expressions.length - 1 ? ",\n" : "\n"; chunks.push(this.indent(), this.printExpression(expression), tail); } this.popIndent(); chunks.push(this.indent()); } return chunks; } // The key difference between this and SourceNode.toStringWithSourceMap() is that SourceNodes with null line/column // will not generate 'empty' mappings in the source map that point to nothing in the original TS. buildSourceMap(sourceRoot, rootSourceNode) { const map = new source_map_1.SourceMapGenerator({ file: path.basename(this.luaFile), sourceRoot, }); let generatedLine = 1; let generatedColumn = 0; let currentMapping; const isNewMapping = (sourceNode) => { if (sourceNode.line === null) { return false; } if (currentMapping === undefined) { return true; } if (currentMapping.generated.line === generatedLine && currentMapping.generated.column === generatedColumn && currentMapping.name === sourceNode.name) { return false; } return (currentMapping.original.line !== sourceNode.line || currentMapping.original.column !== sourceNode.column || currentMapping.name !== sourceNode.name); }; const build = (sourceNode) => { if (isNewMapping(sourceNode)) { currentMapping = { source: sourceNode.source, original: { line: sourceNode.line, column: sourceNode.column }, generated: { line: generatedLine, column: generatedColumn }, name: sourceNode.name, }; map.addMapping(currentMapping); } for (const chunk of sourceNode.children) { if (typeof chunk === "string") { const lines = chunk.split("\n"); if (lines.length > 1) { generatedLine += lines.length - 1; generatedColumn = 0; currentMapping = undefined; // Mappings end at newlines } generatedColumn += lines[lines.length - 1].length; } else { build(chunk); } } }; build(rootSourceNode); return map; } } exports.LuaPrinter = LuaPrinter; LuaPrinter.operatorMap = { [lua.SyntaxKind.AdditionOperator]: "+", [lua.SyntaxKind.SubtractionOperator]: "-", [lua.SyntaxKind.MultiplicationOperator]: "*", [lua.SyntaxKind.DivisionOperator]: "/", [lua.SyntaxKind.FloorDivisionOperator]: "//", [lua.SyntaxKind.ModuloOperator]: "%", [lua.SyntaxKind.PowerOperator]: "^", [lua.SyntaxKind.NegationOperator]: "-", [lua.SyntaxKind.ConcatOperator]: "..", [lua.SyntaxKind.LengthOperator]: "#", [lua.SyntaxKind.EqualityOperator]: "==", [lua.SyntaxKind.InequalityOperator]: "~=", [lua.SyntaxKind.LessThanOperator]: "<", [lua.SyntaxKind.LessEqualOperator]: "<=", [lua.SyntaxKind.GreaterThanOperator]: ">", [lua.SyntaxKind.GreaterEqualOperator]: ">=", [lua.SyntaxKind.AndOperator]: "and", [lua.SyntaxKind.OrOperator]: "or", [lua.SyntaxKind.NotOperator]: "not ", [lua.SyntaxKind.BitwiseAndOperator]: "&", [lua.SyntaxKind.BitwiseOrOperator]: "|", [lua.SyntaxKind.BitwiseExclusiveOrOperator]: "~", [lua.SyntaxKind.BitwiseRightShiftOperator]: ">>", [lua.SyntaxKind.BitwiseLeftShiftOperator]: "<<", [lua.SyntaxKind.BitwiseNotOperator]: "~", }; LuaPrinter.operatorPrecedence = { [lua.SyntaxKind.OrOperator]: 1, [lua.SyntaxKind.AndOperator]: 2, [lua.SyntaxKind.EqualityOperator]: 3, [lua.SyntaxKind.InequalityOperator]: 3, [lua.SyntaxKind.LessThanOperator]: 3, [lua.SyntaxKind.LessEqualOperator]: 3, [lua.SyntaxKind.GreaterThanOperator]: 3, [lua.SyntaxKind.GreaterEqualOperator]: 3, [lua.SyntaxKind.BitwiseOrOperator]: 4, [lua.SyntaxKind.BitwiseExclusiveOrOperator]: 5, [lua.SyntaxKind.BitwiseAndOperator]: 6, [lua.SyntaxKind.BitwiseLeftShiftOperator]: 7, [lua.SyntaxKind.BitwiseRightShiftOperator]: 7, [lua.SyntaxKind.ConcatOperator]: 8, [lua.SyntaxKind.AdditionOperator]: 9, [lua.SyntaxKind.SubtractionOperator]: 9, [lua.SyntaxKind.MultiplicationOperator]: 10, [lua.SyntaxKind.DivisionOperator]: 10, [lua.SyntaxKind.FloorDivisionOperator]: 10, [lua.SyntaxKind.ModuloOperator]: 10, [lua.SyntaxKind.NotOperator]: 11, [lua.SyntaxKind.LengthOperator]: 11, [lua.SyntaxKind.NegationOperator]: 11, [lua.SyntaxKind.BitwiseNotOperator]: 11, [lua.SyntaxKind.PowerOperator]: 12, }; LuaPrinter.rightAssociativeOperators = new Set([lua.SyntaxKind.ConcatOperator, lua.SyntaxKind.PowerOperator]); LuaPrinter.sourceMapTracebackPlaceholder = "{#SourceMapTraceback}"; //# sourceMappingURL=LuaPrinter.js.map