From 82a4e5238407316b4d59023a52b73ca6b0718c16 Mon Sep 17 00:00:00 2001 From: Umur Ozkul Date: Wed, 31 Aug 2022 23:54:54 +0200 Subject: [PATCH] include and "include as" --- .../Reducer_Bindings_test.res | 27 + .../ReducerProject_includes_test.res | 90 ++- .../ReducerProject/ReducerProject_test.res | 23 +- ...educerProject_tutorial_3_includes_test.res | 23 + .../rescript/ForTS/ForTS_ReducerProject.res | 7 +- .../Reducer_Bindings/Reducer_Bindings.res | 79 ++- .../ReducerInterface_Value_Continuation.res | 7 +- .../ReducerProject/ReducerProject.res | 79 ++- .../ReducerProject_IncludeParser.js | 518 +++++++++++++----- .../ReducerProject_IncludeParser.peggy | 26 +- .../ReducerProject_ParseIncludes.res | 10 +- .../ReducerProject_ProjectItem.res | 73 ++- .../ReducerProject_ProjectItem_T.res | 7 +- .../SquiggleLibrary/SquiggleLibrary_Math.res | 2 +- .../SquiggleLibrary_Versions.res | 2 +- 15 files changed, 732 insertions(+), 241 deletions(-) create mode 100644 packages/squiggle-lang/__tests__/Reducer/Reducer_Bindings/Reducer_Bindings_test.res diff --git a/packages/squiggle-lang/__tests__/Reducer/Reducer_Bindings/Reducer_Bindings_test.res b/packages/squiggle-lang/__tests__/Reducer/Reducer_Bindings/Reducer_Bindings_test.res new file mode 100644 index 00000000..9079acfa --- /dev/null +++ b/packages/squiggle-lang/__tests__/Reducer/Reducer_Bindings/Reducer_Bindings_test.res @@ -0,0 +1,27 @@ +@@warning("-44") +module InternalExpressionValue = ReducerInterface_InternalExpressionValue +module Bindings = Reducer_Bindings + +open Jest +open Expect +open Expect.Operators + +describe("Name Space", () => { + let value = InternalExpressionValue.IEvNumber(1967.0) + let nameSpace = Bindings.emptyNameSpace->Bindings.set("value", value) + test("get", () => { + expect(Bindings.get(nameSpace, "value")) == Some(value) + }) + + test("chain and get", () => { + let mainNameSpace = Bindings.emptyNameSpace->Bindings.chainTo([nameSpace]) + expect(Bindings.get(mainNameSpace, "value")) == Some(value) + }) + + test("chain and set", () => { + let mainNameSpace0 = Bindings.emptyNameSpace->Bindings.chainTo([nameSpace]) + let mainNameSpace = + mainNameSpace0->Bindings.set("value", InternalExpressionValue.IEvNumber(1968.0)) + expect(Bindings.get(mainNameSpace, "value")) == Some(InternalExpressionValue.IEvNumber(1968.0)) + }) +}) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res index bce7c84b..d2dbafb3 100644 --- a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_includes_test.res @@ -7,7 +7,7 @@ open Jest open Expect open Expect.Operators -Only.describe("Parse includes", () => { +describe("Parse includes", () => { let project = Project.createProject() Project.setSource( project, @@ -30,4 +30,92 @@ x=1`, | Error(error) => fail(error->Reducer_ErrorValue.errorToString) } }) + let internalProject = project->Project.T.Private.castToInternalProject + test("past chain", () => { + expect(Project.Private.getPastChain(internalProject, "main")) == ["common"] + }) + test("import as variables", () => { + expect(Project.Private.getIncludesAsVariables(internalProject, "main")) == [] + }) +}) + +describe("Parse includes", () => { + let project = Project.createProject() + Project.setSource( + project, + "main", + ` +#include 'common' +#include 'myModule' as myVariable +x=1`, + ) + Project.parseIncludes(project, "main") + + test("dependencies", () => { + expect(Project.getDependencies(project, "main")) == ["common", "myModule"] + }) + + test("dependents", () => { + expect(Project.getDependents(project, "main")) == [] + }) + + test("getIncludes", () => { + let mainIncludes = Project.getIncludes(project, "main") + switch mainIncludes { + | Ok(includes) => expect(includes) == ["common", "myModule"] + | Error(error) => fail(error->Reducer_ErrorValue.errorToString) + } + }) + + let internalProject = project->Project.T.Private.castToInternalProject + + test("direct past chain", () => { + expect(Project.Private.getPastChain(internalProject, "main")) == ["common"] + }) + + test("direct includes", () => { + expect(Project.Private.getDirectIncludes(internalProject, "main")) == ["common"] + }) + + test("include as variables", () => { + expect(Project.Private.getIncludesAsVariables(internalProject, "main")) == [ + ("myVariable", "myModule"), + ] + }) +}) + +describe("Parse multiple direct includes", () => { + let project = Project.createProject() + Project.setSource( + project, + "main", + ` +#include 'common' +#include 'common2' +#include 'myModule' as myVariable +x=1`, + ) + Project.parseIncludes(project, "main") + test("dependencies", () => { + expect(Project.getDependencies(project, "main")) == ["common", "common2", "myModule"] + }) + test("dependents", () => { + expect(Project.getDependents(project, "main")) == [] + }) + test("getIncludes", () => { + let mainIncludes = Project.getIncludes(project, "main") + switch mainIncludes { + | Ok(includes) => expect(includes) == ["common", "common2", "myModule"] + | Error(error) => fail(error->Reducer_ErrorValue.errorToString) + } + }) + let internalProject = project->Project.T.Private.castToInternalProject + test("direct past chain", () => { + expect(Project.getPastChain(project, "main")) == ["common", "common2"] + }) + test("include as variables", () => { + expect(Project.Private.getIncludesAsVariables(internalProject, "main")) == [ + ("myVariable", "myModule"), + ] + }) }) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res index d258d71a..bbed5633 100644 --- a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_test.res @@ -14,11 +14,9 @@ let runFetchResult = (project, sourceId) => { Project.getResult(project, sourceId)->InternalExpressionValue.toStringResult } -let runFetchBindings = (project, sourceId) => { +let runFetchFlatBindings = (project, sourceId) => { Project.run(project, sourceId) - Project.getBindings(project, sourceId) - ->InternalExpressionValue.IEvBindings - ->InternalExpressionValue.toString + Project.getBindings(project, sourceId)->InternalExpressionValue.toStringBindings } test("setting continuation", () => { @@ -51,7 +49,7 @@ test("test library", () => { test("test bindings", () => { let project = Project.createProject() Project.setSource(project, "variables", "myVariable=666") - runFetchBindings(project, "variables")->expect->toBe("@{myVariable: 666}") + runFetchFlatBindings(project, "variables")->expect->toBe("@{myVariable: 666}") }) describe("project1", () => { @@ -59,6 +57,7 @@ describe("project1", () => { Project.setSource(project, "first", "x=1") Project.setSource(project, "main", "x") Project.setContinues(project, "main", ["first"]) + let internalProject = project->Project.T.Private.castToInternalProject test("runOrder", () => { expect(Project.getRunOrder(project)) == ["first", "main"] @@ -75,11 +74,19 @@ describe("project1", () => { test("dependencies main", () => { expect(Project.getDependencies(project, "main")) == ["first"] }) + + test("past chain first", () => { + expect(Project.Private.getPastChain(internalProject, "first")) == [] + }) + test("past chain main", () => { + expect(Project.Private.getPastChain(internalProject, "main")) == ["first"] + }) + test("test result", () => { runFetchResult(project, "main")->expect->toBe("Ok(1)") }) test("test bindings", () => { - runFetchBindings(project, "main")->expect->toBe("@{x: 1}") + runFetchFlatBindings(project, "first")->expect->toBe("@{x: 1}") }) }) @@ -113,7 +120,7 @@ describe("project2", () => { runFetchResult(project, "main")->expect->toBe("Ok(2)") }) test("test bindings", () => { - runFetchBindings(project, "main")->expect->toBe("@{x: 1,y: 2}") + runFetchFlatBindings(project, "main")->expect->toBe("@{x: 1,y: 2}") }) }) @@ -169,6 +176,6 @@ describe("project with include", () => { runFetchResult(project, "main")->expect->toBe("Ok(2)") }) test("test bindings", () => { - runFetchBindings(project, "main")->expect->toBe("@{common: 0,x: 1,y: 2}") + runFetchFlatBindings(project, "main")->expect->toBe("@{common: 0,x: 1,y: 2}") }) }) diff --git a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_includes_test.res b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_includes_test.res index fda7126d..b10f1ef6 100644 --- a/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_includes_test.res +++ b/packages/squiggle-lang/__tests__/ReducerProject/ReducerProject_tutorial_3_includes_test.res @@ -153,4 +153,27 @@ Here we will finally proceed to a real life scenario. */ }) }) }) + + describe("Includes myFile as myVariable", () => { + /* Instead of including into global space you can also put a module into a record variable */ + let project = Project.createProject() + Project.setSource( + project, + "main", + ` + #include "common" as common + x=1 + `, + ) + Project.parseIncludes(project, "main") + test("getDependencies", () => { + Project.getDependencies(project, "main")->expect == ["common"] + }) + test("getIncludes", () => { + switch Project.getIncludes(project, "main") { + | Ok(includes) => includes->expect == ["common"] + | Error(err) => err->Reducer_ErrorValue.errorToString->fail + } + }) + }) }) diff --git a/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res b/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res index 27302313..18838899 100644 --- a/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res +++ b/packages/squiggle-lang/src/rescript/ForTS/ForTS_ReducerProject.res @@ -105,6 +105,11 @@ let getIncludes = (project: reducerProject, sourceId: string): result< reducerErrorValue, > => project->T.Private.castToInternalProject->Private.getIncludes(sourceId) +/* Other sources contributing to the global namespace of this source. */ +@genType +let getPastChain = (project: reducerProject, sourceId: string): array => + project->T.Private.castToInternalProject->Private.getPastChain(sourceId) + /* Answers the source codes after which this source code is continuing */ @@ -183,7 +188,7 @@ let runAll = (project: reducerProject): unit => project->T.Private.castToInternalProject->Private.runAll /* -Get the bindings after running this source file or the project +Get the bindings after running this source fil. The bindings are local to the source */ @genType let getBindings = (project: reducerProject, sourceId: string): squiggleValue_Module => diff --git a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res index 0f1c2037..b1127e05 100644 --- a/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res +++ b/packages/squiggle-lang/src/rescript/Reducer/Reducer_Bindings/Reducer_Bindings.res @@ -1,5 +1,5 @@ // Only Bindings as the global module is supported -// Other module operations such as import export will be prepreocessed jobs +// Other module operations such as import export will be preprocessed jobs module ExpressionT = Reducer_Expression_T module InternalExpressionValue = ReducerInterface_InternalExpressionValue @@ -13,8 +13,7 @@ type t = ReducerInterface_InternalExpressionValue.nameSpace let typeAliasesKey = "_typeAliases_" let typeReferencesKey = "_typeReferences_" -let getType = (nameSpace: t, id: string) => { - let NameSpace(container) = nameSpace +let getType = (NameSpace(container): t, id: string) => { Belt.Map.String.get(container, typeAliasesKey)->Belt.Option.flatMap(aliases => switch aliases { | IEvRecord(r) => Belt.Map.String.get(r, id) @@ -23,8 +22,7 @@ let getType = (nameSpace: t, id: string) => { ) } -let getTypeOf = (nameSpace: t, id: string) => { - let NameSpace(container) = nameSpace +let getTypeOf = (NameSpace(container): t, id: string) => { Belt.Map.String.get(container, typeReferencesKey)->Belt.Option.flatMap(defs => switch defs { | IEvRecord(r) => Belt.Map.String.get(r, id) @@ -33,44 +31,39 @@ let getTypeOf = (nameSpace: t, id: string) => { ) } -let getWithDefault = (nameSpace: t, id: string, default) => { - let NameSpace(container) = nameSpace - Belt.Map.String.getWithDefault(container, id, default) -} +let getWithDefault = (NameSpace(container): t, id: string, default) => + switch Belt.Map.String.get(container, id) { + | Some(v) => v + | None => default + } -let get = (nameSpace: t, id: string) => { - let NameSpace(container) = nameSpace - Belt.Map.String.get(container, id) -} +let get = (NameSpace(container): t, id: string) => Belt.Map.String.get(container, id) let emptyMap: map = Belt.Map.String.empty -let setTypeAlias = (nameSpace: t, id: string, value): t => { - let NameSpace(container) = nameSpace +let setTypeAlias = (NameSpace(container): t, id: string, value): t => { let rValue = Belt.Map.String.getWithDefault(container, typeAliasesKey, IEvRecord(emptyMap)) let r = switch rValue { | IEvRecord(r) => r | _ => emptyMap } let r2 = Belt.Map.String.set(r, id, value)->IEvRecord - Belt.Map.String.set(container, typeAliasesKey, r2)->NameSpace + NameSpace(Belt.Map.String.set(container, typeAliasesKey, r2)) } -let setTypeOf = (nameSpace: t, id: string, value): t => { - let NameSpace(container) = nameSpace +let setTypeOf = (NameSpace(container): t, id: string, value): t => { let rValue = Belt.Map.String.getWithDefault(container, typeReferencesKey, IEvRecord(emptyMap)) let r = switch rValue { | IEvRecord(r) => r | _ => emptyMap } let r2 = Belt.Map.String.set(r, id, value)->IEvRecord - Belt.Map.String.set(container, typeReferencesKey, r2)->NameSpace + NameSpace(Belt.Map.String.set(container, typeReferencesKey, r2)) } -let set = (nameSpace: t, id: string, value): t => { - let NameSpace(container) = nameSpace - Belt.Map.String.set(container, id, value)->NameSpace -} +let set = (NameSpace(container): t, id: string, value): t => NameSpace( + Belt.Map.String.set(container, id, value), +) let emptyModule: t = NameSpace(emptyMap) let emptyBindings = emptyModule @@ -86,29 +79,28 @@ let fromExpressionValue = (aValue: internalExpressionValue): t => | _ => emptyModule } -let fromArray = a => Belt.Map.String.fromArray(a)->NameSpace +let fromArray = a => NameSpace(Belt.Map.String.fromArray(a)) -let merge = (nameSpace: t, other: t): t => { - let NameSpace(container) = nameSpace - let NameSpace(otherContainer) = other - otherContainer - ->Belt.Map.String.reduce(container, (container, key, value) => - Belt.Map.String.set(container, key, value) +let mergeFrom = (NameSpace(container): t, NameSpace(newContainer): t): t => { + NameSpace( + newContainer->Belt.Map.String.reduce(container, (container, key, value) => + Belt.Map.String.set(container, key, value) + ), ) - ->NameSpace } -let removeOther = (nameSpace: t, other: t): t => { - let NameSpace(container) = nameSpace - let NameSpace(otherContainer) = other +let removeOther = (NameSpace(container): t, NameSpace(otherContainer): t): t => { let keys = Belt.Map.String.keysToArray(otherContainer) - Belt.Map.String.keep(container, (key, _value) => { - let removeThis = Js.Array2.includes(keys, key) - !removeThis - })->NameSpace + NameSpace( + Belt.Map.String.keep(container, (key, _value) => { + let removeThis = Js.Array2.includes(keys, key) + !removeThis + }), + ) } external castExpressionToInternalCode: ExpressionT.expressionOrFFI => internalCode = "%identity" + let eLambdaFFIValue = (ffiFn: ExpressionT.ffiFn) => { IEvLambda({ parameters: [], @@ -153,9 +145,8 @@ let convertOptionToFfiFn = ( } // -- Module definition -let define = (nameSpace: t, identifier: string, ev: internalExpressionValue): t => { - let NameSpace(container) = nameSpace - Belt.Map.String.set(container, identifier, ev)->NameSpace +let define = (NameSpace(container): t, identifier: string, ev: internalExpressionValue): t => { + NameSpace(Belt.Map.String.set(container, identifier, ev)) } let defineNumber = (nameSpace: t, identifier: string, value: float): t => @@ -186,3 +177,9 @@ let defineFunctionReturningResult = ( } let emptyStdLib: t = emptyModule->defineBool("_standardLibrary", true) + +let chainTo = (nameSpace: t, previousNameSpaces: array) => { + previousNameSpaces->Belt.Array.reduce(nameSpace, (topNameSpace, prevNameSpace) => + mergeFrom(prevNameSpace, topNameSpace) + ) +} diff --git a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res index af1c16c9..ac58532c 100644 --- a/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res +++ b/packages/squiggle-lang/src/rescript/ReducerInterface/ReducerInterface_Value/ReducerInterface_Value_Continuation.res @@ -21,8 +21,7 @@ let inspectOption = (oNameSpace, label: string) => } let minus = (NameSpace(thisContainer): t, NameSpace(thatContainer): t) => { - Belt.Map.String.removeMany( - thisContainer, - Belt.Map.String.keysToArray(thatContainer), - )->InternalExpressionValue.NameSpace + InternalExpressionValue.NameSpace( + Belt.Map.String.removeMany(thisContainer, Belt.Map.String.keysToArray(thatContainer)), + ) } diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res index 49571ff9..ccf81da3 100644 --- a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject.res @@ -83,6 +83,21 @@ module Private = { let getIncludes = (project: t, sourceId: string): ProjectItem.T.includesType => project->getItem(sourceId)->ProjectItem.getIncludes + // let getDirectIncludes = (project: t, sourceId: string): array => + // project->getItem(sourceId)->ProjectItem.getDirectIncludes + + let getPastChain = (project: t, sourceId: string): array => + project->getItem(sourceId)->ProjectItem.getPastChain + + let getIncludesAsVariables = ( + project: t, + sourceId: string, + ): ProjectItem.T.importAsVariablesType => + project->getItem(sourceId)->ProjectItem.getIncludesAsVariables + + let getDirectIncludes = (project: t, sourceId: string): array => + project->getItem(sourceId)->ProjectItem.getDirectIncludes + let setContinues = (project: t, sourceId: string, continues: array): unit => { let newItem = project->getItem(sourceId)->ProjectItem.setContinues(continues) Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) @@ -155,39 +170,63 @@ module Private = { environment: getEnvironment(project), } - let doRunWithContinuation = ( - project: t, - sourceId: string, - continuation: ProjectItem.T.continuation, - ): unit => { + let getContinuationsBefore = (project: t, sourceId: string): array< + ProjectItem.T.continuation, + > => { + let pastNameSpaces = project->getPastChain(sourceId)->Belt.Array.map(getBindings(project, _)) + let theLength = Belt.Array.length(pastNameSpaces) + if theLength == 0 { + // `getContinuationBefore ${sourceId}: stdLib`->Js.log + [project->getStdLib] + } else { + // `getContinuationBefore ${sourceId}: ${lastOne} = ${InternalExpressionValue.toStringBindings( + // project->getBindings(lastOne), + // )}`->Js.log + pastNameSpaces + } + } + + let linkDependencies = (project: t, sourceId: string): ProjectItem.T.continuation => { + module NameSpace = Reducer_Bindings + let continuationsBefore = project->getContinuationsBefore(sourceId) + let nameSpace = NameSpace.emptyNameSpace->NameSpace.chainTo(continuationsBefore) + let includesAsVariables = project->getIncludesAsVariables(sourceId) + Belt.Array.reduce(includesAsVariables, nameSpace, (currentNameSpace, (variable, includeFile)) => + Bindings.set( + currentNameSpace, + variable, + getBindings(project, includeFile)->InternalExpressionValue.IEvBindings, + ) + ) + } + + let doLinkAndRun = (project: t, sourceId: string): unit => { let accessors = buildProjectAccessors(project) let states = accessors.states + let continuation = linkDependencies(project, sourceId) let newItem = project->getItem(sourceId)->ProjectItem.run(continuation, accessors) Belt.Map.String.set(project["items"], sourceId, newItem)->T.Private.setFieldItems(project, _) setContinuation(project, sourceId, states.continuation) } - type runState = (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) + type runState = ProjectItem.T.resultArgumentType - let tryRunWithContinuation = ( + let tryRunWithResult = ( project: t, sourceId: string, - (rPrevResult: ProjectItem.T.resultArgumentType, continuation: ProjectItem.T.continuation), - ): (ProjectItem.T.resultArgumentType, ProjectItem.T.continuation) => { + rPrevResult: ProjectItem.T.resultArgumentType, + ): ProjectItem.T.resultArgumentType => { switch getResultOption(project, sourceId) { - | Some(result) => (result, getContinuation(project, sourceId)) // already ran + | Some(result) => result // already ran | None => switch rPrevResult { | Error(error) => { setResult(project, sourceId, Error(error)) - (Error(error), continuation) + Error(error) } | Ok(_prevResult) => { - doRunWithContinuation(project, sourceId, continuation) - ( - getResultOption(project, sourceId)->Belt.Option.getWithDefault(rPrevResult), - getContinuation(project, sourceId), - ) + doLinkAndRun(project, sourceId) + getResultOption(project, sourceId)->Belt.Option.getWithDefault(rPrevResult) } } } @@ -195,17 +234,17 @@ module Private = { let runAll = (project: t): unit => { let runOrder = Topology.getRunOrder(project) - let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project)) + let initialState = Ok(InternalExpressionValue.IEvVoid) let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) => - tryRunWithContinuation(project, currId, currState) + tryRunWithResult(project, currId, currState) ) } let run = (project: t, sourceId: string): unit => { let runOrder = Topology.getRunOrderFor(project, sourceId) - let initialState = (Ok(InternalExpressionValue.IEvVoid), getStdLib(project)) + let initialState = Ok(InternalExpressionValue.IEvVoid) let _finalState = Belt.Array.reduce(runOrder, initialState, (currState, currId) => - tryRunWithContinuation(project, currId, currState) + tryRunWithResult(project, currId, currState) ) } diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js index e04b8ba2..7f9c0418 100644 --- a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.js @@ -173,12 +173,14 @@ function peg$parse(input, options) { var peg$startRuleFunctions = { start: peg$parsestart }; var peg$startRuleFunction = peg$parsestart; - var peg$c0 = "#include"; - var peg$c1 = "'"; - var peg$c2 = "\""; - var peg$c3 = "//"; - var peg$c4 = "/*"; - var peg$c5 = "*/"; + var peg$c0 = "#"; + var peg$c1 = "#include"; + var peg$c2 = "as"; + var peg$c3 = "'"; + var peg$c4 = "\""; + var peg$c5 = "//"; + var peg$c6 = "/*"; + var peg$c7 = "*/"; var peg$r0 = /^[^']/; var peg$r1 = /^[^"]/; @@ -186,29 +188,40 @@ function peg$parse(input, options) { var peg$r3 = /^[ \t]/; var peg$r4 = /^[\n\r]/; var peg$r5 = /^[^\r\n]/; + var peg$r6 = /^[_a-z]/; + var peg$r7 = /^[_a-z0-9]/i; - var peg$e0 = peg$literalExpectation("#include", false); - var peg$e1 = peg$otherExpectation("string"); - var peg$e2 = peg$literalExpectation("'", false); - var peg$e3 = peg$classExpectation(["'"], true, false); - var peg$e4 = peg$literalExpectation("\"", false); - var peg$e5 = peg$classExpectation(["\""], true, false); - var peg$e6 = peg$literalExpectation("//", false); - var peg$e7 = peg$literalExpectation("/*", false); - var peg$e8 = peg$classExpectation(["*"], true, false); - var peg$e9 = peg$literalExpectation("*/", false); - var peg$e10 = peg$otherExpectation("white space"); - var peg$e11 = peg$classExpectation([" ", "\t"], false, false); - var peg$e12 = peg$otherExpectation("newline"); - var peg$e13 = peg$classExpectation(["\n", "\r"], false, false); - var peg$e14 = peg$classExpectation(["\r", "\n"], true, false); + var peg$e0 = peg$literalExpectation("#", false); + var peg$e1 = peg$literalExpectation("#include", false); + var peg$e2 = peg$literalExpectation("as", false); + var peg$e3 = peg$otherExpectation("string"); + var peg$e4 = peg$literalExpectation("'", false); + var peg$e5 = peg$classExpectation(["'"], true, false); + var peg$e6 = peg$literalExpectation("\"", false); + var peg$e7 = peg$classExpectation(["\""], true, false); + var peg$e8 = peg$otherExpectation("comment"); + var peg$e9 = peg$literalExpectation("//", false); + var peg$e10 = peg$literalExpectation("/*", false); + var peg$e11 = peg$classExpectation(["*"], true, false); + var peg$e12 = peg$literalExpectation("*/", false); + var peg$e13 = peg$otherExpectation("white space"); + var peg$e14 = peg$classExpectation([" ", "\t"], false, false); + var peg$e15 = peg$otherExpectation("newline"); + var peg$e16 = peg$classExpectation(["\n", "\r"], false, false); + var peg$e17 = peg$otherExpectation("code"); + var peg$e18 = peg$classExpectation(["\r", "\n"], true, false); + var peg$e19 = peg$otherExpectation("identifier"); + var peg$e20 = peg$classExpectation(["_", ["a", "z"]], false, false); + var peg$e21 = peg$classExpectation(["_", ["a", "z"], ["0", "9"]], false, true); var peg$f0 = function(head, tail) {return [head, ...tail].filter( e => e != '');}; var peg$f1 = function() {return [];}; - var peg$f2 = function(characters) {return characters.join('');}; + var peg$f2 = function(file, variable) {return [!variable ? '' : variable, file]}; var peg$f3 = function(characters) {return characters.join('');}; - var peg$f4 = function() { return '';}; + var peg$f4 = function(characters) {return characters.join('');}; var peg$f5 = function() { return '';}; + var peg$f6 = function() { return '';}; + var peg$f7 = function() {return text();}; var peg$currPos = 0; var peg$savedPos = 0; var peg$posDetailsCache = [{ line: 1, column: 1 }]; @@ -369,7 +382,7 @@ function peg$parse(input, options) { function peg$parsestart() { var s0, s1, s2, s3, s4; - var key = peg$currPos * 10 + 0; + var key = peg$currPos * 12 + 0; var cached = peg$resultsCache[key]; if (cached) { @@ -426,7 +439,7 @@ function peg$parse(input, options) { function peg$parseincludes() { var s0, s1, s2, s3, s4, s5; - var key = peg$currPos * 10 + 1; + var key = peg$currPos * 12 + 1; var cached = peg$resultsCache[key]; if (cached) { @@ -436,7 +449,7 @@ function peg$parse(input, options) { } s0 = peg$currPos; - s1 = peg$parseincludeStatement(); + s1 = peg$parsedependencyStatement(); if (s1 !== peg$FAILED) { s2 = []; s3 = peg$currPos; @@ -451,7 +464,7 @@ function peg$parse(input, options) { s4 = peg$FAILED; } if (s4 !== peg$FAILED) { - s5 = peg$parseincludeStatement(); + s5 = peg$parsedependencyStatement(); if (s5 !== peg$FAILED) { s3 = s5; } else { @@ -476,7 +489,7 @@ function peg$parse(input, options) { s4 = peg$FAILED; } if (s4 !== peg$FAILED) { - s5 = peg$parseincludeStatement(); + s5 = peg$parsedependencyStatement(); if (s5 !== peg$FAILED) { s3 = s5; } else { @@ -496,9 +509,26 @@ function peg$parse(input, options) { } if (s0 === peg$FAILED) { s0 = peg$currPos; - s1 = peg$parseignore(); - peg$savedPos = s0; - s1 = peg$f1(); + s1 = peg$currPos; + peg$silentFails++; + if (input.charCodeAt(peg$currPos) === 35) { + s2 = peg$c0; + peg$currPos++; + } else { + s2 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e0); } + } + peg$silentFails--; + if (s2 === peg$FAILED) { + s1 = undefined; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f1(); + } s0 = s1; } @@ -507,10 +537,35 @@ function peg$parse(input, options) { return s0; } - function peg$parseincludeStatement() { - var s0, s1, s2, s3, s4, s5, s6; + function peg$parsedependencyStatement() { + var s0; - var key = peg$currPos * 10 + 2; + var key = peg$currPos * 12 + 2; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + s0 = peg$parseincludeStatement(); + if (s0 === peg$FAILED) { + s0 = peg$parsecomment(); + if (s0 === peg$FAILED) { + s0 = peg$parsedelimitedComment(); + } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseincludeStatement() { + var s0, s1, s2, s3, s4, s5, s6, s7, s8, s9; + + var key = peg$currPos * 12 + 3; var cached = peg$resultsCache[key]; if (cached) { @@ -526,29 +581,107 @@ function peg$parse(input, options) { s1.push(s2); s2 = peg$parse_(); } - if (input.substr(peg$currPos, 8) === peg$c0) { - s2 = peg$c0; + if (input.substr(peg$currPos, 8) === peg$c1) { + s2 = peg$c1; peg$currPos += 8; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e0); } + if (peg$silentFails === 0) { peg$fail(peg$e1); } } if (s2 !== peg$FAILED) { s3 = []; s4 = peg$parse_(); - while (s4 !== peg$FAILED) { - s3.push(s4); - s4 = peg$parse_(); - } - s4 = peg$parsestring(); if (s4 !== peg$FAILED) { - s5 = []; - s6 = peg$parse_(); - while (s6 !== peg$FAILED) { - s5.push(s6); - s6 = peg$parse_(); + while (s4 !== peg$FAILED) { + s3.push(s4); + s4 = peg$parse_(); + } + } else { + s3 = peg$FAILED; + } + if (s3 !== peg$FAILED) { + s4 = peg$parsestring(); + if (s4 !== peg$FAILED) { + s5 = peg$currPos; + s6 = []; + s7 = peg$parse_(); + if (s7 !== peg$FAILED) { + while (s7 !== peg$FAILED) { + s6.push(s7); + s7 = peg$parse_(); + } + } else { + s6 = peg$FAILED; + } + if (s6 !== peg$FAILED) { + if (input.substr(peg$currPos, 2) === peg$c2) { + s7 = peg$c2; + peg$currPos += 2; + } else { + s7 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e2); } + } + if (s7 !== peg$FAILED) { + s8 = []; + s9 = peg$parse_(); + if (s9 !== peg$FAILED) { + while (s9 !== peg$FAILED) { + s8.push(s9); + s9 = peg$parse_(); + } + } else { + s8 = peg$FAILED; + } + if (s8 !== peg$FAILED) { + s9 = peg$parseidentifier(); + if (s9 !== peg$FAILED) { + s5 = s9; + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + } else { + peg$currPos = s5; + s5 = peg$FAILED; + } + if (s5 === peg$FAILED) { + s5 = null; + } + s6 = []; + s7 = peg$parse_(); + while (s7 !== peg$FAILED) { + s6.push(s7); + s7 = peg$parse_(); + } + s7 = peg$currPos; + peg$silentFails++; + s8 = peg$parsenewLine(); + peg$silentFails--; + if (s8 !== peg$FAILED) { + peg$currPos = s7; + s7 = undefined; + } else { + s7 = peg$FAILED; + } + if (s7 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f2(s4, s5); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; } - s0 = s4; } else { peg$currPos = s0; s0 = peg$FAILED; @@ -557,12 +690,6 @@ function peg$parse(input, options) { peg$currPos = s0; s0 = peg$FAILED; } - if (s0 === peg$FAILED) { - s0 = peg$parsecomment(); - if (s0 === peg$FAILED) { - s0 = peg$parsedelimitedComment(); - } - } peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; @@ -572,7 +699,7 @@ function peg$parse(input, options) { function peg$parsestring() { var s0, s1, s2, s3, s4; - var key = peg$currPos * 10 + 3; + var key = peg$currPos * 12 + 4; var cached = peg$resultsCache[key]; if (cached) { @@ -585,11 +712,11 @@ function peg$parse(input, options) { s0 = peg$currPos; s1 = peg$currPos; if (input.charCodeAt(peg$currPos) === 39) { - s2 = peg$c1; + s2 = peg$c3; peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e2); } + if (peg$silentFails === 0) { peg$fail(peg$e4); } } if (s2 !== peg$FAILED) { s3 = []; @@ -598,7 +725,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e3); } + if (peg$silentFails === 0) { peg$fail(peg$e5); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -607,15 +734,15 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e3); } + if (peg$silentFails === 0) { peg$fail(peg$e5); } } } if (input.charCodeAt(peg$currPos) === 39) { - s4 = peg$c1; + s4 = peg$c3; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e2); } + if (peg$silentFails === 0) { peg$fail(peg$e4); } } if (s4 !== peg$FAILED) { s1 = s3; @@ -629,18 +756,18 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f2(s1); + s1 = peg$f3(s1); } s0 = s1; if (s0 === peg$FAILED) { s0 = peg$currPos; s1 = peg$currPos; if (input.charCodeAt(peg$currPos) === 34) { - s2 = peg$c2; + s2 = peg$c4; peg$currPos++; } else { s2 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e4); } + if (peg$silentFails === 0) { peg$fail(peg$e6); } } if (s2 !== peg$FAILED) { s3 = []; @@ -649,7 +776,7 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e5); } + if (peg$silentFails === 0) { peg$fail(peg$e7); } } while (s4 !== peg$FAILED) { s3.push(s4); @@ -658,15 +785,15 @@ function peg$parse(input, options) { peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e5); } + if (peg$silentFails === 0) { peg$fail(peg$e7); } } } if (input.charCodeAt(peg$currPos) === 34) { - s4 = peg$c2; + s4 = peg$c4; peg$currPos++; } else { s4 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e4); } + if (peg$silentFails === 0) { peg$fail(peg$e6); } } if (s4 !== peg$FAILED) { s1 = s3; @@ -680,14 +807,14 @@ function peg$parse(input, options) { } if (s1 !== peg$FAILED) { peg$savedPos = s0; - s1 = peg$f3(s1); + s1 = peg$f4(s1); } s0 = s1; } peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e1); } + if (peg$silentFails === 0) { peg$fail(peg$e3); } } peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; @@ -698,7 +825,7 @@ function peg$parse(input, options) { function peg$parseignore() { var s0, s1; - var key = peg$currPos * 10 + 4; + var key = peg$currPos * 12 + 5; var cached = peg$resultsCache[key]; if (cached) { @@ -732,9 +859,9 @@ function peg$parse(input, options) { } function peg$parsecomment() { - var s0, s1, s2, s3; + var s0, s1, s2, s3, s4; - var key = peg$currPos * 10 + 5; + var key = peg$currPos * 12 + 6; var cached = peg$resultsCache[key]; if (cached) { @@ -743,13 +870,14 @@ function peg$parse(input, options) { return cached.result; } + peg$silentFails++; s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c3) { - s1 = peg$c3; + if (input.substr(peg$currPos, 2) === peg$c5) { + s1 = peg$c5; peg$currPos += 2; } else { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e6); } + if (peg$silentFails === 0) { peg$fail(peg$e9); } } if (s1 !== peg$FAILED) { s2 = []; @@ -758,63 +886,15 @@ function peg$parse(input, options) { s2.push(s3); s3 = peg$parseany(); } - peg$savedPos = s0; - s0 = peg$f4(); - } else { - peg$currPos = s0; - s0 = peg$FAILED; - } - - peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; - - return s0; - } - - function peg$parsedelimitedComment() { - var s0, s1, s2, s3; - - var key = peg$currPos * 10 + 6; - var cached = peg$resultsCache[key]; - - if (cached) { - peg$currPos = cached.nextPos; - - return cached.result; - } - - s0 = peg$currPos; - if (input.substr(peg$currPos, 2) === peg$c4) { - s1 = peg$c4; - peg$currPos += 2; - } else { - s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e7); } - } - if (s1 !== peg$FAILED) { - s2 = []; - if (peg$r2.test(input.charAt(peg$currPos))) { - s3 = input.charAt(peg$currPos); - peg$currPos++; + s3 = peg$currPos; + peg$silentFails++; + s4 = peg$parsenewLine(); + peg$silentFails--; + if (s4 !== peg$FAILED) { + peg$currPos = s3; + s3 = undefined; } else { s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } - } - while (s3 !== peg$FAILED) { - s2.push(s3); - if (peg$r2.test(input.charAt(peg$currPos))) { - s3 = input.charAt(peg$currPos); - peg$currPos++; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e8); } - } - } - if (input.substr(peg$currPos, 2) === peg$c5) { - s3 = peg$c5; - peg$currPos += 2; - } else { - s3 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e9); } } if (s3 !== peg$FAILED) { peg$savedPos = s0; @@ -827,6 +907,80 @@ function peg$parse(input, options) { peg$currPos = s0; s0 = peg$FAILED; } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e8); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parsedelimitedComment() { + var s0, s1, s2, s3; + + var key = peg$currPos * 12 + 7; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + if (input.substr(peg$currPos, 2) === peg$c6) { + s1 = peg$c6; + peg$currPos += 2; + } else { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e10); } + } + if (s1 !== peg$FAILED) { + s2 = []; + if (peg$r2.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e11); } + } + while (s3 !== peg$FAILED) { + s2.push(s3); + if (peg$r2.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e11); } + } + } + if (input.substr(peg$currPos, 2) === peg$c7) { + s3 = peg$c7; + peg$currPos += 2; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e12); } + } + if (s3 !== peg$FAILED) { + peg$savedPos = s0; + s0 = peg$f6(); + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + } else { + peg$currPos = s0; + s0 = peg$FAILED; + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e8); } + } peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; @@ -836,7 +990,7 @@ function peg$parse(input, options) { function peg$parse_() { var s0, s1; - var key = peg$currPos * 10 + 7; + var key = peg$currPos * 12 + 8; var cached = peg$resultsCache[key]; if (cached) { @@ -851,12 +1005,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e11); } + if (peg$silentFails === 0) { peg$fail(peg$e14); } } peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e10); } + if (peg$silentFails === 0) { peg$fail(peg$e13); } } peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; @@ -867,7 +1021,7 @@ function peg$parse(input, options) { function peg$parsenewLine() { var s0, s1; - var key = peg$currPos * 10 + 8; + var key = peg$currPos * 12 + 9; var cached = peg$resultsCache[key]; if (cached) { @@ -882,12 +1036,12 @@ function peg$parse(input, options) { peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e13); } + if (peg$silentFails === 0) { peg$fail(peg$e16); } } peg$silentFails--; if (s0 === peg$FAILED) { s1 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e12); } + if (peg$silentFails === 0) { peg$fail(peg$e15); } } peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; @@ -896,9 +1050,9 @@ function peg$parse(input, options) { } function peg$parseany() { - var s0; + var s0, s1; - var key = peg$currPos * 10 + 9; + var key = peg$currPos * 12 + 10; var cached = peg$resultsCache[key]; if (cached) { @@ -907,12 +1061,96 @@ function peg$parse(input, options) { return cached.result; } + peg$silentFails++; if (peg$r5.test(input.charAt(peg$currPos))) { s0 = input.charAt(peg$currPos); peg$currPos++; } else { s0 = peg$FAILED; - if (peg$silentFails === 0) { peg$fail(peg$e14); } + if (peg$silentFails === 0) { peg$fail(peg$e18); } + } + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e17); } + } + + peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; + + return s0; + } + + function peg$parseidentifier() { + var s0, s1, s2, s3, s4; + + var key = peg$currPos * 12 + 11; + var cached = peg$resultsCache[key]; + + if (cached) { + peg$currPos = cached.nextPos; + + return cached.result; + } + + peg$silentFails++; + s0 = peg$currPos; + s1 = peg$currPos; + s2 = []; + if (peg$r6.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e20); } + } + if (s3 !== peg$FAILED) { + while (s3 !== peg$FAILED) { + s2.push(s3); + if (peg$r6.test(input.charAt(peg$currPos))) { + s3 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s3 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e20); } + } + } + } else { + s2 = peg$FAILED; + } + if (s2 !== peg$FAILED) { + s3 = []; + if (peg$r7.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e21); } + } + while (s4 !== peg$FAILED) { + s3.push(s4); + if (peg$r7.test(input.charAt(peg$currPos))) { + s4 = input.charAt(peg$currPos); + peg$currPos++; + } else { + s4 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e21); } + } + } + s2 = [s2, s3]; + s1 = s2; + } else { + peg$currPos = s1; + s1 = peg$FAILED; + } + if (s1 !== peg$FAILED) { + peg$savedPos = s0; + s1 = peg$f7(); + } + s0 = s1; + peg$silentFails--; + if (s0 === peg$FAILED) { + s1 = peg$FAILED; + if (peg$silentFails === 0) { peg$fail(peg$e19); } } peg$resultsCache[key] = { nextPos: peg$currPos, result: s0 }; diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy index dc65fac4..c96f6ddb 100644 --- a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_IncludeParser.peggy @@ -1,33 +1,37 @@ // Includes are at the start of the file, before any other code. // There might be some comments before or between the includes. // #include "string" -// #include "string2" +// #include "string2" as aVariable start = (newLine/_/comment/delimitedComment)* @includes newLine* ignore includes - = head:includeStatement tail:(newLine+ @includeStatement)* + = head:dependencyStatement tail:(newLine+ @dependencyStatement)* {return [head, ...tail].filter( e => e != '');} - / ignore + / ! '#' {return [];} -includeStatement - = _* '#include' _* @string _* +dependencyStatement + = includeStatement / comment / delimitedComment +includeStatement + = _* '#include' _+ file:string variable:(_+ 'as' _+ @identifier)? _* & newLine + {return [!variable ? '' : variable, file]} + string 'string' = characters:("'" @([^'])* "'") {return characters.join('');} / characters:('"' @([^"])* '"') {return characters.join('');} ignore = (any / newLine / _)* -comment -= '//'any* +comment 'comment' += '//'any* & newLine { return '';} -delimitedComment +delimitedComment 'comment' = '/*' ([^*]*) '*/' { return '';} @@ -37,4 +41,8 @@ _ "white space" newLine "newline" = [\n\r] -any = [^\r\n] +any 'code' + = [^\r\n] + +identifier 'identifier' + = ([_a-z]+[_a-z0-9]i*) {return text();} diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res index f6b17901..38370488 100644 --- a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ParseIncludes.res @@ -1,11 +1,15 @@ -@module("./ReducerProject_IncludeParser.js") external parse__: string => array = "parse" +@module("./ReducerProject_IncludeParser.js") +external parse__: string => array> = "parse" -let parseIncludes = (expr: string): result, Reducer_ErrorValue.errorValue> => +let parseIncludes = (expr: string): result< + array<(string, string)>, + Reducer_ErrorValue.errorValue, +> => try { let answer = parse__(expr) // let logEntry = answer->Js.Array2.joinWith(",") // `parseIncludes: ${logEntry} for expr: ${expr}`->Js.log - answer->Ok + Belt.Array.map(answer, item => (item[0], item[1]))->Ok } catch { | Js.Exn.Error(obj) => RESyntaxError( diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res index 2608e344..8eb915de 100644 --- a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem.res @@ -19,6 +19,8 @@ let emptyItem = T.ProjectItem({ result: None, continues: [], includes: []->Ok, + directIncludes: [], + includeAsVariables: [], }) // source -> rawParse -> includes -> expression -> continuation -> result @@ -30,40 +32,59 @@ let getResult = (T.ProjectItem(r)): T.resultType => r.result let getContinues = (T.ProjectItem(r)): T.continuesType => r.continues let getIncludes = (T.ProjectItem(r)): T.includesType => r.includes +let getDirectIncludes = (T.ProjectItem(r)): array => r.directIncludes +let getIncludesAsVariables = (T.ProjectItem(r)): T.importAsVariablesType => r.includeAsVariables let touchSource = (this: t): t => { let T.ProjectItem(r) = emptyItem T.ProjectItem({ ...r, - includes: getIncludes(this), - continues: getContinues(this), source: getSource(this), + continues: getContinues(this), + includes: getIncludes(this), + includeAsVariables: getIncludesAsVariables(this), + directIncludes: getDirectIncludes(this), }) } + let touchRawParse = (this: t): t => { let T.ProjectItem(r) = emptyItem T.ProjectItem({ ...r, - continues: getContinues(this), source: getSource(this), - rawParse: getRawParse(this), + continues: getContinues(this), includes: getIncludes(this), + includeAsVariables: getIncludesAsVariables(this), + directIncludes: getDirectIncludes(this), + rawParse: getRawParse(this), }) } + let touchExpression = (this: t): t => { let T.ProjectItem(r) = emptyItem T.ProjectItem({ ...r, - continues: getContinues(this), source: getSource(this), - rawParse: getRawParse(this), + continues: getContinues(this), includes: getIncludes(this), + includeAsVariables: getIncludesAsVariables(this), + directIncludes: getDirectIncludes(this), + rawParse: getRawParse(this), expression: getExpression(this), }) } +let resetIncludes = (T.ProjectItem(r): t): t => { + T.ProjectItem({ + ...r, + includes: []->Ok, + includeAsVariables: [], + directIncludes: [], + }) +} + let setSource = (T.ProjectItem(r): t, source: T.sourceArgumentType): t => - T.ProjectItem({...r, source: source})->touchSource + T.ProjectItem({...r, source: source})->resetIncludes->touchSource let setRawParse = (T.ProjectItem(r): t, rawParse: T.rawParseArgumentType): t => T.ProjectItem({...r, rawParse: Some(rawParse)})->touchRawParse @@ -95,6 +116,10 @@ let clean = (this: t): t => { let getImmediateDependencies = (this: t): T.includesType => getIncludes(this)->Belt.Result.map(Js.Array2.concat(_, getContinues(this))) +let getPastChain = (this: t): array => { + Js.Array2.concat(getDirectIncludes(this), getContinues(this)) +} + let setContinues = (T.ProjectItem(r): t, continues: array): t => T.ProjectItem({...r, continues: continues})->touchSource let removeContinues = (T.ProjectItem(r): t): t => T.ProjectItem({...r, continues: []})->touchSource @@ -104,10 +129,38 @@ let setIncludes = (T.ProjectItem(r): t, includes: T.includesType): t => T.Projec includes: includes, }) -//TODO: forward parse errors to the user -let parseIncludes = (this: t): t => - setIncludes(this, getSource(this)->ReducerProject_ParseIncludes.parseIncludes) +let setImportAsVariables = ( + T.ProjectItem(r): t, + includeAsVariables: T.importAsVariablesType, +): t => T.ProjectItem({...r, includeAsVariables: includeAsVariables}) +let setDirectImports = (T.ProjectItem(r): t, directIncludes: array): t => T.ProjectItem({ + ...r, + directIncludes: directIncludes, +}) + +let parseIncludes = (this: t): t => { + let T.ProjectItem(r) = this + let rRawImportAsVariables = getSource(this)->ReducerProject_ParseIncludes.parseIncludes + switch rRawImportAsVariables { + | Error(e) => resetIncludes(this)->setIncludes(Error(e)) + | Ok(rawImportAsVariables) => { + let includes = rawImportAsVariables->Belt.Array.map(((_variable, file)) => file)->Ok + let includeAsVariables = + rawImportAsVariables->Belt.Array.keep(((variable, _file)) => variable != "") + let directIncludes = + rawImportAsVariables + ->Belt.Array.keep(((variable, _file)) => variable == "") + ->Belt.Array.map(((_variable, file)) => file) + T.ProjectItem({ + ...r, + includes: includes, + includeAsVariables: includeAsVariables, + directIncludes: directIncludes, + }) + } + } +} let doRawParse = (this: t): T.rawParseArgumentType => this->getSource->Reducer_Peggy_Parse.parse let rawParse = (this: t): t => diff --git a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res index 6fe251d2..caa80da4 100644 --- a/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res +++ b/packages/squiggle-lang/src/rescript/ReducerProject/ReducerProject_ProjectItem_T.res @@ -21,6 +21,7 @@ type continuesArgumentType = array type continuesType = array type includesArgumentType = string type includesType = result, errorValue> +type importAsVariablesType = array<(string, string)> type projectItem = | ProjectItem({ @@ -30,7 +31,9 @@ type projectItem = continuation: continuationArgumentType, result: resultType, continues: continuesType, - includes: includesType, - }) + includes: includesType, //For loader + includeAsVariables: importAsVariablesType, //For linker + directIncludes: array, + }) //For linker type t = projectItem diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res index ce74f476..14668a52 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Math.res @@ -19,4 +19,4 @@ let mathBindings: Bindings.t = ->Bindings.fromArray let makeBindings = (previousBindings: Bindings.t): Bindings.t => - previousBindings->Bindings.merge(mathBindings) + previousBindings->Bindings.mergeFrom(mathBindings) diff --git a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Versions.res b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Versions.res index 91e9959c..03f23bcb 100644 --- a/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Versions.res +++ b/packages/squiggle-lang/src/rescript/SquiggleLibrary/SquiggleLibrary_Versions.res @@ -6,4 +6,4 @@ let bindings: Bindings.t = ]->Bindings.fromArray let makeBindings = (previousBindings: Bindings.t): Bindings.t => - previousBindings->Bindings.merge(bindings) + previousBindings->Bindings.mergeFrom(bindings)