Skip to content

Commit

Permalink
Merge pull request #100 from Chia-Network/20240706-modern-quotes
Browse files Browse the repository at this point in the history
Change how string output is generated for atoms and strings
  • Loading branch information
prozacchiwawa authored Jul 18, 2024
2 parents 6ed6ee8 + 2208228 commit cfe3f04
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 4 deletions.
20 changes: 20 additions & 0 deletions resources/tests/test_string_repr.clsp
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
;;
;; This program is used by the test_quote_string_generation test
;; which checks the representation of these outputs and ensures
;; that they're properly accepted by brun, which uses the classic
;; chialisp tokenizer/parser.
;;
;; the qs macro appends the given string onto "test"
;; the atom macro gives a quoted atom starting with test and
;; ending with the text given in the string.
;;
;; modern's macro system makes these different objects.
;;
(mod ()
(include *standard-cl-23*)

(defmac qs (X) (string-append "test" X))
(defmac atom (X) (c 1 (string->symbol (string-append "test" X))))

(list (qs '"') (qs "'") (qs " hi") (atom '"') (atom "'") (atom "_hi"))
)
8 changes: 5 additions & 3 deletions src/compiler/sexp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,9 +372,11 @@ pub fn decode_string(v: &[u8]) -> String {

pub fn printable(a: &[u8], quoted: bool) -> bool {
!a.iter().any(|ch| {
(*ch as char).is_control()
|| !(*ch as char).is_ascii()
|| (!quoted && ch.is_ascii_whitespace())
*ch < 32
|| *ch > 126
|| (!quoted && ((*ch as char).is_ascii_whitespace() || *ch == b'\''))
|| *ch == b'"'
|| *ch == b'\\'
})
}

Expand Down
35 changes: 35 additions & 0 deletions src/tests/classic/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2429,6 +2429,41 @@ fn test_assign_cse_tricky_2() {
assert_eq!(program, wanted_repr);
}

#[test]
fn test_quote_string_generation() {
// The program run here produces a list of strings and quoted atoms that have
// representations that must be flattened in various ways in this test.
let filename = "resources/tests/test_string_repr.clsp";
let program = do_basic_run(&vec!["run".to_string(), filename.to_string()])
.trim()
.to_string();
// The proram produces this list
// (list (qs '"') (qs "'") (qs " hi") (atom '"') (atom "'") (atom "_hi"))
//
// where qs puts "test" in front of the given string and atom puts test in front of the
// given string, converts it to an atom and quotes it so that it won't be interpreted
// as an identifier.
//
// in other words
// (list 'test"' "test'" "test hi"
// (q . (string->symbol (string-append "test" '"')))
// (q . (string->symbol (string-append "test" "'")))
// (q . test_hi)
// )
//
// The result below shows that the strings and atoms are reproduced as expected.
let wanted_repr = "(4 (1 . 0x7465737422) (4 (1 . \"test'\") (4 (1 . \"test hi\") (4 (1 . 499918271522) (4 (1 . 499918271527) (4 (1 . test_hi) ()))))))";
assert_eq!(program, wanted_repr);
let brun_result = do_basic_brun(&vec!["brun".to_string(), program])
.trim()
.to_string();
// This shows that brun interpreted and passed through the values successfully.
assert_eq!(
brun_result,
"(0x7465737422 \"test'\" \"test hi\" 0x7465737422 \"test'\" \"test_hi\")"
);
}

#[test]
fn test_classic_modpow() {
let result = do_basic_brun(&vec![
Expand Down
81 changes: 80 additions & 1 deletion src/tests/compiler/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,20 @@ use std::rc::Rc;
use clvm_rs::allocator::Allocator;

use crate::classic::clvm::__type_compatibility__::bi_one;
use crate::classic::clvm_tools::binutils::disassemble;
use crate::classic::clvm_tools::stages::stage_0::DefaultProgramRunner;
use crate::compiler::clvm::run;
use crate::compiler::compiler::{compile_file, DefaultCompilerOpts};
use crate::compiler::comptypes::{CompileErr, CompilerOpts};
use crate::compiler::dialect::AcceptedDialect;
use crate::compiler::dialect::{AcceptedDialect, KNOWN_DIALECTS};
use crate::compiler::frontend::{collect_used_names_sexp, frontend};
use crate::compiler::rename::rename_in_cons;
use crate::compiler::runtypes::RunFailure;
use crate::compiler::sexp::{decode_string, enlist, parse_sexp, SExp};
use crate::compiler::srcloc::Srcloc;

use crate::tests::classic::run::do_basic_brun;

const TEST_TIMEOUT: usize = 1000000;

fn compile_string(content: &String) -> Result<String, CompileErr> {
Expand Down Expand Up @@ -2449,6 +2452,82 @@ fn test_almost_empty_lambda_gives_error() {
assert!(format!("{res:?}").contains("Must provide at least arguments and body to lambda"));
}

#[test]
fn test_exhaustive_chars() {
// Verify that we can create a program that gives the expected output using
// every byte value in the first, mid and last position of a value.
let mut substitute = vec![b'x', b'x', b'x'];

let srcloc = Srcloc::start("*extest*");
let make_test_program = |sub: Rc<SExp>| {
// (mod () (include *standard-cl-23.1*) (q . <sub>))
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Atom(srcloc.clone(), b"mod".to_vec())),
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Nil(srcloc.clone())),
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Atom(srcloc.clone(), b"include".to_vec())),
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Atom(srcloc.clone(), b"*standard-cl-23.1*".to_vec())),
Rc::new(SExp::Nil(srcloc.clone())),
)),
)),
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Cons(
srcloc.clone(),
Rc::new(SExp::Integer(srcloc.clone(), bi_one())),
sub,
)),
Rc::new(SExp::Nil(srcloc.clone())),
)),
)),
)),
))
};

let runner = Rc::new(DefaultProgramRunner::new());

for i in 0..=2 {
for j in 0..=255 {
substitute[i] = j;

let sub_qe = Rc::new(SExp::QuotedString(srcloc.clone(), b'"', substitute.clone()));

let mut allocator = Allocator::new();
let mut opts: Rc<dyn CompilerOpts> = Rc::new(DefaultCompilerOpts::new("*extest*"));
let dialect = KNOWN_DIALECTS["*standard-cl-23.1*"].accepted.clone();
opts = opts.set_dialect(dialect);

let compiled = opts
.compile_program(
&mut allocator,
runner.clone(),
make_test_program(sub_qe),
&mut HashMap::new(),
)
.expect("should compile");

let compiled_output = compiled.to_string();
let result = do_basic_brun(&vec!["brun".to_string(), compiled_output])
.trim()
.to_string();

let classic_atom = allocator.new_atom(&substitute).expect("should work");
let disassembled = disassemble(&mut allocator, classic_atom, None);
assert_eq!(result, disassembled);

substitute[i] = b'x';
}
}
}

#[test]
fn test_odd_hex_works() {
let res = run_string(
Expand Down

0 comments on commit cfe3f04

Please sign in to comment.