aboutsummaryrefslogtreecommitdiff
path: root/src/eval-env
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2023-01-13 19:21:41 +0530
committerAkshay Nair <phenax5@gmail.com>2023-01-13 19:21:41 +0530
commit8ba316461d2dc0a1372af16836ce14ceabc2bf4f (patch)
treeafcd80654b1e83fe78fcb4bf69a71f730ee3e299 /src/eval-env
parentfe710f58a982e31e64c02d887567bcd9a4108b24 (diff)
downloadts-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.ts142
-rw-r--r--src/eval-env/node.ts61
-rw-r--r--src/eval-env/test.ts31
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 []
+ },
+})