more WIP
This commit is contained in:
parent
f2dccd4f1e
commit
fea89abff9
|
@ -1,4 +1,5 @@
|
|||
let fnList = Belt.Array.concatMany([
|
||||
FR_Builtin.library,
|
||||
FR_Dict.library,
|
||||
FR_Dist.library,
|
||||
FR_Danger.library,
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
open FunctionRegistry_Core
|
||||
open FunctionRegistry_Helpers
|
||||
|
||||
let nameSpace = "Builtin"
|
||||
|
||||
type simpleDefinition = {
|
||||
inputs: array<frType>,
|
||||
fn: (array<internalExpressionValue>) => result<internalExpressionValue, string>,
|
||||
}
|
||||
|
||||
let makeFnMany = (name: string, definitions: array<simpleDefinition>) =>
|
||||
Function.make(
|
||||
~name=name,
|
||||
~nameSpace,
|
||||
~requiresNamespace=false,
|
||||
~definitions=definitions->Js.Array2.map(
|
||||
({ inputs, fn }) => FnDefinition.make(
|
||||
~name=name,
|
||||
~inputs=inputs,
|
||||
~run=(inputs, _, _, _) => fn(inputs),
|
||||
()
|
||||
)
|
||||
),
|
||||
(),
|
||||
)
|
||||
|
||||
let makeFn = (name: string, inputs: array<frType>, fn: (array<internalExpressionValue>) => result<internalExpressionValue, string>) =>
|
||||
makeFnMany(name, [{ inputs, fn }])
|
||||
|
||||
let library = [
|
||||
// TODO - other MathJS
|
||||
Function.make(
|
||||
~name="add",
|
||||
~nameSpace,
|
||||
~requiresNamespace=false,
|
||||
~definitions=[
|
||||
FnDefinition.make(
|
||||
~name="add",
|
||||
~inputs=[FRTypeNumber, FRTypeNumber],
|
||||
~run=(inputs, _, _, _) => {
|
||||
switch inputs {
|
||||
| [IEvNumber(x), IEvNumber(y)] => IEvNumber(x+.y)->Ok
|
||||
| _ => Error(impossibleError)
|
||||
}
|
||||
},
|
||||
()
|
||||
),
|
||||
],
|
||||
(),
|
||||
),
|
||||
]
|
|
@ -45,11 +45,11 @@ let callInternal = (
|
|||
->Ok
|
||||
}
|
||||
|
||||
let arrayAtIndex = (aValueArray: array<Reducer_T.value>, fIndex: float) =>
|
||||
switch Belt.Array.get(aValueArray, Belt.Int.fromFloat(fIndex)) {
|
||||
| Some(value) => value->Ok
|
||||
| None => REArrayIndexNotFound("Array index not found", Belt.Int.fromFloat(fIndex))->Error
|
||||
}
|
||||
// let arrayAtIndex = (aValueArray: array<Reducer_T.value>, fIndex: float) =>
|
||||
// switch Belt.Array.get(aValueArray, Belt.Int.fromFloat(fIndex)) {
|
||||
// | Some(value) => value->Ok
|
||||
// | None => REArrayIndexNotFound("Array index not found", Belt.Int.fromFloat(fIndex))->Error
|
||||
// }
|
||||
|
||||
let moduleAtIndex = (nameSpace: Reducer_T.nameSpace, sIndex) =>
|
||||
switch Bindings.get(nameSpace, sIndex) {
|
||||
|
@ -57,11 +57,11 @@ let callInternal = (
|
|||
| None => RERecordPropertyNotFound("Bindings property not found", sIndex)->Error
|
||||
}
|
||||
|
||||
let recordAtIndex = (dict: Belt.Map.String.t<Reducer_T.value>, sIndex) =>
|
||||
switch Belt.Map.String.get(dict, sIndex) {
|
||||
| Some(value) => value->Ok
|
||||
| None => RERecordPropertyNotFound("Record property not found", sIndex)->Error
|
||||
}
|
||||
// let recordAtIndex = (dict: Belt.Map.String.t<Reducer_T.value>, sIndex) =>
|
||||
// switch Belt.Map.String.get(dict, sIndex) {
|
||||
// | Some(value) => value->Ok
|
||||
// | None => RERecordPropertyNotFound("Record property not found", sIndex)->Error
|
||||
// }
|
||||
|
||||
let doAddArray = (originalA, b) => {
|
||||
let a = originalA->Js.Array2.copy
|
||||
|
@ -107,10 +107,10 @@ let callInternal = (
|
|||
// }
|
||||
|
||||
switch call {
|
||||
| ("$_atIndex_$", [IEvArray(aValueArray), IEvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
|
||||
// | ("$_atIndex_$", [IEvArray(aValueArray), IEvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
|
||||
| ("$_atIndex_$", [IEvBindings(dict), IEvString(sIndex)]) => moduleAtIndex(dict, sIndex)
|
||||
| ("$_atIndex_$", [IEvRecord(dict), IEvString(sIndex)]) => recordAtIndex(dict, sIndex)
|
||||
| ("$_constructArray_$", args) => IEvArray(args)->Ok
|
||||
// | ("$_atIndex_$", [IEvRecord(dict), IEvString(sIndex)]) => recordAtIndex(dict, sIndex)
|
||||
// | ("$_constructArray_$", args) => IEvArray(args)->Ok
|
||||
| ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
||||
// | ("$_exportBindings_$", [IEvBindings(nameSpace)]) => doExportBindings(nameSpace)
|
||||
// | ("$_exportBindings_$", [evValue]) => doIdentity(evValue)
|
||||
|
@ -167,19 +167,13 @@ let dispatch = (
|
|||
): Reducer_T.value =>
|
||||
try {
|
||||
let (fn, args) = call
|
||||
if fn->Js.String2.startsWith("$") {
|
||||
switch callInternal((fn, args), env, reducer) {
|
||||
| Ok(v) => v
|
||||
| Error(e) => raise(ErrorException(e))
|
||||
}
|
||||
} else {
|
||||
|
||||
// There is a bug that prevents string match in patterns
|
||||
// So we have to recreate a copy of the string
|
||||
switch ExternalLibrary.dispatch((Js.String.make(fn), args), env, reducer, callInternal) {
|
||||
| Ok(v) => v
|
||||
| Error(e) => raise(ErrorException(e))
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
| ErrorException(e) => raise(ErrorException(e))
|
||||
| Js.Exn.Error(obj) =>
|
||||
|
|
|
@ -19,7 +19,7 @@ let rec evaluate: T.reducerFn = (
|
|||
| T.EBlock(statements) => {
|
||||
let innerContext = {...context, bindings: context.bindings->Bindings.extend}
|
||||
statements->Js.Array2.reduce(
|
||||
(acc, statement) => statement->evaluate(innerContext),
|
||||
(_, statement) => statement->evaluate(innerContext),
|
||||
T.IEvVoid
|
||||
)
|
||||
}
|
||||
|
@ -27,7 +27,7 @@ let rec evaluate: T.reducerFn = (
|
|||
| T.EProgram(statements) => {
|
||||
// Js.log(`bindings: ${context.bindings->Reducer_Bindings.toString}`)
|
||||
let res = statements->Js.Array2.reduce(
|
||||
(acc, statement) => statement->evaluate(context),
|
||||
(_, statement) => statement->evaluate(context),
|
||||
T.IEvVoid
|
||||
)
|
||||
// Js.log(`bindings after: ${context.bindings->Reducer_Bindings.toString}`)
|
||||
|
@ -37,8 +37,16 @@ let rec evaluate: T.reducerFn = (
|
|||
| T.EArray(elements) =>
|
||||
elements->Js.Array2.map(element => evaluate(element, context))->T.IEvArray
|
||||
|
||||
| T.ERecord(map) =>
|
||||
RETodo("TODO")->ErrorException->raise
|
||||
| T.ERecord(pairs) =>
|
||||
pairs->Js.Array2.map(((eKey, eValue)) => {
|
||||
let key = eKey->evaluate(context)
|
||||
let keyString = switch key {
|
||||
| IEvString(s) => s
|
||||
| _ => REOther("Record keys must be strings")->ErrorException->raise
|
||||
}
|
||||
let value = eValue->evaluate(context)
|
||||
(keyString, value)
|
||||
})->Belt.Map.String.fromArray->IEvRecord
|
||||
|
||||
| T.EAssign(left, right) => {
|
||||
let result = right->evaluate(context)
|
||||
|
|
|
@ -24,7 +24,7 @@ let eLambda = (
|
|||
|
||||
let eNumber = aNumber => aNumber->T.IEvNumber->T.EValue
|
||||
|
||||
let eRecord = aMap => aMap->T.IEvRecord->T.EValue
|
||||
let eRecord = (aMap: array<(T.expression, T.expression)>) => aMap->T.ERecord
|
||||
|
||||
let eString = aString => aString->T.IEvString->T.EValue
|
||||
|
||||
|
|
|
@ -21,12 +21,14 @@ let parse = (expr: string): result<node, errorValue> =>
|
|||
|
||||
type nodeBlock = {...node, "statements": array<node>}
|
||||
type nodeProgram = {...node, "statements": array<node>}
|
||||
type nodeArray = {...node, "elements": array<node>}
|
||||
type nodeBoolean = {...node, "value": bool}
|
||||
type nodeCall = {...node, "fn": node, "args": array<node>}
|
||||
type nodeFloat = {...node, "value": float}
|
||||
type nodeIdentifier = {...node, "value": string}
|
||||
type nodeInteger = {...node, "value": int}
|
||||
type nodeKeyValue = {...node, "key": node, "value": node}
|
||||
type nodeRecord = {...node, "elements": array<nodeKeyValue>}
|
||||
type nodeLambda = {...node, "args": array<nodeIdentifier>, "body": nodeBlock}
|
||||
type nodeLetStatement = {...node, "variable": nodeIdentifier, "value": node}
|
||||
type nodeModuleIdentifier = {...node, "value": string}
|
||||
|
@ -37,7 +39,9 @@ type nodeVoid = node
|
|||
|
||||
type peggyNode =
|
||||
| PgNodeBlock(nodeBlock)
|
||||
| PgNodeProgram(nodeBlock)
|
||||
| PgNodeProgram(nodeProgram)
|
||||
| PgNodeArray(nodeArray)
|
||||
| PgNodeRecord(nodeRecord)
|
||||
| PgNodeBoolean(nodeBoolean)
|
||||
| PgNodeFloat(nodeFloat)
|
||||
| PgNodeCall(nodeCall)
|
||||
|
@ -54,6 +58,8 @@ type peggyNode =
|
|||
|
||||
external castNodeBlock: node => nodeBlock = "%identity"
|
||||
external castNodeProgram: node => nodeProgram = "%identity"
|
||||
external castNodeArray: node => nodeArray = "%identity"
|
||||
external castNodeRecord: node => nodeRecord = "%identity"
|
||||
external castNodeBoolean: node => nodeBoolean = "%identity"
|
||||
external castNodeCall: node => nodeCall = "%identity"
|
||||
external castNodeFloat: node => nodeFloat = "%identity"
|
||||
|
@ -73,6 +79,8 @@ let castNodeType = (node: node) =>
|
|||
switch node["type"] {
|
||||
| "Block" => node->castNodeBlock->PgNodeBlock
|
||||
| "Program" => node->castNodeBlock->PgNodeProgram
|
||||
| "Array" => node->castNodeArray->PgNodeArray
|
||||
| "Record" => node->castNodeRecord->PgNodeRecord
|
||||
| "Boolean" => node->castNodeBoolean->PgNodeBoolean
|
||||
| "Call" => node->castNodeCall->PgNodeCall
|
||||
| "Float" => node->castNodeFloat->PgNodeFloat
|
||||
|
@ -96,10 +104,17 @@ let rec pgToString = (peggyNode: peggyNode): string => {
|
|||
let nodesToStringUsingSeparator = (nodes: array<node>, separator: string): string =>
|
||||
nodes->Js.Array2.map(toString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
||||
|
||||
let pgNodesToStringUsingSeparator = (nodes: array<peggyNode>, separator: string): string =>
|
||||
nodes->Js.Array2.map(pgToString)->Extra.Array.intersperse(separator)->Js.String.concatMany("")
|
||||
|
||||
switch peggyNode {
|
||||
| PgNodeBlock(node)
|
||||
| PgNodeProgram(node)
|
||||
=> "{" ++ node["statements"]->nodesToStringUsingSeparator("; ") ++ "}"
|
||||
| PgNodeArray(node)
|
||||
=> "[" ++ node["elements"]->nodesToStringUsingSeparator("; ") ++ "]"
|
||||
| PgNodeRecord(node)
|
||||
=> "{" ++ node["elements"]->Js.Array2.map(element => PgNodeKeyValue(element))->pgNodesToStringUsingSeparator(", ") ++ "}"
|
||||
| PgNodeBoolean(node) => node["value"]->Js.String.make
|
||||
| PgNodeCall(node) => "(" ++ node["fn"]->toString ++ " " ++ node["args"]->nodesToStringUsingSeparator(" ") ++ ")"
|
||||
| PgNodeFloat(node) => node["value"]->Js.String.make
|
||||
|
|
|
@ -18,11 +18,22 @@ let rec fromNode = (node: Parse.node): expression => {
|
|||
let body = nodeLambda["body"]->caseBlock
|
||||
|
||||
ExpressionBuilder.eLambda(args, body)
|
||||
|
||||
}
|
||||
|
||||
let caseRecord = (nodeRecord): expression => {
|
||||
nodeRecord["elements"]
|
||||
->Js.Array2.map(
|
||||
keyValueNode => (keyValueNode["key"]->fromNode, keyValueNode["value"]->fromNode)
|
||||
)
|
||||
->ExpressionBuilder.eRecord
|
||||
}
|
||||
|
||||
switch Parse.castNodeType(node) {
|
||||
| PgNodeBlock(nodeBlock) => caseBlock(nodeBlock)
|
||||
| PgNodeProgram(nodeProgram) => caseProgram(nodeProgram)
|
||||
| PgNodeArray(nodeArray) => ExpressionBuilder.eArray(nodeArray["elements"]->Js.Array2.map(fromNode))
|
||||
| PgNodeRecord(nodeRecord) => caseRecord(nodeRecord)
|
||||
| PgNodeBoolean(nodeBoolean) => ExpressionBuilder.eBool(nodeBoolean["value"])
|
||||
| PgNodeCall(nodeCall) => ExpressionBuilder.eCall(fromNode(nodeCall["fn"]), nodeCall["args"]->Js.Array2.map(fromNode))
|
||||
| PgNodeFloat(nodeFloat) => ExpressionBuilder.eNumber(nodeFloat["value"])
|
||||
|
|
|
@ -45,6 +45,16 @@ type NodeProgram = {
|
|||
statements: AnyPeggyNode[];
|
||||
};
|
||||
|
||||
type NodeArray = {
|
||||
type: "Array";
|
||||
elements: AnyPeggyNode[];
|
||||
};
|
||||
|
||||
type NodeRecord = {
|
||||
type: "Record";
|
||||
elements: NodeKeyValue[];
|
||||
};
|
||||
|
||||
type NodeCall = {
|
||||
type: "Call";
|
||||
fn: AnyPeggyNode;
|
||||
|
@ -103,6 +113,8 @@ type NodeBoolean = {
|
|||
};
|
||||
|
||||
export type AnyPeggyNode =
|
||||
| NodeArray
|
||||
| NodeRecord
|
||||
| NodeBlock
|
||||
| NodeProgram
|
||||
| NodeCall
|
||||
|
@ -124,11 +136,11 @@ export function makeFunctionCall(fn: string, args: AnyPeggyNode[]) {
|
|||
}
|
||||
}
|
||||
|
||||
export function constructArray(elems: AnyPeggyNode[]) {
|
||||
return makeFunctionCall("$_constructArray_$", elems);
|
||||
export function constructArray(elements: AnyPeggyNode[]) {
|
||||
return { type: "Array", elements };
|
||||
}
|
||||
export function constructRecord(elems: AnyPeggyNode[]) {
|
||||
return makeFunctionCall("$_constructRecord_$", elems);
|
||||
export function constructRecord(elements: AnyPeggyNode[]) {
|
||||
return { type: "Record", elements };
|
||||
}
|
||||
|
||||
export function nodeBlock(statements: AnyPeggyNode[]): NodeBlock {
|
||||
|
|
|
@ -34,7 +34,7 @@ and expression =
|
|||
| EBlock(array<expression>)
|
||||
| EProgram(array<expression>) // programs are similar to blocks, but don't create an inner scope. there can be only one program at the top level of the expression.
|
||||
| EArray(array<expression>)
|
||||
| ERecord(Belt.Map.String.t<expression>)
|
||||
| ERecord(array<(expression, expression)>)
|
||||
| ESymbol(string)
|
||||
| ETernary(expression, expression, expression)
|
||||
| EAssign(string, expression)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
exception ErrorException = Reducer_ErrorValue.ErrorException
|
||||
|
||||
let internalStdLib: Reducer_Bindings.t = {
|
||||
let res = Reducer_Bindings.makeEmptyBindings()
|
||||
->SquiggleLibrary_Math.makeBindings
|
||||
|
@ -12,6 +14,51 @@ let internalStdLib: Reducer_Bindings.t = {
|
|||
}
|
||||
)->Reducer_T.IEvLambda)
|
||||
|
||||
let _ = res->Reducer_Bindings.set("$_atIndex_$", Reducer_Expression_Lambda.makeFFILambda(
|
||||
(inputs, _, _) => {
|
||||
switch inputs {
|
||||
| [IEvArray(aValueArray), IEvNumber(fIndex)] => {
|
||||
switch Belt.Array.get(aValueArray, Belt.Int.fromFloat(fIndex)) {
|
||||
| Some(value) => value
|
||||
| None => REArrayIndexNotFound("Array index not found", Belt.Int.fromFloat(fIndex))->ErrorException->raise
|
||||
}
|
||||
}
|
||||
| [IEvRecord(dict), IEvString(sIndex)] => {
|
||||
switch Belt.Map.String.get(dict, sIndex) {
|
||||
| Some(value) => value
|
||||
| None => RERecordPropertyNotFound("Record index not found", sIndex)->ErrorException->raise
|
||||
}
|
||||
}
|
||||
| _ => REOther("Trying to access key on wrong value")->ErrorException->raise
|
||||
}
|
||||
}
|
||||
)->Reducer_T.IEvLambda)
|
||||
|
||||
// TODO:
|
||||
// () => ReducerInterface_GenericDistribution.dispatch(call, environment),
|
||||
// () => ReducerInterface_Date.dispatch(call, environment),
|
||||
// () => ReducerInterface_Duration.dispatch(call, environment),
|
||||
// () => ReducerInterface_Number.dispatch(call, environment),
|
||||
|
||||
// Reducer_Dispatch_BuiltIn:
|
||||
|
||||
// [x] | ("$_atIndex_$", [IEvArray(aValueArray), IEvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex)
|
||||
// [ ] | ("$_atIndex_$", [IEvBindings(dict), IEvString(sIndex)]) => moduleAtIndex(dict, sIndex)
|
||||
// [x] | ("$_atIndex_$", [IEvRecord(dict), IEvString(sIndex)]) => recordAtIndex(dict, sIndex)
|
||||
// [ ] | ("$_constructArray_$", args) => IEvArray(args)->Ok
|
||||
// [ ] | ("$_constructRecord_$", [IEvArray(arrayOfPairs)]) => constructRecord(arrayOfPairs)
|
||||
// [ ] | ("concat", [IEvArray(aValueArray), IEvArray(bValueArray)]) => doAddArray(aValueArray, bValueArray)
|
||||
// [ ] | ("concat", [IEvString(aValueString), IEvString(bValueString)]) => doAddString(aValueString, bValueString)
|
||||
// [ ] | ("inspect", [value, IEvString(label)]) => inspectLabel(value, label)
|
||||
// [ ] | ("inspect", [value]) => inspect(value)
|
||||
// [ ] | (_, [IEvBool(_)])
|
||||
// [ ] | (_, [IEvNumber(_)])
|
||||
// [ ] | (_, [IEvString(_)])
|
||||
// [ ] | (_, [IEvBool(_), IEvBool(_)])
|
||||
// [ ] | (_, [IEvNumber(_), IEvNumber(_)])
|
||||
// [ ] | (_, [IEvString(_), IEvString(_)]) => callMathJs(call)
|
||||
|
||||
|
||||
FunctionRegistry_Library.registry.fnNameDict->Js.Dict.keys->Js.Array2.forEach(
|
||||
(name) => {
|
||||
let _ = res->Reducer_Bindings.set(name, Reducer_Expression_Lambda.makeFFILambda(
|
||||
|
|
Loading…
Reference in New Issue
Block a user