Skip to content

Commit 5c250a4

Browse files
committed
Merge #160: update rust-simplicity to 0.6 and release SimplicityHL 0.3
f76810c bump version to 0.3.0 (Andrew Poelstra) f7c24df update rust-simplictiy to 0.6 (Andrew Poelstra) 2f41378 stick invariant <'brand> tag onto Scope and CoreExt (Andrew Poelstra) Pull request description: Should unblock #158 and also let us update the webide. ACKs for top commit: delta1: ACK f76810c Tree-SHA512: 03ac177a925e91007ae9e72d1bd0c6af3d0ce2b8fe2dd8b2fbfcd8efdfa78578670df7c3943b21d25d51b34f21f901feab35dfa6ffbeee4c9ac3529e94c3016c
2 parents 31c1ee8 + f76810c commit 5c250a4

File tree

8 files changed

+140
-85
lines changed

8 files changed

+140
-85
lines changed

CHANGELOG.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,16 @@
1+
# 0.3.0 - 2025-11-04
2+
3+
* Add `array_fold` builtin function [#145](https://github.com/BlockstreamResearch/SimplicityHL/pull/145)
4+
* Add getters for `Span` and improve error handling [#146](https://github.com/BlockstreamResearch/SimplicityHL/pull/146)
5+
* Add VSCode extension with LSP support
6+
[#148](https://github.com/BlockstreamResearch/SimplicityHL/pull/148)
7+
[#149](https://github.com/BlockstreamResearch/SimplicityHL/pull/149)
8+
* Switch NUMS key to BIP-0341 suggested key [#143](https://github.com/BlockstreamResearch/SimplicityHL/pull/143)
9+
* Fix `array_fold` powers-of-two bug; fix simc CLI when serde is disabled; enable serde by default [#159](https://github.com/BlockstreamResearch/SimplicityHL/pull/159)
10+
* Update rust-simplicity to 0.6
11+
[#143](https://github.com/BlockstreamResearch/SimplicityHL/pull/143)
12+
[#160](https://github.com/BlockstreamResearch/SimplicityHL/pull/160)
13+
114
# 0.2.0 - 2025-07-29
215

316
* Renamed from [Simfony](https://crates.io/crates/simfony)

Cargo.lock

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

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "simplicityhl"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
authors = ["sanket1729 <[email protected]>"]
55
license = "CC0-1.0"
66
homepage = "https://github.com/BlockstreamResearch/SimplicityHL"
@@ -27,7 +27,7 @@ pest = "2.1.3"
2727
pest_derive = "2.7.1"
2828
serde = { version = "1.0.188", features = ["derive"], optional = true }
2929
serde_json = { version = "1.0.105", optional = true }
30-
simplicity-lang = { version = "0.5.0" }
30+
simplicity-lang = { version = "0.6.0" }
3131
miniscript = "12.3.1"
3232
either = "1.12.0"
3333
itertools = "0.13.0"

src/compile/builtins.rs

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,12 +15,15 @@ use crate::named::CoreExt;
1515
/// The fold `(fold f)_n : E^n × A → A`
1616
/// takes the array of type `E^n` and an initial accumulator of type `A`,
1717
/// and it produces the final accumulator of type `A`.
18-
pub fn array_fold(size: NonZeroUsize, f: &ProgNode) -> Result<ProgNode, simplicity::types::Error> {
18+
pub fn array_fold<'brand>(
19+
size: NonZeroUsize,
20+
f: &ProgNode<'brand>,
21+
) -> Result<ProgNode<'brand>, simplicity::types::Error> {
1922
/// Recursively fold the array using the precomputed folding functions.
20-
fn tree_fold(
23+
fn tree_fold<'brand>(
2124
n: usize,
22-
f_powers_of_two: &[ProgNode],
23-
) -> Result<ProgNode, simplicity::types::Error> {
25+
f_powers_of_two: &[ProgNode<'brand>],
26+
) -> Result<ProgNode<'brand>, simplicity::types::Error> {
2427
// Array is a left-balanced (right-associative) binary tree.
2528
let max_pow2 = n.ilog2() as usize;
2629
debug_assert!(max_pow2 < f_powers_of_two.len());
@@ -38,10 +41,10 @@ pub fn array_fold(size: NonZeroUsize, f: &ProgNode) -> Result<ProgNode, simplici
3841
}
3942

4043
/// Fold the two arrays applying the folding function sequentially left -> right.
41-
fn f_array_fold(
42-
f_left: &ProgNode,
43-
f_right: &ProgNode,
44-
) -> Result<ProgNode, simplicity::types::Error> {
44+
fn f_array_fold<'brand>(
45+
f_left: &ProgNode<'brand>,
46+
f_right: &ProgNode<'brand>,
47+
) -> Result<ProgNode<'brand>, simplicity::types::Error> {
4548
// The input is a tuple ((L, R), acc): ([E; n], A) where:
4649
// - L and R are arrays of varying size E^x and E^y respectively (x + y = n).
4750
// - acc is an accumulator of type A.

src/compile/mod.rs

Lines changed: 65 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use std::sync::Arc;
77
use either::Either;
88
use simplicity::jet::Elements;
99
use simplicity::node::{CoreConstructible as _, JetConstructible as _};
10-
use simplicity::{Cmr, FailEntropy};
10+
use simplicity::{types, Cmr, FailEntropy};
1111

1212
use self::builtins::array_fold;
1313
use crate::array::{BTreeSlice, Partition};
@@ -26,7 +26,7 @@ use crate::value::StructuralValue;
2626
use crate::witness::Arguments;
2727
use crate::Value;
2828

29-
type ProgNode = Arc<named::ConstructNode<Elements>>;
29+
type ProgNode<'brand> = Arc<named::ConstructNode<'brand, Elements>>;
3030

3131
/// Each SimplicityHL expression expects an _input value_.
3232
/// A SimplicityHL expression is translated into a Simplicity expression
@@ -39,7 +39,7 @@ type ProgNode = Arc<named::ConstructNode<Elements>>;
3939
/// Bindings from inner scopes overwrite bindings from outer scopes.
4040
/// Bindings live as long as their scope.
4141
#[derive(Debug, Clone)]
42-
struct Scope {
42+
struct Scope<'brand> {
4343
/// For each scope, the set of assigned variables.
4444
///
4545
/// A stack of scopes. Each scope is a stack of patterns.
@@ -66,15 +66,15 @@ struct Scope {
6666
/// Later assignments occur higher in the tree than earlier assignments.
6767
/// ```
6868
variables: Vec<Vec<Pattern>>,
69-
ctx: simplicity::types::Context,
69+
ctx: simplicity::types::Context<'brand>,
7070
/// Tracker of function calls.
7171
call_tracker: Arc<CallTracker>,
7272
/// Values for parameters inside the SimplicityHL program.
7373
arguments: Arguments,
7474
include_debug_symbols: bool,
7575
}
7676

77-
impl Scope {
77+
impl<'brand> Scope<'brand> {
7878
/// Create the main scope.
7979
///
8080
/// _This function should be called at the start of the compilation and then never again._
@@ -84,13 +84,14 @@ impl Scope {
8484
/// The supplied `arguments` are consistent with the program's parameters.
8585
/// Call [`Arguments::is_consistent`] before calling this method!
8686
pub fn new(
87+
ctx: simplicity::types::Context<'brand>,
8788
call_tracker: Arc<CallTracker>,
8889
arguments: Arguments,
8990
include_debug_symbols: bool,
9091
) -> Self {
9192
Self {
9293
variables: vec![vec![Pattern::Ignore]],
93-
ctx: simplicity::types::Context::new(),
94+
ctx,
9495
call_tracker,
9596
arguments,
9697
include_debug_symbols,
@@ -183,12 +184,12 @@ impl Scope {
183184
/// ```
184185
///
185186
/// The expression `drop (IOH & OH)` returns the seeked value.
186-
pub fn get(&self, target: &BasePattern) -> Option<PairBuilder<ProgNode>> {
187+
pub fn get(&self, target: &BasePattern) -> Option<PairBuilder<ProgNode<'brand>>> {
187188
BasePattern::from(&self.get_input_pattern()).translate(&self.ctx, target)
188189
}
189190

190191
/// Access the Simplicity type inference context.
191-
pub fn ctx(&self) -> &simplicity::types::Context {
192+
pub fn ctx(&self) -> &simplicity::types::Context<'brand> {
192193
&self.ctx
193194
}
194195

@@ -200,10 +201,10 @@ impl Scope {
200201
/// for debug symbols will simply ignore it. The semantics of the program remain unchanged.
201202
pub fn with_debug_symbol<S: AsRef<Span>>(
202203
&mut self,
203-
args: PairBuilder<ProgNode>,
204-
body: &ProgNode,
204+
args: PairBuilder<ProgNode<'brand>>,
205+
body: &ProgNode<'brand>,
205206
span: &S,
206-
) -> Result<PairBuilder<ProgNode>, RichError> {
207+
) -> Result<PairBuilder<ProgNode<'brand>>, RichError> {
207208
match self.call_tracker.get_cmr(span.as_ref()) {
208209
Some(cmr) if self.include_debug_symbols => {
209210
let false_and_args = ProgNode::bit(self.ctx(), false).pair(args);
@@ -221,12 +222,12 @@ impl Scope {
221222
}
222223
}
223224

224-
fn compile_blk(
225+
fn compile_blk<'brand>(
225226
stmts: &[Statement],
226-
scope: &mut Scope,
227+
scope: &mut Scope<'brand>,
227228
index: usize,
228229
last_expr: Option<&Expression>,
229-
) -> Result<PairBuilder<ProgNode>, RichError> {
230+
) -> Result<PairBuilder<ProgNode<'brand>>, RichError> {
230231
if index >= stmts.len() {
231232
return match last_expr {
232233
Some(expr) => expr.compile(scope),
@@ -263,22 +264,28 @@ impl Program {
263264
arguments: Arguments,
264265
include_debug_symbols: bool,
265266
) -> Result<Arc<named::CommitNode<Elements>>, RichError> {
266-
let mut scope = Scope::new(
267-
Arc::clone(self.call_tracker()),
268-
arguments,
269-
include_debug_symbols,
270-
);
271-
272-
let main = self.main();
273-
let construct = main.compile(&mut scope).map(PairBuilder::build)?;
274-
// SimplicityHL types should be correct by construction. If not, assign the
275-
// whole main function as the span for them, which is as sensible as anything.
276-
named::finalize_types(&construct).with_span(main)
267+
types::Context::with_context(|ctx| {
268+
let mut scope = Scope::new(
269+
ctx,
270+
Arc::clone(self.call_tracker()),
271+
arguments,
272+
include_debug_symbols,
273+
);
274+
275+
let main = self.main();
276+
let construct = main.compile(&mut scope).map(PairBuilder::build)?;
277+
// SimplicityHL types should be correct by construction. If not, assign the
278+
// whole main function as the span for them, which is as sensible as anything.
279+
named::finalize_types(&construct).with_span(main)
280+
})
277281
}
278282
}
279283

280284
impl Expression {
281-
fn compile(&self, scope: &mut Scope) -> Result<PairBuilder<ProgNode>, RichError> {
285+
fn compile<'brand>(
286+
&self,
287+
scope: &mut Scope<'brand>,
288+
) -> Result<PairBuilder<ProgNode<'brand>>, RichError> {
282289
match self.inner() {
283290
ExpressionInner::Block(stmts, expr) => {
284291
scope.push_scope();
@@ -292,7 +299,10 @@ impl Expression {
292299
}
293300

294301
impl SingleExpression {
295-
fn compile(&self, scope: &mut Scope) -> Result<PairBuilder<ProgNode>, RichError> {
302+
fn compile<'brand>(
303+
&self,
304+
scope: &mut Scope<'brand>,
305+
) -> Result<PairBuilder<ProgNode<'brand>>, RichError> {
296306
let expr = match self.inner() {
297307
SingleExpressionInner::Constant(value) => {
298308
let value = StructuralValue::from(value);
@@ -360,7 +370,10 @@ impl SingleExpression {
360370
}
361371

362372
impl Call {
363-
fn compile(&self, scope: &mut Scope) -> Result<PairBuilder<ProgNode>, RichError> {
373+
fn compile<'brand>(
374+
&self,
375+
scope: &mut Scope<'brand>,
376+
) -> Result<PairBuilder<ProgNode<'brand>>, RichError> {
364377
let args_ast = SingleExpression::tuple(self.args().clone(), *self.as_ref());
365378
let args = args_ast.compile(scope)?;
366379

@@ -453,8 +466,13 @@ impl Call {
453466
/// The fold `(fold f)_n : E^(<2^n) × A → A`
454467
/// takes the list of type `E^(<2^n)` and an initial accumulator of type `A`,
455468
/// and it produces the final accumulator of type `A`.
456-
fn list_fold(bound: NonZeroPow2Usize, f: &ProgNode) -> Result<ProgNode, simplicity::types::Error> {
457-
fn next_f_array(f_array: &ProgNode) -> Result<ProgNode, simplicity::types::Error> {
469+
fn list_fold<'brand>(
470+
bound: NonZeroPow2Usize,
471+
f: &ProgNode<'brand>,
472+
) -> Result<ProgNode<'brand>, simplicity::types::Error> {
473+
fn next_f_array<'brand>(
474+
f_array: &ProgNode<'brand>,
475+
) -> Result<ProgNode<'brand>, simplicity::types::Error> {
458476
/* f_(n + 1) : E^(2^(n + 1)) × A → A
459477
* f_(n + 1) := OIH ▵ (OOH ▵ IH; f_n); f_n
460478
*/
@@ -464,10 +482,10 @@ fn list_fold(bound: NonZeroPow2Usize, f: &ProgNode) -> Result<ProgNode, simplici
464482
let half2_acc = ProgNode::o().i().h(ctx).pair(updated_acc);
465483
half2_acc.comp(f_array).map(PairBuilder::build)
466484
}
467-
fn next_f_fold(
468-
f_array: &ProgNode,
469-
f_fold: &ProgNode,
470-
) -> Result<ProgNode, simplicity::types::Error> {
485+
fn next_f_fold<'brand>(
486+
f_array: &ProgNode<'brand>,
487+
f_fold: &ProgNode<'brand>,
488+
) -> Result<ProgNode<'brand>, simplicity::types::Error> {
471489
/* (fold f)_(n + 1) : E<2^(n + 1) × A → A
472490
* (fold f)_(n + 1) := OOH ▵ (OIH ▵ IH);
473491
* case (drop (fold f)_n)
@@ -525,16 +543,18 @@ fn list_fold(bound: NonZeroPow2Usize, f: &ProgNode) -> Result<ProgNode, simplici
525543
/// In this case, the loop continues without returning anything.
526544
/// The loop returns the final iterator after the final iteration
527545
/// if `f` never returned a successful output.
528-
fn for_while(
546+
fn for_while<'brand>(
529547
bit_width: Pow2Usize,
530-
f: PairBuilder<ProgNode>,
531-
) -> Result<PairBuilder<ProgNode>, simplicity::types::Error> {
548+
f: PairBuilder<ProgNode<'brand>>,
549+
) -> Result<PairBuilder<ProgNode<'brand>>, simplicity::types::Error> {
532550
/* for_while_0 f : E × A → A
533551
* for_while_0 f := (OH ▵ (IH ▵ false); f) ▵ IH;
534552
* case (injl OH)
535553
* (OH ▵ (IH ▵ true); f)
536554
*/
537-
fn for_while_0(f: &ProgNode) -> Result<PairBuilder<ProgNode>, simplicity::types::Error> {
555+
fn for_while_0<'brand>(
556+
f: &ProgNode<'brand>,
557+
) -> Result<PairBuilder<ProgNode<'brand>>, simplicity::types::Error> {
538558
let ctx = f.inference_context();
539559
let f_output = ProgNode::o()
540560
.h(ctx)
@@ -557,7 +577,9 @@ fn for_while(
557577
* where
558578
* f : A × (C × 2^(2^(n + 1))) → B + A
559579
*/
560-
fn adapt_f(f: &ProgNode) -> Result<PairBuilder<ProgNode>, simplicity::types::Error> {
580+
fn adapt_f<'brand>(
581+
f: &ProgNode<'brand>,
582+
) -> Result<PairBuilder<ProgNode<'brand>>, simplicity::types::Error> {
561583
let ctx = f.inference_context();
562584
let f_input = ProgNode::o().h(ctx).pair(
563585
ProgNode::i()
@@ -626,7 +648,10 @@ fn for_while(
626648
}
627649

628650
impl Match {
629-
fn compile(&self, scope: &mut Scope) -> Result<PairBuilder<ProgNode>, RichError> {
651+
fn compile<'brand>(
652+
&self,
653+
scope: &mut Scope<'brand>,
654+
) -> Result<PairBuilder<ProgNode<'brand>>, RichError> {
630655
scope.push_scope();
631656
scope.insert(
632657
self.left()

0 commit comments

Comments
 (0)