Compare commits

...

9 Commits

Author SHA1 Message Date
Sam Nolan
e8aa541fc9 Fix review comments 2022-10-12 12:17:38 +11:00
Sam Nolan
fb5fd8edf8 Merge branch 'develop' into project-serialization 2022-10-11 12:44:36 +11:00
Sam Nolan
534b7a45d3 Merge branch 'develop' into project-serialization 2022-10-08 14:49:21 +11:00
Sam Nolan
17cc2a42cc Fix project serialization not returning class 2022-10-08 14:46:24 +11:00
Sam Nolan
de73a98735 Remove unneccesary genType 2022-10-07 10:53:52 +11:00
Sam Nolan
5076427d03 Fix genType annotations 2022-09-30 12:18:07 +10:00
Sam Nolan
7829efab25 Merge branch 'epic-0.5.0' into project-serialization 2022-09-30 11:53:19 +10:00
Sam Nolan
565694ea00 Merge branch 'epic-0.5.0' into project-serialization 2022-09-30 10:24:58 +10:00
Sam Nolan
f489d0bcfe Add project serialization and run project 2022-09-28 14:14:35 +10:00
8 changed files with 164 additions and 16 deletions

View File

@ -199,3 +199,42 @@ describe("project with independent sources", () => {
expect(Project.getRunOrderFor(project, "second")) == ["second"] expect(Project.getRunOrderFor(project, "second")) == ["second"]
}) })
}) })
describe("project serialization", () => {
let project = Project.createProject()
Project.setSource(project, "first", "x = 1")
Project.setSource(project, "second", "y = 1")
Project.setSource(project, "main", "x + y")
Project.setContinues(project, "main", ["first", "second"])
let expectedJson: Project.reducerProjectJson = {
environment: {
sampleCount: 10000,
xyPointLength: 1000,
},
items: [
{
continues: [],
id: "first",
source: "x = 1",
},
{
continues: ["first", "second"],
id: "main",
source: "x + y",
},
{
continues: [],
id: "second",
source: "y = 1",
},
],
}
test("serializes correctly", () => {
expect(Project.toJson(project)) == expectedJson
})
test("serializes reflexive", () => {
expect(Project.toJson(Project.fromJson(Project.toJson(project)))) == Project.toJson(project)
})
})

View File

@ -22,20 +22,28 @@ export const run = (src, { output, sampleCount } = {}) => {
}); });
} }
project.setSource("main", src); project.setSource("main", src);
const time = measure(() => project.run("main")); runProject(project, output);
};
const bindings = project.getBindings("main");
const result = project.getResult("main"); export const runProject = (project, { output }) => {
const time = measure(() => project.runAll());
if (output) { console.log("Time: ", time);
console.log("Result:", result.tag, result.value.toString());
console.log("Bindings:", bindings.toString()); const ids = project.getSourceIds();
}
ids.forEach((id) => {
console.log( const result = project.getResult(id);
"Time:", const bindings = project.getBindings(id);
String(time),
result.tag === "Error" ? red(result.tag) : green(result.tag), console.log(id + ":");
result.tag === "Error" ? result.value.toStringWithFrameStack() : "" if (output) {
); console.log("Result:", result.tag, result.value.toString());
console.log("Bindings:", bindings.toString());
}
console.log(
result.tag === "Error" ? red(result.tag) : green(result.tag),
result.tag === "Error" ? result.value.toString() : ""
);
});
}; };

View File

@ -0,0 +1,28 @@
#!/usr/bin/env node
import fs from "fs";
import { Command } from "commander";
import { SqProject } from "@quri/squiggle-lang";
import { runProject } from "./lib.mjs";
const program = new Command();
program.option("-o, --output");
program.arguments("<string>");
const options = program.parse(process.argv);
const sampleCount = process.env.SAMPLE_COUNT;
console.log(sampleCount);
const src = fs.readFileSync(program.args[0], "utf-8");
if (!src) {
throw new Error("Expected src");
}
const projectJson = JSON.parse(src);
const project = SqProject.fromJson(projectJson);
runProject(project, options);

View File

