derw
Version:
An Elm-inspired language that transpiles to TypeScript
1,268 lines • 51.8 kB
JavaScript
"use strict";
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.generateTypescript = void 0;
const Blocks_1 = require("../Blocks");
const Utils_1 = require("../Utils");
const builtins_1 = require("../builtins");
const List = __importStar(require("../stdlib/List"));
const types_1 = require("../types");
const Common_1 = require("./Common");
const CommonToEcma_1 = require("./CommonToEcma");
function generateTypeArg(arg, imports) {
return `${arg.name}: ${generateType(arg.type, imports)};`;
}
function generateTagCreator(tag, imports) {
const typeDefArgs = (function (y) {
return y.join("\n ");
})(List.map(function (arg) {
return generateTypeArg(arg, imports);
}, tag.args));
const funcDefArgs = (function (y) {
return y.join(", ");
})(List.map(function (arg) {
return `${arg.name}: ${generateType(arg.type, imports)}`;
}, tag.args));
function filterTypes(arg) {
const isBuiltin = (function () {
switch (arg.kind) {
case "FixedType": {
const { name } = arg;
return (0, builtins_1.isBuiltinType)(name);
}
case "GenericType": {
const { name } = arg;
return (0, builtins_1.isBuiltinType)(name);
}
case "FunctionType": {
return false;
}
}
})();
if (isBuiltin) {
return false;
}
else {
return true;
}
}
const newArgs = List.filter(filterTypes, List.map(function (arg) {
return arg.type;
}, tag.args));
const tagType = (function (y) {
return generateType(y, imports);
})({
kind: "FixedType",
name: tag.name,
args: newArgs
});
const funcDefArgsStr = tag.args.length === 0 ? "{}" : `{ ${funcDefArgs} }`;
const typeDefStr = typeDefArgs === "" ? "" : "\n " + typeDefArgs;
return (function (y) {
return y.join("\n");
})([`type ${tagType} = {`, ` kind: "${tag.name}";${typeDefStr}`, "};", "", `function ${tagType}(args: ${funcDefArgsStr}): ${tagType} {`, " return {", ` kind: "${tag.name}",`, ` ...args,`, ` };`, "}"]);
}
function generateTag(tag, imports) {
function filterTypes(arg) {
const isBuiltin = (function () {
switch (arg.kind) {
case "FixedType": {
const { name } = arg;
return (0, builtins_1.isBuiltinType)(name);
}
case "GenericType": {
const { name } = arg;
return (0, builtins_1.isBuiltinType)(name);
}
case "FunctionType": {
return false;
}
}
})();
if (isBuiltin) {
return false;
}
else {
return true;
}
}
const newArgs = List.filter(filterTypes, List.map(function (arg) {
return arg.type;
}, tag.args));
const tagType = (function (y) {
return generateType(y, imports);
})({
kind: "FixedType",
name: tag.name,
args: newArgs
});
return tagType;
}
function generateUnionType(syntax, imports) {
const tagCreators = (function (y) {
return y.join("\n\n");
})(List.map(function (tag) {
return generateTagCreator(tag, imports);
}, syntax.tags));
const tags = (function (y) {
return y.join(" | ");
})(List.map(function (tag) {
return generateTag(tag, imports);
}, syntax.tags));
return (function (y) {
return y.join("\n");
})([tagCreators, "", `type ${generateType(syntax.type, imports)} = ${tags};`]);
}
function generateUnionUntaggedType(syntax) {
const values = (function (y) {
return y.join(" | ");
})(List.map(function (y) {
return `"${y.body}"`;
}, syntax.values));
return `type ${generateType(syntax.type, [])} = ${values};`;
}
function generateProperty(syntax, imports) {
return `${syntax.name}: ${generateTopLevelType(syntax.type, imports)}`;
}
function generateTypeAlias(syntax, imports) {
const generatedProperties = List.map(function (prop) {
return generateProperty(prop, imports);
}, syntax.properties);
const properties = generatedProperties.length === 0 ? "" : ` ${generatedProperties.join(";\n ")};`;
const typeDef = generateType(syntax.type, imports);
const args = generatedProperties.length === 0 ? " " : ` ${generatedProperties.join(", ")} `;
return (function (y) {
return y.join("\n");
})([`type ${typeDef} = {`, properties, "}", "", `function ${typeDef}(args: {${args}}): ${typeDef} {`, " return {", " ...args,", " };", "}"]);
}
function generateListType(args, imports) {
if (args.length > 0 && args[0].kind === "GenericType") {
return `${generateType(args[0], imports)}[]`;
}
else {
const fixedArgs = List.filter(function (type_) {
return type_.kind === "FixedType";
}, args);
const generatedArgs = List.map(function (arg) {
return generateType(arg, imports);
}, fixedArgs);
switch (fixedArgs.length) {
case 0: {
return "any[]";
}
case fixedArgs.length: {
if (fixedArgs.length === 1) {
const [x] = fixedArgs;
return `${generateType(x, imports)}[]`;
}
}
default: {
return `(${generatedArgs.join(" | ")})[]`;
}
}
;
}
}
function generateListTopLevelType(args, imports) {
if (args.length > 0 && args[0].kind === "GenericType") {
return `${generateTopLevelType(args[0], imports)}[]`;
}
else {
const fixedArgs = List.filter(function (type_) {
return type_.kind === "FixedType";
}, args);
const generatedArgs = List.map(function (arg) {
return generateTopLevelType(arg, imports);
}, fixedArgs);
switch (fixedArgs.length) {
case 0: {
return "any[]";
}
case fixedArgs.length: {
if (fixedArgs.length === 1) {
const [x] = fixedArgs;
return `${generateTopLevelType(x, imports)}[]`;
}
}
default: {
return `(${generatedArgs.join(" | ")})[]`;
}
}
;
}
}
function getGenericTypesFromFunctionType(type_) {
return List.filter(function (arg) {
return arg.kind === "GenericType";
}, type_.args);
}
function modulesHasOverlap(type_, modules) {
switch (modules.length) {
case 0: {
return false;
}
case modules.length: {
if (modules.length >= 1) {
const [module_, ...xs] = modules;
switch (module_.alias.kind) {
case "Just": {
const { value } = module_.alias;
if (value === type_.name) {
return true;
}
else {
return modulesHasOverlap(type_, xs);
}
;
}
case "Nothing": {
return modulesHasOverlap(type_, xs);
}
}
;
}
}
default: {
return false;
}
}
}
function typeHasOverlapWithImportedModule(type_, imports) {
switch (imports.length) {
case 0: {
return false;
}
case imports.length: {
if (imports.length >= 1) {
const [import_, ...xs] = imports;
if (modulesHasOverlap(type_, import_.modules)) {
return true;
}
else {
return typeHasOverlapWithImportedModule(type_, xs);
}
;
}
}
default: {
return false;
}
}
}
function generateTopLevelType(type_, imports) {
switch (type_.kind) {
case "GenericType": {
return generateType(type_, imports);
}
case "FixedType": {
const { name, args } = type_;
if (name === "List") {
return generateListTopLevelType(args, imports);
}
else {
if (args.length > 0 && args[0].kind === "FixedType" && args[0].args.length > 0) {
const generatedArgs = List.map(function (arg) {
return generateTopLevelType(arg, imports);
}, args);
return `${name}<${generatedArgs.join(", ")}>`;
}
else {
function getGenericArgs(type_) {
switch (type_.kind) {
case "GenericType": {
return [type_];
}
case "FunctionType": {
return getGenericTypesFromFunctionType(type_);
}
case "FixedType": {
return [type_];
}
case "ObjectLiteralType": {
return [];
}
}
}
const genericArgs = List.foldl(function (arg, xs) {
return List.append(xs, getGenericArgs(arg));
}, [], args);
const generatedGenericArgs = List.map(function (arg) {
return generateType(arg, imports);
}, genericArgs);
const qualifiedName = typeHasOverlapWithImportedModule(type_, imports) ? `${type_.name}.${type_.name}` : type_.name;
if (genericArgs.length === 0) {
return qualifiedName;
}
else {
return `${qualifiedName}<${generatedGenericArgs.join(", ")}>`;
}
;
}
;
}
;
}
case "FunctionType": {
const { args } = type_;
const typeToReturn = generateType(args[args.length - 1], imports);
const parts = List.indexedMap(function (arg, index) {
return `arg${index}: ${generateTopLevelType(arg, imports)}`;
}, args.slice(0, -1));
return `(${parts.join(", ")}) => ${typeToReturn}`;
}
case "ObjectLiteralType": {
return ``;
}
}
}
function getGenericTypes(type_) {
switch (type_.kind) {
case "GenericType": {
return [type_];
}
case "FunctionType": {
return getGenericTypesFromFunctionType(type_);
}
case "FixedType": {
const { args } = type_;
return List.foldl(function (newType, collection) {
return List.append(collection, getGenericTypes(newType));
}, [], args);
}
case "ObjectLiteralType": {
return [];
}
}
}
function removeDuplicateTypes(xs) {
switch (xs.length) {
case 0: {
return [];
}
case xs.length: {
if (xs.length >= 1) {
const [x, ...rest] = xs;
const restNames = List.map(function (y) {
return y.name;
}, rest);
if (restNames.includes(x.name)) {
return removeDuplicateTypes(rest);
}
else {
return [x, ...removeDuplicateTypes(rest)];
}
;
}
}
default: {
return [];
}
}
}
function generateType(type_, imports) {
switch (type_.kind) {
case "GenericType": {
const { name } = type_;
return name;
}
case "FixedType": {
const { name, args } = type_;
if (name === "List") {
return generateListType(args, imports);
}
else {
const genericArgs = removeDuplicateTypes(List.foldl(function (arg, xs) {
return List.append(xs, getGenericTypes(arg));
}, [], args));
const generatedGenericArgs = List.map(function (arg) {
return generateType(arg, imports);
}, genericArgs);
const qualifiedName = typeHasOverlapWithImportedModule(type_, imports) ? `${type_.name}.${type_.name}` : type_.name;
if (genericArgs.length === 0) {
return qualifiedName;
}
else {
return `${qualifiedName}<${generatedGenericArgs.join(", ")}>`;
}
;
}
;
}
case "FunctionType": {
const { args } = type_;
const typeToReturn = generateType(args[args.length - 1], imports);
const parts = List.indexedMap(function (arg, index) {
return `arg${index}: ${generateType(arg, imports)}`;
}, args.slice(0, -1));
return `(${parts.join(", ")}) => ${typeToReturn}`;
}
case "ObjectLiteralType": {
return ``;
}
}
}
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, parentTypeArguments, imports) {
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, parentTypeArguments, [], imports);
}, body));
const prefixedLines = (0, Common_1.prefixLines)(prefixedBody, 4);
return `\n${prefixedLines}`;
}
}
default: {
return "";
}
}
}
function generateElseIfStatement(elseIfStatement, parentTypeArguments) {
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, parentTypeArguments)));
const bodySuffix = isSimpleBody ? ";" : "";
const maybeLetBody = generateLetBlock(elseIfStatement.letBody, parentTypeArguments, []);
return `} else if (${predicate}) {${maybeLetBody}\n${body}${bodySuffix}`;
}
function generateIfStatement(ifStatement, parentTypeArguments, 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 asyncPrefix = isAsync ? "await " : "";
const elseBodyPrefix = isSimpleElseBody ? "return " : "";
const maybeIfLetBody = generateLetBlock(ifStatement.ifLetBody, parentTypeArguments, []);
const maybeElseLetBody = generateLetBlock(ifStatement.elseLetBody, parentTypeArguments, []);
const predicate = generateExpression(ifStatement.predicate);
const ifBody = generateExpression(ifStatement.ifBody, parentTypeArguments);
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, parentTypeArguments);
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, parentTypeArguments);
}, 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: number = -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, parentTypeArguments) {
const isSimpleBody = (0, types_1.isSimpleValue)(branch.body.kind);
const wrapper = isSimpleBody ? " return " : "";
const maybeLetBody = generateLetBlock(branch.letBody, parentTypeArguments, []);
const bodyIndent = isSimpleBody ? 0 : 4;
const branchBody = (function (y) {
return (0, Common_1.prefixLines)(y, bodyIndent);
})(generateExpression(branch.body, parentTypeArguments));
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, parentTypeArguments) {
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, parentTypeArguments);
}, 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 = (function (y) {
return y.join(", ");
})(List.map(function (arg) {
return `${arg}: any`;
}, lambda.args));
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 = (function (y) {
return y.join(", ");
})(List.map(function (arg) {
return `${arg}: any`;
}, lambdaCall.lambda.args));
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, parentTypeArguments, parentTypes) {
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": {
const actualParentTypeArguments = parentTypeArguments || [];
return generateIfStatement(expression, actualParentTypeArguments, false, false);
}
case "CaseStatement": {
const actualParentTypeArguments = parentTypeArguments || [];
return generateCaseStatement(expression, actualParentTypeArguments);
}
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 collectTypeArguments(type_) {
switch (type_.kind) {
case "GenericType": {
const { name } = type_;
if ((0, builtins_1.isBuiltinType)(name)) {
return [];
}
else {
return [name];
}
;
}
case "FixedType": {
const { name, args } = type_;
if ((0, builtins_1.isBuiltinType)(name)) {
return [];
}
else {
return List.foldl(function (xs, ys) {
return List.append(ys, xs);
}, [], List.map(collectTypeArguments, args));
}
;
}
case "FunctionType": {
const { args } = type_;
return List.foldl(function (xs, ys) {
return List.append(ys, xs);
}, [], List.map(collectTypeArguments, args));
}
case "ObjectLiteralType": {
return [];
}
}
}
function generateDoExpression(expression, parentTypeArguments, parentTypes, imports) {
switch (expression.kind) {
case "Const": {
return generateConst(expression, imports, true);
}
case "Function": {
return generateFunction(expression, parentTypeArguments, parentTypes, imports);
}
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, parentTypeArguments, true, true);
}
}
}
function generateDoBlock(doBody, parentTypeArguments, parentTypes, imports) {
return (function (y) {
return y.join("\n");
})(List.map(function (expression) {
return generateDoExpression(expression, parentTypeArguments, parentTypes, imports);
}, doBody.expressions));
}
function generateFunctionArg(arg, imports) {
switch (arg.kind) {
case "FunctionArg": {
const { name, type } = arg;
return `${name}: ${generateTopLevelType(type, imports)}`;
}
case "AnonFunctionArg": {
const { index, type } = arg;
return `_${index}: ${generateTopLevelType(type, imports)}`;
}
}
}
function generateFunction(function_, parentTypeArguments, parentTypes, imports) {
const args = (function (y) {
return y.join(", ");
})(List.map(function (arg) {
return generateFunctionArg(arg, imports);
}, function_.args));
const flattenedArgTypeArguments = List.foldl(function (xs, ys) {
return List.append(ys, xs);
}, [], List.map(function (arg) {
return collectTypeArguments(arg.type);
}, function_.args));
const typeArguments = List.append(flattenedArgTypeArguments, collectTypeArguments(function_.returnType));
const filteredTypeArguments = typeArguments.filter(function (value, index, arr) {
return arr.indexOf(value) === index && parentTypeArguments.indexOf(value) === -1;
});
const maybeLetBody = generateLetBlock(function_.letBody, List.append(filteredTypeArguments, parentTypeArguments), imports);
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, parentTypeArguments, parentTypes, imports)) : "";
const returnType = isAsync ? generateTopLevelType({
kind: "FixedType",
name: "Promise",
args: [function_.returnType]
}, imports) : generateTopLevelType(function_.returnType, imports);
const isSimpleBody = (0, types_1.isSimpleValue)(function_.body.kind);
const bodyPrefix = isSimpleBody ? "return " : "";
const bodySuffix = isSimpleBody ? ";" : "";
const joinedTypeArguments = List.append(typeArguments, parentTypeArguments);
const allParentTypes = List.append(parentTypes, [function_.returnType]);
const body = (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})((function (y) {
return bodyPrefix + y + bodySuffix;
})(generateExpression(function_.body, joinedTypeArguments, allParentTypes)));
const typeArgumentsString = filteredTypeArguments.length === 0 ? "" : `<${filteredTypeArguments.join(", ")}>`;
return (function (y) {
return y.join("\n");
})([`${maybeAsyncPrefix}function ${function_.name}${typeArgumentsString}(${args}): ${returnType} {${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 (): any {\n${(0, Common_1.prefixLines)(generateExpression(expression), 4)}\n})()`;
}
function generateNestedConst(constDef, body, imports) {
const typeDef = generateTopLevelType(constDef.type, imports);
const generatedBlocks = List.map(function (block) {
return generateBlock(block, [], [], imports);
}, constDef.letBody);
const joinedBlocks = (function (y) {
return (0, Common_1.prefixLines)(y, 4);
})(generatedBlocks.join("\n"));
return `(function(): ${typeDef} {\n${joinedBlocks}\n return ${body};\n})()`;
}
function generateConst(constDef, imports, 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), imports);
}
;
}
case "CaseStatement": {
if (constDef.letBody.length === 0) {
return generateInlineCase(constDef.value);
}
else {
return generateNestedConst(constDef, generateInlineCase(constDef.value), imports);
}
;
}
default: {
if (constDef.letBody.length === 0) {
return generateExpression(constDef.value);
}
else {
return generateNestedConst(constDef, generateExpression(constDef.value), imports);
}
;
}
}
})();
const maybeAsyncPrefix = isAsync ? "await " : "";
const typeDef = generateTopLevelType(constDef.type, imports);
return `const ${constDef.name}: ${typeDef} = ${maybeAsyncPrefix}${body};`;
}
function generateBlock(syntax, parentTypeArguments, parentTypes, im