CallStack, location -> frame, WIP
This commit is contained in:
parent
4c56b2fd07
commit
184584c9f3
|
@ -1,6 +1,8 @@
|
||||||
import * as RSError from "../rescript/SqError.gen";
|
import * as RSError from "../rescript/SqError.gen";
|
||||||
|
|
||||||
export type SqLocation = RSError.location;
|
import * as RSCallStack from "../rescript/Reducer/Reducer_CallStack.gen";
|
||||||
|
|
||||||
|
export type SqFrame = RSCallStack.frame;
|
||||||
|
|
||||||
export class SqError {
|
export class SqError {
|
||||||
constructor(private _value: RSError.t) {}
|
constructor(private _value: RSError.t) {}
|
||||||
|
@ -17,13 +19,17 @@ export class SqError {
|
||||||
return new SqError(RSError.createOtherError(v));
|
return new SqError(RSError.createOtherError(v));
|
||||||
}
|
}
|
||||||
|
|
||||||
toLocationArray() {
|
getTopFrame(): SqCallFrame | undefined {
|
||||||
const stackTrace = RSError.getStackTrace(this._value);
|
const frame = RSCallStack.getTopFrame(RSError.getStackTrace(this._value));
|
||||||
|
return frame ? new SqCallFrame(frame) : undefined;
|
||||||
return stackTrace ? RSError.StackTrace.toLocationArray(stackTrace) : [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
toLocation() {
|
getFrameArray(): SqCallFrame[] {
|
||||||
return RSError.getLocation(this._value);
|
const frames = RSError.getFrameArray(this._value);
|
||||||
|
return frames.map((frame) => new SqCallFrame(frame));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class SqCallFrame {
|
||||||
|
constructor(private _value: SqFrame) {}
|
||||||
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@ export {
|
||||||
environment,
|
environment,
|
||||||
defaultEnvironment,
|
defaultEnvironment,
|
||||||
} from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
|
} from "../rescript/ForTS/ForTS_Distribution/ForTS_Distribution.gen";
|
||||||
export { SqError, SqLocation } from "./SqError";
|
export { SqError } from "./SqError";
|
||||||
export { SqShape } from "./SqPointSetDist";
|
export { SqShape } from "./SqPointSetDist";
|
||||||
|
|
||||||
export { resultMap } from "./types";
|
export { resultMap } from "./types";
|
||||||
|
|
|
@ -67,7 +67,7 @@ module Integration = {
|
||||||
let applyFunctionAtFloatToFloatOption = (point: float) => {
|
let applyFunctionAtFloatToFloatOption = (point: float) => {
|
||||||
// Defined here so that it has access to environment, reducer
|
// Defined here so that it has access to environment, reducer
|
||||||
let pointAsInternalExpression = FunctionRegistry_Helpers.Wrappers.evNumber(point)
|
let pointAsInternalExpression = FunctionRegistry_Helpers.Wrappers.evNumber(point)
|
||||||
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
|
let resultAsInternalExpression = Reducer_Lambda.doLambdaCall(
|
||||||
aLambda,
|
aLambda,
|
||||||
[pointAsInternalExpression],
|
[pointAsInternalExpression],
|
||||||
environment,
|
environment,
|
||||||
|
@ -308,7 +308,7 @@ module DiminishingReturns = {
|
||||||
let applyFunctionAtPoint = (lambda, point: float) => {
|
let applyFunctionAtPoint = (lambda, point: float) => {
|
||||||
// Defined here so that it has access to environment, reducer
|
// Defined here so that it has access to environment, reducer
|
||||||
let pointAsInternalExpression = FunctionRegistry_Helpers.Wrappers.evNumber(point)
|
let pointAsInternalExpression = FunctionRegistry_Helpers.Wrappers.evNumber(point)
|
||||||
let resultAsInternalExpression = Reducer_Expression_Lambda.doLambdaCall(
|
let resultAsInternalExpression = Reducer_Lambda.doLambdaCall(
|
||||||
lambda,
|
lambda,
|
||||||
[pointAsInternalExpression],
|
[pointAsInternalExpression],
|
||||||
environment,
|
environment,
|
||||||
|
|
|
@ -76,7 +76,7 @@ let library = [
|
||||||
->Belt.Array.map(dictValue =>
|
->Belt.Array.map(dictValue =>
|
||||||
switch dictValue {
|
switch dictValue {
|
||||||
| IEvRecord(dict) => dict
|
| IEvRecord(dict) => dict
|
||||||
| _ => impossibleError->SqError.Message.toException
|
| _ => impossibleError->SqError.Message.throw
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
->Internals.mergeMany
|
->Internals.mergeMany
|
||||||
|
|
|
@ -22,7 +22,8 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber],
|
~inputs=[FRTypeDistOrNumber, FRTypeDistOrNumber],
|
||||||
~run=(inputs, env, _) => inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env),
|
~run=(inputs, context, _) =>
|
||||||
|
inputs->Prepare.ToValueTuple.twoDistOrNumber->process(~fn, ~env=context.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -31,8 +32,10 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
|
~inputs=[FRTypeRecord([("p5", FRTypeDistOrNumber), ("p95", FRTypeDistOrNumber)])],
|
||||||
~run=(inputs, env, _) =>
|
~run=(inputs, context, _) =>
|
||||||
inputs->Prepare.ToValueTuple.Record.twoDistOrNumber(("p5", "p95"))->process(~fn, ~env),
|
inputs
|
||||||
|
->Prepare.ToValueTuple.Record.twoDistOrNumber(("p5", "p95"))
|
||||||
|
->process(~fn, ~env=context.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -41,10 +44,10 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
|
~inputs=[FRTypeRecord([("mean", FRTypeDistOrNumber), ("stdev", FRTypeDistOrNumber)])],
|
||||||
~run=(inputs, env, _) =>
|
~run=(inputs, context, _) =>
|
||||||
inputs
|
inputs
|
||||||
->Prepare.ToValueTuple.Record.twoDistOrNumber(("mean", "stdev"))
|
->Prepare.ToValueTuple.Record.twoDistOrNumber(("mean", "stdev"))
|
||||||
->process(~fn, ~env),
|
->process(~fn, ~env=context.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -61,7 +64,8 @@ module DistributionCreation = {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs=[FRTypeDistOrNumber],
|
~inputs=[FRTypeDistOrNumber],
|
||||||
~run=(inputs, env, _) => inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env),
|
~run=(inputs, context, _) =>
|
||||||
|
inputs->Prepare.ToValueTuple.oneDistOrNumber->process(~fn, ~env=context.environment),
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -313,7 +313,7 @@ module Old = {
|
||||||
| None =>
|
| None =>
|
||||||
SqError.Message.REOther(
|
SqError.Message.REOther(
|
||||||
"Internal error in FR_GenericDist implementation",
|
"Internal error in FR_GenericDist implementation",
|
||||||
)->SqError.Message.toException
|
)->SqError.Message.throw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ let makeProxyFn = (name: string, inputs: array<frType>) => {
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name,
|
~name,
|
||||||
~inputs,
|
~inputs,
|
||||||
~run=(inputs, env, _) => Old.dispatch((name, inputs), env),
|
~run=(inputs, context, _) => Old.dispatch((name, inputs), context.environment),
|
||||||
(),
|
(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -402,9 +402,9 @@ let library = E.A.concatMany([
|
||||||
])
|
])
|
||||||
|
|
||||||
// FIXME - impossible to implement with FR due to arbitrary parameters length;
|
// FIXME - impossible to implement with FR due to arbitrary parameters length;
|
||||||
let mxLambda = Reducer_Expression_Lambda.makeFFILambda((inputs, env, _) => {
|
let mxLambda = Reducer_Lambda.makeFFILambda("mx", (inputs, context, _) => {
|
||||||
switch Old.dispatch(("mx", inputs), env) {
|
switch Old.dispatch(("mx", inputs), context.environment) {
|
||||||
| Ok(value) => value
|
| Ok(value) => value
|
||||||
| Error(e) => e->SqError.Message.toException
|
| Error(e) => e->SqError.Message.throw
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -26,11 +26,11 @@ module Internals = {
|
||||||
let map = (
|
let map = (
|
||||||
array: array<Reducer_T.value>,
|
array: array<Reducer_T.value>,
|
||||||
eLambdaValue,
|
eLambdaValue,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
): Reducer_T.value => {
|
): Reducer_T.value => {
|
||||||
Belt.Array.map(array, elem =>
|
Belt.Array.map(array, elem =>
|
||||||
Reducer_Expression_Lambda.doLambdaCall(eLambdaValue, [elem], env, reducer)
|
Reducer_Lambda.doLambdaCall(eLambdaValue, [elem], context, reducer)
|
||||||
)->Wrappers.evArray
|
)->Wrappers.evArray
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,11 +38,11 @@ module Internals = {
|
||||||
aValueArray,
|
aValueArray,
|
||||||
initialValue,
|
initialValue,
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
) => {
|
) => {
|
||||||
aValueArray->E.A.reduce(initialValue, (acc, elem) =>
|
aValueArray->E.A.reduce(initialValue, (acc, elem) =>
|
||||||
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, [acc, elem], env, reducer)
|
Reducer_Lambda.doLambdaCall(aLambdaValue, [acc, elem], context, reducer)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,22 +50,22 @@ module Internals = {
|
||||||
aValueArray,
|
aValueArray,
|
||||||
initialValue,
|
initialValue,
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
) => {
|
) => {
|
||||||
aValueArray->Belt.Array.reduceReverse(initialValue, (acc, elem) =>
|
aValueArray->Belt.Array.reduceReverse(initialValue, (acc, elem) =>
|
||||||
Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, [acc, elem], env, reducer)
|
Reducer_Lambda.doLambdaCall(aLambdaValue, [acc, elem], context, reducer)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
let filter = (
|
let filter = (
|
||||||
aValueArray,
|
aValueArray,
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
) => {
|
) => {
|
||||||
Js.Array2.filter(aValueArray, elem => {
|
Js.Array2.filter(aValueArray, elem => {
|
||||||
let result = Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, [elem], env, reducer)
|
let result = Reducer_Lambda.doLambdaCall(aLambdaValue, [elem], context, reducer)
|
||||||
switch result {
|
switch result {
|
||||||
| IEvBool(true) => true
|
| IEvBool(true) => true
|
||||||
| _ => false
|
| _ => false
|
||||||
|
@ -109,8 +109,8 @@ let library = [
|
||||||
~inputs=[FRTypeNumber, FRTypeNumber],
|
~inputs=[FRTypeNumber, FRTypeNumber],
|
||||||
~run=(inputs, _, _) =>
|
~run=(inputs, _, _) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvNumber(low), IEvNumber(high)] => Internals.upTo(low, high)->Ok
|
| [IEvNumber(low), IEvNumber(high)] => Internals.upTo(low, high)->Ok
|
||||||
| _ => impossibleError->Error
|
| _ => impossibleError->Error
|
||||||
},
|
},
|
||||||
(),
|
(),
|
||||||
),
|
),
|
||||||
|
|
|
@ -16,16 +16,16 @@ let inputsToDist = (inputs: array<Reducer_T.value>, xyShapeToPointSetDist) => {
|
||||||
let yValue = map->Belt.Map.String.get("y")
|
let yValue = map->Belt.Map.String.get("y")
|
||||||
switch (xValue, yValue) {
|
switch (xValue, yValue) {
|
||||||
| (Some(IEvNumber(x)), Some(IEvNumber(y))) => (x, y)
|
| (Some(IEvNumber(x)), Some(IEvNumber(y))) => (x, y)
|
||||||
| _ => impossibleError->SqError.Message.toException
|
| _ => impossibleError->SqError.Message.throw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| _ => impossibleError->SqError.Message.toException
|
| _ => impossibleError->SqError.Message.throw
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
->Ok
|
->Ok
|
||||||
->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString))
|
->E.R.bind(r => r->XYShape.T.makeFromZipped->E.R2.errMap(XYShape.Error.toString))
|
||||||
->E.R2.fmap(r => Reducer_T.IEvDistribution(PointSet(r->xyShapeToPointSetDist)))
|
->E.R2.fmap(r => Reducer_T.IEvDistribution(PointSet(r->xyShapeToPointSetDist)))
|
||||||
| _ => impossibleError->SqError.Message.toException
|
| _ => impossibleError->SqError.Message.throw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ module Internal = {
|
||||||
}
|
}
|
||||||
|
|
||||||
let doLambdaCall = (aLambdaValue, list, env, reducer) =>
|
let doLambdaCall = (aLambdaValue, list, env, reducer) =>
|
||||||
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, env, reducer) {
|
switch Reducer_Lambda.doLambdaCall(aLambdaValue, list, env, reducer) {
|
||||||
| Reducer_T.IEvNumber(f) => Ok(f)
|
| Reducer_T.IEvNumber(f) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
@ -61,13 +61,13 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="fromDist",
|
~name="fromDist",
|
||||||
~inputs=[FRTypeDist],
|
~inputs=[FRTypeDist],
|
||||||
~run=(inputs, env, _) =>
|
~run=(inputs, context, _) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvDistribution(dist)] =>
|
| [IEvDistribution(dist)] =>
|
||||||
GenericDist.toPointSet(
|
GenericDist.toPointSet(
|
||||||
dist,
|
dist,
|
||||||
~xyPointLength=env.xyPointLength,
|
~xyPointLength=context.environment.xyPointLength,
|
||||||
~sampleCount=env.sampleCount,
|
~sampleCount=context.environment.sampleCount,
|
||||||
(),
|
(),
|
||||||
)
|
)
|
||||||
->E.R2.fmap(Wrappers.pointSet)
|
->E.R2.fmap(Wrappers.pointSet)
|
||||||
|
|
|
@ -10,10 +10,10 @@ module Internal = {
|
||||||
let doLambdaCall = (
|
let doLambdaCall = (
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
list,
|
list,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
) =>
|
) =>
|
||||||
switch Reducer_Expression_Lambda.doLambdaCall(aLambdaValue, list, env, reducer) {
|
switch Reducer_Lambda.doLambdaCall(aLambdaValue, list, context, reducer) {
|
||||||
| IEvNumber(f) => Ok(f)
|
| IEvNumber(f) => Ok(f)
|
||||||
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
| _ => Error(Operation.SampleMapNeedsNtoNFunction)
|
||||||
}
|
}
|
||||||
|
@ -25,26 +25,25 @@ module Internal = {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: I don't know why this seems to need at least one input
|
//TODO: I don't know why this seems to need at least one input
|
||||||
let fromFn = (aLambdaValue, environment: Reducer_T.environment, reducer: Reducer_T.reducerFn) => {
|
let fromFn = (aLambdaValue, context: Reducer_T.context, reducer: Reducer_T.reducerFn) => {
|
||||||
let sampleCount = environment.sampleCount
|
let sampleCount = context.environment.sampleCount
|
||||||
let fn = r => doLambdaCall(aLambdaValue, [IEvNumber(r)], environment, reducer)
|
let fn = r => doLambdaCall(aLambdaValue, [IEvNumber(r)], context, reducer)
|
||||||
Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen
|
Belt_Array.makeBy(sampleCount, r => fn(r->Js.Int.toFloat))->E.A.R.firstErrorOrOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
let map1 = (sampleSetDist: t, aLambdaValue, environment: Reducer_T.environment, reducer) => {
|
let map1 = (sampleSetDist: t, aLambdaValue, context: Reducer_T.context, reducer) => {
|
||||||
let fn = r => doLambdaCall(aLambdaValue, [IEvNumber(r)], environment, reducer)
|
let fn = r => doLambdaCall(aLambdaValue, [IEvNumber(r)], context, reducer)
|
||||||
SampleSetDist.samplesMap(~fn, sampleSetDist)->toType
|
SampleSetDist.samplesMap(~fn, sampleSetDist)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
let map2 = (t1: t, t2: t, aLambdaValue, environment: Reducer_T.environment, reducer) => {
|
let map2 = (t1: t, t2: t, aLambdaValue, context: Reducer_T.context, reducer) => {
|
||||||
let fn = (a, b) =>
|
let fn = (a, b) => doLambdaCall(aLambdaValue, [IEvNumber(a), IEvNumber(b)], context, reducer)
|
||||||
doLambdaCall(aLambdaValue, [IEvNumber(a), IEvNumber(b)], environment, reducer)
|
|
||||||
SampleSetDist.map2(~fn, ~t1, ~t2)->toType
|
SampleSetDist.map2(~fn, ~t1, ~t2)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
let map3 = (t1: t, t2: t, t3: t, aLambdaValue, environment: Reducer_T.environment, reducer) => {
|
let map3 = (t1: t, t2: t, t3: t, aLambdaValue, context: Reducer_T.context, reducer) => {
|
||||||
let fn = (a, b, c) =>
|
let fn = (a, b, c) =>
|
||||||
doLambdaCall(aLambdaValue, [IEvNumber(a), IEvNumber(b), IEvNumber(c)], environment, reducer)
|
doLambdaCall(aLambdaValue, [IEvNumber(a), IEvNumber(b), IEvNumber(c)], context, reducer)
|
||||||
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
|
SampleSetDist.map3(~fn, ~t1, ~t2, ~t3)->toType
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +59,7 @@ module Internal = {
|
||||||
let mapN = (
|
let mapN = (
|
||||||
aValueArray: array<Reducer_T.value>,
|
aValueArray: array<Reducer_T.value>,
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
environment: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer,
|
reducer,
|
||||||
) => {
|
) => {
|
||||||
switch parseSampleSetArray(aValueArray) {
|
switch parseSampleSetArray(aValueArray) {
|
||||||
|
@ -69,7 +68,7 @@ module Internal = {
|
||||||
doLambdaCall(
|
doLambdaCall(
|
||||||
aLambdaValue,
|
aLambdaValue,
|
||||||
[IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))],
|
[IEvArray(E.A.fmap(x => Wrappers.evNumber(x), a))],
|
||||||
environment,
|
context,
|
||||||
reducer,
|
reducer,
|
||||||
)
|
)
|
||||||
SampleSetDist.mapN(~fn, ~t1)->toType
|
SampleSetDist.mapN(~fn, ~t1)->toType
|
||||||
|
@ -89,10 +88,10 @@ let libaryBase = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="fromDist",
|
~name="fromDist",
|
||||||
~inputs=[FRTypeDist],
|
~inputs=[FRTypeDist],
|
||||||
~run=(inputs, environment, _) =>
|
~run=(inputs, context, _) =>
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvDistribution(dist)] =>
|
| [IEvDistribution(dist)] =>
|
||||||
GenericDist.toSampleSetDist(dist, environment.sampleCount)
|
GenericDist.toSampleSetDist(dist, context.environment.sampleCount)
|
||||||
->E.R2.fmap(Wrappers.sampleSet)
|
->E.R2.fmap(Wrappers.sampleSet)
|
||||||
->E.R2.fmap(Wrappers.evDistribution)
|
->E.R2.fmap(Wrappers.evDistribution)
|
||||||
->E.R2.errMap(e => SqError.Message.REDistributionError(e))
|
->E.R2.errMap(e => SqError.Message.REDistributionError(e))
|
||||||
|
|
|
@ -30,15 +30,15 @@ let library = [
|
||||||
("prior", FRTypeDist),
|
("prior", FRTypeDist),
|
||||||
]),
|
]),
|
||||||
],
|
],
|
||||||
~run=(inputs, environment, _) => {
|
~run=(inputs, context, _) => {
|
||||||
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(
|
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.threeArgs(
|
||||||
inputs,
|
inputs,
|
||||||
("estimate", "answer", "prior"),
|
("estimate", "answer", "prior"),
|
||||||
) {
|
) {
|
||||||
| Ok([IEvDistribution(estimate), IEvDistribution(d), IEvDistribution(prior)]) =>
|
| Ok([IEvDistribution(estimate), IEvDistribution(d), IEvDistribution(prior)]) =>
|
||||||
runScoring(estimate, Score_Dist(d), Some(prior), environment)
|
runScoring(estimate, Score_Dist(d), Some(prior), context.environment)
|
||||||
| Ok([IEvDistribution(estimate), IEvNumber(d), IEvDistribution(prior)]) =>
|
| Ok([IEvDistribution(estimate), IEvNumber(d), IEvDistribution(prior)]) =>
|
||||||
runScoring(estimate, Score_Scalar(d), Some(prior), environment)
|
runScoring(estimate, Score_Scalar(d), Some(prior), context.environment)
|
||||||
| Error(e) => Error(e->FunctionRegistry_Helpers.wrapError)
|
| Error(e) => Error(e->FunctionRegistry_Helpers.wrapError)
|
||||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||||
}
|
}
|
||||||
|
@ -48,15 +48,15 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="logScore",
|
~name="logScore",
|
||||||
~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])],
|
~inputs=[FRTypeRecord([("estimate", FRTypeDist), ("answer", FRTypeDistOrNumber)])],
|
||||||
~run=(inputs, environment, _) => {
|
~run=(inputs, context, _) => {
|
||||||
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(
|
switch FunctionRegistry_Helpers.Prepare.ToValueArray.Record.twoArgs(
|
||||||
inputs,
|
inputs,
|
||||||
("estimate", "answer"),
|
("estimate", "answer"),
|
||||||
) {
|
) {
|
||||||
| Ok([IEvDistribution(estimate), IEvDistribution(d)]) =>
|
| Ok([IEvDistribution(estimate), IEvDistribution(d)]) =>
|
||||||
runScoring(estimate, Score_Dist(d), None, environment)
|
runScoring(estimate, Score_Dist(d), None, context.environment)
|
||||||
| Ok([IEvDistribution(estimate), IEvNumber(d)]) =>
|
| Ok([IEvDistribution(estimate), IEvNumber(d)]) =>
|
||||||
runScoring(estimate, Score_Scalar(d), None, environment)
|
runScoring(estimate, Score_Scalar(d), None, context.environment)
|
||||||
| Error(e) => Error(e->FunctionRegistry_Helpers.wrapError)
|
| Error(e) => Error(e->FunctionRegistry_Helpers.wrapError)
|
||||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||||
}
|
}
|
||||||
|
@ -76,10 +76,10 @@ let library = [
|
||||||
FnDefinition.make(
|
FnDefinition.make(
|
||||||
~name="klDivergence",
|
~name="klDivergence",
|
||||||
~inputs=[FRTypeDist, FRTypeDist],
|
~inputs=[FRTypeDist, FRTypeDist],
|
||||||
~run=(inputs, environment, _) => {
|
~run=(inputs, context, _) => {
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvDistribution(estimate), IEvDistribution(d)] =>
|
| [IEvDistribution(estimate), IEvDistribution(d)] =>
|
||||||
runScoring(estimate, Score_Dist(d), None, environment)
|
runScoring(estimate, Score_Dist(d), None, context.environment)
|
||||||
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
| _ => Error(FunctionRegistry_Helpers.impossibleError)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,9 +1,7 @@
|
||||||
@genType type squiggleValue_Lambda = Reducer_T.lambdaValue //re-export
|
@genType type squiggleValue_Lambda = Reducer_T.lambdaValue //re-export
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let toString = (v: squiggleValue_Lambda): string => Reducer_Value.toStringFunction(v)
|
let toString = (v: squiggleValue_Lambda): string => Reducer_Value.toStringLambda(v)
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let parameters = (v: squiggleValue_Lambda): array<string> => {
|
let parameters = (v: squiggleValue_Lambda): array<string> => Reducer_Lambda.parameters(v)
|
||||||
v.parameters
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,7 +30,7 @@ type fnDefinition = {
|
||||||
inputs: array<frType>,
|
inputs: array<frType>,
|
||||||
run: (
|
run: (
|
||||||
array<Reducer_T.value>,
|
array<Reducer_T.value>,
|
||||||
Reducer_T.environment,
|
Reducer_T.context,
|
||||||
Reducer_T.reducerFn,
|
Reducer_T.reducerFn,
|
||||||
) => result<Reducer_T.value, errorMessage>,
|
) => result<Reducer_T.value, errorMessage>,
|
||||||
}
|
}
|
||||||
|
@ -122,11 +122,11 @@ module FnDefinition = {
|
||||||
let run = (
|
let run = (
|
||||||
t: t,
|
t: t,
|
||||||
args: array<Reducer_T.value>,
|
args: array<Reducer_T.value>,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
) => {
|
) => {
|
||||||
switch t->isMatch(args) {
|
switch t->isMatch(args) {
|
||||||
| true => t.run(args, env, reducer)
|
| true => t.run(args, context, reducer)
|
||||||
| false => REOther("Incorrect Types")->Error
|
| false => REOther("Incorrect Types")->Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -164,7 +164,7 @@ module Function = {
|
||||||
nameSpace: nameSpace,
|
nameSpace: nameSpace,
|
||||||
definitions: definitions,
|
definitions: definitions,
|
||||||
output: output,
|
output: output,
|
||||||
examples: examples |> E.O.default([]),
|
examples: examples->E.O2.default([]),
|
||||||
isExperimental: isExperimental,
|
isExperimental: isExperimental,
|
||||||
requiresNamespace: requiresNamespace,
|
requiresNamespace: requiresNamespace,
|
||||||
description: description,
|
description: description,
|
||||||
|
@ -225,7 +225,7 @@ module Registry = {
|
||||||
registry,
|
registry,
|
||||||
fnName: string,
|
fnName: string,
|
||||||
args: array<Reducer_T.value>,
|
args: array<Reducer_T.value>,
|
||||||
env: Reducer_T.environment,
|
context: Reducer_T.context,
|
||||||
reducer: Reducer_T.reducerFn,
|
reducer: Reducer_T.reducerFn,
|
||||||
): result<Reducer_T.value, errorMessage> => {
|
): result<Reducer_T.value, errorMessage> => {
|
||||||
switch Belt.Map.String.get(registry.fnNameDict, fnName) {
|
switch Belt.Map.String.get(registry.fnNameDict, fnName) {
|
||||||
|
@ -241,7 +241,7 @@ module Registry = {
|
||||||
|
|
||||||
let match = definitions->Js.Array2.find(def => def->FnDefinition.isMatch(args))
|
let match = definitions->Js.Array2.find(def => def->FnDefinition.isMatch(args))
|
||||||
switch match {
|
switch match {
|
||||||
| Some(def) => def->FnDefinition.run(args, env, reducer)
|
| Some(def) => def->FnDefinition.run(args, context, reducer)
|
||||||
| None => REOther(showNameMatchDefinitions())->Error
|
| None => REOther(showNameMatchDefinitions())->Error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,36 @@
|
||||||
|
@genType.opaque
|
||||||
|
type rec lambdaFrame = {location: Reducer_Peggy_Parse.location, name: string}
|
||||||
|
@genType.opaque and ffiFrame = {name: string}
|
||||||
|
@genType
|
||||||
|
and frame =
|
||||||
|
| InLambda(lambdaFrame)
|
||||||
|
| InFFI(ffiFrame)
|
||||||
|
|
||||||
|
let toStringFrame = (t: frame) =>
|
||||||
|
switch t {
|
||||||
|
| InLambda({location}) =>
|
||||||
|
`Line ${location.start.line->Js.Int.toString}, column ${location.start.column->Js.Int.toString}, source ${location.source}`
|
||||||
|
| InFFI({name}) => `Builtin ${name}`
|
||||||
|
}
|
||||||
|
|
||||||
|
@genType.opaque
|
||||||
|
type rec t = list<frame>
|
||||||
|
|
||||||
|
let make = (): t => list{}
|
||||||
|
|
||||||
|
let extend = (t: t, frame: frame) => t->Belt.List.add(frame)
|
||||||
|
|
||||||
|
let toString = (t: t) =>
|
||||||
|
t->Belt.List.map(s => " " ++ s->toStringFrame ++ "\n")->Belt.List.toArray->Js.Array2.joinWith("")
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let toFrameArray = (t: t): array<frame> => t->Belt.List.toArray
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let getTopFrame = (t: t): option<frame> => t->Belt.List.head
|
||||||
|
|
||||||
|
let isEmpty = (t: t): bool =>
|
||||||
|
switch t->Belt.List.head {
|
||||||
|
| Some(_) => true
|
||||||
|
| None => false
|
||||||
|
}
|
|
@ -4,9 +4,8 @@ let defaultEnvironment: Reducer_T.environment = DistributionOperation.defaultEnv
|
||||||
|
|
||||||
let createContext = (stdLib: Reducer_Namespace.t, environment: Reducer_T.environment): t => {
|
let createContext = (stdLib: Reducer_Namespace.t, environment: Reducer_T.environment): t => {
|
||||||
{
|
{
|
||||||
|
callStack: list{},
|
||||||
bindings: stdLib->Reducer_Bindings.fromNamespace->Reducer_Bindings.extend,
|
bindings: stdLib->Reducer_Bindings.fromNamespace->Reducer_Bindings.extend,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let createDefaultContext = (): t => createContext(SquiggleLibrary_StdLib.stdLib, defaultEnvironment)
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
module Bindings = Reducer_Bindings
|
module Bindings = Reducer_Bindings
|
||||||
module Lambda = Reducer_Expression_Lambda
|
|
||||||
module Result = Belt.Result
|
module Result = Belt.Result
|
||||||
module T = Reducer_T
|
module T = Reducer_T
|
||||||
|
|
||||||
|
@ -7,8 +6,8 @@ let toLocation = (expression: T.expression): SqError.location => {
|
||||||
expression.ast.location
|
expression.ast.location
|
||||||
}
|
}
|
||||||
|
|
||||||
let throwFrom = (error: SqError.Message.t, expression: T.expression) =>
|
let throwFrom = (error: SqError.Message.t, context: T.context) =>
|
||||||
error->SqError.fromMessageWithLocation(expression->toLocation)->SqError.throw
|
error->SqError.throwMessage(context)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Recursively evaluate the expression
|
Recursively evaluate the expression
|
||||||
|
@ -54,7 +53,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
let (key, _) = eKey->evaluate(context)
|
let (key, _) = eKey->evaluate(context)
|
||||||
let keyString = switch key {
|
let keyString = switch key {
|
||||||
| IEvString(s) => s
|
| IEvString(s) => s
|
||||||
| _ => REOther("Record keys must be strings")->throwFrom(expression)
|
| _ => REOther("Record keys must be strings")->throwFrom(context)
|
||||||
}
|
}
|
||||||
let (value, _) = eValue->evaluate(context)
|
let (value, _) = eValue->evaluate(context)
|
||||||
(keyString, value)
|
(keyString, value)
|
||||||
|
@ -78,7 +77,7 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
| T.ESymbol(name) =>
|
| T.ESymbol(name) =>
|
||||||
switch context.bindings->Bindings.get(name) {
|
switch context.bindings->Bindings.get(name) {
|
||||||
| Some(v) => (v, context)
|
| Some(v) => (v, context)
|
||||||
| None => RESymbolNotFound(name)->throwFrom(expression)
|
| None => RESymbolNotFound(name)->throwFrom(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.EValue(value) => (value, context)
|
| T.EValue(value) => (value, context)
|
||||||
|
@ -87,12 +86,18 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
let (predicateResult, _) = predicate->evaluate(context)
|
let (predicateResult, _) = predicate->evaluate(context)
|
||||||
switch predicateResult {
|
switch predicateResult {
|
||||||
| T.IEvBool(value) => (value ? trueCase : falseCase)->evaluate(context)
|
| T.IEvBool(value) => (value ? trueCase : falseCase)->evaluate(context)
|
||||||
| _ => REExpectedType("Boolean", "")->throwFrom(expression)
|
| _ => REExpectedType("Boolean", "")->throwFrom(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
| T.ELambda(parameters, body) => (
|
| T.ELambda(parameters, body) => (
|
||||||
Lambda.makeLambda(parameters, context.bindings, body)->T.IEvLambda,
|
Reducer_Lambda.makeLambda(
|
||||||
|
None, // TODO - pass function name from parser
|
||||||
|
parameters,
|
||||||
|
context.bindings,
|
||||||
|
body,
|
||||||
|
expression->toLocation,
|
||||||
|
)->T.IEvLambda,
|
||||||
context,
|
context,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -103,14 +108,11 @@ let rec evaluate: T.reducerFn = (expression, context): (T.value, T.context) => {
|
||||||
argValue
|
argValue
|
||||||
})
|
})
|
||||||
switch lambda {
|
switch lambda {
|
||||||
| T.IEvLambda(lambda) =>
|
| T.IEvLambda(lambda) => {
|
||||||
try {
|
let result = Reducer_Lambda.doLambdaCall(lambda, argValues, context, evaluate)
|
||||||
let result = Lambda.doLambdaCall(lambda, argValues, context.environment, evaluate)
|
|
||||||
(result, context)
|
(result, context)
|
||||||
} catch {
|
|
||||||
| exn => exn->SqError.fromException->SqError.extend(expression->toLocation)->SqError.throw
|
|
||||||
}
|
}
|
||||||
| _ => RENotAFunction(lambda->Reducer_Value.toString)->throwFrom(expression)
|
| _ => RENotAFunction(lambda->Reducer_Value.toString)->throwFrom(context)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,8 +124,11 @@ module BackCompatible = {
|
||||||
let parse = (peggyCode: string): result<T.expression, Reducer_Peggy_Parse.parseError> =>
|
let parse = (peggyCode: string): result<T.expression, Reducer_Peggy_Parse.parseError> =>
|
||||||
peggyCode->Reducer_Peggy_Parse.parse("main")->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
peggyCode->Reducer_Peggy_Parse.parse("main")->Result.map(Reducer_Peggy_ToExpression.fromNode)
|
||||||
|
|
||||||
|
let createDefaultContext = () =>
|
||||||
|
Reducer_Context.createContext(SquiggleLibrary_StdLib.stdLib, Reducer_Context.defaultEnvironment)
|
||||||
|
|
||||||
let evaluate = (expression: T.expression): result<T.value, SqError.t> => {
|
let evaluate = (expression: T.expression): result<T.value, SqError.t> => {
|
||||||
let context = Reducer_Context.createDefaultContext()
|
let context = createDefaultContext()
|
||||||
try {
|
try {
|
||||||
let (value, _) = expression->evaluate(context)
|
let (value, _) = expression->evaluate(context)
|
||||||
value->Ok
|
value->Ok
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
let doLambdaCall = (
|
|
||||||
lambdaValue: Reducer_T.lambdaValue,
|
|
||||||
args,
|
|
||||||
environment: Reducer_T.environment,
|
|
||||||
reducer: Reducer_T.reducerFn,
|
|
||||||
): Reducer_T.value => {
|
|
||||||
lambdaValue.body(args, environment, reducer)
|
|
||||||
}
|
|
||||||
|
|
||||||
let makeLambda = (
|
|
||||||
parameters: array<string>,
|
|
||||||
bindings: Reducer_T.bindings,
|
|
||||||
body: Reducer_T.expression,
|
|
||||||
): Reducer_T.lambdaValue => {
|
|
||||||
// TODO - clone bindings to avoid later redefinitions affecting lambdas?
|
|
||||||
|
|
||||||
// Note: with this implementation, FFI lambdas (created by other methods than calling `makeLambda`) are allowed to violate the rules, pollute the bindings, etc.
|
|
||||||
// Not sure yet if that's a bug or a feature.
|
|
||||||
// FunctionRegistry functions are unaffected by this, their API is too limited.
|
|
||||||
|
|
||||||
let lambda = (
|
|
||||||
arguments: array<Reducer_T.value>,
|
|
||||||
environment: Reducer_T.environment,
|
|
||||||
reducer: Reducer_T.reducerFn,
|
|
||||||
) => {
|
|
||||||
let argsLength = arguments->Js.Array2.length
|
|
||||||
let parametersLength = parameters->Js.Array2.length
|
|
||||||
if argsLength !== parametersLength {
|
|
||||||
SqError.Message.REArityError(None, parametersLength, argsLength)->SqError.Message.toException
|
|
||||||
}
|
|
||||||
|
|
||||||
let localBindings = bindings->Reducer_Bindings.extend
|
|
||||||
let localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex(localBindings, (
|
|
||||||
currentBindings,
|
|
||||||
parameter,
|
|
||||||
index,
|
|
||||||
) => {
|
|
||||||
currentBindings->Reducer_Bindings.set(parameter, arguments[index])
|
|
||||||
})
|
|
||||||
|
|
||||||
let (value, _) = reducer(
|
|
||||||
body,
|
|
||||||
{bindings: localBindingsWithParameters, environment: environment},
|
|
||||||
)
|
|
||||||
value
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// context: bindings,
|
|
||||||
body: lambda,
|
|
||||||
parameters: parameters,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let makeFFILambda = (body: Reducer_T.lambdaBody): Reducer_T.lambdaValue => {
|
|
||||||
body: body,
|
|
||||||
parameters: ["..."],
|
|
||||||
}
|
|
|
@ -0,0 +1,88 @@
|
||||||
|
type t = Reducer_T.lambdaValue
|
||||||
|
|
||||||
|
// user-defined functions, i.e. `add2 = {|x, y| x + y}`, are built by this method
|
||||||
|
let makeLambda = (
|
||||||
|
name: option<string>,
|
||||||
|
parameters: array<string>,
|
||||||
|
bindings: Reducer_T.bindings,
|
||||||
|
body: Reducer_T.expression,
|
||||||
|
location: Reducer_Peggy_Parse.location,
|
||||||
|
): t => {
|
||||||
|
let lambda = (
|
||||||
|
arguments: array<Reducer_T.value>,
|
||||||
|
context: Reducer_T.context,
|
||||||
|
reducer: Reducer_T.reducerFn,
|
||||||
|
) => {
|
||||||
|
let argsLength = arguments->E.A.length
|
||||||
|
let parametersLength = parameters->E.A.length
|
||||||
|
if argsLength !== parametersLength {
|
||||||
|
SqError.Message.REArityError(None, parametersLength, argsLength)->SqError.Message.throw
|
||||||
|
}
|
||||||
|
|
||||||
|
// create new bindings scope - technically not necessary, since bindings are immutable, but might help with debugging/new features in the future
|
||||||
|
let localBindings = bindings->Reducer_Bindings.extend
|
||||||
|
|
||||||
|
let localBindingsWithParameters = parameters->Belt.Array.reduceWithIndex(localBindings, (
|
||||||
|
currentBindings,
|
||||||
|
parameter,
|
||||||
|
index,
|
||||||
|
) => {
|
||||||
|
currentBindings->Reducer_Bindings.set(parameter, arguments[index])
|
||||||
|
})
|
||||||
|
|
||||||
|
let lambdaContext: Reducer_T.context = {
|
||||||
|
bindings: localBindingsWithParameters, // based on bindings at the moment of lambda creation
|
||||||
|
environment: context.environment, // environment at the moment when lambda is called
|
||||||
|
callStack: context.callStack, // extended by main `evaluate` function
|
||||||
|
}
|
||||||
|
|
||||||
|
let (value, _) = reducer(body, lambdaContext)
|
||||||
|
value
|
||||||
|
}
|
||||||
|
|
||||||
|
FnLambda({
|
||||||
|
// context: bindings,
|
||||||
|
name: name,
|
||||||
|
body: lambda,
|
||||||
|
parameters: parameters,
|
||||||
|
location: location,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// stdlib lambdas (everything in FunctionRegistry) is built by this method. Body is generated in SquiggleLibrary_StdLib.res
|
||||||
|
let makeFFILambda = (name: string, body: Reducer_T.lambdaBody): t => FnBuiltin({
|
||||||
|
// Note: current bindings could be accidentally exposed here through context (compare with native lambda implementation above, where we override them with local bindings).
|
||||||
|
// But FunctionRegistry API is too limited for that to matter. Please take care not to violate that in the future by accident.
|
||||||
|
body: body,
|
||||||
|
name: name,
|
||||||
|
})
|
||||||
|
|
||||||
|
let extendCallStack = (t: t, callStack: Reducer_CallStack.t): Reducer_CallStack.t => {
|
||||||
|
switch t {
|
||||||
|
| FnLambda({location}) =>
|
||||||
|
callStack->Reducer_CallStack.extend(InLambda({location: location, name: "TODO"})) // FIXME
|
||||||
|
| FnBuiltin({name}) => callStack->Reducer_CallStack.extend(InFFI({name: name}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// this function doesn't scale to FunctionRegistry's polymorphic functions
|
||||||
|
let parameters = (t: t): array<string> => {
|
||||||
|
switch t {
|
||||||
|
| FnLambda({parameters}) => parameters
|
||||||
|
| FnBuiltin(_) => ["..."]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let doLambdaCall = (t: t, args, context: Reducer_Context.t, reducer) => {
|
||||||
|
let newContext = {
|
||||||
|
...context,
|
||||||
|
callStack: t->extendCallStack(context.callStack),
|
||||||
|
}
|
||||||
|
|
||||||
|
SqError.contextualizeAndRethrow(() => {
|
||||||
|
switch t {
|
||||||
|
| FnLambda({body}) => body(args, newContext, reducer)
|
||||||
|
| FnBuiltin({body}) => body(args, newContext, reducer)
|
||||||
|
}
|
||||||
|
}, newContext)
|
||||||
|
}
|
|
@ -15,12 +15,16 @@ type rec value =
|
||||||
| IEvVoid
|
| IEvVoid
|
||||||
@genType.opaque and arrayValue = array<value>
|
@genType.opaque and arrayValue = array<value>
|
||||||
@genType.opaque and map = Belt.Map.String.t<value>
|
@genType.opaque and map = Belt.Map.String.t<value>
|
||||||
and lambdaBody = (array<value>, environment, reducerFn) => value
|
and lambdaBody = (array<value>, context, reducerFn) => value
|
||||||
@genType.opaque
|
@genType.opaque
|
||||||
and lambdaValue = {
|
and lambdaValue =
|
||||||
parameters: array<string>,
|
| FnLambda({
|
||||||
body: lambdaBody,
|
parameters: array<string>,
|
||||||
}
|
body: lambdaBody,
|
||||||
|
location: Reducer_Peggy_Parse.location,
|
||||||
|
name: option<string>,
|
||||||
|
})
|
||||||
|
| FnBuiltin({body: lambdaBody, name: string})
|
||||||
@genType.opaque and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
@genType.opaque and lambdaDeclaration = Declaration.declaration<lambdaValue>
|
||||||
and expressionContent =
|
and expressionContent =
|
||||||
| EBlock(array<expression>)
|
| EBlock(array<expression>)
|
||||||
|
@ -49,6 +53,7 @@ and bindings = {
|
||||||
and context = {
|
and context = {
|
||||||
bindings: bindings,
|
bindings: bindings,
|
||||||
environment: environment,
|
environment: environment,
|
||||||
|
callStack: Reducer_CallStack.t,
|
||||||
}
|
}
|
||||||
|
|
||||||
and reducerFn = (expression, context) => (value, context)
|
and reducerFn = (expression, context) => (value, context)
|
||||||
|
|
|
@ -28,10 +28,12 @@ and toStringCall = fName => `:${fName}`
|
||||||
and toStringDate = date => DateTime.Date.toString(date)
|
and toStringDate = date => DateTime.Date.toString(date)
|
||||||
and toStringDeclaration = d => Declaration.toString(d, r => toString(IEvLambda(r)))
|
and toStringDeclaration = d => Declaration.toString(d, r => toString(IEvLambda(r)))
|
||||||
and toStringDistribution = dist => GenericDist.toString(dist)
|
and toStringDistribution = dist => GenericDist.toString(dist)
|
||||||
and toStringLambda = (lambdaValue: T.lambdaValue) =>
|
and toStringLambda = (lambdaValue: T.lambdaValue) => {
|
||||||
`lambda(${Js.Array2.toString(lambdaValue.parameters)}=>internal code)`
|
switch lambdaValue {
|
||||||
and toStringFunction = (lambdaValue: T.lambdaValue) =>
|
| FnLambda({parameters}) => `lambda(${Js.Array2.toString(parameters)}=>internal code)`
|
||||||
`function(${Js.Array2.toString(lambdaValue.parameters)})`
|
| FnBuiltin(_) => "Builtin function"
|
||||||
|
}
|
||||||
|
}
|
||||||
and toStringNumber = aNumber => Js.String.make(aNumber)
|
and toStringNumber = aNumber => Js.String.make(aNumber)
|
||||||
and toStringRecord = aMap => aMap->toStringMap
|
and toStringRecord = aMap => aMap->toStringMap
|
||||||
and toStringString = aString => `'${aString}'`
|
and toStringString = aString => `'${aString}'`
|
||||||
|
@ -143,7 +145,7 @@ let arrayToValueArray = (arr: array<t>): array<t> => arr
|
||||||
let resultToValue = (rExpression: result<t, SqError.Message.t>): t =>
|
let resultToValue = (rExpression: result<t, SqError.Message.t>): t =>
|
||||||
switch rExpression {
|
switch rExpression {
|
||||||
| Ok(expression) => expression
|
| Ok(expression) => expression
|
||||||
| Error(errorValue) => SqError.Message.toException(errorValue)
|
| Error(errorValue) => SqError.Message.throw(errorValue)
|
||||||
}
|
}
|
||||||
|
|
||||||
let recordToKeyValuePairs = (record: T.map): array<(string, t)> => record->Belt.Map.String.toArray
|
let recordToKeyValuePairs = (record: T.map): array<(string, t)> => record->Belt.Map.String.toArray
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
type location = Reducer_Peggy_Parse.location
|
type location = Reducer_Peggy_Parse.location
|
||||||
|
|
||||||
|
// Messages don't contain any stack trace information.
|
||||||
|
// FunctionRegistry functions are allowed to throw MessageExceptions, though, because they will be caught and rewrapped by Reducer_Lambda code
|
||||||
module Message = {
|
module Message = {
|
||||||
@genType.opaque
|
@genType.opaque
|
||||||
type t =
|
type t =
|
||||||
|
@ -82,81 +84,79 @@ module Message = {
|
||||||
| _e => REOther("Unknown error")
|
| _e => REOther("Unknown error")
|
||||||
}
|
}
|
||||||
|
|
||||||
let toException = (errorValue: t) => errorValue->MessageException->raise
|
let throw = (errorValue: t) => errorValue->MessageException->raise
|
||||||
}
|
|
||||||
|
|
||||||
module StackTrace = {
|
|
||||||
@genType.opaque
|
|
||||||
type rec t = {
|
|
||||||
location: location,
|
|
||||||
parent: option<t>,
|
|
||||||
}
|
|
||||||
|
|
||||||
let rec toString = ({location, parent}: t) => {
|
|
||||||
` Line ${location.start.line->Js.Int.toString}, column ${location.start.column->Js.Int.toString}, source ${location.source}\n` ++
|
|
||||||
switch parent {
|
|
||||||
| Some(parent) => toString(parent)
|
|
||||||
| None => ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let rec toLocationList = (t: t): list<location> => {
|
|
||||||
switch t.parent {
|
|
||||||
| Some(parent) => Belt.List.add(toLocationList(parent), t.location)
|
|
||||||
| None => list{t.location}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@genType
|
|
||||||
let toLocationArray = (t: t): array<location> => t->toLocationList->Belt.List.toArray
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@genType.opaque
|
@genType.opaque
|
||||||
type t = {
|
type t = {
|
||||||
message: Message.t,
|
message: Message.t,
|
||||||
stackTrace: option<StackTrace.t>,
|
/*
|
||||||
|
Errors raised from internal functions can have empty location.
|
||||||
|
|
||||||
|
Also, location is not the same as the top of the stackTrace.
|
||||||
|
Consider this:
|
||||||
|
```
|
||||||
|
f() = {
|
||||||
|
x = 5
|
||||||
|
y = z // no such var
|
||||||
|
x + y
|
||||||
|
}
|
||||||
|
```
|
||||||
|
This code should report the location of assignment issue, but there's no function call there.
|
||||||
|
*/
|
||||||
|
location: option<location>,
|
||||||
|
stackTrace: Reducer_CallStack.t,
|
||||||
}
|
}
|
||||||
|
|
||||||
exception SqException(t)
|
exception SqException(t)
|
||||||
|
|
||||||
@genType
|
// `context` should be specified for runtime errors, but can be left empty for errors from Reducer_Project and so on.
|
||||||
let fromMessage = (errorMessage: Message.t): t => {
|
// `location` can be empty for errors raised from FunctionRegistry.
|
||||||
message: errorMessage,
|
let fromMessage = (
|
||||||
stackTrace: None,
|
message: Message.t,
|
||||||
}
|
context: option<Reducer_T.context>,
|
||||||
|
location: option<location>,
|
||||||
let fromMessageWithLocation = (errorMessage: Message.t, location: location): t => {
|
): t => {
|
||||||
message: errorMessage,
|
|
||||||
stackTrace: Some({location: location, parent: None}),
|
|
||||||
}
|
|
||||||
|
|
||||||
let extend = ({message, stackTrace}: t, location: location) => {
|
|
||||||
message: message,
|
message: message,
|
||||||
stackTrace: Some({location: location, parent: stackTrace}),
|
location: location,
|
||||||
|
stackTrace: switch context {
|
||||||
|
| Some(context) => context.callStack
|
||||||
|
| None => Reducer_CallStack.make()
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let getLocation = (t: t): option<location> => t.stackTrace->E.O2.fmap(stack => stack.location)
|
let getTopFrame = (t: t): option<Reducer_CallStack.frame> =>
|
||||||
|
t.stackTrace->Reducer_CallStack.getTopFrame
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let getStackTrace = (t: t): option<StackTrace.t> => t.stackTrace
|
let getStackTrace = (t: t): Reducer_CallStack.t => t.stackTrace
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let toString = (t: t): string => t.message->Message.toString
|
let toString = (t: t): string => t.message->Message.toString
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let createOtherError = (v: string): t => Message.REOther(v)->fromMessage
|
let createOtherError = (v: string): t => Message.REOther(v)->fromMessage()
|
||||||
|
|
||||||
|
@genType
|
||||||
|
let getFrameArray = (t: t): array<Reducer_CallStack.frame> =>
|
||||||
|
t.stackTrace->Reducer_CallStack.toFrameArray
|
||||||
|
|
||||||
@genType
|
@genType
|
||||||
let toStringWithStackTrace = (t: t) =>
|
let toStringWithStackTrace = (t: t) =>
|
||||||
switch t.stackTrace {
|
if t.stackTrace->Reducer_CallStack.isEmpty {
|
||||||
| Some(stack) => "Traceback:\n" ++ stack->StackTrace.toString
|
"Traceback:\n" ++ t.stackTrace->Reducer_CallStack.toString
|
||||||
| None => ""
|
} else {
|
||||||
|
""
|
||||||
} ++
|
} ++
|
||||||
t->toString
|
t->toString
|
||||||
|
|
||||||
let throw = (t: t) => t->SqException->raise
|
let throw = (t: t) => t->SqException->raise
|
||||||
|
|
||||||
|
let throwMessage = (message: Message.t, context: Reducer_T.context, location: location) =>
|
||||||
|
fromMessage(message, context, location)->throw
|
||||||
|
|
||||||
|
// this shouldn't be used for most runtime errors - the resulting error would have an empty stacktrace
|
||||||
let fromException = exn =>
|
let fromException = exn =>
|
||||||
switch exn {
|
switch exn {
|
||||||
| SqException(e) => e
|
| SqException(e) => e
|
||||||
|
@ -164,3 +164,17 @@ let fromException = exn =>
|
||||||
| Js.Exn.Error(obj) => REJavaScriptExn(obj->Js.Exn.message, obj->Js.Exn.name)->fromMessage
|
| Js.Exn.Error(obj) => REJavaScriptExn(obj->Js.Exn.message, obj->Js.Exn.name)->fromMessage
|
||||||
| _ => REOther("Unknown exception")->fromMessage
|
| _ => REOther("Unknown exception")->fromMessage
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// converts raw exceptions into exceptions with stacktrace attached
|
||||||
|
// already converted exceptions won't be affected
|
||||||
|
let contextualizeAndRethrow = (fn: unit => 'a, context: Reducer_T.context) => {
|
||||||
|
try {
|
||||||
|
fn()
|
||||||
|
} catch {
|
||||||
|
| SqException(e) => e->throw
|
||||||
|
| Message.MessageException(e) => e->throwMessage(context)
|
||||||
|
| Js.Exn.Error(obj) =>
|
||||||
|
REJavaScriptExn(obj->Js.Exn.message, obj->Js.Exn.name)->throwMessage(context)
|
||||||
|
| _ => REOther("Unknown exception")->throwMessage(context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
let throwMessage = SqError.Message.toException
|
|
||||||
|
|
||||||
let stdLib: Reducer_T.namespace = {
|
let stdLib: Reducer_T.namespace = {
|
||||||
// constants
|
// constants
|
||||||
let res =
|
let res =
|
||||||
|
@ -10,22 +8,23 @@ let stdLib: Reducer_T.namespace = {
|
||||||
// array and record lookups
|
// array and record lookups
|
||||||
let res = res->Reducer_Namespace.set(
|
let res = res->Reducer_Namespace.set(
|
||||||
"$_atIndex_$",
|
"$_atIndex_$",
|
||||||
Reducer_Expression_Lambda.makeFFILambda((inputs, _, _) => {
|
Reducer_Lambda.makeFFILambda("$_atIndex_$", (inputs, _, _) => {
|
||||||
switch inputs {
|
switch inputs {
|
||||||
| [IEvArray(aValueArray), IEvNumber(fIndex)] => {
|
| [IEvArray(aValueArray), IEvNumber(fIndex)] => {
|
||||||
let index = Belt.Int.fromFloat(fIndex) // TODO - fail on non-integer indices?
|
let index = Belt.Int.fromFloat(fIndex) // TODO - fail on non-integer indices?
|
||||||
|
|
||||||
switch Belt.Array.get(aValueArray, index) {
|
switch Belt.Array.get(aValueArray, index) {
|
||||||
| Some(value) => value
|
| Some(value) => value
|
||||||
| None => REArrayIndexNotFound("Array index not found", index)->throwMessage
|
| None => REArrayIndexNotFound("Array index not found", index)->SqError.Message.throw
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
| [IEvRecord(dict), IEvString(sIndex)] =>
|
| [IEvRecord(dict), IEvString(sIndex)] =>
|
||||||
switch Belt.Map.String.get(dict, sIndex) {
|
switch Belt.Map.String.get(dict, sIndex) {
|
||||||
| Some(value) => value
|
| Some(value) => value
|
||||||
| None => RERecordPropertyNotFound("Record property not found", sIndex)->throwMessage
|
| None =>
|
||||||
|
RERecordPropertyNotFound("Record property not found", sIndex)->SqError.Message.throw
|
||||||
}
|
}
|
||||||
| _ => REOther("Trying to access key on wrong value")->throwMessage
|
| _ => REOther("Trying to access key on wrong value")->SqError.Message.throw
|
||||||
}
|
}
|
||||||
})->Reducer_T.IEvLambda,
|
})->Reducer_T.IEvLambda,
|
||||||
)
|
)
|
||||||
|
@ -45,10 +44,10 @@ let stdLib: Reducer_T.namespace = {
|
||||||
->Belt.Array.reduce(res, (cur, name) => {
|
->Belt.Array.reduce(res, (cur, name) => {
|
||||||
cur->Reducer_Namespace.set(
|
cur->Reducer_Namespace.set(
|
||||||
name,
|
name,
|
||||||
Reducer_Expression_Lambda.makeFFILambda((arguments, environment, reducer) => {
|
Reducer_Lambda.makeFFILambda(name, (arguments, context, reducer) => {
|
||||||
switch FunctionRegistry_Library.call(name, arguments, environment, reducer) {
|
switch FunctionRegistry_Library.call(name, arguments, context, reducer) {
|
||||||
| Ok(value) => value
|
| Ok(value) => value
|
||||||
| Error(error) => error->SqError.Message.toException
|
| Error(error) => error->SqError.Message.throw
|
||||||
}
|
}
|
||||||
})->Reducer_T.IEvLambda,
|
})->Reducer_T.IEvLambda,
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user