derw
Version:
An Elm-inspired language that transpiles to TypeScript
887 lines (886 loc) • 35.3 kB
JavaScript
;
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 (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateJavascript = void 0;
const Blocks_1 = require("../Blocks");
const Utils_1 = require("../Utils");
const List = __importStar(require("../stdlib/List"));
const types_1 = require("../types");
const Common_1 = require("./Common");
const CommonToEcma_1 = require("./CommonToEcma");
function generateTagCreator(tag) {
return (function (y) {
return y.join("\n");
})([`function ${tag.name}(args) {`, " return {", ` kind: "${tag.name}",`, ` ...args,`, ` };`, "}"]);
}
function generateUnionType(syntax) {
return (function (y) {
return y.join("\n\n");
})(List.map(function (tag) {
return generateTagCreator(tag);
}, syntax.tags));
}
function generateTypeAlias(syntax) {
const typeDef = syntax.type.name;
return (function (y) {
return y.join("\n");
})([`function ${typeDef}(args) {`, " return {", " ...args,", " };", "}"]);
}
function generateField(field) {
const value = generateExpression(field.value);
if (field.name === value) {
return field.name;
}
else {
return `${field.name}: ${value}`;
}
}
function generateObjectLiteral(literal) {
const fields = (function (y) {
return y.join(",\n ");
})(literal.fields.map(generateField));
if (literal.base === null) {
switch (literal.fields.length) {
case 0: {
return "{ }";
}
case literal.fields.length: {
if (literal.fields.length === 1) {
const [x] = literal.fields;
return `{ ${fields} }`;
}
}
default: {
return `{\n ${fields}\n}`;
}
}
;
}
else {
switch (literal.fields.length) {
case 0: {
return `{ ${literal.base.body} }`;
}
case literal.fields.length: {
if (literal.fields.length === 1) {
const [x] = literal.fields;
return `{ ${literal.base.body}, ${fields} }`;
}
}
default: {
return `{\n ${literal.base.body},\n ${fields}\n}`;
}
}
;
}
}
function generateListValue(list) {
function generator(expression) {
switch (expression.kind) {
case "IfStatement": {
return generateInlineIf(expression);
}
case "CaseStatement": {
return generateInlineCase(expression);
}
default: {
return generateExpression(expression);
}
}
}
const items = List.map(generator, list.items);
switch (items.length) {
case 0: {
return "[ ]";
}
case items.length: {
if (items.length === 1) {
const [x] = items;
return `[ ${x} ]`;
}
}
default: {
return `[ ${items.join(", ")} ]`;
}
}
}
function generateLetBlock(body) {
switch (body.length) {
case 0: {
return "";
}
case body.length: {
if (body.length >= 1) {
const [x, ...ys] = body;
const prefixedBody = (function (y) {
return y.join("\n");
})(List.map(function (block) {
return generateBlock(block);
}, body));
const prefixedLines = (0, Common_1.prefixLines)(prefixedBody, 4);
return `\n${prefixedLines}`;
}
}
default: {
return "";
}
}
}
function generateElseIfStatement(elseIfStatement) {
const isSimpleBody = (0, types_1.isSimpleValue)(elseIfStatement.body.kind);
const bodyPrefix = isSimpleBody ? "return " : "";
const predicate = generateExpression(elseIfStatement.predicate);
const body = (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})((function (y) {
return bodyPrefix + y;
})(generateExpression(elseIfStatement.body)));
const bodySuffix = isSimpleBody ? ";" : "";
const maybeLetBody = generateLetBlock(elseIfStatement.letBody);
return `} else if (${predicate}) {${maybeLetBody}\n${body}${bodySuffix}`;
}
function generateIfStatement(ifStatement, isAsync, neverSimple) {
const isSimpleIfBody = neverSimple ? false : (0, types_1.isSimpleValue)(ifStatement.ifBody.kind);
const isSimpleElseBody = neverSimple ? false : (0, types_1.isSimpleValue)(ifStatement.elseBody.kind);
const ifBodyPrefix = isSimpleIfBody ? "return " : "";
const elseBodyPrefix = isSimpleElseBody ? "return " : "";
const asyncPrefix = isAsync ? "await " : "";
const maybeIfLetBody = generateLetBlock(ifStatement.ifLetBody);
const maybeElseLetBody = generateLetBlock(ifStatement.elseLetBody);
const predicate = generateExpression(ifStatement.predicate);
const ifBody = generateExpression(ifStatement.ifBody);
const indentedIfBody = (function () {
const _res1668698078 = ifBody.split("\n");
switch (_res1668698078.length) {
case 0: {
return ifBody;
}
case _res1668698078.length: {
if (_res1668698078.length === 1) {
const [x] = _res1668698078;
return ifBody;
}
}
case _res1668698078.length: {
if (_res1668698078.length >= 1) {
const [x, ...xs] = _res1668698078;
return (function (y) {
return y.join("\n");
})([x, (0, Common_1.prefixLines)(xs.join("\n"), 4)]);
}
}
default: {
return ifBody;
}
}
})();
const elseBody = generateExpression(ifStatement.elseBody);
const indentedElseBody = (function () {
const _res415623174 = elseBody.split("\n");
switch (_res415623174.length) {
case 0: {
return elseBody;
}
case _res415623174.length: {
if (_res415623174.length === 1) {
const [x] = _res415623174;
return elseBody;
}
}
case _res415623174.length: {
if (_res415623174.length >= 1) {
const [x, ...xs] = _res415623174;
return (function (y) {
return y.join("\n");
})([x, (0, Common_1.prefixLines)(xs.join("\n"), 4)]);
}
}
default: {
return elseBody;
}
}
})();
const elseIfs = (function (y) {
return y.join("\n");
})(List.map(function (elseIf) {
return generateElseIfStatement(elseIf);
}, ifStatement.elseIf));
const prefixedElseIfs = elseIfs === "" ? "}" : `${elseIfs}\n}`;
return `if (${predicate}) {${maybeIfLetBody}\n ${ifBodyPrefix}${asyncPrefix}${indentedIfBody};\n${prefixedElseIfs} else {${maybeElseLetBody}\n ${elseBodyPrefix}${asyncPrefix}${indentedElseBody};\n}`;
}
function generateConstructor(constructor) {
switch (constructor.pattern.fields.length) {
case 0: {
return `${constructor.constructor}({ })`;
}
default: {
return `${constructor.constructor}(${generateObjectLiteral(constructor.pattern)})`;
}
}
}
const replaceKey = "$REPLACE_ME";
function GapsInfo(args) {
return Object.assign({}, args);
}
function generateListDestructurePartWithGaps(predicate, parts, part, info) {
if (info.partIndex < info.currentIndex) {
return Object.assign(Object.assign({}, info), { partIndex: info.partIndex + 1 });
}
else {
const index = info.currentIndex;
const output = info.output;
const isLastValue = index === parts.length - 1;
switch (part.kind) {
case "Destructure": {
const isNextAValue = isLastValue ? false : parts[index + 1].kind === "Value";
const hasADestructureAfter = index < parts.length - 2 ? parts[index + 2].kind === "Destructure" : false;
if (isNextAValue && hasADestructureAfter) {
const nextValue = (function (y) {
return y;
})(parts[index + 1]);
const destructorAfter = (function (y) {
return y;
})(parts[index + 2]);
return (function (y) {
return Object.assign(Object.assign({}, info), { output: y, partIndex: info.partIndex + 1, currentIndex: info.currentIndex + 2 });
})((function (y) {
return (0, Common_1.prefixLines)(y, 8);
})((function (y) {
return y.join("\n");
})([`const [ _0, ..._rest ] = ${predicate};`, `if (_0.kind === "${part.constructor}") {`, ` let _foundIndex = -1;`, ` for (let _i = 0; _i < _rest.length; _i++) {`, ` if (_rest[_i].kind === "${destructorAfter.constructor}") {`, ` _foundIndex = _i;`, ` break;`, ` }`, ` }`, ``, ` if (_foundIndex > -1) {`, ` const ${nextValue.body} = _rest.slice(0, _foundIndex);`, ` ${replaceKey}`, ` }`, `}`])));
}
else {
return Object.assign(Object.assign({}, info), { partIndex: info.partIndex + 1 });
}
;
}
case "Value": {
const newOutput = output.length === 0 ? `\nconst ${part.body} = _rest;\n ` : (parts[info.partIndex - 1].kind === "Destructure" ? output.replace(replaceKey, `const ${part.body} = _rest.slice(_foundIndex, _rest.length);\n${replaceKey}`) : output.replace(replaceKey, `const ${part.body} = _rest;\n${replaceKey}`));
return Object.assign(Object.assign({}, info), { output: newOutput, partIndex: info.partIndex + 1, currentIndex: info.currentIndex + 1 });
}
default: {
return Object.assign(Object.assign({}, info), { currentIndex: info.currentIndex + 1, partIndex: info.partIndex + 1 });
}
}
;
}
}
function generateListDestructureWithGaps(predicate, branch, pattern) {
const isFinalEmptyList = pattern.parts[pattern.parts.length - 1].kind === "EmptyList";
const partsWithLength = (0, Common_1.destructureLength)(pattern);
const startingInfo = {
output: "",
partIndex: 0,
currentIndex: 0
};
const parts = (function (y) {
return y.output;
})(List.foldl(function (x, info) {
return generateListDestructurePartWithGaps(predicate, pattern.parts, x, info);
}, startingInfo, pattern.parts));
const conditional = isFinalEmptyList ? `${predicate}.length === ${partsWithLength}` : `${predicate}.length >= ${partsWithLength}`;
const isSimpleBody = (0, types_1.isSimpleValue)(branch.body.kind);
const wrapper = isSimpleBody ? ` return ` : "";
const bodyIndent = isSimpleBody ? 0 : 4;
const body = (function (y) {
return (0, Common_1.prefixLines)(y, bodyIndent);
})(generateExpression(branch.body));
const inner = (0, Common_1.prefixLines)(`${wrapper}${body};`, 12);
return `case ${predicate}.length: {\n if (${conditional}) {\n${parts.replace(replaceKey, inner)}\n }\n}`;
}
function generateBranch(predicate, branch) {
const isSimpleBody = (0, types_1.isSimpleValue)(branch.body.kind);
const wrapper = isSimpleBody ? " return " : "";
const maybeLetBody = generateLetBlock(branch.letBody);
const bodyIndent = isSimpleBody ? 0 : 4;
const branchBody = (function (y) {
return (0, Common_1.prefixLines)(y, bodyIndent);
})(generateExpression(branch.body));
switch (branch.pattern.kind) {
case "Destructure": {
const { pattern } = branch.pattern;
const generatedPattern = pattern.trim().length > 0 ? `\n const ${pattern} = ${predicate};` : "";
return `case "${branch.pattern.constructor}": {${generatedPattern}${maybeLetBody}\n${wrapper}${branchBody};\n}`;
}
case "StringValue": {
const { body } = branch.pattern;
return `case "${body}": {${maybeLetBody}\n${wrapper}${branchBody};\n}`;
}
case "FormatStringValue": {
const { body } = branch.pattern;
return `case ` + "`" + body + "`" + `: {${maybeLetBody}\n${wrapper}${branchBody};\n}`;
}
case "EmptyList": {
return `case 0: {${maybeLetBody}\n${wrapper}${branchBody};\n}`;
}
case "ListDestructure": {
const { parts } = branch.pattern;
const length = parts.length;
const isFinalEmptyList = parts[length - 1].kind === "EmptyList";
const partsWithLength = (0, Common_1.destructureLength)(branch.pattern);
const hasGaps = (0, Common_1.patternHasGaps)(branch.pattern);
const gapPositions = (0, Common_1.patternGapPositions)(branch.pattern);
const isOnlyFinalGap = gapPositions.length === 1 && gapPositions[0] === length - 1;
function not(value) {
if (value) {
return false;
}
else {
return true;
}
}
const conditional = isFinalEmptyList && not(hasGaps) ? `${predicate}.length === ${partsWithLength}` : `${predicate}.length >= ${partsWithLength}`;
const firstPart = parts[0];
const isFirstDestructure = firstPart.kind === "Destructure";
if (hasGaps && not(isOnlyFinalGap)) {
return generateListDestructureWithGaps(predicate, branch, branch.pattern);
}
else {
if (isFirstDestructure) {
const destructors = List.filter(function (t) {
return t.kind === "Destructure";
}, parts);
const destructorParts = List.indexedMap(function (_, i) {
return `_${i}`;
}, destructors);
const allButFinalPart = List.map(CommonToEcma_1.generateListDestructurePart, parts.slice(destructorParts.length, -1));
const generatedParts = List.append(destructorParts, allButFinalPart);
const joinedGeneratedParts = generatedParts.join(", ");
const partsString = isFinalEmptyList ? joinedGeneratedParts : `${joinedGeneratedParts}, ...${(0, CommonToEcma_1.generateListDestructurePart)(parts[length - 1])}`;
const conditionals = List.indexedMap(function (destructor, index) {
return `_${index}.kind === "${destructor.constructor}"`;
}, destructors);
const joinedConditionals = conditionals.join(" && ");
function unpackFn(destructor, index) {
if (destructor.pattern.length === 0) {
return "";
}
else {
return `\n const ${destructor.pattern} = _${index};`;
}
}
const unpacked = List.indexedMap(unpackFn, destructors);
const joinedUnpacked = unpacked.length === 0 ? "" : unpacked.join("");
return (function (y) {
return y.join("\n");
})([`case ${predicate}.length: {`, ` if (${conditional}) {`, ` const [ ${partsString} ] = ${predicate};`, ` if (${joinedConditionals}) {${joinedUnpacked}${maybeLetBody ? (0, Common_1.prefixLines)(maybeLetBody, 8) : ""}`, ` ${wrapper}${branchBody};`, ` }`, ` }`, `}`]);
}
else {
const isFirstValue = firstPart.kind === "StringValue" || firstPart.kind === "FormatStringValue";
const partsToGenerate = isFirstValue ? [{
kind: "Value",
body: "_temp"
}, ...branch.pattern.parts.slice(1, -1)] : branch.pattern.parts.slice(0, -1);
const generatedParts = List.map(CommonToEcma_1.generateListDestructurePart, partsToGenerate);
const joinedParts = generatedParts.join(", ");
const partsString = isFinalEmptyList ? joinedParts : `${joinedParts}, ...${(0, CommonToEcma_1.generateListDestructurePart)(branch.pattern.parts[length - 1])}`;
if (isFirstValue) {
const tempConditional = (function () {
switch (firstPart.kind) {
case "StringValue": {
const { body } = firstPart;
return `"${body}"`;
}
case "FormatStringValue": {
const { body } = firstPart;
return "`" + body + "`";
}
default: {
return "";
}
}
})();
return (function (y) {
return y.join("\n");
})([`case ${predicate}.length: {`, ` if (${conditional}) {`, ` const [ ${partsString} ] = ${predicate};${maybeLetBody ? (0, Common_1.prefixLines)(maybeLetBody, 4) : ""}`, ` if (_temp === ${tempConditional}) {`, ` ${wrapper}${branchBody};`, ` }`, ` }`, `}`]);
}
else {
return (function (y) {
return y.join("\n");
})([`case ${predicate}.length: {`, ` if (${conditional}) {`, ` const [ ${partsString} ] = ${predicate};${maybeLetBody ? (0, Common_1.prefixLines)(maybeLetBody, 4) : ""}`, ` ${wrapper}${branchBody};`, ` }`, `}`]);
}
;
}
;
}
;
}
case "Default": {
return `default: {${maybeLetBody}\n${wrapper}${branchBody};\n}`;
}
}
}
function isModuleReferenceToAValue(moduleReference) {
return moduleReference.value.kind === "Value";
}
function generateCaseStatement(caseStatement) {
const predicate = generateExpression(caseStatement.predicate);
const isValue = (function () {
switch (caseStatement.predicate.kind) {
case "Value": {
return true;
}
case "ModuleReference": {
return isModuleReferenceToAValue(caseStatement.predicate);
}
default: {
return false;
}
}
})();
const name = isValue ? predicate : `_res${(0, Utils_1.hashCode)(predicate)}`;
const maybePredicateAssignment = isValue ? "" : `const ${name} = ${predicate};\n`;
const branches = (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})((function (y) {
return y.join("\n");
})(List.map(function (branch) {
return generateBranch(name, branch);
}, caseStatement.branches)));
const isString = (function (y) {
return y.length > 0;
})(List.filter(function (branch) {
return branch.pattern.kind === "StringValue";
}, caseStatement.branches));
const isList = (function (y) {
return y.length > 0;
})(List.filter(function (branch) {
return branch.pattern.kind === "EmptyList" || branch.pattern.kind === "ListDestructure";
}, caseStatement.branches));
if (isString) {
return `${maybePredicateAssignment}switch (${name}) {\n${branches}\n}`;
}
else {
if (isList) {
return `${maybePredicateAssignment}switch (${name}.length) {\n${branches}\n}`;
}
else {
return `${maybePredicateAssignment}switch (${name}.kind) {\n${branches}\n}`;
}
;
}
}
function generateAddition(addition) {
const left = generateExpression(addition.left);
const right = generateExpression(addition.right);
return `${left} + ${right}`;
}
function generateSubtraction(subtraction) {
const left = generateExpression(subtraction.left);
const right = generateExpression(subtraction.right);
return `${left} - ${right}`;
}
function generateMultiplication(multiplication) {
const left = generateExpression(multiplication.left);
const right = generateExpression(multiplication.right);
return `${left} * ${right}`;
}
function generateDivision(division) {
const left = generateExpression(division.left);
const right = generateExpression(division.right);
return `${left} / ${right}`;
}
function generateMod(mod) {
const left = generateExpression(mod.left);
const right = generateExpression(mod.right);
return `${left} % ${right}`;
}
function generateLeftPipe(leftPipe) {
return generateExpression((0, CommonToEcma_1.flattenLeftPipe)(leftPipe));
}
function generateRightPipe(rightPipe) {
const left = generateExpression(rightPipe.left);
const right = generateExpression(rightPipe.right);
return `${left}(${right})`;
}
function generateModuleReference(moduleReference) {
switch (moduleReference.path.length) {
case 0: {
return `(arg0) => arg0.${generateExpression(moduleReference.value)}`;
}
default: {
const left = moduleReference.path.join(".");
const right = generateExpression(moduleReference.value);
return `${left}.${right}`;
}
}
}
function generateFunctionCall(functionCall) {
const args = (function (y) {
return y.join(", ");
})(List.map(generateExpression, functionCall.args));
return `${functionCall.name}(${args})`;
}
function generateLambda(lambda) {
const isSimple = (0, types_1.isSimpleValue)(lambda.body.kind);
const args = lambda.args.join(", ");
const body = isSimple ? generateExpression(lambda.body) : (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})(generateExpression(lambda.body));
if (isSimple) {
return `function(${args}) {\n return ${body};\n}`;
}
else {
return `function(${args}) {\n${body}\n}`;
}
}
function generateLambdaCall(lambdaCall) {
const args = lambdaCall.lambda.args.join(", ");
const argsValues = (function (y) {
return y.join(", ");
})(List.map(generateExpression, lambdaCall.args));
const body = generateExpression(lambdaCall.lambda.body);
return `(function(${args}) {\n return ${body};\n})(${argsValues})`;
}
function generateEquality(equality) {
const left = generateExpression(equality.left);
const right = generateExpression(equality.right);
return `${left} === ${right}`;
}
function generateInEquality(inEquality) {
const left = generateExpression(inEquality.left);
const right = generateExpression(inEquality.right);
return `${left} !== ${right}`;
}
function generateLessThan(lessThan) {
const left = generateExpression(lessThan.left);
const right = generateExpression(lessThan.right);
return `${left} < ${right}`;
}
function generateLessThanOrEqual(lessThanOrEqual) {
const left = generateExpression(lessThanOrEqual.left);
const right = generateExpression(lessThanOrEqual.right);
return `${left} <= ${right}`;
}
function generateGreaterThan(greaterThan) {
const left = generateExpression(greaterThan.left);
const right = generateExpression(greaterThan.right);
return `${left} > ${right}`;
}
function generateGreaterThanOrEqual(greaterThanOrEqual) {
const left = generateExpression(greaterThanOrEqual.left);
const right = generateExpression(greaterThanOrEqual.right);
return `${left} >= ${right}`;
}
function generateAnd(and) {
const left = generateExpression(and.left);
const right = generateExpression(and.right);
return `${left} && ${right}`;
}
function generateOr(or) {
const left = generateExpression(or.left);
const right = generateExpression(or.right);
return `${left} || ${right}`;
}
function generateListPrepend(prepend) {
const left = generateExpression(prepend.left);
const right = generateExpression(prepend.right);
return `[ ${left}, ...${right} ]`;
}
function generateExpression(expression) {
switch (expression.kind) {
case "Value": {
return (0, CommonToEcma_1.generateValue)(expression);
}
case "StringValue": {
return (0, CommonToEcma_1.generateStringValue)(expression);
}
case "FormatStringValue": {
return (0, CommonToEcma_1.generateFormatStringValue)(expression);
}
case "ListValue": {
return generateListValue(expression);
}
case "ListRange": {
return (0, CommonToEcma_1.generateListRange)(expression);
}
case "ObjectLiteral": {
return generateObjectLiteral(expression);
}
case "IfStatement": {
return generateIfStatement(expression, false, false);
}
case "CaseStatement": {
return generateCaseStatement(expression);
}
case "Addition": {
return generateAddition(expression);
}
case "Subtraction": {
return generateSubtraction(expression);
}
case "Multiplication": {
return generateMultiplication(expression);
}
case "Division": {
return generateDivision(expression);
}
case "Mod": {
return generateMod(expression);
}
case "And": {
return generateAnd(expression);
}
case "Or": {
return generateOr(expression);
}
case "ListPrepend": {
return generateListPrepend(expression);
}
case "LeftPipe": {
return generateLeftPipe(expression);
}
case "RightPipe": {
return generateRightPipe(expression);
}
case "ModuleReference": {
return generateModuleReference(expression);
}
case "FunctionCall": {
return generateFunctionCall(expression);
}
case "Lambda": {
return generateLambda(expression);
}
case "LambdaCall": {
return generateLambdaCall(expression);
}
case "Constructor": {
return generateConstructor(expression);
}
case "Equality": {
return generateEquality(expression);
}
case "InEquality": {
return generateInEquality(expression);
}
case "LessThan": {
return generateLessThan(expression);
}
case "LessThanOrEqual": {
return generateLessThanOrEqual(expression);
}
case "GreaterThan": {
return generateGreaterThan(expression);
}
case "GreaterThanOrEqual": {
return generateGreaterThanOrEqual(expression);
}
}
}
function generateDoExpression(expression) {
switch (expression.kind) {
case "Const": {
return generateConst(expression, true);
}
case "Function": {
return generateFunction(expression);
}
case "FunctionCall": {
return (function (y) {
return "await " + y + ";";
})(generateFunctionCall(expression));
}
case "ModuleReference": {
return (function (y) {
return "await " + y + ";";
})(generateModuleReference(expression));
}
case "IfStatement": {
return generateIfStatement(expression, true, true);
}
}
}
function generateDoBlock(doBody) {
return (function (y) {
return y.join("\n");
})(List.map(function (expression) {
return generateDoExpression(expression);
}, doBody.expressions));
}
function generateFunctionArg(arg) {
switch (arg.kind) {
case "FunctionArg": {
const { name } = arg;
return name;
}
case "AnonFunctionArg": {
const { index } = arg;
return `_${index}`;
}
}
}
function generateFunction(function_) {
const args = (function (y) {
return y.join(", ");
})(List.map(function (arg) {
return generateFunctionArg(arg);
}, function_.args));
const maybeLetBody = generateLetBlock(function_.letBody);
const isAsync = function_.doBody !== null;
const maybeAsyncPrefix = isAsync ? "async " : "";
const maybeDoBody = function_.doBody === null ? "" : (function (y) {
return `\n${(0, Common_1.prefixLines)(y, 4)}`;
})(generateDoBlock(function_.doBody));
const isSimpleBody = (0, types_1.isSimpleValue)(function_.body.kind);
const bodyPrefix = isSimpleBody ? "return " : "";
const bodySuffix = isSimpleBody ? ";" : "";
const body = (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})((function (y) {
return bodyPrefix + y + bodySuffix;
})(generateExpression(function_.body)));
return (function (y) {
return y.join("\n");
})([`${maybeAsyncPrefix}function ${function_.name}(${args}) {${maybeLetBody}${maybeDoBody}`, `${body}`, `}`]);
}
function generateInlineIf(expression) {
const ifBody = (function () {
switch (expression.ifBody.kind) {
case "IfStatement": {
return `( ${generateInlineIf(expression.ifBody)} )`;
}
default: {
return generateExpression(expression.ifBody);
}
}
})();
const elseBody = (function () {
switch (expression.elseBody.kind) {
case "IfStatement": {
return `( ${generateInlineIf(expression.elseBody)} )`;
}
default: {
return generateExpression(expression.elseBody);
}
}
})();
return `${generateExpression(expression.predicate)} ? ${ifBody} : ${elseBody}`;
}
function generateInlineCase(expression) {
return `(function () {\n${(0, Common_1.prefixLines)(generateExpression(expression), 4)}\n})()`;
}
function generateNestedConst(constDef, body) {
const generatedBlocks = List.map(function (block) {
return generateBlock(block);
}, constDef.letBody);
const joinedBlocks = (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})(generatedBlocks.join("\n"));
return `(function() {\n${joinedBlocks}\n return ${body};\n})()`;
}
function generateConst(constDef, isAsync) {
const body = (function () {
switch (constDef.value.kind) {
case "IfStatement": {
if (constDef.letBody.length === 0) {
return generateInlineIf(constDef.value);
}
else {
return generateNestedConst(constDef, generateInlineIf(constDef.value));
}
;
}
case "CaseStatement": {
if (constDef.letBody.length === 0) {
return generateInlineCase(constDef.value);
}
else {
return generateNestedConst(constDef, generateInlineCase(constDef.value));
}
;
}
default: {
if (constDef.letBody.length === 0) {
return generateExpression(constDef.value);
}
else {
return generateNestedConst(constDef, generateExpression(constDef.value));
}
;
}
}
})();
const maybeAsyncPrefix = isAsync ? "await " : "";
return `const ${constDef.name} = ${maybeAsyncPrefix}${body};`;
}
function generateBlock(syntax, unionTypeNames) {
switch (syntax.kind) {
case "Import": {
return (0, CommonToEcma_1.generateImportBlock)(syntax);
}
case "Export": {
const actualUnionTypeNames = unionTypeNames || [];
const exportingBlock = Object.assign(Object.assign({}, syntax), { names: syntax.names.filter(function (name) {
return !actualUnionTypeNames.includes(name);
}) });
return (0, CommonToEcma_1.generateExportBlock)(exportingBlock);
}
case "UnionType": {
return generateUnionType(syntax);
}
case "UnionUntaggedType": {
return "";
}
case "TypeAlias": {
return generateTypeAlias(syntax);
}
case "Typeclass": {
return "";
}
case "Impl": {
return "";
}
case "Function": {
return generateFunction(syntax);
}
case "Const": {
return generateConst(syntax, false);
}
case "Comment": {
return "";
}
case "MultilineComment": {
return "";
}
}
}
function generateJavascript(module) {
const unionTypeNames = List.map(function (block) {
return block.type.name;
}, List.filter(function (block) {
return block.kind === "UnionType";
}, module.body));
const testExports = (0, Blocks_1.exportTests)(module);
const withTestExports = [testExports, ...module.body];
return (function (y) {
return y.join("\n\n");
})(List.filter(function (line) {
return line.length > 0;
}, List.map(function (block) {
return generateBlock(block, unionTypeNames);
}, withTestExports)));
}
exports.generateJavascript = generateJavascript;