Merged with develop
This commit is contained in:
commit
ee244463fa
|
@ -13,7 +13,7 @@
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chalk": "^5.0.1",
|
"chalk": "^5.0.1",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
"commander": "^9.3.0",
|
"commander": "^9.4.0",
|
||||||
"fs": "^0.0.1-security",
|
"fs": "^0.0.1-security",
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
"indent-string": "^5.0.0"
|
"indent-string": "^5.0.0"
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
"@quri/squiggle-lang": "^0.2.8",
|
"@quri/squiggle-lang": "^0.2.8",
|
||||||
"@react-hook/size": "^2.1.2",
|
"@react-hook/size": "^2.1.2",
|
||||||
"clsx": "^1.2.1",
|
"clsx": "^1.2.1",
|
||||||
"framer-motion": "^6.4.3",
|
"framer-motion": "^6.5.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"react": "^18.1.0",
|
"react": "^18.1.0",
|
||||||
"react-ace": "^10.1.0",
|
"react-ace": "^10.1.0",
|
||||||
|
@ -37,7 +37,7 @@
|
||||||
"@testing-library/user-event": "^14.2.6",
|
"@testing-library/user-event": "^14.2.6",
|
||||||
"@types/jest": "^27.5.0",
|
"@types/jest": "^27.5.0",
|
||||||
"@types/lodash": "^4.14.182",
|
"@types/lodash": "^4.14.182",
|
||||||
"@types/node": "^18.0.3",
|
"@types/node": "^18.0.6",
|
||||||
"@types/react": "^18.0.9",
|
"@types/react": "^18.0.9",
|
||||||
"@types/styled-components": "^5.1.24",
|
"@types/styled-components": "^5.1.24",
|
||||||
"@types/webpack": "^5.28.0",
|
"@types/webpack": "^5.28.0",
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
import * as React from "react";
|
import * as React from "react";
|
||||||
import { lambdaValue, environment, runForeign } from "@quri/squiggle-lang";
|
import {
|
||||||
|
lambdaValue,
|
||||||
|
environment,
|
||||||
|
runForeign,
|
||||||
|
errorValueToString,
|
||||||
|
} from "@quri/squiggle-lang";
|
||||||
import { FunctionChart1Dist } from "./FunctionChart1Dist";
|
import { FunctionChart1Dist } from "./FunctionChart1Dist";
|
||||||
import { FunctionChart1Number } from "./FunctionChart1Number";
|
import { FunctionChart1Number } from "./FunctionChart1Number";
|
||||||
import { DistributionPlottingSettings } from "./DistributionChart";
|
import { DistributionPlottingSettings } from "./DistributionChart";
|
||||||
|
@ -45,10 +50,16 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
const validResult = getValidResult();
|
const validResult = getValidResult();
|
||||||
const resultType =
|
|
||||||
validResult.tag === "Ok" ? validResult.value.tag : ("Error" as const);
|
|
||||||
|
|
||||||
switch (resultType) {
|
if (validResult.tag === "Error") {
|
||||||
|
return (
|
||||||
|
<ErrorAlert heading="Error">
|
||||||
|
{errorValueToString(validResult.value)}
|
||||||
|
</ErrorAlert>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (validResult.value.tag) {
|
||||||
case "distribution":
|
case "distribution":
|
||||||
return (
|
return (
|
||||||
<FunctionChart1Dist
|
<FunctionChart1Dist
|
||||||
|
@ -68,15 +79,11 @@ export const FunctionChart: React.FC<FunctionChartProps> = ({
|
||||||
height={height}
|
height={height}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
case "Error":
|
|
||||||
return (
|
|
||||||
<ErrorAlert heading="Error">The function failed to be run</ErrorAlert>
|
|
||||||
);
|
|
||||||
default:
|
default:
|
||||||
return (
|
return (
|
||||||
<MessageAlert heading="Function Display Not Supported">
|
<MessageAlert heading="Function Display Not Supported">
|
||||||
There is no function visualization for this type of output:{" "}
|
There is no function visualization for this type of output:{" "}
|
||||||
<span className="font-bold">{resultType}</span>
|
<span className="font-bold">{validResult.value.tag}</span>
|
||||||
</MessageAlert>
|
</MessageAlert>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -88,7 +88,7 @@ let getPercentiles = ({ chartSettings, fn, environment }) => {
|
||||||
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
let chartPointsData: point[] = chartPointsToRender.map((x) => {
|
||||||
let result = runForeign(fn, [x], environment);
|
let result = runForeign(fn, [x], environment);
|
||||||
if (result.tag === "Ok") {
|
if (result.tag === "Ok") {
|
||||||
if (result.value.tag == "distribution") {
|
if (result.value.tag === "distribution") {
|
||||||
return { x, value: { tag: "Ok", value: result.value.value } };
|
return { x, value: { tag: "Ok", value: result.value.value } };
|
||||||
} else {
|
} else {
|
||||||
return {
|
return {
|
||||||
|
@ -165,12 +165,14 @@ export const FunctionChart1Dist: React.FC<FunctionChart1DistProps> = ({
|
||||||
setMouseOverlay(NaN);
|
setMouseOverlay(NaN);
|
||||||
}
|
}
|
||||||
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
const signalListeners = { mousemove: handleHover, mouseout: handleOut };
|
||||||
|
|
||||||
|
//TODO: This custom error handling is a bit hacky and should be improved.
|
||||||
let mouseItem: result<squiggleExpression, errorValue> = !!mouseOverlay
|
let mouseItem: result<squiggleExpression, errorValue> = !!mouseOverlay
|
||||||
? runForeign(fn, [mouseOverlay], environment)
|
? runForeign(fn, [mouseOverlay], environment)
|
||||||
: {
|
: {
|
||||||
tag: "Error",
|
tag: "Error",
|
||||||
value: {
|
value: {
|
||||||
tag: "REExpectedType",
|
tag: "RETodo",
|
||||||
value: "Hover x-coordinate returned NaN. Expected a number.",
|
value: "Hover x-coordinate returned NaN. Expected a number.",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -223,7 +223,7 @@ export function buildVegaSpec(
|
||||||
},
|
},
|
||||||
size: [{ value: 100 }],
|
size: [{ value: 100 }],
|
||||||
tooltip: {
|
tooltip: {
|
||||||
signal: "datum.y",
|
signal: "{ probability: datum.y, value: datum.x }",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
update: {
|
update: {
|
||||||
|
|
|
@ -21,6 +21,10 @@ describe("builtin", () => {
|
||||||
"addOne(t)=t+1; toList(mapSamples(fromSamples([1,2,3,4,5,6]), addOne))",
|
"addOne(t)=t+1; toList(mapSamples(fromSamples([1,2,3,4,5,6]), addOne))",
|
||||||
"Ok([2,3,4,5,6,7])",
|
"Ok([2,3,4,5,6,7])",
|
||||||
)
|
)
|
||||||
|
testEval(
|
||||||
|
"toList(mapSamplesN([fromSamples([1,2,3,4,5,6]), fromSamples([6, 5, 4, 3, 2, 1])], {|x| x[0] > x[1] ? x[0] : x[1]}))",
|
||||||
|
"Ok([6,5,4,4,5,6])",
|
||||||
|
)
|
||||||
})
|
})
|
||||||
|
|
||||||
describe("builtin exception", () => {
|
describe("builtin exception", () => {
|
||||||
|
|
|
@ -20,7 +20,7 @@ describe("Peggy parse type", () => {
|
||||||
"{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}",
|
"{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("high priority modifier", () => {
|
describe("high priority contract", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: number<-min<-max(100)|string",
|
"answer: number<-min<-max(100)|string",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string))))}",
|
"{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string))))}",
|
||||||
|
@ -30,7 +30,7 @@ describe("Peggy parse type", () => {
|
||||||
"{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5))))}",
|
"{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5))))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("low priority modifier", () => {
|
describe("low priority contract", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"answer: number | string $ opaque",
|
"answer: number | string $ opaque",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
||||||
|
@ -63,14 +63,14 @@ describe("Peggy parse type", () => {
|
||||||
"{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ()))))))}",
|
"{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ()))))))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("type paranthesis", () => {
|
describe("type parenthesis", () => {
|
||||||
//$ is introduced to avoid paranthesis
|
//$ is introduced to avoid parenthesis
|
||||||
testParse(
|
testParse(
|
||||||
"answer: (number|string)<-opaque",
|
"answer: (number|string)<-opaque",
|
||||||
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
"{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}",
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("squiggle expressions in type modifiers", () => {
|
describe("squiggle expressions in type contracts", () => {
|
||||||
testParse(
|
testParse(
|
||||||
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
||||||
"{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2)))}",
|
"{:odds1 = {(::$_constructArray_$ (1 3 5))}; :odds2 = {(::$_constructArray_$ (7 9))}; (::$_typeAlias_$ #odds (::$_typeModifier_memberOf_$ #number (::concat :odds1 :odds2)))}",
|
||||||
|
|
|
@ -3,11 +3,10 @@ module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
|
||||||
open Jest
|
open Jest
|
||||||
open Reducer_Peggy_TestHelpers
|
open Reducer_Peggy_TestHelpers
|
||||||
open Expect
|
|
||||||
|
|
||||||
describe("Peggy to Expression", () => {
|
describe("Peggy to Expression", () => {
|
||||||
describe("literals operators parenthesis", () => {
|
describe("literals operators parenthesis", () => {
|
||||||
// Note that there is always an outer block. Otherwise, external bindings are ignrored at the first statement
|
// Note that there is always an outer block. Otherwise, external bindings are ignored at the first statement
|
||||||
testToExpression("1", "{1}", ~v="1", ())
|
testToExpression("1", "{1}", ~v="1", ())
|
||||||
testToExpression("'hello'", "{'hello'}", ~v="'hello'", ())
|
testToExpression("'hello'", "{'hello'}", ~v="'hello'", ())
|
||||||
testToExpression("true", "{true}", ~v="true", ())
|
testToExpression("true", "{true}", ~v="true", ())
|
||||||
|
|
|
@ -40,7 +40,7 @@ describe("Peggy Types to Expression", () => {
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("high priority modifier", () => {
|
describe("high priority contract", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number<-min(1)<-max(100)|string",
|
"answer: number<-min(1)<-max(100)|string",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}",
|
"{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}",
|
||||||
|
@ -78,7 +78,7 @@ describe("Peggy Types to Expression", () => {
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("low priority modifier", () => {
|
describe("low priority contract", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"answer: number | string $ opaque",
|
"answer: number | string $ opaque",
|
||||||
"{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}",
|
"{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}",
|
||||||
|
@ -86,7 +86,7 @@ describe("Peggy Types to Expression", () => {
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
describe("squiggle expressions in type modifiers", () => {
|
describe("squiggle expressions in type contracts", () => {
|
||||||
testToExpression(
|
testToExpression(
|
||||||
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
"odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(concat(odds1, odds2))",
|
||||||
"{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2)))}",
|
"{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:concat :odds1 :odds2)))}",
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
module Expression = Reducer_Expression
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module T = Reducer_Type_T
|
||||||
|
module TypeCompile = Reducer_Type_Compile
|
||||||
|
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
let myIevEval = (aTypeSourceCode: string) =>
|
||||||
|
TypeCompile.ievFromTypeExpression(aTypeSourceCode, Expression.reduceExpression)
|
||||||
|
let myIevEvalToString = (aTypeSourceCode: string) =>
|
||||||
|
myIevEval(aTypeSourceCode)->InternalExpressionValue.toStringResult
|
||||||
|
|
||||||
|
let myIevExpectEqual = (aTypeSourceCode, answer) =>
|
||||||
|
expect(myIevEvalToString(aTypeSourceCode))->toEqual(answer)
|
||||||
|
|
||||||
|
let myIevTest = (test, aTypeSourceCode, answer) =>
|
||||||
|
test(aTypeSourceCode, () => myIevExpectEqual(aTypeSourceCode, answer))
|
||||||
|
|
||||||
|
let myTypeEval = (aTypeSourceCode: string) =>
|
||||||
|
TypeCompile.fromTypeExpression(aTypeSourceCode, Expression.reduceExpression)
|
||||||
|
let myTypeEvalToString = (aTypeSourceCode: string) => myTypeEval(aTypeSourceCode)->T.toStringResult
|
||||||
|
|
||||||
|
let myTypeExpectEqual = (aTypeSourceCode, answer) =>
|
||||||
|
expect(myTypeEvalToString(aTypeSourceCode))->toEqual(answer)
|
||||||
|
|
||||||
|
let myTypeTest = (test, aTypeSourceCode, answer) =>
|
||||||
|
test(aTypeSourceCode, () => myTypeExpectEqual(aTypeSourceCode, answer))
|
||||||
|
|
||||||
|
// | ItTypeIdentifier(string)
|
||||||
|
myTypeTest(test, "number", "number")
|
||||||
|
myTypeTest(test, "(number)", "number")
|
||||||
|
// | ItModifiedType({modifiedType: iType})
|
||||||
|
myIevTest(test, "number<-min(0)", "Ok({min: 0,typeIdentifier: #number,typeTag: 'typeIdentifier'})")
|
||||||
|
myTypeTest(test, "number<-min(0)", "number<-min(0)")
|
||||||
|
// | ItTypeOr({typeOr: array<iType>})
|
||||||
|
myTypeTest(test, "number | string", "(number | string)")
|
||||||
|
// | ItTypeFunction({inputs: array<iType>, output: iType})
|
||||||
|
myTypeTest(test, "number => number => number", "(number => number => number)")
|
||||||
|
// | ItTypeArray({element: iType})
|
||||||
|
myIevTest(test, "[number]", "Ok({element: #number,typeTag: 'typeArray'})")
|
||||||
|
myTypeTest(test, "[number]", "[number]")
|
||||||
|
// | ItTypeTuple({elements: array<iType>})
|
||||||
|
myTypeTest(test, "[number, string]", "[number, string]")
|
||||||
|
// | ItTypeRecord({properties: Belt.Map.String.t<iType>})
|
||||||
|
myIevTest(
|
||||||
|
test,
|
||||||
|
"{age: number, name: string}",
|
||||||
|
"Ok({properties: {age: #number,name: #string},typeTag: 'typeRecord'})",
|
||||||
|
)
|
||||||
|
myTypeTest(test, "{age: number, name: string}", "{age: number, name: string}")
|
|
@ -0,0 +1,41 @@
|
||||||
|
module Expression = Reducer_Expression
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module T = Reducer_Type_T
|
||||||
|
module TypeChecker = Reducer_Type_TypeChecker
|
||||||
|
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
let checkArgumentsSourceCode = (aTypeSourceCode: string, sourceCode: string): result<
|
||||||
|
'v,
|
||||||
|
ErrorValue.t,
|
||||||
|
> => {
|
||||||
|
let reducerFn = Expression.reduceExpression
|
||||||
|
let rResult =
|
||||||
|
Reducer.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||||
|
reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment)
|
||||||
|
)
|
||||||
|
rResult->Belt.Result.flatMap(result =>
|
||||||
|
switch result {
|
||||||
|
| IEvArray(args) => TypeChecker.checkArguments(aTypeSourceCode, args, reducerFn)
|
||||||
|
| _ => Js.Exn.raiseError("Arguments has to be an array")
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
let myCheckArguments = (aTypeSourceCode: string, sourceCode: string): string =>
|
||||||
|
switch checkArgumentsSourceCode(aTypeSourceCode, sourceCode) {
|
||||||
|
| Ok(_) => "Ok"
|
||||||
|
| Error(error) => ErrorValue.errorToString(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
let myCheckArgumentsExpectEqual = (aTypeSourceCode, sourceCode, answer) =>
|
||||||
|
expect(myCheckArguments(aTypeSourceCode, sourceCode))->toEqual(answer)
|
||||||
|
|
||||||
|
let myCheckArgumentsTest = (test, aTypeSourceCode, sourceCode, answer) =>
|
||||||
|
test(aTypeSourceCode, () => myCheckArgumentsExpectEqual(aTypeSourceCode, sourceCode, answer))
|
||||||
|
|
||||||
|
myCheckArgumentsTest(test, "number=>number=>number", "[1,2]", "Ok")
|
|
@ -0,0 +1,70 @@
|
||||||
|
module Expression = Reducer_Expression
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module T = Reducer_Type_T
|
||||||
|
module TypeChecker = Reducer_Type_TypeChecker
|
||||||
|
|
||||||
|
open Jest
|
||||||
|
open Expect
|
||||||
|
|
||||||
|
// In development, you are expected to use TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn).
|
||||||
|
// isTypeOfSourceCode is written to use strings instead of expression values.
|
||||||
|
|
||||||
|
let isTypeOfSourceCode = (aTypeSourceCode: string, sourceCode: string): result<
|
||||||
|
'v,
|
||||||
|
ErrorValue.t,
|
||||||
|
> => {
|
||||||
|
let reducerFn = Expression.reduceExpression
|
||||||
|
let rResult =
|
||||||
|
Reducer.parse(sourceCode)->Belt.Result.flatMap(expr =>
|
||||||
|
reducerFn(expr, Bindings.emptyBindings, InternalExpressionValue.defaultEnvironment)
|
||||||
|
)
|
||||||
|
rResult->Belt.Result.flatMap(result => TypeChecker.isTypeOf(aTypeSourceCode, result, reducerFn))
|
||||||
|
}
|
||||||
|
|
||||||
|
let myTypeCheck = (aTypeSourceCode: string, sourceCode: string): string =>
|
||||||
|
switch isTypeOfSourceCode(aTypeSourceCode, sourceCode) {
|
||||||
|
| Ok(_) => "Ok"
|
||||||
|
| Error(error) => ErrorValue.errorToString(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
let myTypeCheckExpectEqual = (aTypeSourceCode, sourceCode, answer) =>
|
||||||
|
expect(myTypeCheck(aTypeSourceCode, sourceCode))->toEqual(answer)
|
||||||
|
|
||||||
|
let myTypeCheckTest = (test, aTypeSourceCode, sourceCode, answer) =>
|
||||||
|
test(aTypeSourceCode, () => myTypeCheckExpectEqual(aTypeSourceCode, sourceCode, answer))
|
||||||
|
|
||||||
|
myTypeCheckTest(test, "number", "1", "Ok")
|
||||||
|
myTypeCheckTest(test, "number", "'2'", "Expected type: number but got: '2'")
|
||||||
|
myTypeCheckTest(test, "string", "3", "Expected type: string but got: 3")
|
||||||
|
myTypeCheckTest(test, "string", "'a'", "Ok")
|
||||||
|
myTypeCheckTest(test, "[number]", "[1,2,3]", "Ok")
|
||||||
|
myTypeCheckTest(test, "[number]", "['a','a','a']", "Expected type: number but got: 'a'")
|
||||||
|
myTypeCheckTest(test, "[number]", "[1,'a',3]", "Expected type: number but got: 'a'")
|
||||||
|
myTypeCheckTest(test, "[number, string]", "[1,'a']", "Ok")
|
||||||
|
myTypeCheckTest(test, "[number, string]", "[1, 2]", "Expected type: string but got: 2")
|
||||||
|
myTypeCheckTest(
|
||||||
|
test,
|
||||||
|
"[number, string, string]",
|
||||||
|
"[1,'a']",
|
||||||
|
"Expected type: [number, string, string] but got: [1,'a']",
|
||||||
|
)
|
||||||
|
myTypeCheckTest(
|
||||||
|
test,
|
||||||
|
"[number, string]",
|
||||||
|
"[1,'a', 3]",
|
||||||
|
"Expected type: [number, string] but got: [1,'a',3]",
|
||||||
|
)
|
||||||
|
myTypeCheckTest(test, "{age: number, name: string}", "{age: 1, name: 'a'}", "Ok")
|
||||||
|
myTypeCheckTest(
|
||||||
|
test,
|
||||||
|
"{age: number, name: string}",
|
||||||
|
"{age: 1, name: 'a', job: 'IT'}",
|
||||||
|
"Expected type: {age: number, name: string} but got: {age: 1,job: 'IT',name: 'a'}",
|
||||||
|
)
|
||||||
|
myTypeCheckTest(test, "number | string", "1", "Ok")
|
||||||
|
myTypeCheckTest(test, "date | string", "1", "Expected type: (date | string) but got: 1")
|
||||||
|
myTypeCheckTest(test, "number<-min(10)", "10", "Ok")
|
||||||
|
myTypeCheckTest(test, "number<-min(10)", "0", "Expected type: number<-min(10) but got: 0")
|
|
@ -10,5 +10,5 @@ describe("Evaluate ternary operator", () => {
|
||||||
testEvalToBe("false ? 'YES' : 'NO'", "Ok('NO')")
|
testEvalToBe("false ? 'YES' : 'NO'", "Ok('NO')")
|
||||||
testEvalToBe("2 > 1 ? 'YES' : 'NO'", "Ok('YES')")
|
testEvalToBe("2 > 1 ? 'YES' : 'NO'", "Ok('YES')")
|
||||||
testEvalToBe("2 <= 1 ? 'YES' : 'NO'", "Ok('NO')")
|
testEvalToBe("2 <= 1 ? 'YES' : 'NO'", "Ok('NO')")
|
||||||
testEvalToBe("1+1 ? 'YES' : 'NO'", "Error(Expected type: Boolean)")
|
testEvalToBe("1+1 ? 'YES' : 'NO'", "Error(Expected type: Boolean but got: )")
|
||||||
})
|
})
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
"chalk": "^5.0.1",
|
"chalk": "^5.0.1",
|
||||||
"codecov": "^3.8.3",
|
"codecov": "^3.8.3",
|
||||||
"fast-check": "^3.0.1",
|
"fast-check": "^3.0.1",
|
||||||
"gentype": "^4.4.0",
|
"gentype": "^4.5.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"moduleserve": "^0.9.1",
|
"moduleserve": "^0.9.1",
|
||||||
"nyc": "^15.1.0",
|
"nyc": "^15.1.0",
|
||||||
|
|
|
@ -117,6 +117,11 @@ let map3 = (
|
||||||
): result<t, sampleSetError> =>
|
): result<t, sampleSetError> =>
|
||||||
E.A.zip3(get(t1), get(t2), get(t3))->E.A2.fmap(E.Tuple3.toFnCall(fn))->_fromSampleResultArray
|
E.A.zip3(get(t1), get(t2), get(t3))->E.A2.fmap(E.Tuple3.toFnCall(fn))->_fromSampleResultArray
|
||||||
|
|
||||||
|
let mapN = (~fn: array<float> => result<float, Operation.Error.t>, ~t1: array<t>): result<
|
||||||
|
t,
|
||||||
|
sampleSetError,
|
||||||
|
> => E.A.transpose(E.A.fmap(get, t1))->E.A2.fmap(fn)->_fromSampleResultArray
|
||||||
|
|
||||||
let mean = t => T.get(t)->E.A.Floats.mean
|
let mean = t => T.get(t)->E.A.Floats.mean
|
||||||
let geomean = t => T.get(t)->E.A.Floats.geomean
|
let geomean = t => T.get(t)->E.A.Floats.geomean
|
||||||
let mode = t => T.get(t)->E.A.Floats.mode
|
let mode = t => T.get(t)->E.A.Floats.mode
|
||||||
|
|
|
@ -1,3 +1,6 @@
|
||||||
|
// Only Bindings as the global module is supported
|
||||||
|
// Other module operations such as import export will be prepreocessed jobs
|
||||||
|
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
|
@ -10,8 +10,8 @@ open ReducerInterface_InternalExpressionValue
|
||||||
open Reducer_ErrorValue
|
open Reducer_ErrorValue
|
||||||
|
|
||||||
/*
|
/*
|
||||||
MathJs provides default implementations for builtins
|
MathJs provides default implementations for built-ins
|
||||||
This is where all the expected builtins like + = * / sin cos log ln etc are handled
|
This is where all the expected built-ins like + = * / sin cos log ln etc are handled
|
||||||
DO NOT try to add external function mapping here!
|
DO NOT try to add external function mapping here!
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
@ -149,6 +149,27 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)})
|
doLambdaCall(aLambdaValue, list{IEvNumber(a), IEvNumber(b), IEvNumber(c)})
|
||||||
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
|
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let parseSampleSetArray = (arr: array<internalExpressionValue>): option<
|
||||||
|
array<SampleSetDist.t>,
|
||||||
|
> => {
|
||||||
|
let parseSampleSet = (value: internalExpressionValue): option<SampleSetDist.t> =>
|
||||||
|
switch value {
|
||||||
|
| IEvDistribution(SampleSet(dist)) => Some(dist)
|
||||||
|
| _ => None
|
||||||
|
}
|
||||||
|
E.A.O.openIfAllSome(E.A.fmap(parseSampleSet, arr))
|
||||||
|
}
|
||||||
|
|
||||||
|
let mapN = (aValueArray: array<internalExpressionValue>, aLambdaValue) => {
|
||||||
|
switch parseSampleSetArray(aValueArray) {
|
||||||
|
| Some(t1) =>
|
||||||
|
let fn = a => doLambdaCall(aLambdaValue, list{IEvArray(E.A.fmap(x => IEvNumber(x), a))})
|
||||||
|
SampleSetDist.mapN(~fn, ~t1)->toType
|
||||||
|
| None =>
|
||||||
|
Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let doReduceArray = (aValueArray, initialValue, aLambdaValue) => {
|
let doReduceArray = (aValueArray, initialValue, aLambdaValue) => {
|
||||||
|
@ -198,7 +219,7 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
| ("$_typeFunction_$", [IEvArray(arr)]) => TypeBuilder.typeFunction(arr)
|
| ("$_typeFunction_$", [IEvArray(arr)]) => TypeBuilder.typeFunction(arr)
|
||||||
| ("$_typeTuple_$", [IEvArray(elems)]) => TypeBuilder.typeTuple(elems)
|
| ("$_typeTuple_$", [IEvArray(elems)]) => TypeBuilder.typeTuple(elems)
|
||||||
| ("$_typeArray_$", [elem]) => TypeBuilder.typeArray(elem)
|
| ("$_typeArray_$", [elem]) => TypeBuilder.typeArray(elem)
|
||||||
| ("$_typeRecord_$", [IEvArray(arrayOfPairs)]) => TypeBuilder.typeRecord(arrayOfPairs)
|
| ("$_typeRecord_$", [IEvRecord(propertyMap)]) => TypeBuilder.typeRecord(propertyMap)
|
||||||
| ("concat", [IEvArray(aValueArray), IEvArray(bValueArray)]) =>
|
| ("concat", [IEvArray(aValueArray), IEvArray(bValueArray)]) =>
|
||||||
doAddArray(aValueArray, bValueArray)
|
doAddArray(aValueArray, bValueArray)
|
||||||
| ("concat", [IEvString(aValueString), IEvString(bValueString)]) =>
|
| ("concat", [IEvString(aValueString), IEvString(bValueString)]) =>
|
||||||
|
@ -230,6 +251,8 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
],
|
],
|
||||||
) =>
|
) =>
|
||||||
SampleMap.map3(dist1, dist2, dist3, aLambdaValue)
|
SampleMap.map3(dist1, dist2, dist3, aLambdaValue)
|
||||||
|
| ("mapSamplesN", [IEvArray(aValueArray), IEvLambda(aLambdaValue)]) =>
|
||||||
|
SampleMap.mapN(aValueArray, aLambdaValue)
|
||||||
| ("reduce", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) =>
|
| ("reduce", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) =>
|
||||||
doReduceArray(aValueArray, initialValue, aLambdaValue)
|
doReduceArray(aValueArray, initialValue, aLambdaValue)
|
||||||
| ("reduceReverse", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) =>
|
| ("reduceReverse", [IEvArray(aValueArray), initialValue, IEvLambda(aLambdaValue)]) =>
|
||||||
|
@ -246,7 +269,6 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce
|
||||||
Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) // Report full type signature as error
|
Error(REFunctionNotFound(call->functionCallToCallSignature->functionCallSignatureToString)) // Report full type signature as error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reducer uses Result monad while reducing expressions
|
Reducer uses Result monad while reducing expressions
|
||||||
*/
|
*/
|
||||||
|
@ -255,11 +277,10 @@ let dispatch = (call: functionCall, environment, reducer: ExpressionT.reducerFn)
|
||||||
errorValue,
|
errorValue,
|
||||||
> =>
|
> =>
|
||||||
try {
|
try {
|
||||||
let callInternalWithReducer = (call, environment) => callInternal(call, environment, reducer)
|
|
||||||
let (fn, args) = call
|
let (fn, args) = call
|
||||||
// There is a bug that prevents string match in patterns
|
// There is a bug that prevents string match in patterns
|
||||||
// So we have to recreate a copy of the string
|
// So we have to recreate a copy of the string
|
||||||
ExternalLibrary.dispatch((Js.String.make(fn), args), environment, callInternalWithReducer)
|
ExternalLibrary.dispatch((Js.String.make(fn), args), environment, reducer, callInternal)
|
||||||
} catch {
|
} catch {
|
||||||
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
| Js.Exn.Error(obj) => REJavaScriptExn(Js.Exn.message(obj), Js.Exn.name(obj))->Error
|
||||||
| _ => RETodo("unhandled rescript exception")->Error
|
| _ => RETodo("unhandled rescript exception")->Error
|
||||||
|
|
|
@ -144,7 +144,7 @@ let dispatchMacroCall = (
|
||||||
let ifTrueBlock = eBlock(list{ifTrue})
|
let ifTrueBlock = eBlock(list{ifTrue})
|
||||||
ExpressionWithContext.withContext(ifTrueBlock, bindings)->Ok
|
ExpressionWithContext.withContext(ifTrueBlock, bindings)->Ok
|
||||||
}
|
}
|
||||||
| _ => REExpectedType("Boolean")->Error
|
| _ => REExpectedType("Boolean", "")->Error
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ type errorValue =
|
||||||
| REArrayIndexNotFound(string, int)
|
| REArrayIndexNotFound(string, int)
|
||||||
| REAssignmentExpected
|
| REAssignmentExpected
|
||||||
| REDistributionError(DistributionTypes.error)
|
| REDistributionError(DistributionTypes.error)
|
||||||
| REExpectedType(string)
|
| REExpectedType(string, string)
|
||||||
| REExpressionExpected
|
| REExpressionExpected
|
||||||
| REFunctionExpected(string)
|
| REFunctionExpected(string)
|
||||||
| REFunctionNotFound(string)
|
| REFunctionNotFound(string)
|
||||||
|
@ -55,6 +55,6 @@ let errorToString = err =>
|
||||||
| RESymbolNotFound(symbolName) => `${symbolName} is not defined`
|
| RESymbolNotFound(symbolName) => `${symbolName} is not defined`
|
||||||
| RESyntaxError(desc, _) => `Syntax Error: ${desc}`
|
| RESyntaxError(desc, _) => `Syntax Error: ${desc}`
|
||||||
| RETodo(msg) => `TODO: ${msg}`
|
| RETodo(msg) => `TODO: ${msg}`
|
||||||
| REExpectedType(typeName) => `Expected type: ${typeName}`
|
| REExpectedType(typeName, valueString) => `Expected type: ${typeName} but got: ${valueString}`
|
||||||
| REUnitNotFound(unitName) => `Unit not found: ${unitName}`
|
| REUnitNotFound(unitName) => `Unit not found: ${unitName}`
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
// There are switch stament cases in the code which are impossible to reach by design.
|
// There are switch statement cases in the code which are impossible to reach by design.
|
||||||
// ImpossibleException is a sign of programming error.
|
// ImpossibleException is a sign of programming error.
|
||||||
exception ImpossibleException
|
exception ImpossibleException(string)
|
||||||
|
|
|
@ -30,12 +30,12 @@ let rec toString = expression =>
|
||||||
switch expression {
|
switch expression {
|
||||||
| EList(list{EValue(IEvCall("$$_block_$$")), ...statements}) =>
|
| EList(list{EValue(IEvCall("$$_block_$$")), ...statements}) =>
|
||||||
`{${Belt.List.map(statements, aValue => toString(aValue))
|
`{${Belt.List.map(statements, aValue => toString(aValue))
|
||||||
->Extra.List.interperse("; ")
|
->Extra.List.intersperse("; ")
|
||||||
->Belt.List.toArray
|
->Belt.List.toArray
|
||||||
->Js.String.concatMany("")}}`
|
->Js.String.concatMany("")}}`
|
||||||
| EList(aList) =>
|
| EList(aList) =>
|
||||||
`(${Belt.List.map(aList, aValue => toString(aValue))
|
`(${Belt.List.map(aList, aValue => toString(aValue))
|
||||||
->Extra.List.interperse(" ")
|
->Extra.List.intersperse(" ")
|
||||||
->Belt.List.toArray
|
->Belt.List.toArray
|
||||||
->Js.String.concatMany("")})`
|
->Js.String.concatMany("")})`
|
||||||
| EValue(aValue) => InternalExpressionValue.toString(aValue)
|
| EValue(aValue) => InternalExpressionValue.toString(aValue)
|
||||||
|
|
|
@ -3,5 +3,5 @@
|
||||||
*/
|
*/
|
||||||
module ExtraList = Reducer_Extra_List
|
module ExtraList = Reducer_Extra_List
|
||||||
|
|
||||||
let interperse = (anArray, seperator) =>
|
let intersperse = (anArray, seperator) =>
|
||||||
anArray->Belt.List.fromArray->ExtraList.interperse(seperator)->Belt.List.toArray
|
anArray->Belt.List.fromArray->ExtraList.intersperse(seperator)->Belt.List.toArray
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
/*
|
/*
|
||||||
Insert seperator between the elements of a list
|
Insert seperator between the elements of a list
|
||||||
*/
|
*/
|
||||||
let rec interperse = (aList, seperator) =>
|
let rec intersperse = (aList, seperator) =>
|
||||||
switch aList {
|
switch aList {
|
||||||
| list{} => list{}
|
| list{} => list{}
|
||||||
| list{a} => list{a}
|
| list{a} => list{a}
|
||||||
| list{a, ...rest} => list{a, seperator, ...interperse(rest, seperator)}
|
| list{a, ...rest} => list{a, seperator, ...intersperse(rest, seperator)}
|
||||||
}
|
}
|
||||||
|
|
|
@ -91,7 +91,7 @@ let rec pgToString = (peggyNode: peggyNode): string => {
|
||||||
args->Js.Array2.map(arg => PgNodeIdentifier(arg)->pgToString)->Js.Array2.toString
|
args->Js.Array2.map(arg => PgNodeIdentifier(arg)->pgToString)->Js.Array2.toString
|
||||||
|
|
||||||
let nodesToStringUsingSeparator = (nodes: array<node>, separator: string): string =>
|
let nodesToStringUsingSeparator = (nodes: array<node>, separator: string): string =>
|
||||||
nodes->Js.Array2.map(toString)->Extra.Array.interperse(separator)->Js.String.concatMany("")
|
nodes->Js.Array2.map(toString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
||||||
|
|
||||||
switch peggyNode {
|
switch peggyNode {
|
||||||
| PgNodeBlock(node) => "{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}"
|
| PgNodeBlock(node) => "{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}"
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
module ErrorValue = Reducer_ErrorValue
|
||||||
|
module ExpressionT = Reducer_Expression_T
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module Bindings = Reducer_Bindings
|
||||||
|
module T = Reducer_Type_T
|
||||||
|
|
||||||
|
let ievFromTypeExpression = (
|
||||||
|
typeExpressionSourceCode: string,
|
||||||
|
reducerFn: ExpressionT.reducerFn,
|
||||||
|
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||||
|
let sIndex = "compiled"
|
||||||
|
let sourceCode = `type ${sIndex}=${typeExpressionSourceCode}`
|
||||||
|
Reducer_Expression.parse(sourceCode)->Belt.Result.flatMap(expr => {
|
||||||
|
let rContext = reducerFn(
|
||||||
|
expr,
|
||||||
|
Bindings.emptyBindings,
|
||||||
|
InternalExpressionValue.defaultEnvironment,
|
||||||
|
)
|
||||||
|
Belt.Result.map(rContext, context =>
|
||||||
|
switch context {
|
||||||
|
| IEvBindings(nameSpace) =>
|
||||||
|
switch Bindings.getType(nameSpace, sIndex) {
|
||||||
|
| Some(value) => value
|
||||||
|
| None => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-none"))
|
||||||
|
}
|
||||||
|
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_Compile-raise"))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
let fromTypeExpression = (
|
||||||
|
typeExpressionSourceCode: string,
|
||||||
|
reducerFn: ExpressionT.reducerFn,
|
||||||
|
): result<T.t, ErrorValue.t> => {
|
||||||
|
ievFromTypeExpression(
|
||||||
|
(typeExpressionSourceCode: string),
|
||||||
|
(reducerFn: ExpressionT.reducerFn),
|
||||||
|
)->Belt.Result.map(T.fromIEvValue)
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
|
module T = Reducer_Type_T
|
||||||
|
|
||||||
|
let isMin = (modifierArg: InternalExpressionValue.t, aValue: InternalExpressionValue.t): bool => {
|
||||||
|
let pair = (modifierArg, aValue)
|
||||||
|
switch pair {
|
||||||
|
| (IEvNumber(a), IEvNumber(b)) => a <= b
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let isMax = (modifierArg: InternalExpressionValue.t, aValue: InternalExpressionValue.t): bool => {
|
||||||
|
let pair = (modifierArg, aValue)
|
||||||
|
switch pair {
|
||||||
|
| (IEvNumber(a), IEvNumber(b)) => a >= b
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let isMemberOf = (
|
||||||
|
modifierArg: InternalExpressionValue.t,
|
||||||
|
aValue: InternalExpressionValue.t,
|
||||||
|
): bool => {
|
||||||
|
let pair = (modifierArg, aValue)
|
||||||
|
switch pair {
|
||||||
|
| (ievA, IEvArray(b)) => Js.Array2.includes(b, ievA)
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkModifier = (
|
||||||
|
key: string,
|
||||||
|
modifierArg: InternalExpressionValue.t,
|
||||||
|
aValue: InternalExpressionValue.t,
|
||||||
|
): bool =>
|
||||||
|
switch key {
|
||||||
|
| "min" => isMin(modifierArg, aValue)
|
||||||
|
| "max" => isMax(modifierArg, aValue)
|
||||||
|
| "isMemberOf" => isMemberOf(modifierArg, aValue)
|
||||||
|
| _ => false
|
||||||
|
}
|
||||||
|
|
||||||
|
let checkModifiers = (
|
||||||
|
contracts: Belt.Map.String.t<InternalExpressionValue.t>,
|
||||||
|
aValue: InternalExpressionValue.t,
|
||||||
|
): bool => {
|
||||||
|
contracts->Belt.Map.String.reduce(true, (acc, key, modifierArg) =>
|
||||||
|
switch acc {
|
||||||
|
| true => checkModifier(key, modifierArg, aValue)
|
||||||
|
| _ => acc
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
|
@ -3,13 +3,42 @@ open InternalExpressionValue
|
||||||
|
|
||||||
type rec iType =
|
type rec iType =
|
||||||
| ItTypeIdentifier(string)
|
| ItTypeIdentifier(string)
|
||||||
| ItModifiedType({modifiedType: iType})
|
| ItModifiedType({modifiedType: iType, contracts: Belt.Map.String.t<InternalExpressionValue.t>})
|
||||||
| ItTypeOr({typeOr: array<iType>})
|
| ItTypeOr({typeOr: array<iType>})
|
||||||
| ItTypeFunction({inputs: array<iType>, output: iType})
|
| ItTypeFunction({inputs: array<iType>, output: iType})
|
||||||
| ItTypeArray({element: iType})
|
| ItTypeArray({element: iType})
|
||||||
| ItTypeTuple({elements: array<iType>})
|
| ItTypeTuple({elements: array<iType>})
|
||||||
| ItTypeRecord({properties: Belt.Map.String.t<iType>})
|
| ItTypeRecord({properties: Belt.Map.String.t<iType>})
|
||||||
|
|
||||||
|
type t = iType
|
||||||
|
type typeErrorValue = TypeMismatch(t, InternalExpressionValue.t)
|
||||||
|
|
||||||
|
let rec toString = (t: t): string => {
|
||||||
|
switch t {
|
||||||
|
| ItTypeIdentifier(s) => s
|
||||||
|
| ItModifiedType({modifiedType, contracts}) =>
|
||||||
|
`${toString(modifiedType)}${contracts->Belt.Map.String.reduce("", (acc, k, v) =>
|
||||||
|
Js.String2.concatMany(acc, ["<-", k, "(", InternalExpressionValue.toString(v), ")"])
|
||||||
|
)}`
|
||||||
|
| ItTypeOr({typeOr}) => `(${Js.Array2.map(typeOr, toString)->Js.Array2.joinWith(" | ")})`
|
||||||
|
| ItTypeFunction({inputs, output}) =>
|
||||||
|
`(${inputs->Js.Array2.map(toString)->Js.Array2.joinWith(" => ")} => ${toString(output)})`
|
||||||
|
| ItTypeArray({element}) => `[${toString(element)}]`
|
||||||
|
| ItTypeTuple({elements}) => `[${Js.Array2.map(elements, toString)->Js.Array2.joinWith(", ")}]`
|
||||||
|
| ItTypeRecord({properties}) =>
|
||||||
|
`{${properties
|
||||||
|
->Belt.Map.String.toArray
|
||||||
|
->Js.Array2.map(((k, v)) => Js.String2.concatMany(k, [": ", toString(v)]))
|
||||||
|
->Js.Array2.joinWith(", ")}}`
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let toStringResult = (rt: result<t, ErrorValue.t>) =>
|
||||||
|
switch rt {
|
||||||
|
| Ok(t) => toString(t)
|
||||||
|
| Error(e) => ErrorValue.errorToString(e)
|
||||||
|
}
|
||||||
|
|
||||||
let rec fromTypeMap = typeMap => {
|
let rec fromTypeMap = typeMap => {
|
||||||
let default = IEvString("")
|
let default = IEvString("")
|
||||||
let evTypeTag: InternalExpressionValue.t = Belt.Map.String.getWithDefault(
|
let evTypeTag: InternalExpressionValue.t = Belt.Map.String.getWithDefault(
|
||||||
|
@ -52,31 +81,39 @@ let rec fromTypeMap = typeMap => {
|
||||||
"properties",
|
"properties",
|
||||||
default,
|
default,
|
||||||
)
|
)
|
||||||
//TODO: map type modifiers
|
|
||||||
switch evTypeTag {
|
let contracts =
|
||||||
| IEvString("typeIdentifier") => ItModifiedType({modifiedType: fromIEvValue(evTypeIdentifier)})
|
typeMap->Belt.Map.String.keep((k, _v) => ["min", "max", "memberOf"]->Js.Array2.includes(k))
|
||||||
|
|
||||||
|
let makeIt = switch evTypeTag {
|
||||||
|
| IEvString("typeIdentifier") => fromIEvValue(evTypeIdentifier)
|
||||||
| IEvString("typeOr") => ItTypeOr({typeOr: fromIEvArray(evTypeOr)})
|
| IEvString("typeOr") => ItTypeOr({typeOr: fromIEvArray(evTypeOr)})
|
||||||
| IEvString("typeFunction") =>
|
| IEvString("typeFunction") =>
|
||||||
ItTypeFunction({inputs: fromIEvArray(evInputs), output: fromIEvValue(evOutput)})
|
ItTypeFunction({inputs: fromIEvArray(evInputs), output: fromIEvValue(evOutput)})
|
||||||
| IEvString("typeArray") => ItTypeArray({element: fromIEvValue(evElement)})
|
| IEvString("typeArray") => ItTypeArray({element: fromIEvValue(evElement)})
|
||||||
| IEvString("typeTuple") => ItTypeTuple({elements: fromIEvArray(evElements)})
|
| IEvString("typeTuple") => ItTypeTuple({elements: fromIEvArray(evElements)})
|
||||||
| IEvString("typeRecord") => ItTypeRecord({properties: fromIEvRecord(evProperties)})
|
| IEvString("typeRecord") => ItTypeRecord({properties: fromIEvRecord(evProperties)})
|
||||||
| _ => raise(Reducer_Exception.ImpossibleException)
|
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-evTypeTag"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Belt.Map.String.isEmpty(contracts)
|
||||||
|
? makeIt
|
||||||
|
: ItModifiedType({modifiedType: makeIt, contracts: contracts})
|
||||||
}
|
}
|
||||||
and fromIEvValue = (ievValue: InternalExpressionValue.t) =>
|
|
||||||
|
and fromIEvValue = (ievValue: InternalExpressionValue.t): iType =>
|
||||||
switch ievValue {
|
switch ievValue {
|
||||||
| IEvTypeIdentifier(typeIdentifier) => ItTypeIdentifier({typeIdentifier})
|
| IEvTypeIdentifier(typeIdentifier) => ItTypeIdentifier({typeIdentifier})
|
||||||
| IEvType(typeMap) => fromTypeMap(typeMap)
|
| IEvType(typeMap) => fromTypeMap(typeMap)
|
||||||
| _ => raise(Reducer_Exception.ImpossibleException)
|
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-ievValue"))
|
||||||
}
|
}
|
||||||
and fromIEvArray = (ievArray: InternalExpressionValue.t) =>
|
and fromIEvArray = (ievArray: InternalExpressionValue.t) =>
|
||||||
switch ievArray {
|
switch ievArray {
|
||||||
| IEvArray(array) => array->Belt.Array.map(fromIEvValue)
|
| IEvArray(array) => array->Belt.Array.map(fromIEvValue)
|
||||||
| _ => raise(Reducer_Exception.ImpossibleException)
|
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-ievArray"))
|
||||||
}
|
}
|
||||||
and fromIEvRecord = (ievRecord: InternalExpressionValue.t) =>
|
and fromIEvRecord = (ievRecord: InternalExpressionValue.t) =>
|
||||||
switch ievRecord {
|
switch ievRecord {
|
||||||
| IEvRecord(record) => record->Belt.Map.String.map(fromIEvValue)
|
| IEvRecord(record) => record->Belt.Map.String.map(fromIEvValue)
|
||||||
| _ => raise(Reducer_Exception.ImpossibleException)
|
| _ => raise(Reducer_Exception.ImpossibleException("Reducer_Type_T-ievRecord"))
|
||||||
}
|
}
|
||||||
|
|
|
@ -56,7 +56,7 @@ let typeFunction = anArray => {
|
||||||
|
|
||||||
let typeArray = element => {
|
let typeArray = element => {
|
||||||
let newRecord = Belt.Map.String.fromArray([
|
let newRecord = Belt.Map.String.fromArray([
|
||||||
("typeTag", IEvString("typeTuple")),
|
("typeTag", IEvString("typeArray")),
|
||||||
("element", element),
|
("element", element),
|
||||||
])
|
])
|
||||||
newRecord->IEvType->Ok
|
newRecord->IEvType->Ok
|
||||||
|
@ -64,22 +64,14 @@ let typeArray = element => {
|
||||||
|
|
||||||
let typeTuple = anArray => {
|
let typeTuple = anArray => {
|
||||||
let newRecord = Belt.Map.String.fromArray([
|
let newRecord = Belt.Map.String.fromArray([
|
||||||
("typeTag", IEvString("typeArray")),
|
("typeTag", IEvString("typeTuple")),
|
||||||
("elements", IEvArray(anArray)),
|
("elements", IEvArray(anArray)),
|
||||||
])
|
])
|
||||||
newRecord->IEvType->Ok
|
newRecord->IEvType->Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
let typeRecord = arrayOfPairs => {
|
let typeRecord = propertyMap => {
|
||||||
let newProperties =
|
let newProperties = propertyMap->IEvRecord
|
||||||
Belt.Array.map(arrayOfPairs, pairValue =>
|
|
||||||
switch pairValue {
|
|
||||||
| IEvArray([IEvString(key), valueValue]) => (key, valueValue)
|
|
||||||
| _ => ("wrong key type", pairValue->toStringWithType->IEvString)
|
|
||||||
}
|
|
||||||
)
|
|
||||||
->Belt.Map.String.fromArray
|
|
||||||
->IEvRecord
|
|
||||||
let newRecord = Belt.Map.String.fromArray([
|
let newRecord = Belt.Map.String.fromArray([
|
||||||
("typeTag", IEvString("typeRecord")),
|
("typeTag", IEvString("typeRecord")),
|
||||||
("properties", newProperties),
|
("properties", newProperties),
|
||||||
|
|
|
@ -1,81 +1,168 @@
|
||||||
module ExpressionT = Reducer_Expression_T
|
module ExpressionT = Reducer_Expression_T
|
||||||
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
module InternalExpressionValue = ReducerInterface_InternalExpressionValue
|
||||||
module T = Reducer_Type_T
|
module T = Reducer_Type_T
|
||||||
module TypeBuilder = Reducer_Type_TypeBuilder
|
module TypeContracts = Reducer_Type_Contracts
|
||||||
open InternalExpressionValue
|
open InternalExpressionValue
|
||||||
|
|
||||||
type typeErrorValue =
|
let rec isITypeOf = (anIType: T.iType, aValue): result<bool, T.typeErrorValue> => {
|
||||||
| TypeError(T.iType, InternalExpressionValue.t)
|
|
||||||
| TypeErrorWithPosition(T.iType, InternalExpressionValue.t, int)
|
|
||||||
| TypeErrorWithProperty(T.iType, InternalExpressionValue.t, string)
|
|
||||||
|
|
||||||
let rec isOfResolvedIType = (anIType: T.iType, aValue): result<bool, typeErrorValue> => {
|
|
||||||
let caseTypeIdentifier = (anUpperTypeName, aValue) => {
|
let caseTypeIdentifier = (anUpperTypeName, aValue) => {
|
||||||
let aTypeName = anUpperTypeName->Js.String2.toLowerCase
|
let aTypeName = anUpperTypeName->Js.String2.toLowerCase
|
||||||
let valueTypeName = aValue->valueToValueType->valueTypeToString->Js.String2.toLowerCase
|
let valueTypeName = aValue->valueToValueType->valueTypeToString->Js.String2.toLowerCase
|
||||||
switch aTypeName === valueTypeName {
|
switch aTypeName == valueTypeName {
|
||||||
| true => Ok(true)
|
| true => Ok(true)
|
||||||
| false => TypeError(anIType, aValue)->Error
|
| false => T.TypeMismatch(anIType, aValue)->Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let _caseRecord = (anIType, evValue, propertyMap, map) => {
|
let caseRecord = (anIType, propertyMap: Belt.Map.String.t<T.iType>, evValue) =>
|
||||||
Belt.Map.String.reduce(propertyMap, Ok(true), (acc, property, propertyType) => {
|
switch evValue {
|
||||||
|
| IEvRecord(aRecord) =>
|
||||||
|
if (
|
||||||
|
Js.Array2.length(propertyMap->Belt.Map.String.keysToArray) ==
|
||||||
|
Js.Array2.length(aRecord->Belt.Map.String.keysToArray)
|
||||||
|
) {
|
||||||
|
Belt.Map.String.reduce(propertyMap, Ok(true), (acc, property, propertyType) => {
|
||||||
|
Belt.Result.flatMap(acc, _ =>
|
||||||
|
switch Belt.Map.String.get(aRecord, property) {
|
||||||
|
| Some(propertyValue) => isITypeOf(propertyType, propertyValue)
|
||||||
|
| None => T.TypeMismatch(anIType, evValue)->Error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
T.TypeMismatch(anIType, evValue)->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
| _ => T.TypeMismatch(anIType, evValue)->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
let caseArray = (anIType, elementType, evValue) =>
|
||||||
|
switch evValue {
|
||||||
|
| IEvArray(anArray) =>
|
||||||
|
Belt.Array.reduce(anArray, Ok(true), (acc, element) =>
|
||||||
|
Belt.Result.flatMap(acc, _ =>
|
||||||
|
switch isITypeOf(elementType, element) {
|
||||||
|
| Ok(_) => Ok(true)
|
||||||
|
| Error(error) => error->Error
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
| _ => T.TypeMismatch(anIType, evValue)->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
let caseTuple = (anIType, elementTypes, evValue) =>
|
||||||
|
switch evValue {
|
||||||
|
| IEvArray(anArray) =>
|
||||||
|
if Js.Array2.length(elementTypes) == Js.Array2.length(anArray) {
|
||||||
|
let zipped = Belt.Array.zip(elementTypes, anArray)
|
||||||
|
Belt.Array.reduce(zipped, Ok(true), (acc, (elementType, element)) =>
|
||||||
|
switch acc {
|
||||||
|
| Ok(_) =>
|
||||||
|
switch isITypeOf(elementType, element) {
|
||||||
|
| Ok(_) => acc
|
||||||
|
| Error(error) => Error(error)
|
||||||
|
}
|
||||||
|
| _ => acc
|
||||||
|
}
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
T.TypeMismatch(anIType, evValue)->Error
|
||||||
|
}
|
||||||
|
| _ => T.TypeMismatch(anIType, evValue)->Error
|
||||||
|
}
|
||||||
|
|
||||||
|
let caseOr = (anIType, anITypeArray, evValue) =>
|
||||||
|
switch Belt.Array.reduce(anITypeArray, Ok(false), (acc, anIType) =>
|
||||||
Belt.Result.flatMap(acc, _ =>
|
Belt.Result.flatMap(acc, _ =>
|
||||||
switch Belt.Map.String.get(map, property) {
|
switch acc {
|
||||||
| Some(propertyValue) => isOfResolvedIType(propertyType, propertyValue)
|
| Ok(false) =>
|
||||||
| None => TypeErrorWithProperty(anIType, evValue, property)->Error
|
switch isITypeOf(anIType, evValue) {
|
||||||
|
| Ok(_) => Ok(true)
|
||||||
|
| Error(_) => acc
|
||||||
|
}
|
||||||
|
| _ => acc
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
})
|
) {
|
||||||
}
|
| Ok(true) => Ok(true)
|
||||||
let _caseArray = (anIType, evValue, elementType, anArray) => {
|
| Ok(false) => T.TypeMismatch(anIType, evValue)->Error
|
||||||
Belt.Array.reduceWithIndex(anArray, Ok(true), (acc, element, index) => {
|
| Error(error) => Error(error)
|
||||||
switch isOfResolvedIType(elementType, element) {
|
}
|
||||||
| Ok(_) => acc
|
|
||||||
| Error(_) => TypeErrorWithPosition(anIType, evValue, index)->Error
|
let caseModifiedType = (
|
||||||
|
anIType: T.iType,
|
||||||
|
modifiedType: T.iType,
|
||||||
|
contracts: Belt.Map.String.t<InternalExpressionValue.t>,
|
||||||
|
aValue: InternalExpressionValue.t,
|
||||||
|
) => {
|
||||||
|
isITypeOf(modifiedType, aValue)->Belt.Result.flatMap(_result => {
|
||||||
|
if TypeContracts.checkModifiers(contracts, aValue) {
|
||||||
|
Ok(true)
|
||||||
|
} else {
|
||||||
|
T.TypeMismatch(anIType, aValue)->Error
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
switch anIType {
|
switch anIType {
|
||||||
| ItTypeIdentifier(name) => caseTypeIdentifier(name, aValue)
|
| ItTypeIdentifier(name) => caseTypeIdentifier(name, aValue)
|
||||||
// TODO: Work in progress. Code is commented to make an a release of other features
|
| ItModifiedType({modifiedType, contracts}) =>
|
||||||
// | ItModifiedType({modifiedType: anIType}) => raise(Reducer_Exception.ImpossibleException)
|
caseModifiedType(anIType, modifiedType, contracts, aValue) //{modifiedType: iType, contracts: Belt.Map.String.t<InternalExpressionValue.t>}
|
||||||
// | ItTypeOr({typeOr: anITypeArray}) => raise(Reducer_Exception.ImpossibleException)
|
| ItTypeOr({typeOr}) => caseOr(anIType, typeOr, aValue)
|
||||||
// | ItTypeFunction({inputs: anITypeArray, output: anIType}) =>
|
| ItTypeFunction(_) =>
|
||||||
// raise(Reducer_Exception.ImpossibleException)
|
raise(
|
||||||
// | ItTypeArray({element: anIType}) => raise(Reducer_Exception.ImpossibleException)
|
Reducer_Exception.ImpossibleException(
|
||||||
// | ItTypeTuple({elements: anITypeArray}) => raise(Reducer_Exception.ImpossibleException)
|
"Reducer_TypeChecker-functions are without a type at the moment",
|
||||||
// | ItTypeRecord({properties: anITypeMap}) => raise(Reducer_Exception.ImpossibleException)
|
),
|
||||||
| _ => raise(Reducer_Exception.ImpossibleException)
|
)
|
||||||
|
| ItTypeArray({element}) => caseArray(anIType, element, aValue)
|
||||||
|
| ItTypeTuple({elements}) => caseTuple(anIType, elements, aValue)
|
||||||
|
| ItTypeRecord({properties}) => caseRecord(anIType, properties, aValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let isOfResolvedType = (aType: InternalExpressionValue.t, aValue): result<bool, typeErrorValue> =>
|
let isTypeOf = (
|
||||||
aType->T.fromIEvValue->isOfResolvedIType(aValue)
|
typeExpressionSourceCode: string,
|
||||||
|
aValue: InternalExpressionValue.t,
|
||||||
|
reducerFn: ExpressionT.reducerFn,
|
||||||
|
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||||
|
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
||||||
|
| Ok(anIType) =>
|
||||||
|
switch isITypeOf(anIType, aValue) {
|
||||||
|
| Ok(_) => Ok(aValue)
|
||||||
|
| Error(T.TypeMismatch(anIType, evValue)) =>
|
||||||
|
Error(
|
||||||
|
ErrorValue.REExpectedType(anIType->T.toString, evValue->InternalExpressionValue.toString),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
| Error(error) => Error(error) // Directly propagating - err => err - causes type mismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: Work in progress. Code is commented to make an a release of other features
|
let checkITypeArguments = (anIType: T.iType, args: array<InternalExpressionValue.t>): result<
|
||||||
// let checkArguments = (
|
bool,
|
||||||
// evFunctionType: InternalExpressionValue.t,
|
T.typeErrorValue,
|
||||||
// args: array<InternalExpressionValue.t>,
|
> => {
|
||||||
// ) => {
|
switch anIType {
|
||||||
// let functionType = switch evFunctionType {
|
| T.ItTypeFunction({inputs}) => isITypeOf(T.ItTypeTuple({elements: inputs}), args->IEvArray)
|
||||||
// | IEvRecord(functionType) => functionType
|
| _ => T.TypeMismatch(anIType, args->IEvArray)->Error
|
||||||
// | _ => raise(Reducer_Exception.ImpossibleException)
|
}
|
||||||
// }
|
}
|
||||||
// let evInputs = functionType->Belt.Map.String.getWithDefault("inputs", []->IEvArray)
|
|
||||||
// let inputs = switch evInputs {
|
|
||||||
// | IEvArray(inputs) => inputs
|
|
||||||
// | _ => raise(Reducer_Exception.ImpossibleException)
|
|
||||||
// }
|
|
||||||
// let rTupleType = TypeBuilder.typeTuple(inputs)
|
|
||||||
// Belt.Result.flatMap(rTupleType, tuppleType => isOfResolvedType(tuppleType, args->IEvArray))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// let compileTypeExpression = (typeExpression: string, bindings: ExpressionT.bindings, reducerFn: ExpressionT.reducerFn) => {
|
let checkArguments = (
|
||||||
// statement = `type compiled=${typeExpression}`
|
typeExpressionSourceCode: string,
|
||||||
|
args: array<InternalExpressionValue.t>,
|
||||||
// }
|
reducerFn: ExpressionT.reducerFn,
|
||||||
|
): result<InternalExpressionValue.t, ErrorValue.t> => {
|
||||||
//TODO: asGuard
|
switch typeExpressionSourceCode->Reducer_Type_Compile.fromTypeExpression(reducerFn) {
|
||||||
|
| Ok(anIType) =>
|
||||||
|
switch checkITypeArguments(anIType, args) {
|
||||||
|
| Ok(_) => Ok(args->IEvArray)
|
||||||
|
| Error(T.TypeMismatch(anIType, evValue)) =>
|
||||||
|
Error(
|
||||||
|
ErrorValue.REExpectedType(anIType->T.toString, evValue->InternalExpressionValue.toString),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
| Error(error) => Error(error) // Directly propagating - err => err - causes type mismatch
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -4,7 +4,7 @@ type internalExpressionValue = InternalExpressionValue.t
|
||||||
/*
|
/*
|
||||||
Map external calls of Reducer
|
Map external calls of Reducer
|
||||||
*/
|
*/
|
||||||
let dispatch = (call: InternalExpressionValue.functionCall, environment, chain): result<
|
let dispatch = (call: InternalExpressionValue.functionCall, environment, reducer, chain): result<
|
||||||
internalExpressionValue,
|
internalExpressionValue,
|
||||||
'e,
|
'e,
|
||||||
> => {
|
> => {
|
||||||
|
@ -14,7 +14,7 @@ let dispatch = (call: InternalExpressionValue.functionCall, environment, chain):
|
||||||
() => ReducerInterface_Duration.dispatch(call, environment),
|
() => ReducerInterface_Duration.dispatch(call, environment),
|
||||||
() => ReducerInterface_Number.dispatch(call, environment),
|
() => ReducerInterface_Number.dispatch(call, environment),
|
||||||
() => FunctionRegistry_Library.dispatch(call, environment),
|
() => FunctionRegistry_Library.dispatch(call, environment),
|
||||||
])->E.O2.default(chain(call, environment))
|
])->E.O2.default(chain(call, environment, reducer))
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -84,7 +84,7 @@ let toStringWithType = aValue =>
|
||||||
| IEvDeclaration(_) => `Declaration::${toString(aValue)}`
|
| IEvDeclaration(_) => `Declaration::${toString(aValue)}`
|
||||||
| IEvDistribution(_) => `Distribution::${toString(aValue)}`
|
| IEvDistribution(_) => `Distribution::${toString(aValue)}`
|
||||||
| IEvLambda(_) => `Lambda::${toString(aValue)}`
|
| IEvLambda(_) => `Lambda::${toString(aValue)}`
|
||||||
| IEvBindings(_) => `Module::${toString(aValue)}`
|
| IEvBindings(_) => `Bindings::${toString(aValue)}`
|
||||||
| IEvNumber(_) => `Number::${toString(aValue)}`
|
| IEvNumber(_) => `Number::${toString(aValue)}`
|
||||||
| IEvRecord(_) => `Record::${toString(aValue)}`
|
| IEvRecord(_) => `Record::${toString(aValue)}`
|
||||||
| IEvString(_) => `String::${toString(aValue)}`
|
| IEvString(_) => `String::${toString(aValue)}`
|
||||||
|
|
|
@ -631,6 +631,19 @@ module A = {
|
||||||
)
|
)
|
||||||
let filter = Js.Array.filter
|
let filter = Js.Array.filter
|
||||||
let joinWith = Js.Array.joinWith
|
let joinWith = Js.Array.joinWith
|
||||||
|
let transpose = (xs: array<array<'a>>): array<array<'a>> => {
|
||||||
|
let arr: array<array<'a>> = []
|
||||||
|
for i in 0 to length(xs) - 1 {
|
||||||
|
for j in 0 to length(xs[i]) - 1 {
|
||||||
|
if Js.Array.length(arr) <= j {
|
||||||
|
ignore(Js.Array.push([xs[i][j]], arr))
|
||||||
|
} else {
|
||||||
|
ignore(Js.Array.push(xs[i][j], arr[j]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
arr
|
||||||
|
}
|
||||||
|
|
||||||
let all = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) == length(xs)
|
let all = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) == length(xs)
|
||||||
let any = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) > 0
|
let any = (p: 'a => bool, xs: array<'a>): bool => length(filter(p, xs)) > 0
|
||||||
|
|
|
@ -148,7 +148,7 @@
|
||||||
"vsce-yarn-patch": "^1.66.2"
|
"vsce-yarn-patch": "^1.66.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"vscode-languageclient": "^8.0.1",
|
"vscode-languageclient": "^8.0.2",
|
||||||
"vscode-languageserver": "^8.0.2",
|
"vscode-languageserver": "^8.0.2",
|
||||||
"vscode-languageserver-textdocument": "^1.0.5",
|
"vscode-languageserver-textdocument": "^1.0.5",
|
||||||
"@quri/squiggle-lang": "^0.2.11"
|
"@quri/squiggle-lang": "^0.2.11"
|
||||||
|
|
64
yarn.lock
64
yarn.lock
|
@ -2634,7 +2634,7 @@
|
||||||
"@motionone/utils" "^10.12.0"
|
"@motionone/utils" "^10.12.0"
|
||||||
tslib "^2.3.1"
|
tslib "^2.3.1"
|
||||||
|
|
||||||
"@motionone/dom@^10.11.1":
|
"@motionone/dom@10.12.0":
|
||||||
version "10.12.0"
|
version "10.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.12.0.tgz#ae30827fd53219efca4e1150a5ff2165c28351ed"
|
resolved "https://registry.yarnpkg.com/@motionone/dom/-/dom-10.12.0.tgz#ae30827fd53219efca4e1150a5ff2165c28351ed"
|
||||||
integrity sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==
|
integrity sha512-UdPTtLMAktHiqV0atOczNYyDd/d8Cf5fFsd1tua03PqTwwCe/6lwhLSQ8a7TbnQ5SN0gm44N1slBfj+ORIhrqw==
|
||||||
|
@ -4686,10 +4686,10 @@
|
||||||
"@types/node" "*"
|
"@types/node" "*"
|
||||||
form-data "^3.0.0"
|
form-data "^3.0.0"
|
||||||
|
|
||||||
"@types/node@*", "@types/node@18.x", "@types/node@^18.0.3":
|
"@types/node@*", "@types/node@18.x", "@types/node@^18.0.6":
|
||||||
version "18.0.3"
|
version "18.0.6"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.3.tgz#463fc47f13ec0688a33aec75d078a0541a447199"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-18.0.6.tgz#0ba49ac517ad69abe7a1508bc9b3a5483df9d5d7"
|
||||||
integrity sha512-HzNRZtp4eepNitP+BD6k2L6DROIDG4Q0fm4x+dwfsr6LGmROENnok75VGw40628xf+iR24WeMFcHuuBDUAzzsQ==
|
integrity sha512-/xUq6H2aQm261exT6iZTMifUySEt4GR5KX8eYyY+C4MSNPqSh9oNIP7tz2GLKTlFaiBbgZNxffoR3CVRG+cljw==
|
||||||
|
|
||||||
"@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0":
|
"@types/node@^14.0.10 || ^16.0.0", "@types/node@^14.14.20 || ^16.0.0":
|
||||||
version "16.11.41"
|
version "16.11.41"
|
||||||
|
@ -7213,10 +7213,10 @@ commander@^8.0.0, commander@^8.3.0:
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
|
||||||
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
|
integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
|
||||||
|
|
||||||
commander@^9.3.0:
|
commander@^9.3.0, commander@^9.4.0:
|
||||||
version "9.3.0"
|
version "9.4.0"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-9.3.0.tgz#f619114a5a2d2054e0d9ff1b31d5ccf89255e26b"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-9.4.0.tgz#bc4a40918fefe52e22450c111ecd6b7acce6f11c"
|
||||||
integrity sha512-hv95iU5uXPbK83mjrJKuZyFM/LBAoCV/XhVGkS5Je6tl7sxr6A0ITMw5WoRV46/UaJ46Nllm3Xt7IaJhXTIkzw==
|
integrity sha512-sRPT+umqkz90UA8M1yqYfnHlZA7fF6nSphDtxeywPZ49ysjxDQybzk13CL+mXekDRG92skbcqCLVovuCusNmFw==
|
||||||
|
|
||||||
common-path-prefix@^3.0.0:
|
common-path-prefix@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
|
@ -9597,12 +9597,12 @@ fragment-cache@^0.2.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
map-cache "^0.2.2"
|
map-cache "^0.2.2"
|
||||||
|
|
||||||
framer-motion@^6.4.3:
|
framer-motion@^6.5.1:
|
||||||
version "6.4.3"
|
version "6.5.1"
|
||||||
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.4.3.tgz#1d60f352ccc2840b0302c35c0993d972da550d03"
|
resolved "https://registry.yarnpkg.com/framer-motion/-/framer-motion-6.5.1.tgz#802448a16a6eb764124bf36d8cbdfa6dd6b931a7"
|
||||||
integrity sha512-prcyOGFkGjwGEgbxObIWteVz1ihuWaDLdR03626cbA1GxTaPRpLb8ioJfWPmP5mwcWC7TlhMOjS5kBYnuiktFA==
|
integrity sha512-o1BGqqposwi7cgDrtg0dNONhkmPsUFDaLcKXigzuTFC5x58mE8iyTazxSudFzmT6MEyJKfjjU8ItoMe3W+3fiw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@motionone/dom" "^10.11.1"
|
"@motionone/dom" "10.12.0"
|
||||||
framesync "6.0.1"
|
framesync "6.0.1"
|
||||||
hey-listen "^1.0.8"
|
hey-listen "^1.0.8"
|
||||||
popmotion "11.0.3"
|
popmotion "11.0.3"
|
||||||
|
@ -9745,10 +9745,10 @@ gensync@^1.0.0-beta.1, gensync@^1.0.0-beta.2:
|
||||||
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
|
||||||
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
|
||||||
|
|
||||||
gentype@^4.4.0:
|
gentype@^4.5.0:
|
||||||
version "4.4.0"
|
version "4.5.0"
|
||||||
resolved "https://registry.yarnpkg.com/gentype/-/gentype-4.4.0.tgz#20a61776703ce79c638c4db34b8808e1896d3267"
|
resolved "https://registry.yarnpkg.com/gentype/-/gentype-4.5.0.tgz#460152da93db783626fd25bbd38fb574d886f5f3"
|
||||||
integrity sha512-hLcKmMhD3DJzHffDqwYUkEZfdGSWJk6ehYmdzGHBs35mTJa2dhiAp31WqmhjkZIqKvD+A+gFEE+//QHG5dZfwg==
|
integrity sha512-XqHBQPS6Qb2HSgNJAwYRXbQJ4LSvz+MgNvuWnj8bz0teSorsy2kDxA6F1eZx5ft8cnfKAls4uNEgd5uNcPbQDg==
|
||||||
|
|
||||||
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
get-caller-file@^2.0.1, get-caller-file@^2.0.5:
|
||||||
version "2.0.5"
|
version "2.0.5"
|
||||||
|
@ -18390,32 +18390,19 @@ vsce-yarn-patch@^1.66.2:
|
||||||
yauzl "^2.3.1"
|
yauzl "^2.3.1"
|
||||||
yazl "^2.2.2"
|
yazl "^2.2.2"
|
||||||
|
|
||||||
vscode-jsonrpc@8.0.1:
|
|
||||||
version "8.0.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.1.tgz#f30b0625ebafa0fb3bc53e934ca47b706445e57e"
|
|
||||||
integrity sha512-N/WKvghIajmEvXpatSzvTvOIz61ZSmOSa4BRA4pTLi+1+jozquQKP/MkaylP9iB68k73Oua1feLQvH3xQuigiQ==
|
|
||||||
|
|
||||||
vscode-jsonrpc@8.0.2:
|
vscode-jsonrpc@8.0.2:
|
||||||
version "8.0.2"
|
version "8.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9"
|
resolved "https://registry.yarnpkg.com/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2.tgz#f239ed2cd6004021b6550af9fd9d3e47eee3cac9"
|
||||||
integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==
|
integrity sha512-RY7HwI/ydoC1Wwg4gJ3y6LpU9FJRZAUnTYMXthqhFXXu77ErDd/xkREpGuk4MyYkk4a+XDWAMqe0S3KkelYQEQ==
|
||||||
|
|
||||||
vscode-languageclient@^8.0.1:
|
vscode-languageclient@^8.0.2:
|
||||||
version "8.0.1"
|
version "8.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.1.tgz#bf5535c4463a78daeaca0bcb4f5868aec86bb301"
|
resolved "https://registry.yarnpkg.com/vscode-languageclient/-/vscode-languageclient-8.0.2.tgz#f1f23ce8c8484aa11e4b7dfb24437d3e59bb61c6"
|
||||||
integrity sha512-9XoE+HJfaWvu7Y75H3VmLo5WLCtsbxEgEhrLPqwt7eyoR49lUIyyrjb98Yfa50JCMqF2cePJAEVI6oe2o1sIhw==
|
integrity sha512-lHlthJtphG9gibGb/y72CKqQUxwPsMXijJVpHEC2bvbFqxmkj9LwQ3aGU9dwjBLqsX1S4KjShYppLvg1UJDF/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
semver "^7.3.5"
|
semver "^7.3.5"
|
||||||
vscode-languageserver-protocol "3.17.1"
|
vscode-languageserver-protocol "3.17.2"
|
||||||
|
|
||||||
vscode-languageserver-protocol@3.17.1:
|
|
||||||
version "3.17.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.1.tgz#e801762c304f740208b6c804a0cf21f2c87509ed"
|
|
||||||
integrity sha512-BNlAYgQoYwlSgDLJhSG+DeA8G1JyECqRzM2YO6tMmMji3Ad9Mw6AW7vnZMti90qlAKb0LqAlJfSVGEdqMMNzKg==
|
|
||||||
dependencies:
|
|
||||||
vscode-jsonrpc "8.0.1"
|
|
||||||
vscode-languageserver-types "3.17.1"
|
|
||||||
|
|
||||||
vscode-languageserver-protocol@3.17.2:
|
vscode-languageserver-protocol@3.17.2:
|
||||||
version "3.17.2"
|
version "3.17.2"
|
||||||
|
@ -18430,11 +18417,6 @@ vscode-languageserver-textdocument@^1.0.5:
|
||||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.5.tgz#838769940ece626176ec5d5a2aa2d0aa69f5095c"
|
resolved "https://registry.yarnpkg.com/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.5.tgz#838769940ece626176ec5d5a2aa2d0aa69f5095c"
|
||||||
integrity sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg==
|
integrity sha512-1ah7zyQjKBudnMiHbZmxz5bYNM9KKZYz+5VQLj+yr8l+9w3g+WAhCkUkWbhMEdC5u0ub4Ndiye/fDyS8ghIKQg==
|
||||||
|
|
||||||
vscode-languageserver-types@3.17.1:
|
|
||||||
version "3.17.1"
|
|
||||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.1.tgz#c2d87fa7784f8cac389deb3ff1e2d9a7bef07e16"
|
|
||||||
integrity sha512-K3HqVRPElLZVVPtMeKlsyL9aK0GxGQpvtAUTfX4k7+iJ4mc1M+JM+zQwkgGy2LzY0f0IAafe8MKqIkJrxfGGjQ==
|
|
||||||
|
|
||||||
vscode-languageserver-types@3.17.2:
|
vscode-languageserver-types@3.17.2:
|
||||||
version "3.17.2"
|
version "3.17.2"
|
||||||
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2"
|
resolved "https://registry.yarnpkg.com/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2.tgz#b2c2e7de405ad3d73a883e91989b850170ffc4f2"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user