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
39 changes: 39 additions & 0 deletions silverscript-lang/src/ast/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,13 @@ impl<'i> Expr<'i> {
Self::new(ExprKind::Array(value.into_iter().map(Expr::byte).collect()), Span::default())
}

pub fn bool_array(value: Vec<bool>) -> Self {
Self::new(
ExprKind::Array(value.into_iter().map(Expr::bool).collect()),
Span::default(),
)
}

pub fn string(value: impl Into<String>) -> Self {
Self::new(ExprKind::String(value.into()), Span::default())
}
Expand Down Expand Up @@ -579,6 +586,12 @@ impl<'i> From<Vec<u8>> for Expr<'i> {
}
}

impl<'i> From<Vec<bool>> for Expr<'i> {
fn from(value: Vec<bool>) -> Self {
Expr::bool_array(value)
}
}

impl<'i> From<String> for Expr<'i> {
fn from(value: String) -> Self {
Expr::string(value)
Expand Down Expand Up @@ -2591,3 +2604,29 @@ fn parse_identifier<'i>(pair: Pair<'i, Rule>) -> Result<Identifier<'i>, Compiler

Ok(Identifier { name: value, span })
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn bool_array_helper_builds_expr_array() {
let expr = Expr::bool_array(vec![true, false, true]);
if let ExprKind::Array(items) = expr.kind {
assert_eq!(items.len(), 3);
if let ExprKind::Bool(b) = items[0].kind {
assert!(b);
} else {
panic!("expected Bool");
}
} else {
panic!("expected Array");
}
}

#[test]
fn from_vec_bool_impl_works() {
let _expr: Expr = vec![true, false].into();
let _expr2: Expr = Expr::from(vec![false, true, false]);
}
}
19 changes: 19 additions & 0 deletions silverscript-lang/src/compiler/compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -516,6 +516,9 @@ fn fixed_type_size(type_ref: &TypeRef) -> Option<i64> {
if elem_type.is_int() {
return Some((size * 8) as i64);
}
if elem_type.is_bool() {
return Some(size as i64);
}
}
return None;
}
Expand Down Expand Up @@ -3839,6 +3842,22 @@ mod tests {

use super::{Op0, OpPushData1, OpPushData2, StackBindings, data_prefix, eval_const_int};

#[test]
fn fixed_type_size_accepts_bool_array() {
use crate::ast::TypeRef;
use crate::ast::TypeBase;
use crate::ast::ArrayDim;
// bool[2] → Some(2) (1 byte per element)
let bool2 = TypeRef { base: TypeBase::Bool, array_dims: vec![ArrayDim::Fixed(2)] };
assert_eq!(super::fixed_type_size(&bool2), Some(2));
// bool[4] → Some(4)
let bool4 = TypeRef { base: TypeBase::Bool, array_dims: vec![ArrayDim::Fixed(4)] };
assert_eq!(super::fixed_type_size(&bool4), Some(4));
// scalar bool → Some(1)
let bool_scalar = TypeRef { base: TypeBase::Bool, array_dims: vec![] };
assert_eq!(super::fixed_type_size(&bool_scalar), Some(1));
}

#[test]
fn data_prefix_encodes_small_pushes() {
assert_eq!(data_prefix(0), vec![Op0]);
Expand Down
38 changes: 38 additions & 0 deletions silverscript-lang/tests/compiler_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5467,6 +5467,28 @@ fn compiles_validate_output_state_to_expected_script() {
assert_eq!(compiled.script, expected);
}

#[test]
fn compiles_validate_output_state_with_bool_array_field() {
let source = r#"
contract C(bool[2] initW) {
bool[2] w = initW;

entrypoint function main() {
validateOutputState(0, { w: w });
}
}
"#;

let compiled = compile_contract(
source,
&[vec![Expr::bool(true), Expr::bool(false)].into()],
CompileOptions::default(),
)
.expect("bool[2] field ref in validateOutputState should compile");
// Verify script is non-empty (compilation produced output)
assert!(!compiled.script.is_empty(), "compiled script must not be empty");
}

#[test]
fn runs_validate_output_state() {
let source = r#"
Expand Down Expand Up @@ -11225,3 +11247,19 @@ fn blake3_with_key_requires_a_fixed_32_byte_key() {
let err = compile_contract(numeric_data, &[], CompileOptions::default()).expect_err("numeric Blake3 data should be rejected");
assert!(err.to_string().contains("argument 'data' expects byte[], got int"), "unexpected error: {err}");
}

#[test]
fn compiles_validate_output_state_with_bool_array_literal() {
let source = r#"
contract C(bool[2] initW) {
bool[2] w = initW;
entrypoint function main() {
validateOutputState(0, { w: initW });
}
}
"#;
let result = compile_contract(source, &[vec![true, false].into()], CompileOptions::default());
if let Err(ref e) = result {
panic!("compile failed: {e}");
}
}