Skip to content
Open
Show file tree
Hide file tree
Changes from all 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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
# Unreleased

* Remove ModuleProgram and the parsing of Arguments and Witnesses from the core compiler [#323](https://github.com/BlockstreamResearch/SimplicityHL/pull/323)

# 0.6.0-rc.0 - 2026-04-24

* Add imports and dependency resolution, including `pub`/`use` syntax, re-exports, aliases, transitive dependencies, collision diagnostics, functional tests, examples, and `simc --dep` for compiling multi-file programs. [#264](https://github.com/BlockstreamResearch/SimplicityHL/pull/264)
Expand Down
7 changes: 0 additions & 7 deletions fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,6 @@ test = false
doc = false
bench = false

[[bin]]
name = "parse_witness_module_rtt"
path = "fuzz_targets/parse_witness_module_rtt.rs"
test = false
doc = false
bench = false

[[bin]]
name = "reconstruct_value"
path = "fuzz_targets/reconstruct_value.rs"
Expand Down
17 changes: 0 additions & 17 deletions fuzz/fuzz_targets/parse_witness_json_rtt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,3 @@ fn main() {}

#[cfg(fuzzing)]
libfuzzer_sys::fuzz_target!(|data: simplicityhl::WitnessValues| do_test(data));

#[cfg(test)]
mod test {
use simplicityhl::{parse::ParseFromStr, WitnessValues};
#[test]
fn test() {
let witness_text = r#"mod witness {
const A: u32 = 1;
const B: u32 = 2;
const C: u32 = 3;
}"#;

let witness_values = WitnessValues::parse_from_str(witness_text)
.expect("parsing of valid string should work");
super::do_test(witness_values);
}
}
38 changes: 0 additions & 38 deletions fuzz/fuzz_targets/parse_witness_module_rtt.rs

This file was deleted.

1 change: 0 additions & 1 deletion justfile
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ check_fuzz:
just fuzz display_parse_tree
just fuzz parse_value_rtt
just fuzz parse_witness_json_rtt
just fuzz parse_witness_module_rtt
just fuzz reconstruct_value

# Build fuzz tests
Expand Down
68 changes: 1 addition & 67 deletions src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::types::{
AliasedType, ResolvedType, StructuralType, TypeConstructible, TypeDeconstructible, UIntType,
};
use crate::value::{UIntValue, Value};
use crate::witness::{Parameters, WitnessTypes, WitnessValues};
use crate::witness::{Parameters, WitnessTypes};
use crate::{driver, impl_eq_hash, parse};

/// A program consists of the main function.
Expand Down Expand Up @@ -1568,72 +1568,6 @@ impl AbstractSyntaxTree for Match {
}
}

fn analyze_named_module(
name: ModuleName,
from: &parse::ModuleProgram,
) -> Result<HashMap<WitnessName, Value>, RichError> {
let unit = ResolvedType::unit();

// IMPORTANT! If modules allow imports, then we need to consider
// passing the resolution conetxt by calling `Scope::new(resolutions)`
let mut scope = Scope::default();
let items = from
.items()
.iter()
.map(|s| ModuleItem::analyze(s, &unit, &mut scope))
.collect::<Result<Vec<ModuleItem>, RichError>>()?;
debug_assert!(scope.is_topmost());
let mut iter = items.into_iter().filter_map(|item| match item {
ModuleItem::Module(module) if module.name == name => Some(module),
_ => None,
});
let Some(witness_module) = iter.next() else {
return Ok(HashMap::new()); // "not present" is equivalent to empty
};
if iter.next().is_some() {
return Err(Error::ModuleRedefined(name)).with_span(from);
}
let mut map = HashMap::new();
for assignment in witness_module.assignments() {
if map.contains_key(assignment.name()) {
return Err(Error::WitnessReassigned(assignment.name().shallow_clone()))
.with_span(assignment);
}
map.insert(
assignment.name().shallow_clone(),
assignment.value().clone(),
);
}
Ok(map)
}

impl WitnessValues {
pub fn analyze(from: &parse::ModuleProgram) -> Result<Self, RichError> {
analyze_named_module(ModuleName::witness(), from).map(Self::from)
}
}

impl crate::witness::Arguments {
pub fn analyze(from: &parse::ModuleProgram) -> Result<Self, RichError> {
analyze_named_module(ModuleName::param(), from).map(Self::from)
}
}

