From 8fbc09362277a4994971daefa9c8675f3221ec7d Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sun, 1 May 2022 07:04:45 -0700 Subject: [PATCH 01/10] new codegen type: json (emits the AST) --- Cargo.lock | 75 +++++++++++++++++++ crates/percival-cli/src/main.rs | 24 +++++- crates/percival-wasm/src/lib.rs | 2 +- crates/percival/Cargo.toml | 3 + crates/percival/src/ast.rs | 26 +++++-- .../src/{codegen.rs => codegen_js.rs} | 0 crates/percival/src/codegen_json.rs | 10 +++ crates/percival/src/lib.rs | 3 +- 8 files changed, 130 insertions(+), 13 deletions(-) rename crates/percival/src/{codegen.rs => codegen_js.rs} (100%) create mode 100644 crates/percival/src/codegen_json.rs diff --git a/Cargo.lock b/Cargo.lock index cbfd98e..19fbd04 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "Inflector" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" + [[package]] name = "ahash" version = "0.3.8" @@ -183,6 +189,12 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "itoa" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" + [[package]] name = "js-sys" version = "0.3.55" @@ -242,7 +254,10 @@ dependencies = [ "chumsky", "maplit", "rpds", + "serde", + "serde_json", "thiserror", + "ts-rs", ] [[package]] @@ -321,12 +336,49 @@ dependencies = [ "archery", ] +[[package]] +name = "ryu" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" + [[package]] name = "scoped-tls" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +[[package]] +name = "serde" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.136" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" +dependencies = [ + "itoa", + "ryu", + "serde", +] + [[package]] name = "static_assertions" version = "1.1.0" @@ -394,6 +446,29 @@ dependencies = [ "crunchy", ] +[[package]] +name = "ts-rs" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d26cba30c9b3a2f537f765cf754126f11c983b7426d280ae0b4cef2374cab98" +dependencies = [ + "thiserror", + "ts-rs-macros", +] + +[[package]] +name = "ts-rs-macros" +version = "6.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd8e302fbcf5b60dfa1df443535967511442c5ce4eac8b4c9fa811f2274280a4" +dependencies = [ + "Inflector", + "proc-macro2", + "quote", + "syn", + "termcolor", +] + [[package]] name = "unicode-xid" version = "0.2.2" diff --git a/crates/percival-cli/src/main.rs b/crates/percival-cli/src/main.rs index 341955a..9a2b984 100644 --- a/crates/percival-cli/src/main.rs +++ b/crates/percival-cli/src/main.rs @@ -1,5 +1,6 @@ //! Crate containing code for the `percival-cli` binary. +use std::error::Error; use std::{ fs::read_to_string, io::{self, Read, Write}, @@ -7,9 +8,18 @@ use std::{ process::{self, Command, Stdio}, }; -use clap::Parser; +use clap::{ArgEnum, Parser}; -use percival::{codegen::compile, errors::format_errors, parser::Grammar}; +use percival::{ + codegen_js::compile as compile_js, codegen_json::compile as compile_json, + errors::format_errors, parser::Grammar, +}; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum, Debug)] +enum Emitter { + JS, + JSON, +} /// Convenience CLI for testing the Percival language compiler. #[derive(Parser, Debug)] @@ -22,6 +32,9 @@ struct Opt { /// Runs prettier and bat on the output. #[clap(short, long)] format: bool, + + #[clap(short, long, arg_enum, default_value_t = Emitter::JS)] + emit: Emitter, } /// Run the main program. @@ -49,7 +62,12 @@ fn main() { } }; - match compile(&prog) { + let emitted: Result> = match opt.emit { + Emitter::JS => compile_js(&prog).map_err(|err| err.into()), + Emitter::JSON => compile_json(&prog).map_err(|err| err.into()), + }; + + match emitted { Ok(js) => { if !opt.format { println!("{}", js); diff --git a/crates/percival-wasm/src/lib.rs b/crates/percival-wasm/src/lib.rs index 4b602c0..044dce1 100644 --- a/crates/percival-wasm/src/lib.rs +++ b/crates/percival-wasm/src/lib.rs @@ -36,7 +36,7 @@ pub fn compile(src: &str) -> CompilerResult { .parse(&src[..]) .map_err(|err| format_errors(&src[..], err)) .and_then(|prog| { - let js = codegen::compile(&prog) + let js = codegen_js::compile(&prog) .map_err(|err| format!("{} {}", Paint::red("Error:"), err))?; Ok((prog, js)) }) diff --git a/crates/percival/Cargo.toml b/crates/percival/Cargo.toml index b014188..8564817 100644 --- a/crates/percival/Cargo.toml +++ b/crates/percival/Cargo.toml @@ -9,6 +9,9 @@ ariadne = "0.1.3" chumsky = "0.7.0" rpds = "0.11.0" thiserror = "1.0.30" +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +ts-rs = "6.1" [dev-dependencies] maplit = "1.0.2" diff --git a/crates/percival/src/ast.rs b/crates/percival/src/ast.rs index b685f74..40bc906 100644 --- a/crates/percival/src/ast.rs +++ b/crates/percival/src/ast.rs @@ -1,9 +1,12 @@ //! Abstract syntax tree definitions for the Percival language. +use serde::Serialize; use std::collections::{BTreeMap, BTreeSet}; +use ts_rs::TS; /// A program translation unit in the Percival language. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub struct Program { /// Rules that make up the program. pub rules: Vec, @@ -12,7 +15,8 @@ pub struct Program { } /// Represents a single Horn clause. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub struct Rule { /// Head or implicand of the Horn clause. pub goal: Fact, @@ -21,7 +25,8 @@ pub struct Rule { } /// An element of the right-hand side of a rule. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub enum Clause { /// Relational assumption in the rule. Fact(Fact), @@ -32,7 +37,8 @@ pub enum Clause { } /// Literal part of a Horn clause, written in terms of relations. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub struct Fact { /// Name of the relation being referenced. pub name: String, @@ -41,7 +47,8 @@ pub struct Fact { } /// A bound or unbound value assigned to part of a relation. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub enum Value { /// A simple identifier, which can be either bound or unbound. Id(String), @@ -54,7 +61,8 @@ pub enum Value { } /// Literal values supported by the Percival grammar. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub enum Literal { /// A standard floating-point number literal. Number(String), @@ -65,7 +73,8 @@ pub enum Literal { } /// An aggregate operation over stratified dependency relations. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub struct Aggregate { /// Name of the aggregate operator, such as `min` or `sum`. pub operator: String, @@ -76,7 +85,8 @@ pub struct Aggregate { } /// An external import from a static JSON dataset. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] +#[ts(export)] pub struct Import { /// Name of the relation being imported. pub name: String, diff --git a/crates/percival/src/codegen.rs b/crates/percival/src/codegen_js.rs similarity index 100% rename from crates/percival/src/codegen.rs rename to crates/percival/src/codegen_js.rs diff --git a/crates/percival/src/codegen_json.rs b/crates/percival/src/codegen_json.rs new file mode 100644 index 0000000..7004833 --- /dev/null +++ b/crates/percival/src/codegen_json.rs @@ -0,0 +1,10 @@ +//! JSON AST emitter + +use serde_json::to_string_pretty; + +use crate::ast::Program; + +/// Generates a JSON representation of the program AST. +pub fn compile(prog: &Program) -> Result { + to_string_pretty(prog) +} diff --git a/crates/percival/src/lib.rs b/crates/percival/src/lib.rs index 9eb8d54..e831670 100644 --- a/crates/percival/src/lib.rs +++ b/crates/percival/src/lib.rs @@ -4,6 +4,7 @@ #![warn(missing_docs)] pub mod ast; -pub mod codegen; +pub mod codegen_js; +pub mod codegen_json; pub mod errors; pub mod parser; From 0140a7b281a7cae084a31bb4303759e10202a357 Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sun, 1 May 2022 08:55:56 -0700 Subject: [PATCH 02/10] Add AST emit to percival-wasm --- .gitignore | 3 +++ Cargo.lock | 2 ++ Makefile | 22 ++++++++++++++++++++++ crates/percival-wasm/Cargo.toml | 2 +- crates/percival-wasm/src/lib.rs | 18 +++++++++++++++++- crates/percival/src/codegen_json.rs | 2 +- package-lock.json | 1 + src/lib/runtime.ts | 3 +++ 8 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 Makefile diff --git a/.gitignore b/.gitignore index 8560ff9..d6aa7b7 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,6 @@ pkg/ /mocha-setup.js /test-loader.js /test.html + +# auto-generated AST typedefs +/crates/percival/bindings diff --git a/Cargo.lock b/Cargo.lock index 19fbd04..7fc82ff 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -494,6 +494,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "632f73e236b219150ea279196e54e610f5dbafa5d61786303d4da54f84e47fce" dependencies = [ "cfg-if", + "serde", + "serde_json", "wasm-bindgen-macro", ] diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fd3a517 --- /dev/null +++ b/Makefile @@ -0,0 +1,22 @@ +# Filetypes +RUST = $(shell find crates -name '*.rs') +PATCHES = $(shell find patches -name '*.patch') + +# Repeated paths +percival_wasm_pkg = crates/percival-wasm/pkg +percival_bindings = crates/percival/bindings + +node_modules: package.json package-lock.json $(PATCHES) $(percival_wasm_pkg) + npm install + +crates/percival-wasm/pkg: $(RUST) + # Build WASM + wasm-pack build --target web crates/percival-wasm + # Build AST types + cargo test ast::export_bindings + mkdir -p $(percival_wasm_pkg)/ast + for ts in $(percival_bindings)/* ; do \ + cp $$ts $(percival_wasm_pkg)/ast/"$$(basename "$${ts%.ts}.d.ts")" ; \ + done + # Patch WASM types to use AST types + sed -i '' -e 's~ast(): any~ast(): import("./ast/Program").Program | undefined~' $(percival_wasm_pkg)/percival_wasm.d.ts diff --git a/crates/percival-wasm/Cargo.toml b/crates/percival-wasm/Cargo.toml index 873baa1..26b66a6 100644 --- a/crates/percival-wasm/Cargo.toml +++ b/crates/percival-wasm/Cargo.toml @@ -13,7 +13,7 @@ default = ["console_error_panic_hook"] [dependencies] console_error_panic_hook = { version = "0.1", optional = true } percival = { path = "../percival" } -wasm-bindgen = "0.2" +wasm-bindgen = { version = "0.2", features = ["serde-serialize"] } yansi = "0.5.0" [dev-dependencies] diff --git a/crates/percival-wasm/src/lib.rs b/crates/percival-wasm/src/lib.rs index 044dce1..08b036d 100644 --- a/crates/percival-wasm/src/lib.rs +++ b/crates/percival-wasm/src/lib.rs @@ -5,7 +5,7 @@ use wasm_bindgen::prelude::*; use yansi::Paint; -use percival::{ast::Program, codegen, errors::format_errors, parser::Grammar}; +use percival::{ast::Program, codegen_js, errors::format_errors, parser::Grammar}; /// Set a panic listener to display better error messages. #[wasm_bindgen(start)] @@ -54,6 +54,22 @@ impl CompilerResult { self.0.as_ref().ok().map(|(_, js)| js.clone()) } + /// Returns the AST of the program's source. + pub fn ast(&self) -> JsValue { + self.0 + .as_ref() + .ok() + .map(|(prog, _)| match JsValue::from_serde(prog) { + Ok(ast) => ast, + Err(err) => { + // XX: wasm-bindgen claims to have errors, but doesn't + eprintln!("{} {}", Paint::red("Error:"), err); + JsValue::UNDEFINED + } + }) + .unwrap_or(JsValue::UNDEFINED) + } + /// Returns the names of relations that are dependencies of this program. pub fn deps(&self) -> Option> { self.0.as_ref().ok().map(|(prog, _)| { diff --git a/crates/percival/src/codegen_json.rs b/crates/percival/src/codegen_json.rs index 7004833..9ebf7b0 100644 --- a/crates/percival/src/codegen_json.rs +++ b/crates/percival/src/codegen_json.rs @@ -1,4 +1,4 @@ -//! JSON AST emitter +//! JSON AST emitter (is this really needed??) use serde_json::to_string_pretty; diff --git a/package-lock.json b/package-lock.json index c23714e..8806319 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,6 +58,7 @@ } }, "crates/percival-wasm/pkg": { + "name": "percival-wasm", "version": "0.1.0" }, "node_modules/@ampproject/remapping": { diff --git a/src/lib/runtime.ts b/src/lib/runtime.ts index 0770200..cd44991 100644 --- a/src/lib/runtime.ts +++ b/src/lib/runtime.ts @@ -1,4 +1,5 @@ import { compile } from "percival-wasm"; +import type { Program } from "percival-wasm/ast/Program"; import Worker from "./runtime.worker?worker&inline"; interface CancellablePromise extends Promise { @@ -12,6 +13,7 @@ type CompilerResultOk = { evaluate: (deps: Record) => EvalPromise; deps: string[]; results: string[]; + ast: Program | undefined; }; type CompilerResultErr = { @@ -51,6 +53,7 @@ export function build(src: string): CompilerResult { }, deps: result.deps()!, results: [...result.results()!], + ast: result.ast(), }; } else { return { ok: false, errors: result.err()! }; From 31bbc368112ca5ffc5da6429fdeb40d2f2fae3f5 Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sun, 1 May 2022 09:00:04 -0700 Subject: [PATCH 03/10] README: use make --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 590ba60..cc5dfc8 100644 --- a/README.md +++ b/README.md @@ -40,11 +40,12 @@ information below is technical documentation intended for contributors. Building Percival from scratch requires [Node v16+](https://nodejs.org/en/), [NPM v8+](https://www.npmjs.com/), [Rust 1.56+](https://www.rust-lang.org/), [Cargo](https://crates.io/), and -[Wasm-Pack](https://rustwasm.github.io/wasm-pack/) installed on your machine. To -build the Rust/WebAssembly portion of the project, use the command: +[Wasm-Pack](https://rustwasm.github.io/wasm-pack/) installed on your machine. + +To build the Rust/WebAssembly portion of the project, use the command: ```shell -wasm-pack build --target web crates/percival-wasm +make crates/percival-wasm/pkg ``` Next, run `npm install` to install JavaScript dependencies, then run the From 28d7feab0658ce54e874794b1e123defc5e64f53 Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sun, 1 May 2022 10:17:55 -0700 Subject: [PATCH 04/10] render AST when ?ast in URL --- package-lock.json | 11 ++++ package.json | 1 + src/components/cell/Cell.svelte | 4 ++ src/components/cell/CellOutput.svelte | 2 +- src/components/cell/output/ASTView.svelte | 68 +++++++++++++++++++++++ 5 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 src/components/cell/output/ASTView.svelte diff --git a/package-lock.json b/package-lock.json index 8806319..700089e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "remark-rehype": "^10.1.0", "svelte": "^3.46.6", "svelte-icons": "^2.1.0", + "svelte-json-tree": "^1.0.0", "unified": "^10.1.2" }, "devDependencies": { @@ -6129,6 +6130,11 @@ "resolved": "https://registry.npmjs.org/svelte-icons/-/svelte-icons-2.1.0.tgz", "integrity": "sha512-rHPQjweEc9fGSnvM0/4gA3pDHwyZyYsC5KhttCZRhSMJfLttJST5Uq0B16Czhw+HQ+HbSOk8kLigMlPs7gZtfg==" }, + "node_modules/svelte-json-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-json-tree/-/svelte-json-tree-1.0.0.tgz", + "integrity": "sha512-scs1OdkC8uFpTN4MX0yKkOzZ1/EG3eP1ARC+xcFthXp2IfcwBaXgab0FqA4Am0vQwffNNB+1Gd1LFkJBlynWTA==" + }, "node_modules/svelte-preprocess": { "version": "4.10.4", "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.4.tgz", @@ -11099,6 +11105,11 @@ "resolved": "https://registry.npmjs.org/svelte-icons/-/svelte-icons-2.1.0.tgz", "integrity": "sha512-rHPQjweEc9fGSnvM0/4gA3pDHwyZyYsC5KhttCZRhSMJfLttJST5Uq0B16Czhw+HQ+HbSOk8kLigMlPs7gZtfg==" }, + "svelte-json-tree": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/svelte-json-tree/-/svelte-json-tree-1.0.0.tgz", + "integrity": "sha512-scs1OdkC8uFpTN4MX0yKkOzZ1/EG3eP1ARC+xcFthXp2IfcwBaXgab0FqA4Am0vQwffNNB+1Gd1LFkJBlynWTA==" + }, "svelte-preprocess": { "version": "4.10.4", "resolved": "https://registry.npmjs.org/svelte-preprocess/-/svelte-preprocess-4.10.4.tgz", diff --git a/package.json b/package.json index 379028d..621df2b 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "remark-rehype": "^10.1.0", "svelte": "^3.46.6", "svelte-icons": "^2.1.0", + "svelte-json-tree": "^1.0.0", "unified": "^10.1.2" }, "devDependencies": { diff --git a/src/components/cell/Cell.svelte b/src/components/cell/Cell.svelte index f7d2142..8c8aa32 100644 --- a/src/components/cell/Cell.svelte +++ b/src/components/cell/Cell.svelte @@ -8,6 +8,7 @@ import type { CellState } from "@/lib/notebook"; import CellInput from "./CellInput.svelte"; import CellOutput from "./CellOutput.svelte"; +import AstView from "./output/ASTView.svelte"; const dispatch = createEventDispatcher(); @@ -35,6 +36,9 @@ + {#if state.type === "code" && state.result.ok} + + {/if} From e9ea4fad8c1a5bdc4f034b8330f7423a2d9e623f Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sun, 1 May 2022 10:18:43 -0700 Subject: [PATCH 05/10] show ast when ?debug --- src/components/cell/output/ASTView.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/cell/output/ASTView.svelte b/src/components/cell/output/ASTView.svelte index ddf420e..0f65395 100644 --- a/src/components/cell/output/ASTView.svelte +++ b/src/components/cell/output/ASTView.svelte @@ -8,7 +8,7 @@ import { onMount } from "svelte"; onMount(() => { const params = new URLSearchParams(window.location.search); - if (params.has('ast')) { + if (params.has('debug')) { showAst = true; } }) From 6fe8aa4e4343e24e2dd43ef49a1c0e072fe1417b Mon Sep 17 00:00:00 2001 From: infogulch Date: Fri, 6 May 2022 13:41:44 -0500 Subject: [PATCH 06/10] Prettier; move display logic into ASTView; display ASTView based on button; remove Makefile; document how to generate TS types in ast.rs --- .gitignore | 3 -- Makefile | 22 --------- README.md | 5 ++- crates/percival-cli/src/main.rs | 4 +- crates/percival/src/ast.rs | 10 +++++ src/components/cell/Cell.svelte | 22 +++++---- src/components/cell/CellOutput.svelte | 2 +- src/components/cell/output/ASTView.svelte | 54 +++++++++-------------- src/lib/notebook.ts | 2 + src/lib/runtime.ts | 3 +- 10 files changed, 55 insertions(+), 72 deletions(-) delete mode 100644 Makefile diff --git a/.gitignore b/.gitignore index d6aa7b7..8560ff9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,3 @@ pkg/ /mocha-setup.js /test-loader.js /test.html - -# auto-generated AST typedefs -/crates/percival/bindings diff --git a/Makefile b/Makefile deleted file mode 100644 index fd3a517..0000000 --- a/Makefile +++ /dev/null @@ -1,22 +0,0 @@ -# Filetypes -RUST = $(shell find crates -name '*.rs') -PATCHES = $(shell find patches -name '*.patch') - -# Repeated paths -percival_wasm_pkg = crates/percival-wasm/pkg -percival_bindings = crates/percival/bindings - -node_modules: package.json package-lock.json $(PATCHES) $(percival_wasm_pkg) - npm install - -crates/percival-wasm/pkg: $(RUST) - # Build WASM - wasm-pack build --target web crates/percival-wasm - # Build AST types - cargo test ast::export_bindings - mkdir -p $(percival_wasm_pkg)/ast - for ts in $(percival_bindings)/* ; do \ - cp $$ts $(percival_wasm_pkg)/ast/"$$(basename "$${ts%.ts}.d.ts")" ; \ - done - # Patch WASM types to use AST types - sed -i '' -e 's~ast(): any~ast(): import("./ast/Program").Program | undefined~' $(percival_wasm_pkg)/percival_wasm.d.ts diff --git a/README.md b/README.md index cc5dfc8..810fa54 100644 --- a/README.md +++ b/README.md @@ -40,12 +40,13 @@ information below is technical documentation intended for contributors. Building Percival from scratch requires [Node v16+](https://nodejs.org/en/), [NPM v8+](https://www.npmjs.com/), [Rust 1.56+](https://www.rust-lang.org/), [Cargo](https://crates.io/), and -[Wasm-Pack](https://rustwasm.github.io/wasm-pack/) installed on your machine. +[Wasm-Pack](https://rustwasm.github.io/wasm-pack/) installed on your machine. To +build the Rust/WebAssembly portion of the project, use the command: To build the Rust/WebAssembly portion of the project, use the command: ```shell -make crates/percival-wasm/pkg +wasm-pack build --target web crates/percival-wasm ``` Next, run `npm install` to install JavaScript dependencies, then run the diff --git a/crates/percival-cli/src/main.rs b/crates/percival-cli/src/main.rs index 9a2b984..9741ebf 100644 --- a/crates/percival-cli/src/main.rs +++ b/crates/percival-cli/src/main.rs @@ -18,7 +18,7 @@ use percival::{ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum, Debug)] enum Emitter { JS, - JSON, + Json, } /// Convenience CLI for testing the Percival language compiler. @@ -64,7 +64,7 @@ fn main() { let emitted: Result> = match opt.emit { Emitter::JS => compile_js(&prog).map_err(|err| err.into()), - Emitter::JSON => compile_json(&prog).map_err(|err| err.into()), + Emitter::Json => compile_json(&prog).map_err(|err| err.into()), }; match emitted { diff --git a/crates/percival/src/ast.rs b/crates/percival/src/ast.rs index 40bc906..d3eb1f3 100644 --- a/crates/percival/src/ast.rs +++ b/crates/percival/src/ast.rs @@ -1,5 +1,15 @@ //! Abstract syntax tree definitions for the Percival language. +// How to build AST types: +// +// cargo test ast::export_bindings +// mkdir -p $(percival_wasm_pkg)/ast +// for ts in $(percival_bindings)/* ; do \ +// cp $$ts $(percival_wasm_pkg)/ast/"$$(basename "$${ts%.ts}.d.ts")" ; \ +// done +// sed -i '' -e 's~ast(): any~ast(): import("./ast/Program").Program | undefined~' $(percival_wasm_pkg)/percival_wasm.d.ts +// + use serde::Serialize; use std::collections::{BTreeMap, BTreeSet}; use ts_rs::TS; diff --git a/src/components/cell/Cell.svelte b/src/components/cell/Cell.svelte index 8c8aa32..87d66d4 100644 --- a/src/components/cell/Cell.svelte +++ b/src/components/cell/Cell.svelte @@ -1,6 +1,7 @@ -{#if showAst && ast !== undefined} +{#if state.type === "code" && state.displayDebug && state.result.ok && state.result.ast !== undefined}
-
-
- AST - - := -
- {#key expandAll} - - {/key} +
+
+ AST + + :=
+ {#key expandAll} + + {/key} +
{/if} diff --git a/src/lib/notebook.ts b/src/lib/notebook.ts index 3e523e8..dd710d7 100644 --- a/src/lib/notebook.ts +++ b/src/lib/notebook.ts @@ -27,6 +27,7 @@ export type CellData = MarkdownCell | CodeCellData | PlotCellData; export type CodeCellState = CodeCellData & { result: CompilerResult; status: "stale" | "pending" | "done"; + displayDebug: boolean; output?: Record; graphErrors?: string; runtimeErrors?: string; @@ -97,6 +98,7 @@ export class NotebookState { ...cell, result: build(cell.value), status: "stale", + displayDebug: false, }); } else { this.cells.set(id, { diff --git a/src/lib/runtime.ts b/src/lib/runtime.ts index cd44991..1b6fae4 100644 --- a/src/lib/runtime.ts +++ b/src/lib/runtime.ts @@ -1,5 +1,4 @@ import { compile } from "percival-wasm"; -import type { Program } from "percival-wasm/ast/Program"; import Worker from "./runtime.worker?worker&inline"; interface CancellablePromise extends Promise { @@ -13,7 +12,7 @@ type CompilerResultOk = { evaluate: (deps: Record) => EvalPromise; deps: string[]; results: string[]; - ast: Program | undefined; + ast: any; }; type CompilerResultErr = { From 55ff95ad0ba0487f62234d069de1bcf0b2bf05af Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sat, 7 May 2022 14:14:14 -0700 Subject: [PATCH 07/10] slightly tighter type for ast --- src/lib/runtime.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/runtime.ts b/src/lib/runtime.ts index 1b6fae4..4734f7d 100644 --- a/src/lib/runtime.ts +++ b/src/lib/runtime.ts @@ -12,7 +12,7 @@ type CompilerResultOk = { evaluate: (deps: Record) => EvalPromise; deps: string[]; results: string[]; - ast: any; + ast: object | undefined; }; type CompilerResultErr = { From cd78df5519749a4fea8afd9c430435b83fb48a56 Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sat, 7 May 2022 14:32:10 -0700 Subject: [PATCH 08/10] undo codegen_js stuff --- crates/percival-cli/src/main.rs | 7 ++----- crates/percival-wasm/src/lib.rs | 4 ++-- crates/percival/src/ast.rs | 8 ++++++++ crates/percival/src/{codegen_js.rs => codegen.rs} | 0 crates/percival/src/codegen_json.rs | 10 ---------- crates/percival/src/lib.rs | 3 +-- 6 files changed, 13 insertions(+), 19 deletions(-) rename crates/percival/src/{codegen_js.rs => codegen.rs} (100%) delete mode 100644 crates/percival/src/codegen_json.rs diff --git a/crates/percival-cli/src/main.rs b/crates/percival-cli/src/main.rs index 9741ebf..f846006 100644 --- a/crates/percival-cli/src/main.rs +++ b/crates/percival-cli/src/main.rs @@ -10,10 +10,7 @@ use std::{ use clap::{ArgEnum, Parser}; -use percival::{ - codegen_js::compile as compile_js, codegen_json::compile as compile_json, - errors::format_errors, parser::Grammar, -}; +use percival::{codegen::compile as compile_js, errors::format_errors, parser::Grammar}; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ArgEnum, Debug)] enum Emitter { @@ -64,7 +61,7 @@ fn main() { let emitted: Result> = match opt.emit { Emitter::JS => compile_js(&prog).map_err(|err| err.into()), - Emitter::Json => compile_json(&prog).map_err(|err| err.into()), + Emitter::Json => prog.json().map_err(|err| err.into()), }; match emitted { diff --git a/crates/percival-wasm/src/lib.rs b/crates/percival-wasm/src/lib.rs index 08b036d..aad19b7 100644 --- a/crates/percival-wasm/src/lib.rs +++ b/crates/percival-wasm/src/lib.rs @@ -5,7 +5,7 @@ use wasm_bindgen::prelude::*; use yansi::Paint; -use percival::{ast::Program, codegen_js, errors::format_errors, parser::Grammar}; +use percival::{ast::Program, codegen, errors::format_errors, parser::Grammar}; /// Set a panic listener to display better error messages. #[wasm_bindgen(start)] @@ -36,7 +36,7 @@ pub fn compile(src: &str) -> CompilerResult { .parse(&src[..]) .map_err(|err| format_errors(&src[..], err)) .and_then(|prog| { - let js = codegen_js::compile(&prog) + let js = codegen::compile(&prog) .map_err(|err| format!("{} {}", Paint::red("Error:"), err))?; Ok((prog, js)) }) diff --git a/crates/percival/src/ast.rs b/crates/percival/src/ast.rs index d3eb1f3..5d6e955 100644 --- a/crates/percival/src/ast.rs +++ b/crates/percival/src/ast.rs @@ -11,6 +11,7 @@ // use serde::Serialize; +use serde_json::{to_string_pretty, Result as JsonResult}; use std::collections::{BTreeMap, BTreeSet}; use ts_rs::TS; @@ -24,6 +25,13 @@ pub struct Program { pub imports: Vec, } +impl Program { + /// Convert the program to a JSON string. + pub fn json(&self) -> JsonResult { + to_string_pretty(self) + } +} + /// Represents a single Horn clause. #[derive(Clone, Debug, PartialEq, Eq, Serialize, TS)] #[ts(export)] diff --git a/crates/percival/src/codegen_js.rs b/crates/percival/src/codegen.rs similarity index 100% rename from crates/percival/src/codegen_js.rs rename to crates/percival/src/codegen.rs diff --git a/crates/percival/src/codegen_json.rs b/crates/percival/src/codegen_json.rs deleted file mode 100644 index 9ebf7b0..0000000 --- a/crates/percival/src/codegen_json.rs +++ /dev/null @@ -1,10 +0,0 @@ -//! JSON AST emitter (is this really needed??) - -use serde_json::to_string_pretty; - -use crate::ast::Program; - -/// Generates a JSON representation of the program AST. -pub fn compile(prog: &Program) -> Result { - to_string_pretty(prog) -} diff --git a/crates/percival/src/lib.rs b/crates/percival/src/lib.rs index e831670..9eb8d54 100644 --- a/crates/percival/src/lib.rs +++ b/crates/percival/src/lib.rs @@ -4,7 +4,6 @@ #![warn(missing_docs)] pub mod ast; -pub mod codegen_js; -pub mod codegen_json; +pub mod codegen; pub mod errors; pub mod parser; From b6c8de2506b7eafb21bb010d76dd0029c4bfbf27 Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sat, 7 May 2022 14:33:16 -0700 Subject: [PATCH 09/10] ignore TS bindings files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 8560ff9..8444843 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,5 @@ pkg/ /mocha-setup.js /test-loader.js /test.html + +/crates/percival/bindings/ From 5632e3739105268877d4cdcc24c6d72a11dd9a18 Mon Sep 17 00:00:00 2001 From: Jake Teton-Landis Date: Sat, 7 May 2022 14:38:18 -0700 Subject: [PATCH 10/10] Revert README.md change --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 810fa54..590ba60 100644 --- a/README.md +++ b/README.md @@ -43,8 +43,6 @@ Building Percival from scratch requires [Node v16+](https://nodejs.org/en/), [Wasm-Pack](https://rustwasm.github.io/wasm-pack/) installed on your machine. To build the Rust/WebAssembly portion of the project, use the command: -To build the Rust/WebAssembly portion of the project, use the command: - ```shell wasm-pack build --target web crates/percival-wasm ```