diff options
Diffstat (limited to '')
| -rw-r--r-- | src/index.ts | 218 |
1 files changed, 7 insertions, 211 deletions
diff --git a/src/index.ts b/src/index.ts index 34038bf..2fa1f96 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,218 +1,14 @@ -import { Project, ScriptTarget, Type, Node, SyntaxKind } from 'ts-morph' -import path from 'path' -import { promises as fs } from 'fs' -import readline from 'readline'; -import { v4 as uuid } from 'uuid'; -import { match } from './util'; - -const rl = readline.createInterface({ - input: process.stdin, - output: process.stdout, - terminal: false -}); - -const readLineFromStdin = (): Promise<string> => new Promise((res) => { - rl.on('line', res) -}) - -const project = new Project({ - compilerOptions: { - target: ScriptTarget.ES3, - }, -}) - -const typeChecker = project.getTypeChecker() - -const [filePath] = process.argv.slice(2) - -if (!filePath) { - throw new Error('Must specify runtime file') -} - -const sourceFile = project.addSourceFileAtPath(path.resolve(filePath)) - -const entryPoint = sourceFile.getExportedDeclarations().get('main')?.[0] - -const typeToString = (ty: Type | undefined): string => - ty ? typeChecker.compilerObject.typeToString(ty.compilerType) : '' - -const typeRefNode = entryPoint?.getLastChild() - -const RESULT_TYPE_NAME = '__$result' - -const [resultTypeNode] = sourceFile.addStatements(`type ${RESULT_TYPE_NAME} = {}`) - -const addResult = (name: string, ty: string): Node | undefined => { - if (resultTypeNode?.isKind(SyntaxKind.TypeAliasDeclaration)) { - const value = resultTypeNode.getChildAtIndex(3) - if (value.isKind(SyntaxKind.TypeLiteral)) { - return value.addProperty({ - name: JSON.stringify(name), - type: `{ output: ${ty} }`, - }) - } - } - return -} - -const customEffects: Record<string, (...args: Type[]) => any> = {} - -const evaluateType = async (effTyp: Type, node: Node): Promise<string[]> => { - const name = effTyp.getSymbol()?.getName() - // console.log(name) - - return match(name, { - DefineEffect: async () => { - const [nameTyp, exprTyp] = effTyp.getTypeArguments() - const name = nameTyp?.getLiteralValue() as string - const exprStr = exprTyp?.getLiteralValue() as string - const func = eval(exprStr) - - Object.assign(customEffects, { [name]: func }) - return [] - }, - - Print: async () => { - console.log(...effTyp.getTypeArguments().map(typeToString)); - return [] - }, - - PutString: async () => { - const [strinTyp] = effTyp.getTypeArguments() - const typString = typeToString(strinTyp) - const string = JSON.parse(!typString.startsWith('"') ? `"${typString}"` : typString) - process.stdout.write(string); - return [] - }, - - Debug: async () => { - const [labelTyp, valueTyp] = effTyp.getTypeArguments() - const label = JSON.parse(typeToString(labelTyp)) - const value = typeToString(valueTyp) - console.log(label, value) - // TODO: Return value - return [] - }, - - ReadFile: async () => { - const [pathTyp] = effTyp.getTypeArguments() - const filePath = JSON.parse(typeToString(pathTyp)) - const contents = await fs.readFile(filePath, 'utf-8') - const hash = uuid() - addResult(hash, JSON.stringify(contents)) - return [hash] - }, - - WriteFile: async () => { - const [pathTyp, contentsTyp] = effTyp.getTypeArguments() - const filePath = JSON.parse(typeToString(pathTyp)) - const contents = JSON.parse(typeToString(contentsTyp)) - await fs.writeFile(filePath, contents) - return [] - }, - - Bind: async () => { - const [inputTyp, chainToKind] = effTyp.getTypeArguments() - const [resultKey] = inputTyp ? await evaluateType(inputTyp, node) : [] - - const hash = uuid() - const compNode = addResult(hash, - `(${typeToString(chainToKind)} & { input: ${RESULT_TYPE_NAME}[${JSON.stringify(resultKey)}]['output'] })['return']`) - const compTyp = compNode?.getType().getProperty('output')?.getTypeAtLocation(node) - - return compTyp ? await evaluateType(compTyp, node) : [] - }, - - GetEnv: async () => { - const [envTyp] = effTyp.getTypeArguments() - const envName = JSON.parse(typeToString(envTyp)) - const hash = uuid() - addResult(hash, `${JSON.stringify(process.env[envName] ?? '')}`) - return [hash] - }, - - GetArgs: async () => { - const hash = uuid() - addResult(hash, `${JSON.stringify(process.argv.slice(2))}`) - return [hash] - }, - - ReadLine: async () => { - const line = await readLineFromStdin() - const hash = uuid() - addResult(hash, `${JSON.stringify(line)}`) - return [hash] - }, - - JsExpr: async () => { - const [exprTyp] = effTyp.getTypeArguments() - const exprStr = JSON.parse(typeToString(exprTyp)) - const result = eval(`JSON.stringify(${exprStr})`) - const hash = uuid() - addResult(hash, `${result}`) - return [hash] - }, - - Seq: async () => { - const [effectTyps] = effTyp.getTypeArguments() - const effectResults = await evalList(effectTyps?.getTupleElements() ?? [], node) - const hash = uuid() - addResult(hash, `[ - ${effectResults.map(r => `${RESULT_TYPE_NAME}[${JSON.stringify(r)}]`).join(', ')} - ]`) - return [hash] - }, - - Do: async () => { - const [effectTyps] = effTyp.getTypeArguments() - const effectResults = await evalList(effectTyps?.getTupleElements() ?? [], node) - const resultKey = effectResults[effectResults.length - 1] - const hash = uuid() - addResult(hash, `${RESULT_TYPE_NAME}[${JSON.stringify(resultKey)}]['output']`) - return [hash] - }, - - _: async () => { - if (name && customEffects[name]) { - const out = await customEffects[name]?.(...effTyp.getTypeArguments()) - if (out) { - const hash = uuid() - addResult(hash, `${JSON.stringify(out)}`) - return [hash] - } - } else { - console.log(`${name} result effect is unhandled`) - } - return [] - }, - }) -} - -const evalList = async (effectTyps: Type[], node: Node) => { - const effectResults: string[] = [] - for (const item of effectTyps ?? []) { - effectResults.push(...(await evaluateType(item, node))) - } - return effectResults -} +import { createContext } from './context'; +import { evalList } from './eval'; const main = async () => { - if (typeRefNode) { - const resultType = entryPoint?.getType() - - if (resultType) { - const effects = resultType.isTuple() ? resultType.getTupleElements() : [resultType] - await evalList(effects, typeRefNode) - } - } + const ctx = createContext() + const resultType = ctx.entryPoint.getType() + const effects = resultType.isTuple() ? resultType.getTupleElements() : [resultType] + await evalList(ctx, effects) } main() - .then(() => { - // console.log(entryPoint?.print()) - // console.log(resultTypeNode?.print()) - rl.close() - process.exit(0) - }) + .then(() => process.exit(0)) .catch(e => (console.error(e), process.exit(1))) |