impl AbstractSyntaxTree for ModuleItem {
type From = parse::ModuleItem;

fn analyze(from: &Self::From, ty: &ResolvedType, scope: &mut Scope) -> Result<Self, RichError> {
assert!(ty.is_unit(), "Items cannot return anything");
assert!(scope.is_topmost(), "Items live in the topmost scope only");
match from {
parse::ModuleItem::Ignored => Ok(Self::Ignored),
parse::ModuleItem::Module(witness_module) => {
Module::analyze(witness_module, ty, scope).map(Self::Module)
}
}
}
}

impl AbstractSyntaxTree for Module {
type From = parse::Module;

Expand Down
60 changes: 0 additions & 60 deletions src/parse.rs
Original file line number Diff line number Diff line change
Expand Up @@ -617,34 +617,6 @@ impl MatchPattern {
}
}

/// Program root when parsing modules.
#[derive(Clone, Debug)]
pub struct ModuleProgram {
items: Arc<[ModuleItem]>,
span: Span,
}

impl ModuleProgram {
/// Access the items of the program.
pub fn items(&self) -> &[ModuleItem] {
&self.items
}

/// Access the span of the program.
pub fn span(&self) -> &Span {
&self.span
}
}

impl_eq_hash!(ModuleProgram; items);

/// Item when parsing modules.
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ModuleItem {
Ignored,
Module(Module),
}

#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub struct Module {
name: ModuleName,
Expand Down Expand Up @@ -2091,32 +2063,6 @@ impl Match {
}
}

impl ChumskyParse for ModuleItem {
fn parser<'tokens, 'src: 'tokens, I>() -> impl Parser<'tokens, I, Self, ParseError<'src>> + Clone
where
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
{
let module = Module::parser().map(Self::Module);

module
}
}

impl ChumskyParse for ModuleProgram {
fn parser<'tokens, 'src: 'tokens, I>() -> impl Parser<'tokens, I, Self, ParseError<'src>> + Clone
where
I: ValueInput<'tokens, Token = Token<'src>, Span = Span>,
{
ModuleItem::parser()
.repeated()
.collect::<Vec<_>>()
.map_with(|items, e| Self {
items: Arc::from(items),
span: e.span(),
})
}
}

impl ChumskyParse for Module {
fn parser<'tokens, 'src: 'tokens, I>() -> impl Parser<'tokens, I, Self, ParseError<'src>> + Clone
where
Expand Down Expand Up @@ -2227,12 +2173,6 @@ impl AsRef<Span> for Match {
}
}

impl AsRef<Span> for ModuleProgram {
fn as_ref(&self) -> &Span {
&self.span
}
}

impl AsRef<Span> for Module {
fn as_ref(&self) -> &Span {
&self.span
Expand Down
29 changes: 0 additions & 29 deletions src/witness.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ use std::fmt;
use std::sync::Arc;

use crate::error::{Error, RichError, WithContent, WithSpan};
use crate::parse;
use crate::parse::ParseFromStr;
use crate::str::WitnessName;
use crate::types::{AliasedType, ResolvedType};
Expand Down Expand Up @@ -67,12 +66,6 @@ macro_rules! impl_name_value_map {
}
}

impl ParseFromStr for $wrapper {
fn parse_from_str(s: &str) -> Result<Self, RichError> {
parse::ModuleProgram::parse_from_str(s).and_then(|x| Self::analyze(&x))
}
}

impl fmt::Display for $wrapper {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
use itertools::Itertools;
Expand Down Expand Up @@ -284,28 +277,6 @@ fn main() {
}
}

#[test]
fn missing_witness_module() {
match WitnessValues::parse_from_str("") {
Ok(v) => assert!(
v.iter().next().is_none(),
"empty witness module was parsed as nonempty"
),
Err(error) => panic!("Missing witness module was falsely rejected: {error}"),
}
}

#[test]
fn redefined_witness_module() {
let s = r#"mod witness {} mod witness {}"#;
match WitnessValues::parse_from_str(s) {
Ok(_) => panic!("Redefined witness module was falsely accepted"),
Err(error) => assert!(error
.to_string()
.contains("Module `witness` is defined twice")),
}
}

#[test]
fn witness_to_string() {
let witness = WitnessValues::from(HashMap::from([
Expand Down
Loading