Skip to content

Commit bb1e301

Browse files
committed
add unstable flags and move arith ops to it
1 parent 1c5db60 commit bb1e301

8 files changed

Lines changed: 215 additions & 34 deletions

File tree

examples/infix_operators.simf

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,26 @@ fn main() {
1212
let a: u8 = 20;
1313
let b: u8 = 6;
1414

15+
// run `simc` with `-Z infix_arithmetic_operators` to allow these.
1516
// Addition: u8 + u8 → u8, panics on overflow
16-
let sum: u8 = a + b;
17-
assert!(jet::eq_8(sum, 26));
17+
// let sum: u8 = a + b;
18+
// assert!(jet::eq_8(sum, 26));
1819

1920
// Subtraction: u8 - u8 → u8, panics on underflow
20-
let diff: u8 = a - b;
21-
assert!(jet::eq_8(diff, 14));
21+
// let diff: u8 = a - b;
22+
// assert!(jet::eq_8(diff, 14));
2223

2324
// Multiplication: u8 * u8 → u16 (full precision, no overflow possible)
24-
let product: u16 = a * b;
25-
assert!(jet::eq_16(product, 120));
25+
// let product: u16 = a * b;
26+
// assert!(jet::eq_16(product, 120));
2627

2728
// Division: u8 / u8 → u8, panics if divisor is zero
28-
let quotient: u8 = a / b;
29-
assert!(jet::eq_8(quotient, 3));
29+
// let quotient: u8 = a / b;
30+
// assert!(jet::eq_8(quotient, 3));
3031

3132
// Modulo: u8 % u8 → u8, panics if divisor is zero
32-
let remainder: u8 = a % b;
33-
assert!(jet::eq_8(remainder, 2));
33+
// let remainder: u8 = a % b;
34+
// assert!(jet::eq_8(remainder, 2));
3435

3536
// Equality: u8 == u8 → bool
3637
assert!(a == a); // 20 == 20 is true

src/lib.rs

Lines changed: 47 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ mod serde;
1717
pub mod str;
1818
pub mod tracker;
1919
pub mod types;
20+
pub mod unstable_flags;
2021
pub mod value;
2122
mod witness;
2223

@@ -34,6 +35,7 @@ use crate::debug::DebugSymbols;
3435
use crate::error::{ErrorCollector, WithFile};
3536
use crate::parse::ParseFromStrWithErrors;
3637
pub use crate::types::ResolvedType;
38+
pub use crate::unstable_flags::{UnstableFlags, with_flags};
3739
pub use crate::value::Value;
3840
pub use crate::witness::{Arguments, Parameters, WitnessTypes, WitnessValues};
3941

@@ -53,10 +55,17 @@ impl TemplateProgram {
5355
/// ## Errors
5456
///
5557
/// The string is not a valid SimplicityHL program.
56-
pub fn new<Str: Into<Arc<str>>>(s: Str, deny_all_warnings: bool) -> Result<Self, String> {
58+
pub fn new<Str: Into<Arc<str>>>(
59+
s: Str,
60+
deny_all_warnings: bool,
61+
flags: UnstableFlags,
62+
) -> Result<Self, String> {
5763
let file = s.into();
5864
let mut error_handler = ErrorCollector::new(Arc::clone(&file));
59-
let parse_program = parse::Program::parse_from_str_with_errors(&file, &mut error_handler);
65+
let parse_program =
66+
with_flags(flags, || {
67+
parse::Program::parse_from_str_with_errors(&file, &mut error_handler)
68+
});
6069
if let Some(program) = parse_program {
6170
let (ast_program, warnings) =
6271
ast::Program::analyze(&program).with_file(Arc::clone(&file))?;
@@ -199,8 +208,9 @@ impl CompiledProgram {
199208
arguments: Arguments,
200209
include_debug_symbols: bool,
201210
deny_all_warnings: bool,
211+
flags: UnstableFlags,
202212
) -> Result<Self, String> {
203-
TemplateProgram::new(s, deny_all_warnings)
213+
TemplateProgram::new(s, deny_all_warnings, flags)
204214
.and_then(|template| template.instantiate(arguments, include_debug_symbols))
205215
}
206216

@@ -285,9 +295,10 @@ impl SatisfiedProgram {
285295
witness_values: WitnessValues,
286296
include_debug_symbols: bool,
287297
deny_all_warnings: bool,
298+
flags: UnstableFlags,
288299
) -> Result<Self, String> {
289300
let compiled =
290-
CompiledProgram::new(s, arguments, include_debug_symbols, deny_all_warnings)?;
301+
CompiledProgram::new(s, arguments, include_debug_symbols, deny_all_warnings, flags)?;
291302
compiled.satisfy(witness_values)
292303
}
293304

@@ -390,7 +401,11 @@ pub(crate) mod tests {
390401
}
391402

392403
pub fn template_text(program_text: Cow<str>) -> Self {
393-
let program = match TemplateProgram::new(program_text.as_ref()) {
404+
Self::template_text_with_flags(program_text, UnstableFlags::new())
405+
}
406+
407+
pub fn template_text_with_flags(program_text: Cow<str>, flags: UnstableFlags) -> Self {
408+
let program = match TemplateProgram::new(program_text.as_ref(), false, flags) {
394409
Ok(x) => x,
395410
Err(error) => panic!("{error}"),
396411
};
@@ -731,6 +746,8 @@ fn main() {
731746
Arguments::default(),
732747
WitnessValues::default(),
733748
false,
749+
false,
750+
UnstableFlags::new(),
734751
) {
735752
Ok(_) => panic!("Accepted faulty program"),
736753
Err(error) => {
@@ -780,7 +797,13 @@ fn main() {
780797
.assert_run_success();
781798
}
782799

783-
// --- infix operator integration tests ---
800+
// --- infix operator integration tests (require -Z infix_arithmetic_operators) ---
801+
802+
fn arith_flags() -> UnstableFlags {
803+
let mut f = UnstableFlags::new();
804+
f.enable(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators);
805+
f
806+
}
784807

785808
#[test]
786809
fn infix_op_add_u8() {
@@ -790,7 +813,8 @@ fn main() {
790813
let (_, sum): (bool, u8) = a + b;
791814
assert!(jet::eq_8(sum, 19));
792815
}"#;
793-
TestCase::program_text(Cow::Borrowed(prog))
816+
TestCase::template_text_with_flags(Cow::Borrowed(prog), arith_flags())
817+
.with_arguments(Arguments::default())
794818
.with_witness_values(WitnessValues::default())
795819
.assert_run_success();
796820
}
@@ -803,7 +827,8 @@ fn main() {
803827
let (_, diff): (bool, u8) = a - b;
804828
assert!(jet::eq_8(diff, 13));
805829
}"#;
806-
TestCase::program_text(Cow::Borrowed(prog))
830+
TestCase::template_text_with_flags(Cow::Borrowed(prog), arith_flags())
831+
.with_arguments(Arguments::default())
807832
.with_witness_values(WitnessValues::default())
808833
.assert_run_success();
809834
}
@@ -816,7 +841,8 @@ fn main() {
816841
let product: u16 = a * b;
817842
assert!(jet::eq_16(product, 42));
818843
}"#;
819-
TestCase::program_text(Cow::Borrowed(prog))
844+
TestCase::template_text_with_flags(Cow::Borrowed(prog), arith_flags())
845+
.with_arguments(Arguments::default())
820846
.with_witness_values(WitnessValues::default())
821847
.assert_run_success();
822848
}
@@ -829,7 +855,8 @@ fn main() {
829855
let quotient: u8 = a / b;
830856
assert!(jet::eq_8(quotient, 5));
831857
}"#;
832-
TestCase::program_text(Cow::Borrowed(prog))
858+
TestCase::template_text_with_flags(Cow::Borrowed(prog), arith_flags())
859+
.with_arguments(Arguments::default())
833860
.with_witness_values(WitnessValues::default())
834861
.assert_run_success();
835862
}
@@ -842,7 +869,8 @@ fn main() {
842869
let remainder: u8 = a % b;
843870
assert!(jet::eq_8(remainder, 2));
844871
}"#;
845-
TestCase::program_text(Cow::Borrowed(prog))
872+
TestCase::template_text_with_flags(Cow::Borrowed(prog), arith_flags())
873+
.with_arguments(Arguments::default())
846874
.with_witness_values(WitnessValues::default())
847875
.assert_run_success();
848876
}
@@ -856,7 +884,14 @@ fn main() {
856884
let sum: u8 = a + b;
857885
assert!(jet::eq_8(sum, 3));
858886
}"#;
859-
match SatisfiedProgram::new(prog, Arguments::default(), WitnessValues::default(), false) {
887+
match SatisfiedProgram::new(
888+
prog,
889+
Arguments::default(),
890+
WitnessValues::default(),
891+
false,
892+
false,
893+
arith_flags(),
894+
) {
860895
Ok(_) => panic!("Expected type error for `+` with plain u8 output"),
861896
Err(error) => assert!(
862897
error.contains("Expected expression of type"),

src/main.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ use base64::display::Base64Display;
22
use base64::engine::general_purpose::STANDARD;
33
use clap::{Arg, ArgAction, Command};
44

5-
use simplicityhl::{AbiMeta, TemplateProgram};
5+
use simplicityhl::{AbiMeta, TemplateProgram, UnstableFlags};
6+
use simplicityhl::unstable_flags::UnstableFlag;
67
use std::{env, fmt};
78

89
#[cfg_attr(feature = "serde", derive(serde::Serialize))]
@@ -89,6 +90,16 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
8990
.action(ArgAction::SetTrue)
9091
.help("Treat warnings as errors"),
9192
)
93+
.arg(
94+
Arg::new("unstable_flags")
95+
.short('Z')
96+
.value_name("FLAG")
97+
.action(ArgAction::Append)
98+
.help(
99+
"Enable an unstable feature flag (can be passed multiple times). \
100+
Known flags: infix_arithmetic_operators",
101+
),
102+
)
92103
};
93104

94105
let matches = command.get_matches();
@@ -120,7 +131,22 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
120131
};
121132

122133
let deny_warnings = matches.get_flag("deny_warnings");
123-
let template = match TemplateProgram::new(prog_text, deny_warnings) {
134+
135+
let mut flags = UnstableFlags::new();
136+
for flag_str in matches
137+
.get_many::<String>("unstable_flags")
138+
.unwrap_or_default()
139+
{
140+
match flag_str.parse::<UnstableFlag>() {
141+
Ok(flag) => flags.enable(flag),
142+
Err(e) => {
143+
eprintln!("error: {e}");
144+
std::process::exit(1);
145+
}
146+
}
147+
}
148+
149+
let template = match TemplateProgram::new(prog_text, deny_warnings, flags) {
124150
Ok(t) => t,
125151
Err(e) => {
126152
eprintln!("{}", e);

src/parse.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1706,11 +1706,11 @@ impl SingleExpression {
17061706
.map(|es| SingleExpressionInner::Expression(Arc::from(es)));
17071707

17081708
let op = select! {
1709-
Token::Plus => InfixOp::Add,
1710-
Token::Minus => InfixOp::Sub,
1711-
Token::Star => InfixOp::Mul,
1712-
Token::Slash => InfixOp::Div,
1713-
Token::Percent => InfixOp::Rem,
1709+
Token::Plus if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Add,
1710+
Token::Minus if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Sub,
1711+
Token::Star if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Mul,
1712+
Token::Slash if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Div,
1713+
Token::Percent if crate::unstable_flags::is_enabled(crate::unstable_flags::UnstableFlag::InfixArithmeticOperators) => InfixOp::Rem,
17141714
Token::EqEq => InfixOp::Eq,
17151715
Token::BangEq => InfixOp::Ne,
17161716
Token::LAngle => InfixOp::Lt,

src/tracker.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -472,7 +472,7 @@ mod tests {
472472

473473
#[test]
474474
fn test_debug_and_jet_tracing() {
475-
let program = TemplateProgram::new(TEST_PROGRAM).unwrap();
475+
let program = TemplateProgram::new(TEST_PROGRAM, false, crate::UnstableFlags::new()).unwrap();
476476
let program = program.instantiate(Arguments::default(), true).unwrap();
477477
let satisfied = program.satisfy(WitnessValues::default()).unwrap();
478478

@@ -541,7 +541,7 @@ mod tests {
541541
fn test_arith_jet_trace_regression() {
542542
let env = create_test_env();
543543

544-
let program = TemplateProgram::new(TEST_ARITHMETIC_JETS).unwrap();
544+
let program = TemplateProgram::new(TEST_ARITHMETIC_JETS, false, crate::UnstableFlags::new()).unwrap();
545545
let program = program.instantiate(Arguments::default(), true).unwrap();
546546
let satisfied = program.satisfy(WitnessValues::default()).unwrap();
547547

0 commit comments

Comments
 (0)