Skip to content

Commit 1d4cfaa

Browse files
committed
Merge #251: Move jets documentation inside compiler
57597c7 add README.md to `codegen` crate (Volodymyr Herashchenko) 03bc3c7 implement clap parser for codegen and json generation (Volodymyr Herashchenko) 2ea3a12 add dependencies for codegen binary (Volodymyr Herashchenko) f8f7163 add helpers for Jet documentation (Volodymyr Herashchenko) 5d0e9d2 docs: fix typos in jet documentation (Volodymyr Herashchenko) 3a71244 move jet documentation to SimplicityHL (Volodymyr Herashchenko) Pull request description: Right now we have 3 different sources in which we are getting information about Jet: LSP, `codegen` crate (which would generate modules for [SimplicityHL-as-Rust](https://github.com/BlockstreamResearch/SimplicityHL-as-rust)) and [simplicity-lang-org](https://github.com/BlockstreamResearch/simplicity-lang-org). This PR moves Jet documentation from `codegen` crate to SimplicityHL compiler, which is gated behind `docs` feature. Also, I had added `codegen` executable to be distributed alongside with `simplicityhl` crate, also gated behind `docs` feature. This executable supports old behavior of generating modules, and also extends to generating JSON file with jet documentation (see BlockstreamResearch/simplicity-lang-org#42 for more context). There are launch instructions in codegen/README.md. In future, I would like to add `JetInfo` as a trait for `Jet`, after [this issue](#224) resolved, so it could also load in runtime jets documentation. ACKs for top commit: apoelstra: ACK 57597c7; successfully ran local tests KyrylR: ACK 57597c7; code review Tree-SHA512: ff171e55477c841517e0449ccbe42313029c7ddb29f7cc469ccdfec168f77d17824382111a38de3cba35f02f55dd771224aa566814e4ff98152c53e1281fa109
2 parents 77a9f5e + 57597c7 commit 1d4cfaa

8 files changed

Lines changed: 272 additions & 67 deletions

File tree

Cargo.lock

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ repository = "https://github.com/BlockstreamResearch/SimplicityHL"
88
description = "Rust-like language that compiles to Simplicity bytecode."
99
edition = "2021"
1010
rust-version = "1.79.0"
11+
default-run = "simc"
1112

1213
[lib]
1314
name = "simplicityhl"
@@ -17,9 +18,15 @@ path = "src/lib.rs"
1718
name = "simc"
1819
path = "src/main.rs"
1920

21+
[[bin]]
22+
name = "simplicityhl-codegen"
23+
path = "codegen/src/main.rs"
24+
required-features = ["docs", "serde"]
25+
2026
[features]
2127
default = [ "serde" ]
2228
serde = ["dep:serde", "dep:serde_json"]
29+
docs = []
2330

2431
[dependencies]
2532
base64 = "0.21.2"

codegen/Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,8 @@ description = "Generator of Rust code as interface between SimplicityHL and Rust
66
publish = false
77

88
[dependencies]
9-
simplicityhl = { path = ".." }
9+
simplicityhl = { path = ".." , features = ["docs"]}
10+
11+
serde = { version = "1.0.188", features = ["derive"]}
12+
serde_json = { version = "1.0.105"}
13+
clap = "4.5.37"

codegen/README.md

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Code and documentation generation
2+
3+
## Generate Rust code
4+
5+
Generate Rust modules, like in this [repository](https://github.com/BlockstreamResearch/SimplicityHL-as-rust):
6+
7+
```bash
8+
cargo run --bin codegen -- modules --out-dir modules/
9+
```
10+
11+
## Generate Jet documentation in a JSON file
12+
13+
Generate JSON file containing jet information:
14+
15+
```bash
16+
cargo run --bin codegen -- docs elements.json
17+
```
18+
19+
This JSON file contains an array of jets, each of which includes the following information:
20+
- "haskell_name" -- The name of the jet used in the Haskell and Rust code.
21+
- "simplicityhl_name" -- The name of the jet as it is used in SimplicityHL.
22+
- "section" -- The category to which the jet belongs.
23+
- "input_type" -- The input types represented as a vector of `AliasedType`s in SimplicityHL, separated by comma.
24+
- "output_type" -- The output type represented as an `AliasedType` in SimplicityHL.
25+
- "description" -- A description of the jet's functionality.
26+
- "deprecated" (optional) -- Indicates if jet is deprecated.
27+
28+
> [!NOTE]
29+
> Structure of generated JSON similar to file in [`simplicity-lang-org`](https://github.com/BlockstreamResearch/simplicity-lang-org/blob/28c67437c6cef3b111339443293a672d237d72a3/jets.json) repo, but it contains only array, without an object `elements` above.
30+
31+
## Installation
32+
33+
Install `simplicityhl` via `cargo` with `docs` feature -- `simplicityhl-codegen` would be installed alongside `simc`:
34+
35+
```bash
36+
cargo install simplicityhl --features docs
37+
```
38+
39+
Or install from local repository:
40+
41+
```bash
42+
cargo install --path ./ --features docs
43+
```

codegen/src/main.rs

Lines changed: 110 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,30 @@
1-
use std::fs::File;
1+
use std::fs::{self, File};
22
use std::io;
3+
use std::path::PathBuf;
34

5+
use clap::{Arg, Command};
6+
use serde::Serialize;
7+
8+
use simplicityhl::docs::jet;
9+
use simplicityhl::docs::jet::JetInfo;
410
use simplicityhl::simplicity::jet::{Elements, Jet};
511
use simplicityhl::types::TypeDeconstructible;
612

7-
mod jet;
13+
#[derive(Serialize)]
14+
struct JetObject {
15+
pub haskell_name: String,
16+
pub simplicityhl_name: String,
17+
pub section: String,
18+
pub input_type: String,
19+
pub output_type: String,
20+
pub description: String,
21+
#[serde(skip_serializing_if = "std::ops::Not::not")]
22+
pub deprecated: bool,
23+
}
824

925
/// Write a SimplicityHL jet as a Rust function to the sink.
1026
fn write_jet<W: io::Write>(jet: Elements, w: &mut W) -> io::Result<()> {
11-
for line in jet::documentation(jet).lines() {
27+
for line in jet.documentation().lines() {
1228
match line.is_empty() {
1329
true => writeln!(w, "///")?,
1430
false => writeln!(w, "/// {line}")?,
@@ -49,20 +65,108 @@ fn write_module<W: io::Write>(category: jet::Category, w: &mut W) -> io::Result<
4965
writeln!(w)?;
5066
writeln!(w, "use super::*;")?;
5167

52-
for jet in category.iter().cloned() {
68+
for jet in category.iter().copied() {
5369
writeln!(w)?;
5470
write_jet(jet, w)?;
5571
}
5672

5773
Ok(())
5874
}
5975

60-
fn main() -> io::Result<()> {
76+
/// Generate Rust modules divided by category.
77+
fn generate_modules(out_dir: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
78+
fs::create_dir_all(&out_dir)?;
79+
6180
for category in jet::Category::ALL {
6281
let file_name = format!("{category}.rs");
63-
let mut file = File::create(file_name)?;
82+
let file_path = out_dir.join(file_name);
83+
let mut file = File::create(&file_path)?;
6484
write_module(category, &mut file)?;
6585
}
6686

87+
println!(
88+
"Successfully generated Rust modules in: {}",
89+
out_dir.display()
90+
);
91+
Ok(())
92+
}
93+
94+
/// Generate JSON file with jet documentation.
95+
fn generate_docs(output_path: PathBuf) -> Result<(), Box<dyn std::error::Error>> {
96+
let generated_elements: Vec<JetObject> = jet::Category::ALL
97+
.into_iter()
98+
.flat_map(|category| {
99+
let section_name = category.to_pretty_string();
100+
101+
category
102+
.iter()
103+
.map(move |&jet| JetObject {
104+
haskell_name: format!("{:?}", jet),
105+
simplicityhl_name: jet.to_string(),
106+
section: section_name.clone(),
107+
input_type: simplicityhl::jet::source_type(jet)
108+
.iter()
109+
.map(|ty| ty.to_string())
110+
.collect::<Vec<_>>()
111+
.join(", "),
112+
output_type: simplicityhl::jet::target_type(jet).to_string(),
113+
description: jet.documentation().to_string(),
114+
deprecated: jet.is_deprecated(),
115+
})
116+
.collect::<Vec<_>>()
117+
})
118+
.collect();
119+
120+
let json_string = serde_json::to_string_pretty(&generated_elements)?
121+
// Replacing Rust documentation links to render normally in MarkDown.
122+
.replace("[`", "`")
123+
.replace("`]", "`");
124+
125+
fs::write(&output_path, json_string)?;
126+
127+
println!("Successfully wrote JSON data to: {}", output_path.display());
128+
129+
Ok(())
130+
}
131+
132+
fn main() -> Result<(), Box<dyn std::error::Error>> {
133+
let matches = Command::new("simplicityhl-gen")
134+
.about("Generates SimplicityHL Rust modules and JSON documentation for jets")
135+
.subcommand_required(true)
136+
.arg_required_else_help(true)
137+
.subcommand(
138+
Command::new("modules")
139+
.about("Generates SimplicityHL jets as Rust modules")
140+
.arg(
141+
Arg::new("out_dir")
142+
.short('o')
143+
.long("out-dir")
144+
.default_value(".")
145+
.help("Optional directory to output the .rs files (defaults to current directory)"),
146+
),
147+
)
148+
.subcommand(
149+
Command::new("docs")
150+
.about("Generates SimplicityHL documentation for jets as a JSON file")
151+
.arg(
152+
Arg::new("output_path")
153+
.required(true)
154+
.help("Path to write the JSON documentation file"),
155+
),
156+
)
157+
.get_matches();
158+
159+
match matches.subcommand() {
160+
Some(("modules", sub_matches)) => {
161+
let out_dir = sub_matches.get_one::<String>("out_dir").unwrap();
162+
generate_modules(PathBuf::from(out_dir))?;
163+
}
164+
Some(("docs", sub_matches)) => {
165+
let output_path = sub_matches.get_one::<String>("output_path").unwrap();
166+
generate_docs(PathBuf::from(output_path))?;
167+
}
168+
_ => unreachable!("Exhausted list of subcommands and subcommand_required is true"),
169+
}
170+
67171
Ok(())
68172
}

0 commit comments

Comments
 (0)