typescript-to-lua
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -9,9 +9,4 @@ "use strict"; | ||
const transformBreakStatement = (breakStatement, context) => { | ||
const breakableScope = scope_1.findScope(context, scope_1.ScopeType.Loop | scope_1.ScopeType.Switch); | ||
if ((breakableScope === null || breakableScope === void 0 ? void 0 : breakableScope.type) === scope_1.ScopeType.Switch) { | ||
return lua.createGotoStatement(`____switch${breakableScope.id}_end`); | ||
} | ||
else { | ||
return lua.createBreakStatement(breakStatement); | ||
} | ||
void context; | ||
return lua.createBreakStatement(breakStatement); | ||
}; | ||
@@ -18,0 +13,0 @@ exports.transformBreakStatement = transformBreakStatement; |
@@ -5,44 +5,123 @@ "use strict"; | ||
const ts = require("typescript"); | ||
const CompilerOptions_1 = require("../../CompilerOptions"); | ||
const lua = require("../../LuaAST"); | ||
const diagnostics_1 = require("../utils/diagnostics"); | ||
const scope_1 = require("../utils/scope"); | ||
const containsBreakOrReturn = (nodes) => { | ||
for (const s of nodes) { | ||
if (ts.isBreakStatement(s) || ts.isReturnStatement(s)) { | ||
return true; | ||
} | ||
else if (ts.isBlock(s) && containsBreakOrReturn(s.getChildren())) { | ||
return true; | ||
} | ||
else if (s.kind === ts.SyntaxKind.SyntaxList && containsBreakOrReturn(s.getChildren())) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
}; | ||
const coalesceCondition = (condition, switchVariable, expression, context) => { | ||
// Coalesce skipped statements | ||
if (condition) { | ||
return lua.createBinaryExpression(condition, lua.createBinaryExpression(switchVariable, context.transformExpression(expression), lua.SyntaxKind.EqualityOperator), lua.SyntaxKind.OrOperator); | ||
} | ||
// Next condition | ||
return lua.createBinaryExpression(switchVariable, context.transformExpression(expression), lua.SyntaxKind.EqualityOperator); | ||
}; | ||
const transformSwitchStatement = (statement, context) => { | ||
if (context.luaTarget === CompilerOptions_1.LuaTarget.Universal || context.luaTarget === CompilerOptions_1.LuaTarget.Lua51) { | ||
context.diagnostics.push(diagnostics_1.unsupportedForTarget(statement, "Switch statements", CompilerOptions_1.LuaTarget.Lua51)); | ||
} | ||
const scope = scope_1.pushScope(context, scope_1.ScopeType.Switch); | ||
// Give the switch a unique name to prevent nested switches from acting up. | ||
// Give the switch and condition accumulator a unique name to prevent nested switches from acting up. | ||
const switchName = `____switch${scope.id}`; | ||
const conditionName = `____cond${scope.id}`; | ||
const switchVariable = lua.createIdentifier(switchName); | ||
const conditionVariable = lua.createIdentifier(conditionName); | ||
// If the switch only has a default clause, wrap it in a single do. | ||
// Otherwise, we need to generate a set of if statements to emulate the switch. | ||
let statements = []; | ||
// Starting from the back, concatenating ifs into one big if/elseif statement | ||
const concatenatedIf = statement.caseBlock.clauses.reduceRight((previousCondition, clause, index) => { | ||
if (ts.isDefaultClause(clause)) { | ||
// Skip default clause here (needs to be included to ensure index lines up with index later) | ||
return previousCondition; | ||
const clauses = statement.caseBlock.clauses; | ||
if (clauses.length === 1 && ts.isDefaultClause(clauses[0])) { | ||
const defaultClause = clauses[0].statements; | ||
if (defaultClause.length) { | ||
statements.push(lua.createDoStatement(context.transformStatements(defaultClause))); | ||
} | ||
// If the clause condition holds, go to the correct label | ||
const condition = lua.createBinaryExpression(switchVariable, context.transformExpression(clause.expression), lua.SyntaxKind.EqualityOperator); | ||
const goto = lua.createGotoStatement(`${switchName}_case_${index}`); | ||
return lua.createIfStatement(condition, lua.createBlock([goto]), previousCondition); | ||
}, undefined); | ||
if (concatenatedIf) { | ||
statements.push(concatenatedIf); | ||
} | ||
const hasDefaultCase = statement.caseBlock.clauses.some(ts.isDefaultClause); | ||
statements.push(lua.createGotoStatement(`${switchName}_${hasDefaultCase ? "case_default" : "end"}`)); | ||
for (const [index, clause] of statement.caseBlock.clauses.entries()) { | ||
const labelName = `${switchName}_case_${ts.isCaseClause(clause) ? index : "default"}`; | ||
statements.push(lua.createLabelStatement(labelName)); | ||
statements.push(lua.createDoStatement(context.transformStatements(clause.statements))); | ||
else { | ||
// Build up the condition for each if statement | ||
let isInitialCondition = true; | ||
let condition = undefined; | ||
for (let i = 0; i < clauses.length; i++) { | ||
const clause = clauses[i]; | ||
const previousClause = clauses[i - 1]; | ||
// Skip redundant default clauses, will be handled in final default case | ||
if (i === 0 && ts.isDefaultClause(clause)) | ||
continue; | ||
if (ts.isDefaultClause(clause) && previousClause && containsBreakOrReturn(previousClause.statements)) { | ||
continue; | ||
} | ||
// Compute the condition for the if statement | ||
if (!ts.isDefaultClause(clause)) { | ||
condition = coalesceCondition(condition, switchVariable, clause.expression, context); | ||
// Skip empty clauses unless final clause (i.e side-effects) | ||
if (i !== clauses.length - 1 && clause.statements.length === 0) | ||
continue; | ||
// Declare or assign condition variable | ||
statements.push(isInitialCondition | ||
? lua.createVariableDeclarationStatement(conditionVariable, condition) | ||
: lua.createAssignmentStatement(conditionVariable, lua.createBinaryExpression(conditionVariable, condition, lua.SyntaxKind.OrOperator))); | ||
isInitialCondition = false; | ||
} | ||
else { | ||
// If the default is proceeded by empty clauses and will be emitted we may need to initialize the condition | ||
if (isInitialCondition) { | ||
statements.push(lua.createVariableDeclarationStatement(conditionVariable, condition !== null && condition !== void 0 ? condition : lua.createBooleanLiteral(false))); | ||
// Clear condition ot ensure it is not evaluated twice | ||
condition = undefined; | ||
isInitialCondition = false; | ||
} | ||
// Allow default to fallthrough to final default clause | ||
if (i === clauses.length - 1) { | ||
// Evaluate the final condition that we may be skipping | ||
if (condition) { | ||
statements.push(lua.createAssignmentStatement(conditionVariable, lua.createBinaryExpression(conditionVariable, condition, lua.SyntaxKind.OrOperator))); | ||
} | ||
continue; | ||
} | ||
} | ||
// Transform the clause and append the final break statement if necessary | ||
const clauseStatements = context.transformStatements(clause.statements); | ||
if (i === clauses.length - 1 && !containsBreakOrReturn(clause.statements)) { | ||
clauseStatements.push(lua.createBreakStatement()); | ||
} | ||
// Push if statement for case | ||
statements.push(lua.createIfStatement(conditionVariable, lua.createBlock(clauseStatements))); | ||
// Clear condition for next clause | ||
condition = undefined; | ||
} | ||
// If no conditions above match, we need to create the final default case code-path, | ||
// as we only handle fallthrough into defaults in the previous if statement chain | ||
const start = clauses.findIndex(c => ts.isDefaultClause(c)); | ||
if (start >= 0) { | ||
// Find the last clause that we can fallthrough to | ||
const end = clauses.findIndex((clause, index) => index >= start && containsBreakOrReturn(clause.statements)); | ||
// Combine the default and all fallthrough statements | ||
const defaultStatements = []; | ||
clauses | ||
.slice(start, end >= 0 ? end + 1 : undefined) | ||
.forEach(c => defaultStatements.push(...context.transformStatements(c.statements))); | ||
// Add the default clause if it has any statements | ||
// The switch will always break on the final clause and skip execution if valid to do so | ||
if (defaultStatements.length) { | ||
statements.push(lua.createDoStatement(defaultStatements)); | ||
} | ||
} | ||
} | ||
statements.push(lua.createLabelStatement(`${switchName}_end`)); | ||
// Hoist the variable, function, and import statements to the top of the switch | ||
statements = scope_1.performHoisting(context, statements); | ||
scope_1.popScope(context); | ||
// Add the switch expression after hoisting | ||
const expression = context.transformExpression(statement.expression); | ||
statements.unshift(lua.createVariableDeclarationStatement(switchVariable, expression)); | ||
return statements; | ||
// Wrap the statements in a repeat until true statement to facilitate dynamic break/returns | ||
return lua.createRepeatStatement(lua.createBlock(statements), lua.createBooleanLiteral(true)); | ||
}; | ||
exports.transformSwitchStatement = transformSwitchStatement; | ||
//# sourceMappingURL=switch.js.map |
@@ -16,3 +16,3 @@ "use strict"; | ||
local ____originalRequire = require | ||
local function require(file) | ||
local function require(file, ...) | ||
if ____moduleCache[file] then | ||
@@ -22,3 +22,4 @@ return ____moduleCache[file].value | ||
if ____modules[file] then | ||
____moduleCache[file] = { value = ____modules[file]() } | ||
local module = ____modules[file] | ||
____moduleCache[file] = { value = (select("#", ...) > 0) and module(...) or module(file) } | ||
return ____moduleCache[file].value | ||
@@ -50,3 +51,3 @@ else | ||
// return require("<entry module path>") | ||
const entryPoint = `return require(${createModulePath(entryModule, program)})\n`; | ||
const entryPoint = `return require(${createModulePath(entryModule, program)}, ...)\n`; | ||
const sourceChunks = [requireOverride, moduleTable, entryPoint]; | ||
@@ -70,3 +71,3 @@ if (!options.noHeader) { | ||
function moduleSourceNode({ code, sourceMapNode }, modulePath) { | ||
const tableEntryHead = `[${modulePath}] = function() `; | ||
const tableEntryHead = `[${modulePath}] = function(...) `; | ||
const tableEntryTail = " end,\n"; | ||
@@ -73,0 +74,0 @@ return joinSourceChunks([tableEntryHead, sourceMapNode !== null && sourceMapNode !== void 0 ? sourceMapNode : code, tableEntryTail]); |
@@ -140,4 +140,9 @@ "use strict"; | ||
} | ||
// Check if the import is relative | ||
const isRelative = ["/", "./", "../"].some(p => dependency.startsWith(p)); | ||
// If the import is relative, always resolve it relative to the requiring file | ||
// If the import is not relative, resolve it relative to options.baseUrl if it is set | ||
const relativeTo = isRelative ? fileDirectory : (_a = options.baseUrl) !== null && _a !== void 0 ? _a : fileDirectory; | ||
// Check if file is a file in the project | ||
const resolvedPath = path.join((_a = options.baseUrl) !== null && _a !== void 0 ? _a : fileDirectory, dependency); | ||
const resolvedPath = path.join(relativeTo, dependency); | ||
const possibleProjectFiles = [ | ||
@@ -144,0 +149,0 @@ resolvedPath, |
{ | ||
"name": "typescript-to-lua", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "A generic TypeScript to Lua transpiler. Write your code in TypeScript and publish Lua!", | ||
@@ -5,0 +5,0 @@ "repository": "https://github.com/TypeScriptToLua/TypeScriptToLua", |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
800155
12180