Added FunctionRegistry test and got simple polymorphism working
This commit is contained in:
parent
3f09f5f307
commit
8839f1d9c7
82
packages/squiggle-lang/__tests__/FunctionRegistry_test.res
Normal file
82
packages/squiggle-lang/__tests__/FunctionRegistry_test.res
Normal file
|
@ -0,0 +1,82 @@
|
|||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||
module ExpressionT = Reducer_Expression_T
|
||||
module Module = Reducer_Module
|
||||
module Bindings = Reducer_Module
|
||||
module ErrorValue = Reducer_ErrorValue
|
||||
|
||||
open Jest
|
||||
open Expect
|
||||
|
||||
// ----------------------
|
||||
// --- Start of Module File
|
||||
// ----------------------
|
||||
|
||||
module FooImplementation = {
|
||||
open FunctionRegistry_Core
|
||||
open FunctionRegistry_Helpers
|
||||
|
||||
let library = [
|
||||
Function.make(
|
||||
~name="add",
|
||||
~nameSpace="Foo",
|
||||
~definitions=[
|
||||
FnDefinition.make(
|
||||
~requiresNamespace=false,
|
||||
~name="add",
|
||||
~inputs=[FRTypeNumber, FRTypeNumber],
|
||||
~run=(_, inputs, _) =>
|
||||
switch inputs {
|
||||
| [FRValueNumber(a), FRValueNumber(b)] => Ok(Wrappers.evNumber(a +. b))
|
||||
| _ => Error("False")
|
||||
},
|
||||
(),
|
||||
),
|
||||
FnDefinition.make(
|
||||
~requiresNamespace=true,
|
||||
~name="add",
|
||||
~inputs=[FRTypeNumber, FRTypeNumber, FRTypeNumber],
|
||||
~run=(_, inputs, _) =>
|
||||
switch inputs {
|
||||
| [FRValueNumber(a), FRValueNumber(b), FRValueNumber(c)] =>
|
||||
Ok(Wrappers.evNumber(a +. b +. c))
|
||||
| _ => Error("False")
|
||||
},
|
||||
(),
|
||||
),
|
||||
],
|
||||
(),
|
||||
),
|
||||
]
|
||||
}
|
||||
|
||||
let makeBindings = (previousBindings: Bindings.t): Bindings.t =>
|
||||
previousBindings->FunctionRegistry_Core.Registry.makeModules(FooImplementation.library)
|
||||
|
||||
let stdLibWithFoo = Bindings.emptyBindings->makeBindings
|
||||
|
||||
let evalWithFoo = sourceCode =>
|
||||
Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||
Reducer_Expression.reduceExpression(
|
||||
expr,
|
||||
stdLibWithFoo,
|
||||
InternalExpressionValue.defaultEnvironment,
|
||||
)
|
||||
)
|
||||
|
||||
let evalToStringResultWithFoo = sourceCode =>
|
||||
evalWithFoo(sourceCode)->InternalExpressionValue.toStringResult
|
||||
|
||||
describe("Module", () => {
|
||||
test("add(1,2)", () => {
|
||||
let result = evalToStringResultWithFoo("Foo.add(1,2)")
|
||||
expect(result)->toEqual("Ok(3)")
|
||||
})
|
||||
test("add(1,2,3)", () => {
|
||||
let result = evalToStringResultWithFoo("Foo.add(1,2,3)")
|
||||
expect(result)->toEqual("Ok(6)")
|
||||
})
|
||||
test("add(1,2,3,5)", () => {
|
||||
let result = evalToStringResultWithFoo("Foo.add(1,2,3,5)")
|
||||
expect(result)->toEqual("Ok(6)")
|
||||
})
|
||||
})
|
|
@ -15,6 +15,7 @@
|
|||
"start": "rescript build -w -with-deps",
|
||||
"clean": "rescript clean && rm -rf dist",
|
||||
"test:reducer": "jest __tests__/Reducer*/",
|
||||
"test:reducer2": "jest __tests__/FunctionRegistry_test",
|
||||
"benchmark": "ts-node benchmark/conversion_tests.ts",
|
||||
"test": "jest",
|
||||
"test:ts": "jest __tests__/TS/",
|
||||
|
|
|
@ -328,6 +328,14 @@ module FnDefinition = {
|
|||
t.name ++ `(${inputs})`
|
||||
}
|
||||
|
||||
let isMatch = (t: t, args: array<internalExpressionValue>) => {
|
||||
let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
|
||||
switch argValues {
|
||||
| Some(values) => true
|
||||
| None => false
|
||||
}
|
||||
}
|
||||
|
||||
let run = (t: t, args: array<internalExpressionValue>, env: GenericDist.env) => {
|
||||
let argValues = FRType.matchWithExpressionValueArray(t.inputs, args)
|
||||
switch argValues {
|
||||
|
@ -387,6 +395,32 @@ module Function = {
|
|||
}
|
||||
}
|
||||
|
||||
module NameSpace = {
|
||||
type t = {name: string, functions: array<function>}
|
||||
let definitions = (t: t) => t.functions->E.A2.fmap(f => f.definitions)->E.A.concatMany
|
||||
let uniqueFnNames = (t: t) => definitions(t)->E.A2.fmap(r => r.name)->E.A.uniq
|
||||
let nameToDefinitions = (t: t, name: string) => definitions(t)->E.A2.filter(r => r.name == name)
|
||||
|
||||
//todo: It could be good to set a warning if two definitions are both valid, but I don't expect this often.
|
||||
let nameFfiFn = (t: t, name: string): Reducer_Expression_T.optionFfiFn => {
|
||||
(args, environment) => {
|
||||
let definitions =
|
||||
nameToDefinitions(t, name)->E.A2.fmap((def, ()) =>
|
||||
FnDefinition.isMatch(def, args)
|
||||
? FnDefinition.run(def, args, environment) |> E.R.toOption
|
||||
: None
|
||||
)
|
||||
E.A.O.firstSomeFn(definitions)
|
||||
}
|
||||
}
|
||||
|
||||
let toModule = (t: t): Reducer_Module.t =>
|
||||
E.A.reduce(uniqueFnNames(t), Reducer_Module.emptyStdLib, (acc, uniqueName) => {
|
||||
let relevantDefinitions = nameFfiFn(t, uniqueName)
|
||||
acc->Reducer_Module.defineFunction(uniqueName, relevantDefinitions)
|
||||
})
|
||||
}
|
||||
|
||||
module Registry = {
|
||||
let toJson = (r: registry) => r->E.A2.fmap(Function.toJson)
|
||||
let definitionsWithFunctions = (r: registry) =>
|
||||
|
@ -428,13 +462,11 @@ module Registry = {
|
|||
let makeModules = (prevBindings: Reducer_Module.t, t: registry): Reducer_Module.t => {
|
||||
let nameSpaces = allNamespaces(t)
|
||||
let nameSpaceBindings = nameSpaces->E.A2.fmap(nameSpace => {
|
||||
let definitions =
|
||||
t->definitionsWithFunctions->E.A2.filter(((_, fn)) => fn.nameSpace === nameSpace)
|
||||
|
||||
let newModule = E.A.reduce(definitions, Reducer_Module.emptyStdLib, (acc, (def, _)) => {
|
||||
acc->Reducer_Module.defineFunction(def.name, FnDefinition.toFfiFn(def))
|
||||
})
|
||||
(nameSpace, newModule)
|
||||
let foo: NameSpace.t = {
|
||||
name: nameSpace,
|
||||
functions: t->E.A2.filter(r => r.nameSpace == nameSpace),
|
||||
}
|
||||
(nameSpace, NameSpace.toModule(foo))
|
||||
})
|
||||
E.A.reduce(nameSpaceBindings, prevBindings, (acc, (name, fn)) =>
|
||||
acc->Reducer_Module.defineModule(name, fn)
|
||||
|
|
|
@ -19,6 +19,7 @@ let mathBindings: Bindings.t =
|
|||
->E.A2.fmap(((name, v)) => (name, ReducerInterface_InternalExpressionValue.IEvNumber(v)))
|
||||
->Bindings.fromArray
|
||||
|
||||
//TODO: This should be in a different place.
|
||||
let makeBindings = (previousBindings: Bindings.t): Bindings.t =>
|
||||
previousBindings
|
||||
->Bindings.defineModule("Math", mathBindings)
|
||||
|
|
Loading…
Reference in New Issue
Block a user