From 6b25e82f581692b58c83530f44b5d955408a0e80 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Thu, 26 May 2022 11:09:08 +0200 Subject: [PATCH] typeExpression type statements type paranthesis type paranthesis comments TODO typeExpression type statements type paranthesis type paranthesis comments TODO peggy construct functions typeExpression type statements type paranthesis type paranthesis comments TODO peggy construct functions apply typeExpression type statements type paranthesis type paranthesis comments TODO peggy construct functions apply all types are expressions typeExpression type statements type paranthesis type paranthesis comments TODO peggy construct functions apply all types are expressions modifiers typeExpression type statements type paranthesis type paranthesis comments TODO peggy construct functions apply all types are expressions modifiers 0 arg constructors and $ (low priority type modifier) remove GeneratedParser.js peggy test helpers test type parsing type of test defined act of binding refactored recognize all binding functions | "$_setBindings_$" | "$_setTypeOfBindings_$" | "$_setTypeAliasBindings_$" doBindStatement bindings default statemetn doBindExpression clone type references and type aliases doSetBindingsInNamespace member_of, min, max typeOr type function type with expression --- .../Reducer_Peggy_Parse_test.res | 23 +--- .../Reducer_Peggy_Parse_type_test.res | 79 +++++++++++ .../Reducer_Peggy_TestHelpers.res | 46 +++++++ .../Reducer_Peggy_ToExpression_test.res | 38 +----- .../Reducer_Peggy_ToExpression_type_test.res | 99 ++++++++++++++ packages/squiggle-lang/src/js/index.ts | 2 + .../squiggle-lang/src/js/rescript_interop.ts | 9 +- .../Reducer_Dispatch_BuiltIn.res | 129 ++++++++++++++++++ .../Reducer_Dispatch_BuiltInMacros.res | 127 +++++++++-------- .../Reducer_Expression/Reducer_Expression.res | 6 +- .../Reducer_Expression_Bindings.res | 53 ++++++- .../Reducer_Expression_ExpressionBuilder.res | 3 + .../Reducer_Peggy_GeneratedParser.peggy | 110 +++++++++++++-- .../Reducer_Peggy/Reducer_Peggy_Parse.res | 5 + .../Reducer_Peggy_ToExpression.res | 2 + .../ReducerInterface_ExpressionValue.res | 6 + 16 files changed, 589 insertions(+), 148 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res index b0e723f4..82ae328d 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_test.res @@ -1,26 +1,5 @@ -module Parse = Reducer_Peggy_Parse -module Result = Belt.Result - open Jest -open Expect - -let expectParseToBe = (expr, answer) => - Parse.parse(expr)->Parse.toStringResult->expect->toBe(answer) - -let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) - -module MySkip = { - let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) - - let testDescriptionParse = (desc, expr, answer) => - Skip.test(desc, () => expectParseToBe(expr, answer)) -} - -module MyOnly = { - let testParse = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) - let testDescriptionParse = (desc, expr, answer) => - Only.test(desc, () => expectParseToBe(expr, answer)) -} +open Reducer_Peggy_TestHelpers describe("Peggy parse", () => { describe("float", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res new file mode 100644 index 00000000..ea18effc --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_Parse_type_test.res @@ -0,0 +1,79 @@ +open Jest +open Reducer_Peggy_TestHelpers + +describe("Peggy parse type", () => { + describe("type of", () => { + testParse("p: number", "{(::$_typeOf_$ :p #number)}") + }) + describe("type alias", () => { + testParse("type index=number", "{(::$_typeAlias_$ #index #number)}") + }) + describe("type or", () => { + testParse( + "answer: number|string", + "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ (#number #string))))}", + ) + }) + describe("type function", () => { + testParse( + "f: number=>number=>number", + "{(::$_typeOf_$ :f (::$_typeFunction_$ (::$_constructArray_$ (#number #number #number))))}", + ) + }) + describe("high priority modifier", () => { + testParse( + "answer: number<-min<-max(100)|string", + "{(::$_typeOf_$ :answer (::$_typeOr_$ (::$_constructArray_$ ((::$_typeModifier_max_$ (::$_typeModifier_min_$ #number) 100) #string))))}", + ) + testParse( + "answer: number<-memberOf([1,3,5])", + "{(::$_typeOf_$ :answer (::$_typeModifier_memberOf_$ #number (::$_constructArray_$ (1 3 5))))}", + ) + }) + describe("low priority modifier", () => { + testParse( + "answer: number | string $ opaque", + "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", + ) + }) + describe("type array", () => { + testParse("answer: [number]", "{(::$_typeOf_$ :answer (::$_typeArray_$ #number))}") + }) + describe("type record", () => { + testParse( + "answer: {a: number, b: string}", + "{(::$_typeOf_$ :answer (::$_typeRecord_$ (::$_constructRecord_$ ('a': #number 'b': #string))))}", + ) + }) + describe("type constructor", () => { + testParse( + "answer: Age(number)", + "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Age (::$_constructArray_$ (#number))))}", + ) + testParse( + "answer: Complex(number, number)", + "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Complex (::$_constructArray_$ (#number #number))))}", + ) + testParse( + "answer: Person({age: number, name: string})", + "{(::$_typeOf_$ :answer (::$_typeConstructor_$ #Person (::$_constructArray_$ ((::$_typeRecord_$ (::$_constructRecord_$ ('age': #number 'name': #string)))))))}", + ) + testParse( + "weekend: Saturday | Sunday", + "{(::$_typeOf_$ :weekend (::$_typeOr_$ (::$_constructArray_$ ((::$_typeConstructor_$ #Saturday (::$_constructArray_$ ())) (::$_typeConstructor_$ #Sunday (::$_constructArray_$ ()))))))}", + ) + }) + describe("type paranthesis", () => { + //$ is introduced to avoid paranthesis + testParse( + "answer: (number|string)<-opaque", + "{(::$_typeOf_$ :answer (::$_typeModifier_opaque_$ (::$_typeOr_$ (::$_constructArray_$ (#number #string)))))}", + ) + }) + describe("squiggle expressions in type modifiers", () => { + testParse( + "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)))}", + ) + }) +}) diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res new file mode 100644 index 00000000..7f2160ee --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_TestHelpers.res @@ -0,0 +1,46 @@ +module Expression = Reducer_Expression +module ExpressionT = Reducer_Expression_T +module ExpressionValue = ReducerInterface_ExpressionValue +module Parse = Reducer_Peggy_Parse +module Result = Belt.Result +module ToExpression = Reducer_Peggy_ToExpression + +open Jest +open Expect + +let expectParseToBe = (expr, answer) => + Parse.parse(expr)->Parse.toStringResult->expect->toBe(answer) + +let testParse = (expr, answer) => test(expr, () => expectParseToBe(expr, answer)) + +let expectToExpressionToBe = (expr, answer, ~v="_", ()) => { + let rExpr = Parse.parse(expr)->Result.map(ToExpression.fromNode) + let a1 = rExpr->ExpressionT.toStringResultOkless + + if v == "_" { + a1->expect->toBe(answer) + } else { + let a2 = + rExpr + ->Result.flatMap(expr => + Expression.reduceExpression(expr, Belt.Map.String.empty, ExpressionValue.defaultEnvironment) + ) + ->ExpressionValue.toStringResultOkless + (a1, a2)->expect->toEqual((answer, v)) + } +} + +let testToExpression = (expr, answer, ~v="_", ()) => + test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) + +module MyOnly = { + let testParse = (expr, answer) => Only.test(expr, () => expectParseToBe(expr, answer)) + let testToExpression = (expr, answer, ~v="_", ()) => + Only.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) +} + +module MySkip = { + let testParse = (expr, answer) => Skip.test(expr, () => expectParseToBe(expr, answer)) + let testToExpression = (expr, answer, ~v="_", ()) => + Skip.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) +} diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res index 6091e6fe..baa9a5f0 100644 --- a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_test.res @@ -1,41 +1,5 @@ -module Expression = Reducer_Expression -module ExpressionT = Reducer_Expression_T -module ExpressionValue = ReducerInterface_ExpressionValue -module Parse = Reducer_Peggy_Parse -module ToExpression = Reducer_Peggy_ToExpression -module Result = Belt.Result - open Jest -open Expect - -let expectToExpressionToBe = (expr, answer, ~v="_", ()) => { - let rExpr = Parse.parse(expr)->Result.map(ToExpression.fromNode) - let a1 = rExpr->ExpressionT.toStringResultOkless - if v == "_" { - a1->expect->toBe(answer) - } else { - let a2 = - rExpr - ->Result.flatMap(expr => - Expression.reduceExpression(expr, Belt.Map.String.empty, ExpressionValue.defaultEnvironment) - ) - ->ExpressionValue.toStringResultOkless - (a1, a2)->expect->toEqual((answer, v)) - } -} - -let testToExpression = (expr, answer, ~v="_", ()) => - test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) - -module MySkip = { - let testToExpression = (expr, answer, ~v="_", ()) => - Skip.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) -} - -module MyOnly = { - let testToExpression = (expr, answer, ~v="_", ()) => - Only.test(expr, () => expectToExpressionToBe(expr, answer, ~v, ())) -} +open Reducer_Peggy_TestHelpers describe("Peggy to Expression", () => { describe("literals operators parenthesis", () => { diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res new file mode 100644 index 00000000..05ec5722 --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression_type_test.res @@ -0,0 +1,99 @@ +open Jest +open Reducer_Peggy_TestHelpers + +describe("Peggy Types to Expression", () => { + describe("type of", () => { + testToExpression( + "p: number", + "{(:$_typeOf_$ :p #number)}", + ~v="{_typeReferences_: {p: #number}}", + (), + ) + }) + describe("type alias", () => { + testToExpression( + "type index=number", + "{(:$_typeAlias_$ #index #number)}", + ~v="{_typeAliases_: {index: #number}}", + (), + ) + }) + describe("type or", () => { + testToExpression( + "answer: number|string|distribution", + "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ (#number #string #distribution))))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeOr',typeOr: [#number,#string,#distribution]}}}", + (), + ) + }) + describe("type function", () => { + testToExpression( + "f: number=>number=>number", + "{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number #number))))}", + ~v="{_typeReferences_: {f: {typeTag: 'typeFunction',inputs: [#number,#number],output: #number}}}", + (), + ) + testToExpression( + "f: number=>number", + "{(:$_typeOf_$ :f (:$_typeFunction_$ (:$_constructArray_$ (#number #number))))}", + ~v="{_typeReferences_: {f: {typeTag: 'typeFunction',inputs: [#number],output: #number}}}", + (), + ) + }) + describe("high priority modifier", () => { + testToExpression( + "answer: number<-min(1)<-max(100)|string", + "{(:$_typeOf_$ :answer (:$_typeOr_$ (:$_constructArray_$ ((:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 100) #string))))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeOr',typeOr: [{typeTag: 'typeIdentifier',typeIdentifier: #number,min: 1,max: 100},#string]}}}", + (), + ) + testToExpression( + "answer: number<-memberOf([1,3,5])", + "{(:$_typeOf_$ :answer (:$_typeModifier_memberOf_$ #number (:$_constructArray_$ (1 3 5))))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeIdentifier',typeIdentifier: #number,memberOf: [1,3,5]}}}", + (), + ) + testToExpression( + "answer: number<-min(1)", + "{(:$_typeOf_$ :answer (:$_typeModifier_min_$ #number 1))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeIdentifier',typeIdentifier: #number,min: 1}}}", + (), + ) + testToExpression( + "answer: number<-max(10)", + "{(:$_typeOf_$ :answer (:$_typeModifier_max_$ #number 10))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeIdentifier',typeIdentifier: #number,max: 10}}}", + (), + ) + testToExpression( + "answer: number<-min(1)<-max(10)", + "{(:$_typeOf_$ :answer (:$_typeModifier_max_$ (:$_typeModifier_min_$ #number 1) 10))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeIdentifier',typeIdentifier: #number,min: 1,max: 10}}}", + (), + ) + testToExpression( + "answer: number<-max(10)<-min(1)", + "{(:$_typeOf_$ :answer (:$_typeModifier_min_$ (:$_typeModifier_max_$ #number 10) 1))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeIdentifier',typeIdentifier: #number,max: 10,min: 1}}}", + (), + ) + }) + describe("low priority modifier", () => { + testToExpression( + "answer: number | string $ opaque", + "{(:$_typeOf_$ :answer (:$_typeModifier_opaque_$ (:$_typeOr_$ (:$_constructArray_$ (#number #string)))))}", + ~v="{_typeReferences_: {answer: {typeTag: 'typeOr',typeOr: [#number,#string],opaque: true}}}", + (), + ) + }) + describe("squiggle expressions in type modifiers", () => { + testToExpression( + "odds1 = [1,3,5]; odds2 = [7, 9]; type odds = number<-memberOf(odds1 + odds2)", + "{(:$_let_$ :odds1 {(:$_constructArray_$ (1 3 5))}); (:$_let_$ :odds2 {(:$_constructArray_$ (7 9))}); (:$_typeAlias_$ #odds (:$_typeModifier_memberOf_$ #number (:add :odds1 :odds2)))}", + ~v="{_typeAliases_: {odds: {typeTag: 'typeIdentifier',typeIdentifier: #number,memberOf: [1,3,5,7,9]}},odds1: [1,3,5],odds2: [7,9]}", + (), + ) + }) + // TODO: type bindings. Type bindings are not yet supported. + // TODO: type constructor +}) diff --git a/packages/squiggle-lang/src/js/index.ts b/packages/squiggle-lang/src/js/index.ts index 03068a51..6ba8676d 100644 --- a/packages/squiggle-lang/src/js/index.ts +++ b/packages/squiggle-lang/src/js/index.ts @@ -189,5 +189,7 @@ function createTsExport( return tag("timeDuration", x.value); case "EvDeclaration": return tag("lambdaDeclaration", x.value); + case "EvTypeIdentifier": + return tag("typeIdentifier", x.value); } } diff --git a/packages/squiggle-lang/src/js/rescript_interop.ts b/packages/squiggle-lang/src/js/rescript_interop.ts index 9f9bdb39..c7c4910f 100644 --- a/packages/squiggle-lang/src/js/rescript_interop.ts +++ b/packages/squiggle-lang/src/js/rescript_interop.ts @@ -69,6 +69,10 @@ export type rescriptExport = | { TAG: 12; // EvDeclaration _0: rescriptLambdaDeclaration; + } + | { + TAG: 13; // EvTypeIdentifier + _0: string; }; type rescriptDist = @@ -120,7 +124,8 @@ export type squiggleExpression = | tagged<"date", Date> | tagged<"timeDuration", number> | tagged<"lambdaDeclaration", lambdaDeclaration> - | tagged<"record", { [key: string]: squiggleExpression }>; + | tagged<"record", { [key: string]: squiggleExpression }> + | tagged<"typeIdentifier", string>; export { lambdaValue }; @@ -170,6 +175,8 @@ export function convertRawToTypescript( fn: result._0.fn, args: result._0.args.map(convertDeclaration), }); + case 13: // EvSymbol + return tag("typeIdentifier", result._0); } } diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res index 4d3bc49f..218aa673 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltIn.res @@ -52,6 +52,16 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce | None => RERecordPropertyNotFound("Record property not found", sIndex)->Error } + let doAddArray = (originalA, b) => { + let a = originalA->Js.Array2.copy + let _ = Js.Array2.pushMany(a, b) + a->EvArray->Ok + } + let doAddString = (a, b) => { + let answer = Js.String2.concat(a, b) + answer->EvString->Ok + } + let inspect = (value: expressionValue) => { Js.log(value->toString) value->Ok @@ -74,6 +84,40 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce ->Ok } + let doSetBindingsInNamespace = ( + externalBindings: externalBindings, + symbol: string, + value: expressionValue, + namespace: string, + ) => { + let bindings = Bindings.fromExternalBindings(externalBindings) + let evAliases = bindings->Belt.Map.String.getWithDefault(namespace, EvRecord(Js.Dict.empty())) + let newEvAliases = switch evAliases { + | EvRecord(dict) => { + Js.Dict.set(dict, symbol, value) + dict->EvRecord + } + | _ => Js.Dict.empty()->EvRecord + } + bindings + ->Belt.Map.String.set(namespace, newEvAliases) + ->Bindings.toExternalBindings + ->EvRecord + ->Ok + } + + let doSetTypeAliasBindings = ( + externalBindings: externalBindings, + symbol: string, + value: expressionValue, + ) => doSetBindingsInNamespace(externalBindings, symbol, value, Bindings.typeAliasesKey) + + let doSetTypeOfBindings = ( + externalBindings: externalBindings, + symbol: string, + value: expressionValue, + ) => doSetBindingsInNamespace(externalBindings, symbol, value, Bindings.typeReferencesKey) + let doExportBindings = (externalBindings: externalBindings) => EvRecord(externalBindings)->Ok let doKeepArray = (aValueArray, aLambdaValue) => { @@ -147,6 +191,69 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce ) } + let typeModifier_memberOf = (aType, anArray) => { + let newRecord = Js.Dict.fromArray([ + ("typeTag", EvString("typeIdentifier")), + ("typeIdentifier", aType), + ]) + newRecord->Js.Dict.set("memberOf", anArray) + newRecord->EvRecord->Ok + } + let typeModifier_memberOf_update = (aRecord, anArray) => { + let newRecord = aRecord->Js.Dict.entries->Js.Dict.fromArray + newRecord->Js.Dict.set("memberOf", anArray) + newRecord->EvRecord->Ok + } + + let typeModifier_min = (aType, value) => { + let newRecord = Js.Dict.fromArray([ + ("typeTag", EvString("typeIdentifier")), + ("typeIdentifier", aType), + ]) + newRecord->Js.Dict.set("min", value) + newRecord->EvRecord->Ok + } + let typeModifier_min_update = (aRecord, value) => { + let newRecord = aRecord->Js.Dict.entries->Js.Dict.fromArray + newRecord->Js.Dict.set("min", value) + newRecord->EvRecord->Ok + } + + let typeModifier_max = (aType, value) => { + let newRecord = Js.Dict.fromArray([ + ("typeTag", EvString("typeIdentifier")), + ("typeIdentifier", aType), + ]) + newRecord->Js.Dict.set("max", value) + newRecord->EvRecord->Ok + } + let typeModifier_max_update = (aRecord, value) => { + let newRecord = aRecord->Js.Dict.entries->Js.Dict.fromArray + newRecord->Js.Dict.set("max", value) + newRecord->EvRecord->Ok + } + + let typeModifier_opaque_update = aRecord => { + let newRecord = aRecord->Js.Dict.entries->Js.Dict.fromArray + newRecord->Js.Dict.set("opaque", EvBool(true)) + newRecord->EvRecord->Ok + } + + let typeOr = evArray => { + let newRecord = Js.Dict.fromArray([("typeTag", EvString("typeOr")), ("typeOr", evArray)]) + newRecord->EvRecord->Ok + } + let typeFunction = anArray => { + let output = Belt.Array.getUnsafe(anArray, Js.Array2.length(anArray) - 1) + let inputs = Js.Array2.slice(anArray, ~start=0, ~end_=-1) + let newRecord = Js.Dict.fromArray([ + ("typeTag", EvString("typeFunction")), + ("inputs", EvArray(inputs)), + ("output", output), + ]) + newRecord->EvRecord->Ok + } + switch call { | ("$_atIndex_$", [EvArray(aValueArray), EvNumber(fIndex)]) => arrayAtIndex(aValueArray, fIndex) | ("$_atIndex_$", [EvRecord(dict), EvString(sIndex)]) => recordAtIndex(dict, sIndex) @@ -155,6 +262,28 @@ let callInternal = (call: functionCall, environment, reducer: ExpressionT.reduce | ("$_exportBindings_$", [EvRecord(externalBindings)]) => doExportBindings(externalBindings) | ("$_setBindings_$", [EvRecord(externalBindings), EvSymbol(symbol), value]) => doSetBindings(externalBindings, symbol, value) + | ("$_setTypeAliasBindings_$", [EvRecord(externalBindings), EvTypeIdentifier(symbol), value]) => + doSetTypeAliasBindings(externalBindings, symbol, value) + | ("$_setTypeOfBindings_$", [EvRecord(externalBindings), EvSymbol(symbol), value]) => + doSetTypeOfBindings(externalBindings, symbol, value) + | ("$_typeModifier_memberOf_$", [EvTypeIdentifier(typeIdentifier), EvArray(arr)]) => + typeModifier_memberOf(EvTypeIdentifier(typeIdentifier), EvArray(arr)) + | ("$_typeModifier_memberOf_$", [EvRecord(typeRecord), EvArray(arr)]) => + typeModifier_memberOf_update(typeRecord, EvArray(arr)) + | ("$_typeModifier_min_$", [EvTypeIdentifier(typeIdentifier), value]) => + typeModifier_min(EvTypeIdentifier(typeIdentifier), value) + | ("$_typeModifier_min_$", [EvRecord(typeRecord), value]) => + typeModifier_min_update(typeRecord, value) + | ("$_typeModifier_max_$", [EvTypeIdentifier(typeIdentifier), value]) => + typeModifier_max(EvTypeIdentifier(typeIdentifier), value) + | ("$_typeModifier_max_$", [EvRecord(typeRecord), value]) => + typeModifier_max_update(typeRecord, value) + | ("$_typeModifier_opaque_$", [EvRecord(typeRecord)]) => typeModifier_opaque_update(typeRecord) + | ("$_typeOr_$", [EvArray(arr)]) => typeOr(EvArray(arr)) + | ("$_typeFunction_$", [EvArray(arr)]) => typeFunction(arr) + | ("add", [EvArray(aValueArray), EvArray(bValueArray)]) => doAddArray(aValueArray, bValueArray) + | ("add", [EvString(aValueString), EvString(bValueString)]) => + doAddString(aValueString, bValueString) | ("inspect", [value, EvString(label)]) => inspectLabel(value, label) | ("inspect", [value]) => inspect(value) | ("keep", [EvArray(aValueArray), EvLambda(aLambdaValue)]) => diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res index 8bd07157..cb2ce425 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Dispatch/Reducer_Dispatch_BuiltInMacros.res @@ -4,6 +4,7 @@ Macros are used to define language building blocks. They are like Lisp macros. */ module Bindings = Reducer_Expression_Bindings +module ErrorValue = Reducer_ErrorValue module ExpressionBuilder = Reducer_Expression_ExpressionBuilder module ExpressionT = Reducer_Expression_T module ExpressionValue = ReducerInterface.ExpressionValue @@ -12,7 +13,7 @@ module Result = Belt.Result open Reducer_Expression_ExpressionBuilder type environment = ExpressionValue.environment -type errorValue = Reducer_ErrorValue.errorValue +type errorValue = ErrorValue.errorValue type expression = ExpressionT.expression type expressionValue = ExpressionValue.expressionValue type expressionWithContext = ExpressionWithContext.expressionWithContext @@ -23,84 +24,78 @@ let dispatchMacroCall = ( environment, reduceExpression: ExpressionT.reducerFn, ): result => { - let doBindStatement = (bindingExpr: expression, statement: expression, environment) => - switch statement { - | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$_let_$")), symbolExpr, statement}) => { - let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) + let useExpressionToSetBindings = (bindingExpr: expression, environment, statement, newCode) => { + let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) - rExternalBindingsValue->Result.flatMap(externalBindingsValue => { - let newBindings = Bindings.fromValue(externalBindingsValue) + rExternalBindingsValue->Result.flatMap(externalBindingsValue => { + let newBindings = Bindings.fromValue(externalBindingsValue) - // Js.log( - // `bindStatement ${Bindings.toString(newBindings)}<==${ExpressionT.toString( - // bindingExpr, - // )} statement: $_let_$ ${ExpressionT.toString(symbolExpr)}=${ExpressionT.toString( - // statement, - // )}`, - // ) + let rNewStatement = Bindings.replaceSymbols(newBindings, statement) + rNewStatement->Result.map(boundStatement => + ExpressionWithContext.withContext( + newCode(newBindings->Bindings.toExternalBindings->eRecord, boundStatement), + newBindings, + ) + ) + }) + } - let rNewStatement = Bindings.replaceSymbols(newBindings, statement) - rNewStatement->Result.map(newStatement => - ExpressionWithContext.withContext( - eFunction( - "$_setBindings_$", - list{newBindings->Bindings.toExternalBindings->eRecord, symbolExpr, newStatement}, - ), - newBindings, - ) - ) - }) - } - | _ => REAssignmentExpected->Error + let correspondingSetBindingsFn = (fnName: string): string => + switch fnName { + | "$_let_$" => "$_setBindings_$" + | "$_typeOf_$" => "$_setTypeOfBindings_$" + | "$_typeAlias_$" => "$_setTypeAliasBindings_$" + | _ => "" } + let doBindStatement = (bindingExpr: expression, statement: expression, environment) => { + let defaultStatement = ErrorValue.REAssignmentExpected->Error + switch statement { + | ExpressionT.EList(list{ExpressionT.EValue(EvCall(callName)), symbolExpr, statement}) => { + let setBindingsFn = correspondingSetBindingsFn(callName) + if setBindingsFn !== "" { + useExpressionToSetBindings(bindingExpr, environment, statement, ( + newBindingsExpr, + boundStatement, + ) => eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})) + } else { + defaultStatement + } + } + | _ => defaultStatement + } + } + let doBindExpression = (bindingExpr: expression, statement: expression, environment): result< expressionWithContext, errorValue, - > => - switch statement { - | ExpressionT.EList(list{ExpressionT.EValue(EvCall("$_let_$")), symbolExpr, statement}) => { - let rExternalBindingsValue = reduceExpression(bindingExpr, bindings, environment) + > => { + let defaultStatement = () => + useExpressionToSetBindings(bindingExpr, environment, statement, ( + _newBindingsExpr, + boundStatement, + ) => boundStatement) - rExternalBindingsValue->Result.flatMap(externalBindingsValue => { - let newBindings = Bindings.fromValue(externalBindingsValue) - let rNewStatement = Bindings.replaceSymbols(newBindings, statement) - rNewStatement->Result.map(newStatement => - ExpressionWithContext.withContext( - eFunction( - "$_exportBindings_$", - list{ - eFunction( - "$_setBindings_$", - list{ - newBindings->Bindings.toExternalBindings->eRecord, - symbolExpr, - newStatement, - }, - ), - }, - ), - newBindings, + switch statement { + | ExpressionT.EList(list{ExpressionT.EValue(EvCall(callName)), symbolExpr, statement}) => { + let setBindingsFn = correspondingSetBindingsFn(callName) + if setBindingsFn !== "" { + useExpressionToSetBindings(bindingExpr, environment, statement, ( + newBindingsExpr, + boundStatement, + ) => + eFunction( + "$_exportBindings_$", + list{eFunction(setBindingsFn, list{newBindingsExpr, symbolExpr, boundStatement})}, ) ) - }) - } - | _ => { - let rExternalBindingsValue: result = reduceExpression( - bindingExpr, - bindings, - environment, - ) - - rExternalBindingsValue->Result.flatMap(externalBindingsValue => { - let newBindings = Bindings.fromValue(externalBindingsValue) - let rNewStatement = Bindings.replaceSymbols(newBindings, statement) - rNewStatement->Result.map(newStatement => - ExpressionWithContext.withContext(newStatement, newBindings) - ) - }) + } else { + defaultStatement() + } } + | _ => defaultStatement() } + } let doBlock = (exprs: list, _bindings: ExpressionT.bindings, _environment): result< expressionWithContext, diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res index 64faa43b..c62201ce 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression.res @@ -75,9 +75,9 @@ and reduceValueList = (valueList: list, environment): result< > => switch valueList { | list{EvCall(fName), ...args} => { - let rCheckedArgs = switch fName == "$_setBindings_$" { - | false => args->Lambda.checkIfReduced - | true => args->Ok + let rCheckedArgs = switch fName { + | "$_setBindings_$" | "$_setTypeOfBindings_$" | "$_setTypeAliasBindings_$" => args->Ok + | _ => args->Lambda.checkIfReduced } rCheckedArgs->Result.flatMap(checkedArgs => diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res index 7c0c048a..abc636be 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_Bindings.res @@ -10,13 +10,8 @@ type externalBindings = ReducerInterface_ExpressionValue.externalBindings let defaultBindings: ExpressionT.bindings = Belt.Map.String.empty -let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings => { - let keys = Js.Dict.keys(externalBindings) - keys->Belt.Array.reduce(defaultBindings, (acc, key) => { - let value = Js.Dict.unsafeGet(externalBindings, key) - acc->Belt.Map.String.set(key, value) - }) -} +let typeAliasesKey = "_typeAliases_" +let typeReferencesKey = "_typeReferences_" let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings => { let keys = Belt.Map.String.keysToArray(bindings) @@ -27,6 +22,50 @@ let toExternalBindings = (bindings: ExpressionT.bindings): externalBindings => { }) } +let fromExternalBindings_ = (externalBindings: externalBindings): ExpressionT.bindings => { + let keys = Js.Dict.keys(externalBindings) + keys->Belt.Array.reduce(defaultBindings, (acc, key) => { + let value = Js.Dict.unsafeGet(externalBindings, key) + acc->Belt.Map.String.set(key, value) + }) +} + +let fromExternalBindings = (externalBindings: externalBindings): ExpressionT.bindings => { + // TODO: This code will be removed in the future when maps are used instead of records. Please don't mind this function for now. + + let internalBindings0 = fromExternalBindings_(externalBindings) + + let oExistingTypeAliases = Belt.Map.String.get(internalBindings0, typeAliasesKey) + let internalBindings1 = Belt.Option.mapWithDefault( + oExistingTypeAliases, + internalBindings0, + existingTypeAliases => { + let newTypeAliases = switch existingTypeAliases { + | EvRecord(actualTypeAliases) => + actualTypeAliases->fromExternalBindings_->toExternalBindings->ExpressionValue.EvRecord + | _ => existingTypeAliases + } + Belt.Map.String.set(internalBindings0, typeAliasesKey, newTypeAliases) + }, + ) + + let oExistingTypeReferences = Belt.Map.String.get(internalBindings1, typeReferencesKey) + let internalBindings2 = Belt.Option.mapWithDefault( + oExistingTypeReferences, + internalBindings1, + existingTypeReferences => { + let newTypeReferences = switch existingTypeReferences { + | EvRecord(actualTypeReferences) => + actualTypeReferences->fromExternalBindings_->toExternalBindings->ExpressionValue.EvRecord + | _ => existingTypeReferences + } + Belt.Map.String.set(internalBindings0, typeReferencesKey, newTypeReferences) + }, + ) + + internalBindings2 +} + let fromValue = (aValue: expressionValue) => switch aValue { | EvRecord(externalBindings) => fromExternalBindings(externalBindings) diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res index cdf3425b..39d49655 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Expression/Reducer_Expression_ExpressionBuilder.res @@ -64,3 +64,6 @@ let eBindExpression = (bindingExpr: expression, expression: expression): express let eBindExpressionDefault = (expression: expression): expression => eFunction("$$_bindExpression_$$", list{expression}) + +let eTypeIdentifier = (name: string): expression => + name->BExpressionValue.EvTypeIdentifier->BExpressionT.EValue diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy index 15cc05a0..61016ca9 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_GeneratedParser.peggy @@ -36,11 +36,6 @@ '[]': '$_atIndex_$', } - function nodeBlock(statements) {return{type: 'Block', statements: statements}} - function nodeBoolean(value) {return {type: 'Boolean', value: value}} - function nodeCallIndentifier(value) {return {type: 'CallIdentifier', value: value}} - function nodeExpression(args) {return {type: 'Expression', nodes: args}} - function nodeFloat(value) {return {type: 'Float', value: value}} function makeFunctionCall(fn, args) { if (fn === '$$_applyAll_$$') { // Any list of values is applied from left to right anyway. @@ -52,6 +47,16 @@ return nodeExpression([nodeCallIndentifier(fn), ...args]) } } + + function apply(fn, arg) { return makeFunctionCall(fn, [arg]); } + function constructArray(elems) { return apply('$_constructArray_$', nodeExpression(elems)); } + function constructRecord(elems) { return apply('$_constructRecord_$', nodeExpression(elems)); } + + function nodeBlock(statements) {return{type: 'Block', statements: statements}} + function nodeBoolean(value) {return {type: 'Boolean', value: value}} + function nodeCallIndentifier(value) {return {type: 'CallIdentifier', value: value}} + function nodeExpression(args) {return {type: 'Expression', nodes: args}} + function nodeFloat(value) {return {type: 'Float', value: value}} function nodeIdentifier(value) {return {type: 'Identifier', value: value}} function nodeInteger(value) {return {type: 'Integer', value: value}} function nodeKeyValue(key, value) { @@ -61,9 +66,12 @@ function nodeLetStatment(variable, value) {return {type: 'LetStatement', variable: variable, value: value}} function nodeString(value) {return {type: 'String', value: value}} function nodeTernary(condition, trueExpression, falseExpression) {return {type: 'Ternary', condition: condition, trueExpression: trueExpression, falseExpression: falseExpression}} + + function nodeTypeIdentifier(typeValue) {return {type: 'TypeIdentifier', value: typeValue}} }} start + // = _nl start:typeExpression _nl finalComment? {return start} = _nl start:outerBlock _nl finalComment? {return start} zeroOMoreArgumentsBlockOrExpression = innerBlockOrExpression / lambda @@ -96,6 +104,7 @@ array_statements statement = letStatement / defunStatement + / typeStatement letStatement = variable:identifier _ assignmentOp _nl value:zeroOMoreArgumentsBlockOrExpression @@ -205,7 +214,7 @@ chainFunctionCall unary = unaryOperator:unaryOperator _nl right:(unary/postOperator) - { return makeFunctionCall(unaryToFunction[unaryOperator], [right])} + { return apply(unaryToFunction[unaryOperator], right)} / postOperator unaryOperator "unary operator" @@ -267,7 +276,7 @@ number = number:(float / integer) unit:identifier? if (unit === null) { return number } else - { return makeFunctionCall('fromUnit_'+unit.value, [number]) + { return apply('fromUnit_'+unit.value, number) } } @@ -301,9 +310,9 @@ lambda arrayConstructor 'array' = '[' _nl ']' - { return makeFunctionCall('$_constructArray_$', [nodeExpression([])])} + { return constructArray([]); } / '[' _nl args:array_elements _nl ']' - { return makeFunctionCall('$_constructArray_$', [nodeExpression(args)])} + { return constructArray(args); } array_elements = head:expression tail:(_ ',' _nl @expression)* @@ -311,7 +320,7 @@ arrayConstructor 'array' recordConstructor 'record' = '{' _nl args:array_recordArguments _nl '}' - { return makeFunctionCall('$_constructRecord_$', [nodeExpression(args)])} + { return constructRecord(args); } array_recordArguments = head:keyValuePair tail:(_ ',' _nl @keyValuePair)* @@ -320,7 +329,9 @@ recordConstructor 'record' keyValuePair = key:expression _ ':' _nl value:expression { return nodeKeyValue(key, value)} - + +// Separators + _ 'whitespace' = whiteSpaceCharactersOrComment* @@ -351,4 +362,79 @@ statementSeparator 'statement separator' newLine "newline" = [\n\r] - \ No newline at end of file +// Types + +noArguments = ('(' _nl ')' )? + +typeIdentifier 'type identifier' + = ([a-z]+[_a-z0-9]i*) {return nodeTypeIdentifier(text())} + +typeConstructorIdentifier 'type constructor identifier' + = ([A-Z]+[_a-z0-9]i*) {return nodeTypeIdentifier(text())} + +typeExpression = typePostModifierExpression + +typePostModifierExpression = head:typeOr tail:(_ '$' _nl @typeModifier)* + { + return tail.reduce((result, element) => { + return makeFunctionCall('$_typeModifier_'+element.modifier.value+'_$', [result, ...element.args]) + }, head) + } + +typeOr = head:typeFunction tail:(_ '|' _nl @typeFunction)* + { return tail.length === 0 ? head : apply('$_typeOr_$', constructArray([head, ...tail])); } + +typeFunction = head:typeModifierExpression tail:(_ '=>' _nl @typeModifierExpression)* + { return tail.length === 0 ? head : apply( '$_typeFunction_$', constructArray([head, ...tail])); } + +typeModifierExpression = head:basicType tail:(_ '<-' _nl @typeModifier)* + { + return tail.reduce((result, element) => { + return makeFunctionCall('$_typeModifier_'+element.modifier.value+'_$', [result, ...element.args]) + }, head) + } + + typeModifier + = modifier:identifier _ '(' _nl args:array_elements _nl ')' + { return {modifier: modifier, args: args}; } + / modifier:identifier _ noArguments + { return {modifier: modifier, args: []}; } + +basicType = typeConstructor / typeArray / typeRecord / typeInParanthesis / typeIdentifier + +typeArray = '[' _nl elem:typeExpression _nl ']' + {return apply('$_typeArray_$', elem)} + +typeRecord = '{' _nl elems:array_typeRecordArguments _nl '}' + { return apply('$_typeRecord_$', constructRecord(elems)); } + + array_typeRecordArguments + = head:typeKeyValuePair tail:(_ ',' _nl @typeKeyValuePair)* + { return [head, ...tail]; } + + typeKeyValuePair + = key:identifier _ ':' _nl value:typeExpression + { return nodeKeyValue(key, value)} + +typeConstructor + = constructor:typeConstructorIdentifier _ '(' _nl args:array_types _nl ')' + { return makeFunctionCall('$_typeConstructor_$', [constructor, constructArray(args)]); } + / constructor:typeConstructorIdentifier _ noArguments + { return makeFunctionCall('$_typeConstructor_$', [constructor, constructArray([])]); } + + array_types = head:typeExpression tail:(_ ',' _nl @typeExpression)* + { return [head, ...tail]; } + +typeStatement = typeAliasStatement / typeOfStatement +typeAliasStatement = 'type' __nl typeIdentifier:typeIdentifier _nl '=' _nl typeExpression:typeExpression + { return makeFunctionCall('$_typeAlias_$', [typeIdentifier, typeExpression])} +typeOfStatement = identifier:identifier _ ':' _nl typeExpression:typeExpression + { return makeFunctionCall('$_typeOf_$', [identifier, typeExpression])} + +typeInParanthesis = '(' _nl typeExpression:typeExpression _nl ')' {return typeExpression} + +// TODO: min max example +// TODO: Example of foo = {a: 2, b: 5}; type fooKeys = string $ memberOf(foo->keys) +// TODO: Example of memberOf( [1,2,3] ) +// TODO: Example of $ +// TODO: Cons(a, list) | EmptyList \ No newline at end of file diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res index 313639fb..c53fab7a 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_Parse.res @@ -24,6 +24,7 @@ type nodeLambda = {...node, "args": array, "body": nodeBlock} type nodeLetStatement = {...node, "variable": nodeIdentifier, "value": node} type nodeString = {...node, "value": string} type nodeTernary = {...node, "condition": node, "trueExpression": node, "falseExpression": node} +type nodeTypeIdentifier = {...node, "value": string} type peggyNode = | PgNodeBlock(nodeBlock) @@ -38,6 +39,7 @@ type peggyNode = | PgNodeLetStatement(nodeLetStatement) | PgNodeString(nodeString) | PgNodeTernary(nodeTernary) + | PgNodeTypeIdentifier(nodeTypeIdentifier) external castNodeBlock: node => nodeBlock = "%identity" external castNodeBoolean: node => nodeBoolean = "%identity" @@ -51,6 +53,7 @@ external castNodeLambda: node => nodeLambda = "%identity" external castNodeLetStatement: node => nodeLetStatement = "%identity" external castNodeString: node => nodeString = "%identity" external castNodeTernary: node => nodeTernary = "%identity" +external castNodeTypeIdentifier: node => nodeTypeIdentifier = "%identity" exception UnsupportedPeggyNodeType(string) // This should never happen; programming error let castNodeType = (node: node) => @@ -67,6 +70,7 @@ let castNodeType = (node: node) => | "LetStatement" => node->castNodeLetStatement->PgNodeLetStatement | "String" => node->castNodeString->PgNodeString | "Ternary" => node->castNodeTernary->PgNodeTernary + | "TypeIdentifier" => node->castNodeTypeIdentifier->PgNodeTypeIdentifier | _ => raise(UnsupportedPeggyNodeType(node["type"])) } @@ -98,6 +102,7 @@ let rec pgToString = (peggyNode: peggyNode): string => { toString(node["trueExpression"]) ++ " " ++ toString(node["falseExpression"]) ++ ")" + | PgNodeTypeIdentifier(node) => `#${node["value"]}` } } and toString = (node: node): string => node->castNodeType->pgToString diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res index a9d4fb22..ce265b41 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Peggy/Reducer_Peggy_ToExpression.res @@ -44,5 +44,7 @@ let rec fromNode = (node: Parse.node): expression => { fromNode(nodeTernary["falseExpression"]), }, ) + | PgNodeTypeIdentifier(nodeTypeIdentifier) => + ExpressionBuilder.eTypeIdentifier(nodeTypeIdentifier["value"]) } } diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res index aa040fc2..628dfc8e 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_ExpressionValue.res @@ -23,6 +23,7 @@ type rec expressionValue = | EvDate(Js.Date.t) | EvTimeDuration(float) | EvDeclaration(lambdaDeclaration) + | EvTypeIdentifier(string) and record = Js.Dict.t and externalBindings = record and lambdaValue = { @@ -58,6 +59,7 @@ let rec toString = aValue => | EvDate(date) => DateTime.Date.toString(date) | EvTimeDuration(t) => DateTime.Duration.toString(t) | EvDeclaration(d) => Declaration.toString(d, r => toString(EvLambda(r))) + | EvTypeIdentifier(id) => `#${id}` } and toStringRecord = aRecord => { let pairs = @@ -83,6 +85,7 @@ let toStringWithType = aValue => | EvDate(_) => `Date::${toString(aValue)}` | EvTimeDuration(_) => `Date::${toString(aValue)}` | EvDeclaration(_) => `Declaration::${toString(aValue)}` + | EvTypeIdentifier(_) => `TypeIdentifier::${toString(aValue)}` } let argsToString = (args: array): string => { @@ -129,6 +132,7 @@ type expressionValueType = | EvtDate | EvtTimeDuration | EvtDeclaration + | EvtTypeIdentifier type functionCallSignature = CallSignature(string, array) type functionDefinitionSignature = @@ -149,6 +153,7 @@ let valueToValueType = value => | EvDate(_) => EvtDate | EvTimeDuration(_) => EvtTimeDuration | EvDeclaration(_) => EvtDeclaration + | EvTypeIdentifier(_) => EvtTypeIdentifier } let functionCallToCallSignature = (functionCall: functionCall): functionCallSignature => { @@ -171,6 +176,7 @@ let valueTypeToString = (valueType: expressionValueType): string => | EvtDate => `Date` | EvtTimeDuration => `Duration` | EvtDeclaration => `Declaration` + | EvtTypeIdentifier => `TypeIdentifier` } let functionCallSignatureToString = (functionCallSignature: functionCallSignature): string => {