@ -119,4 +119,12 @@ export class SqProject {
getEnvironment(): environment { getEnvironment(): environment {
return RSProject.getEnvironment(this._value); return RSProject.getEnvironment(this._value);
} }
toJSON(): RSProject.reducerProjectJson {
return RSProject.toJson(this._value);
}
static fromJson(projectJson: RSProject.reducerProjectJson): SqProject {
return new SqProject(RSProject.fromJson(projectJson));
}
} }

View File

@ -1,4 +1,5 @@
@genType type reducerProject = ReducerProject_T.project //re-export @genType type reducerProject = ReducerProject_T.project //re-export
@genType type reducerProjectJson = ReducerProject_T.projectJson //re-export
type error = SqError.t //use type error = SqError.t //use
type errorMessage = SqError.Message.t //use type errorMessage = SqError.Message.t //use
@ -215,3 +216,30 @@ let setEnvironment = (project: reducerProject, environment: environment): unit =
@genType @genType
let getEnvironment = (project: reducerProject): environment => project->Private.getEnvironment let getEnvironment = (project: reducerProject): environment => project->Private.getEnvironment
@genType
let toJson = (project: reducerProject): reducerProjectJson => project->Private.toJson
@genType
let fromJson = (project: reducerProjectJson): reducerProject => project->Private.fromJson
/*
Foreign function interface is intentionally demolished.
There is another way to do that: Umur.
Also there is no more conversion from javascript to squiggle values currently.
If the conversion to the new project is too difficult, I can add it later.
*/
// let foreignFunctionInterface = (
// lambdaValue: squiggleValue_Lambda,
// argArray: array<squiggleValue>,
// environment: environment,
// ): result<squiggleValue, reducerErrorValue> => {
// let accessors = ReducerProject_ProjectAccessors_T.identityAccessorsWithEnvironment(environment)
// Reducer_Expression_Lambda.foreignFunctionInterface(
// lambdaValue,
// argArray,
// accessors,
// Reducer_Expression.reduceExpressionInProject,
// )
// }

View File

@ -1,3 +1,4 @@
@genType
type environment = GenericDist.env type environment = GenericDist.env
@genType.opaque @genType.opaque

View File

@ -150,6 +150,28 @@ let setEnvironment = (project: t, value: Reducer_T.environment): unit => {
project.environment = value project.environment = value
} }
let toJson = (project: t): T.projectJson => {
items: Belt.Array.map(Belt.MutableMap.String.toArray(project.items), ((id, projectItem)) => {
let projectItem: T.projectItemJson = {
id: id,
source: ProjectItem.getSource(projectItem),
continues: ProjectItem.getContinues(projectItem),
}
projectItem
}),
environment: getEnvironment(project),
}
let fromJson = (json: T.projectJson): t => {
let project = createProject()
setEnvironment(project, json.environment)
Belt.Array.forEach(json.items, item => {
setSource(project, item.id, item.source)
setContinues(project, item.id, item.continues)
})
project
}
let getBindings = (project: t, sourceId: string): Reducer_T.namespace => { let getBindings = (project: t, sourceId: string): Reducer_T.namespace => {
project->getItem(sourceId)->ProjectItem.getContinuation project->getItem(sourceId)->ProjectItem.getContinuation
} }

View File

@ -7,8 +7,22 @@ type project = {
mutable environment: Reducer_T.environment, mutable environment: Reducer_T.environment,
mutable previousRunOrder: array<string>, mutable previousRunOrder: array<string>,
} }
type t = project type t = project
@genType
type projectItemJson = {
id: string,
source: string,
continues: array<string>,
}
@genType
type projectJson = {
items: array<projectItemJson>,
environment: Reducer_T.environment,
}
// these functions are used in ReducerProject_Topology, so they are defined here to avoid circular dependencies // these functions are used in ReducerProject_Topology, so they are defined here to avoid circular dependencies
let getSourceIds = (project: t): array<string> => Belt.MutableMap.String.keysToArray(project.items) let getSourceIds = (project: t): array<string> => Belt.MutableMap.String.keysToArray(project.items)