diff options
| author | Akshay Nair <phenax5@gmail.com> | 2023-01-13 19:21:41 +0530 |
|---|---|---|
| committer | Akshay Nair <phenax5@gmail.com> | 2023-01-13 19:21:41 +0530 |
| commit | 8ba316461d2dc0a1372af16836ce14ceabc2bf4f (patch) | |
| tree | afcd80654b1e83fe78fcb4bf69a71f730ee3e299 /src/eval-env | |
| parent | fe710f58a982e31e64c02d887567bcd9a4108b24 (diff) | |
| download | ts-types-lang-8ba316461d2dc0a1372af16836ce14ceabc2bf4f.tar.gz ts-types-lang-8ba316461d2dc0a1372af16836ce14ceabc2bf4f.zip | |
feat: adds test to stdlib + refactors runtime environment
Diffstat (limited to '')
| -rw-r--r-- | src/eval-env/builtins.ts | 142 | ||||
| -rw-r--r-- | src/eval-env/node.ts | 61 | ||||
| -rw-r--r-- | src/eval-env/test.ts | 31 |
3 files changed, 234 insertions, 0 deletions
diff --git a/src/eval-env/builtins.ts b/src/eval-env/builtins.ts new file mode 100644 index 0000000..3adde06 --- /dev/null +++ b/src/eval-env/builtins.ts @@ -0,0 +1,142 @@ +import { Type } from 'ts-morph' +import { Ctx } from "../types" + +export default (ctx: Ctx, args: Type[]) => ({ + SetEvalEnvironment: async () => { + ctx.setEnv(ctx.getTypeValue(args[0])) + return [] + }, + + DefineEffect: async () => { + const [nameTyp, exprTyp] = args + const name = nameTyp?.getLiteralValue() as string + const exprStr = exprTyp?.getLiteralValue() as string + + ctx.addCustomEffect(name, exprStr) + return [] + }, + + CreateRef: async () => { + const val = ctx.typeToString(args[0]) + const refKey = ctx.createRef(val) + const [resultKey, _] = ctx.createResult(JSON.stringify(refKey)) + return [resultKey] + }, + + GetRef: async () => { + const refKey = ctx.getTypeValue(args[0]) + const val = ctx.getRef(refKey) + if (!val) throw new Error('Ref has been deleted') + const [resultKey, _] = ctx.createResult(val) + return [resultKey] + }, + + SetRef: async () => { + const [ keyTy, valTyp ] = args + ctx.setRef(ctx.getTypeValue(keyTy), ctx.typeToString(valTyp)) + return [] + }, + + DeleteRef: async () => { + ctx.deleteRef(ctx.getTypeValue(args[0])) + return [] + }, + + Pure: async () => { + const [valTyp] = args + const [resultKey, _] = ctx.createResult(ctx.typeToString(valTyp)) + return [resultKey] + }, + + Print: async () => { + console.log(...args.map(ctx.typeToString)) + return [] + }, + + PutString: async () => { + const [strinTyp] = args + const typString = ctx.getTypeValue(strinTyp) ?? ctx.typeToString(strinTyp) + process.stdout.write(typString) + return [] + }, + + Debug: async () => { + const [labelTyp, valueTyp] = args + const label = ctx.getTypeValue(labelTyp) + const value = ctx.typeToString(valueTyp) + console.log(label, value) + const [resultKey, _] = ctx.createResult(JSON.stringify(value)) + return [resultKey] + }, + + Bind: async () => { + const [inputTyp, chainToKind] = args + const [resultKey] = inputTyp ? await ctx.evaluateType(ctx, inputTyp) : [] + + // TODO: Handle resultKey undefined case + const [_, compNode] = ctx.createResult( + `(${ctx.typeToString(chainToKind)} & { input: (${ctx.getResultExpr( + resultKey + )})['output'] })['return']` + ) + // TODO: Avoid using getTypeAtLocation? + const compTyp = compNode + ?.getType() + .getProperty('output') + ?.getTypeAtLocation(ctx.entryPoint) + + return compTyp ? await ctx.evaluateType(ctx, compTyp) : [] + }, + + Try: async () => { + const [effTyp, catchK] = args + + try { + if (!effTyp) throw new Error('wow') + return await ctx.evaluateType(ctx, effTyp) + } catch(e) { + const error = JSON.stringify((e as any)?.message ?? e) + const catchResExpr = `(${ctx.typeToString(catchK)} & { input: ${error} })['return']` + const [resultKey, _] = ctx.createResult(catchResExpr) + return [resultKey] + } + }, + + Throw: async () => { + throw args[0] && ctx.getTypeValue(args[0]) + }, + + JsExpr: async () => { + const [exprTyp] = args + const exprStr = ctx.getTypeValue(exprTyp) + const result = eval(`JSON.stringify(${exprStr})`) + const [resultKey, _] = ctx.createResult(`${result}`) + return [resultKey] + }, + + Seq: async () => { + const [effectTyps] = args + const effectResults = await evalList( + ctx, + effectTyps?.getTupleElements() ?? [] + ) + const [resultKey, _] = ctx.createResult(`[ + ${effectResults.map(ctx.getResultExpr).join(', ')} + ]`) + return [resultKey] + }, + + Do: async () => { + const [effectTyps] = args + const effectResults = await evalList( + ctx, + effectTyps?.getTupleElements() ?? [] + ) + // TODO: Use last type's result instead of last result key + const lastResKey = effectResults[effectResults.length - 1] + const [resultKey, _] = ctx.createResult( + `(${ctx.getResultExpr(lastResKey)})['output']` + ) + return [resultKey] + }, +}) diff --git a/src/eval-env/node.ts b/src/eval-env/node.ts new file mode 100644 index 0000000..5e73987 --- /dev/null +++ b/src/eval-env/node.ts @@ -0,0 +1,61 @@ +import { Type } from 'ts-morph' +import { promises as fs } from 'fs' +import readline from 'readline' +import { Ctx } from '../types' + +const rl = readline.createInterface({ + input: process.stdin, + output: process.stdout, + terminal: false, +}) + +const readLineFromStdin = (): Promise<string> => + new Promise((res) => rl.on('line', res)) + +export const cleanup = () => { + rl.close() +} + +export default (ctx: Ctx, args: Type[]) => ({ + ReadFile: async () => { + const [pathTyp] = args + const filePath = ctx.getTypeValue(pathTyp) + const contents = await fs.readFile(filePath, 'utf-8') + const [resultKey, _] = ctx.createResult(JSON.stringify(contents)) + return [resultKey] + }, + + WriteFile: async () => { + const [pathTyp, contentsTyp] = args + const filePath = ctx.getTypeValue(pathTyp) + const contents = ctx.getTypeValue(contentsTyp) + await fs.writeFile(filePath, contents) + return [] + }, + + GetEnv: async () => { + const [envTyp] = args + const envName = ctx.getTypeValue(envTyp) + const [resultKey, _] = ctx.createResult( + `${JSON.stringify(process.env[envName] ?? '')}` + ) + return [resultKey] + }, + + GetArgs: async () => { + const [resultKey, _] = ctx.createResult( + `${JSON.stringify(process.argv.slice(2))}` + ) + return [resultKey] + }, + + Exit: async () => { + process.exit(args[0] && ctx.getTypeValue(args[0])) + }, + + ReadLine: async () => { + const line = await readLineFromStdin() + const [resultKey, _] = ctx.createResult(`${JSON.stringify(line)}`) + return [resultKey] + }, +}) diff --git a/src/eval-env/test.ts b/src/eval-env/test.ts new file mode 100644 index 0000000..c394752 --- /dev/null +++ b/src/eval-env/test.ts @@ -0,0 +1,31 @@ +import { Type } from 'ts-morph' +import { Ctx } from '../types' + +export const cleanup = () => {} + +export default (ctx: Ctx, args: Type[]) => ({ + Test: async () => { + const [msg, effs] = args + process.stdout.write(` - ${ctx.getTypeValue(msg)}`) + + try { + for (const eff of effs?.getTupleElements() ?? []) { + await ctx.evaluateType(ctx, eff) + } + + console.log(' [✓]') + } catch(e) { + console.log(' [TEST FAILED]') + throw e + } + return [] + }, + + Assert: async () => { + const [b] = args + if (!ctx.getTypeValue(b)) { + throw new Error('Assertion failed') + } + return [] + }, +}) |
