aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/eval-env/builtins.ts8
-rw-r--r--src/eval-env/test.ts17
-rw-r--r--src/eval.ts2
-rw-r--r--src/index.ts17
-rw-r--r--stdlib/test.ts31
-rw-r--r--tests/builtins.spec.ts96
6 files changed, 151 insertions, 20 deletions
diff --git a/src/eval-env/builtins.ts b/src/eval-env/builtins.ts
index 669a005..35f8485 100644
--- a/src/eval-env/builtins.ts
+++ b/src/eval-env/builtins.ts
@@ -6,10 +6,10 @@ const applyFunc = (ctx: Ctx, fn: Type | undefined, val: string): Type => {
const resultType = (() => {
const baseTypes = fn
?.getBaseTypes()
- .flatMap((t) => t.getSymbol()?.getName())
+ .flatMap((t) => t.getSymbol()?.getName() ?? [])
- if (baseTypes?.includes('Kind1')) {
- const [_, resultNode] = ctx.createResult(
+ if (!!fn?.getProperty('return') || baseTypes?.includes('Kind1')) {
+ const [_key, resultNode] = ctx.createResult(
`(${ctx.typeToString(fn)} & { input: ${val} })['return']`
)
return resultNode
@@ -53,7 +53,7 @@ const applyFunc = (ctx: Ctx, fn: Type | undefined, val: string): Type => {
// TODO: Cleanup unwanted result node values
if (!resultType) {
- throw new Error('Fuck shit')
+ throw new Error('Couldnt get result for function application')
}
return resultType
diff --git a/src/eval-env/test.ts b/src/eval-env/test.ts
index 84ae138..4dd8c8d 100644
--- a/src/eval-env/test.ts
+++ b/src/eval-env/test.ts
@@ -2,7 +2,7 @@ import { Type } from 'ts-morph'
import { Ctx } from '../types'
export default (ctx: Ctx, args: Type[]) => ({
- Test: async () => {
+ Test: ctx.withScope(async () => {
const [msg, effs] = args
process.stdout.write(` - ${ctx.getTypeValue(msg)} `)
@@ -13,12 +13,12 @@ export default (ctx: Ctx, args: Type[]) => ({
console.log('[✓]')
} catch (e) {
- console.log('[TEST FAILED]')
+ // console.log('[TEST FAILED]')
throw e
}
return []
- },
+ }),
Assert: async () => {
if (!ctx.getTypeValue(args[0])) {
@@ -27,4 +27,15 @@ export default (ctx: Ctx, args: Type[]) => ({
return []
},
+
+ ShowAssertionError: async () => {
+ const [left, right] = args
+ console.log()
+ console.log(' | Assertion error:')
+ console.log(' | - Left: ', ctx.typeToString(left))
+ console.log(' | - Right:', ctx.typeToString(right))
+ console.log()
+
+ return []
+ },
})
diff --git a/src/eval.ts b/src/eval.ts
index a7b1fb1..6eb72a1 100644
--- a/src/eval.ts
+++ b/src/eval.ts
@@ -32,6 +32,7 @@ export const evaluateType = async (
const name = effTyp.getSymbol()?.getName()
const args = effTyp.getTypeArguments()
+ // console.log('>>>>>', name)
// console.log(ctx.typeToString(effTyp))
// console.log(name, args.map(ctx.typeToString))
@@ -58,6 +59,7 @@ export const evaluateType = async (
prevEnv = ctx.currentEnv
}
+ // Evaluate custom effects (overrides builtins)
if (name && ctx.hasCustomEffect(name)) {
return ctx.runCustomEffect(name, args)
}
diff --git a/src/index.ts b/src/index.ts
index f6d46d6..4775823 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -15,12 +15,17 @@ const main = () => {
.description('Run a typescript .ts file')
.argument('<file>', 'Typescript file to run')
.action(async (filePath) => {
- const ctx = createContext({ filePath })
- const resultType = ctx.entryPoint.getType()
- const effects = resultType.isTuple()
- ? resultType.getTupleElements()
- : [resultType]
- await evalList(ctx, effects)
+ try {
+ const ctx = createContext({ filePath })
+ const resultType = ctx.entryPoint.getType()
+ const effects = resultType.isTuple()
+ ? resultType.getTupleElements()
+ : [resultType]
+ await evalList(ctx, effects)
+ } catch (e) {
+ console.error(e)
+ process.exit(1)
+ }
})
return program.parseAsync()
diff --git a/stdlib/test.ts b/stdlib/test.ts
index 639c433..a592d87 100644
--- a/stdlib/test.ts
+++ b/stdlib/test.ts
@@ -1,12 +1,29 @@
-import { Effect } from './effect'
+import { Do, Effect, Kind1 } from './effect'
+import { Throw, Try } from './exception'
+import { Equals } from './util'
export interface Config {
- compileTimeTestFailures: false
- stopAtFailure: true // TODO: stopAtFailure
+ // compileTimeTestFailures: false
+ // stopAtFailure: true // TODO: stopAtFailure
}
-type Assertion = Config['compileTimeTestFailures'] extends true ? true : boolean
+export interface Assert<_B extends boolean> extends Effect {}
+
+export interface Test<_m extends string, _effs extends Effect[]> extends Effect {}
+
+export interface ShowAssertionError<_L extends unknown, _R extends unknown> extends Effect {}
+
+export type AssertEquals<Left, Right> = Try<
+ Assert<Equals<Left, Right>>,
+ <e extends string>() => Do<[
+ ShowAssertionError<Left, Right>,
+ Throw<e>,
+ ]>
+>
+
+export interface AssertEqualsK<Right extends unknown> extends Kind1 {
+ return: AssertEquals<this['input'], Right>
+}
+
+// TODO: export interface AssertFails?
-export interface Assert<_B extends Assertion> extends Effect {}
-export interface Test<_m extends string, _effs extends Effect[]>
- extends Effect {}
diff --git a/tests/builtins.spec.ts b/tests/builtins.spec.ts
new file mode 100644
index 0000000..cd4b5c4
--- /dev/null
+++ b/tests/builtins.spec.ts
@@ -0,0 +1,96 @@
+import { Bind, BindTo, Do, Effect, Label, Pure } from '../stdlib/effect'
+import { Throw, Try } from '../stdlib/exception'
+import { PutStringLn } from '../stdlib/stdio'
+import { DefineEffect, JsExpr, SetEvalEnvironment } from '../stdlib/sys'
+import { Test, AssertEqualsK, AssertEquals } from '../stdlib/test'
+
+type testBind = Do<[
+ PutStringLn<'Bind & BindTo'>,
+
+ Test<'should bind value to function and kind', [
+ Bind<Pure<[1,2,3]>, <val extends number[]>() =>
+ AssertEquals<val, [1, 2, 3]>>,
+
+ Bind<Pure<[1,2,3]>, AssertEqualsK<[1,2,3]>>,
+ ]>,
+
+ Test<'should bind label correctly', [
+ BindTo<"value", Pure<{ a: 'b', c: { d: 1 } }>>,
+
+ Bind<Label<"value">, AssertEqualsK<{ a: 'b', c: { d: 1 } }>>,
+ ]>,
+
+ Test<'should bind only inside Do scope', [
+ Do<[
+ BindTo<"value", Pure<"some value">>,
+ Bind<Label<"value">, AssertEqualsK<"some value">>,
+ ]>,
+
+ Bind<
+ Try<Label<"value">, <_>() => Pure<"none">>,
+ AssertEqualsK<"none">
+ >,
+ ]>,
+
+ Test<'should bind only inside Bind scope', [
+ Bind<
+ BindTo<"value", Pure<"some value">>,
+ <_>() => Bind<Label<"value">, AssertEqualsK<"some value">>
+ >,
+
+ Bind<
+ Try<Label<"value">, <_>() => Pure<"none">>,
+ AssertEqualsK<"none">
+ >,
+ ]>,
+]>
+
+type testExcpt = Do<[
+ PutStringLn<'Try/Throw'>,
+
+ Test<'should return the result of effect', [
+ Bind<Try<Pure<20>, <_>() => Pure<0>>,
+ AssertEqualsK<20>>,
+ ]>,
+
+ Test<'should return the result of error handler', [
+ Bind<Try<Do<[ Throw<"wow">, Pure<20> ]>, <_>() => Pure<0>>,
+ AssertEqualsK<0>>,
+
+ Bind<Try<Do<[ Throw<"wow">, Pure<20> ]>, <e>() => Pure<e>>,
+ AssertEqualsK<"wow">>,
+ ]>,
+]>
+
+interface MyEffect<_a extends number, _b extends string, _c extends unknown> extends Effect {}
+type testFFI = Do<[
+ PutStringLn<'FFI'>,
+
+ Test<'should return the result of js expression', [
+ Bind<JsExpr<'69 * 420'>, AssertEqualsK<28980>>,
+ ]>,
+
+ Test<'should test custom effect', [
+ DefineEffect<'MyEffect', `([a, b, c], ctx) => {
+ return [
+ ctx.getTypeValue(a) * 2,
+ ctx.getTypeValue(b) + '!',
+ [...ctx.getTypeValue(c), 'wow'],
+ ]
+ }`>,
+ Bind<MyEffect<4, "hey", [1, 2]>, AssertEqualsK<[
+ 8, "hey!", [1, 2, 'wow'],
+ ]>>,
+ ]>,
+]>
+
+export type main = [
+ SetEvalEnvironment<'test.node'>,
+
+ PutStringLn<'====================='>,
+ PutStringLn<'=== Running tests ==='>,
+ PutStringLn<'=====================\n\n'>,
+ testBind,
+ testExcpt,
+ testFFI,
+]