Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debug button to show Datalog AST #16

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ pkg/
/mocha-setup.js
/test-loader.js
/test.html

# auto-generated AST typedefs
/crates/percival/bindings
77 changes: 77 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -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
infogulch marked this conversation as resolved.
Show resolved Hide resolved
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 21 additions & 3 deletions crates/percival-cli/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
//! Crate containing code for the `percival-cli` binary.

use std::error::Error;
use std::{
fs::read_to_string,
io::{self, Read, Write},
path::PathBuf,
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)]
Expand All @@ -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.
Expand Down Expand Up @@ -49,7 +62,12 @@ fn main() {
}
};

match compile(&prog) {
let emitted: Result<String, Box<dyn Error>> = 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);
Expand Down
2 changes: 1 addition & 1 deletion crates/percival-wasm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
20 changes: 18 additions & 2 deletions crates/percival-wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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))
})
Expand All @@ -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<Vec<JsValue>> {
self.0.as_ref().ok().map(|(prog, _)| {
Expand Down
3 changes: 3 additions & 0 deletions crates/percival/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
26 changes: 18 additions & 8 deletions crates/percival/src/ast.rs
Original file line number Diff line number Diff line change
@@ -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<Rule>,
Expand All @@ -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,
Expand All @@ -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),
Expand All @@ -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,
Expand All @@ -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),
Expand All @@ -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),
Expand All @@ -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,
Expand All @@ -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,
Expand Down
File renamed without changes.
10 changes: 10 additions & 0 deletions crates/percival/src/codegen_json.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//! 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<String, serde_json::Error> {
to_string_pretty(prog)
}
3 changes: 2 additions & 1 deletion crates/percival/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Loading