UNPKG

derw

Version:

An Elm-inspired language that transpiles to TypeScript

274 lines (255 loc) 8.43 kB
import { getNameFromPath } from "../Utils"; import * as List from "../stdlib/List"; import { Value, StringValue, FormatStringValue, ListRange, ListDestructurePart, ModuleReference, Expression, LeftPipe, Lambda, Export, ImportModule, Import } from "../types"; export { generateValue }; export { generateStringValue }; export { generateFormatStringValue }; export { generateListRange }; export { generateListDestructurePart }; export { flattenLeftPipe }; export { generateImportBlock }; export { generateExportBlock }; type FunctionCall = { kind: "FunctionCall"; name: string; args: Expression[]; }; function FunctionCall(args: { name: string, args: Expression[] }): FunctionCall { return { kind: "FunctionCall", ...args, }; } type LambdaCall = { kind: "LambdaCall"; args: Expression[]; lambda: Lambda; }; function LambdaCall(args: { args: Expression[], lambda: Lambda }): LambdaCall { return { kind: "LambdaCall", ...args, }; } type MyExpressions = FunctionCall | LambdaCall; function generateValue(value: Value): string { return value.body; } function generateStringValue(string: StringValue): string { return `"${string.body}"`; } function generateFormatStringValue(string: FormatStringValue): string { return "`" + string.body + "`"; } function generateListRange(list: ListRange): string { const gap: string = `${list.end.body} - ${list.start.body} + 1`; return `Array.from({ length: ${gap} }, (_ReservedX, _ReservedI) => _ReservedI + ${list.start.body})`; } function generateListDestructurePart(part: ListDestructurePart): string { switch (part.kind) { case "EmptyList": { return "[]"; } case "StringValue": { const { body } = part; return body; } case "FormatStringValue": { const { body } = part; return body; } case "Value": { const { body } = part; return body; } case "Destructure": { const { constructor, pattern } = part; const generatedPattern: string = pattern ? ` ${pattern}` : ""; return `${constructor}${pattern}`; } } } function addArgsToModuleReference(moduleReference: ModuleReference, newArgs: Expression[]): ModuleReference { switch (moduleReference.value.kind) { case "FunctionCall": { const { args, name } = moduleReference.value; return { ...moduleReference, value: FunctionCall({ name, args: List.append(args, newArgs) }) }; } case "Value": { const { body } = moduleReference.value; return { ...moduleReference, value: FunctionCall({ name: body, args: newArgs }) }; } default: { return moduleReference; } } } function flattenLeftPipe(leftPipe: LeftPipe): any { const left: Expression = leftPipe.left; const right: Expression = leftPipe.right; switch (right.kind) { case "FunctionCall": { const { name, args } = right; return FunctionCall({ name, args: List.append(args, [ left ]) }); } case "Value": { const { body } = right; return FunctionCall({ name: body, args: [ left ] }); } case "ModuleReference": { return addArgsToModuleReference(right, [ left ]); } case "Lambda": { return LambdaCall({ lambda: right, args: [ left ] }); } case "LeftPipe": { switch (right.left.kind) { case "FunctionCall": { const { args, name } = right.left; const fn: FunctionCall = FunctionCall({ name, args: List.append(args, [ left ]) }); return flattenLeftPipe({ kind: "LeftPipe", left: fn, right: right.right }); } case "Value": { const { body } = right.left; const fn: FunctionCall = FunctionCall({ name: body, args: [ left ] }); return flattenLeftPipe({ kind: "LeftPipe", left: fn, right: right.right }); } case "ModuleReference": { const fn: ModuleReference = addArgsToModuleReference(right.left, [ left ]); return flattenLeftPipe({ kind: "LeftPipe", left: fn, right: right.right }); } case "Lambda": { const fn: any = LambdaCall({ lambda: right.left, args: [ left ] }); return flattenLeftPipe({ kind: "LeftPipe", left: fn, right: right.right }); } case "LeftPipe": { return right; } default: { return right.left; } }; } } } function generateModule(module: ImportModule): string { if (module.namespace === "Relative") { const withoutQuotes: string = module.name.slice(1, -1); const name: string = (function (): any { switch (module.alias.kind) { case "Just": { const { value } = module.alias; return value; } case "Nothing": { return getNameFromPath(withoutQuotes); } } })(); const filteredExposing: string[] = (function (): any { switch (module.alias.kind) { case "Just": { const { value } = module.alias; return List.filter(function(expose: any) { return expose !== value; }, module.exposing); } case "Nothing": { return module.exposing; } } })(); const exposed: string = `import { ${filteredExposing.join(", ")} } from ${module.name};`; if (module.exposing.length === 0) { return `import * as ${name} from ${module.name};`; } else { switch (module.alias.kind) { case "Just": { return `import * as ${name} from ${module.name};\n${exposed}`; } case "Nothing": { return exposed; } }; }; } else { const name: string = (function (): any { switch (module.alias.kind) { case "Just": { const { value } = module.alias; return value; } case "Nothing": { return module.name; } } })(); const exposed: string = `import { ${module.exposing.join(", ")} } from "${module.name}";`; if (module.exposing.length === 0) { return `import * as ${name} from "${module.name}";`; } else { switch (module.alias.kind) { case "Just": { return `import * as ${name} from "${module.name}";\n${exposed}`; } case "Nothing": { return exposed; } }; }; } } function generateImportBlock(imports: Import): string { return (function(y: any) { return y.join("\n"); })(List.map(generateModule, List.filter(function(module: any) { return module.name !== "globalThis"; }, imports.modules))); } function generateExportBlock(exports: Export): string { return (function(x: any) { return x.join("\n"); })(List.map(function(name: any) { return `export { ${name} };`; }, exports.names)); }